what doesnt do anything must go
that sounds like someone
This commit is contained in:
@@ -100,7 +100,7 @@ wakey-control-plane state-stats
|
|||||||
List/revoke enroll tokens from CLI:
|
List/revoke enroll tokens from CLI:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wakey-control-plane list-enroll-tokens --include-expired
|
wakey-control-plane list-enroll-tokens
|
||||||
wakey-control-plane revoke-enroll-token --token enr-...
|
wakey-control-plane revoke-enroll-token --token enr-...
|
||||||
wakey-control-plane revoke-agent --agent-id agent-...
|
wakey-control-plane revoke-agent --agent-id agent-...
|
||||||
```
|
```
|
||||||
@@ -108,7 +108,7 @@ wakey-control-plane revoke-agent --agent-id agent-...
|
|||||||
Machine-readable output is available:
|
Machine-readable output is available:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wakey-control-plane list-enroll-tokens --include-expired --json
|
wakey-control-plane list-enroll-tokens --json
|
||||||
wakey-control-plane state-stats --json
|
wakey-control-plane state-stats --json
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ During daemon control/state operations:
|
|||||||
Control-plane admin API includes token management endpoints:
|
Control-plane admin API includes token management endpoints:
|
||||||
|
|
||||||
- `POST /api/v1/control/enroll-token?ttl_seconds=<n>`
|
- `POST /api/v1/control/enroll-token?ttl_seconds=<n>`
|
||||||
- `GET /api/v1/control/enroll-tokens?include_expired=true|false`
|
- `GET /api/v1/control/enroll-tokens`
|
||||||
- `DELETE /api/v1/control/enroll-tokens/{token}`
|
- `DELETE /api/v1/control/enroll-tokens/{token}`
|
||||||
- `GET /api/v1/control/audit/events?agent_id=<id>&event_type=<type>&limit=<n>`
|
- `GET /api/v1/control/audit/events?agent_id=<id>&event_type=<type>&limit=<n>`
|
||||||
- `GET /api/v1/control/alerts?lookback_seconds=900`
|
- `GET /api/v1/control/alerts?lookback_seconds=900`
|
||||||
|
|||||||
+2
-6
@@ -111,12 +111,8 @@ export function fetchAudit(limit = 50): Promise<AuditEvent[]> {
|
|||||||
return request<AuditEvent[]>(`/api/v1/control/audit/events?limit=${limit}`);
|
return request<AuditEvent[]>(`/api/v1/control/audit/events?limit=${limit}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchEnrollTokens(
|
export function fetchEnrollTokens(): Promise<EnrollTokenStatus[]> {
|
||||||
includeExpired = false,
|
return request<EnrollTokenStatus[]>(`/api/v1/control/enroll-tokens`);
|
||||||
): Promise<EnrollTokenStatus[]> {
|
|
||||||
return request<EnrollTokenStatus[]>(
|
|
||||||
`/api/v1/control/enroll-tokens?include_expired=${includeExpired ? "true" : "false"}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function issueEnrollToken(
|
export function issueEnrollToken(
|
||||||
|
|||||||
@@ -10,13 +10,6 @@ import { Badge } from "@/components/ui/badge";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
|
|
||||||
function formatUnix(unix: number): string {
|
function formatUnix(unix: number): string {
|
||||||
return new Date(unix * 1000).toLocaleString();
|
return new Date(unix * 1000).toLocaleString();
|
||||||
@@ -24,7 +17,6 @@ function formatUnix(unix: number): string {
|
|||||||
|
|
||||||
export function TokensPage() {
|
export function TokensPage() {
|
||||||
const [tokens, setTokens] = useState<EnrollTokenStatus[]>([]);
|
const [tokens, setTokens] = useState<EnrollTokenStatus[]>([]);
|
||||||
const [includeExpired, setIncludeExpired] = useState(false);
|
|
||||||
const [ttlSeconds, setTtlSeconds] = useState("86400");
|
const [ttlSeconds, setTtlSeconds] = useState("86400");
|
||||||
const [status, setStatus] = useState("");
|
const [status, setStatus] = useState("");
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
@@ -39,7 +31,7 @@ export function TokensPage() {
|
|||||||
setBusy(true);
|
setBusy(true);
|
||||||
setError("");
|
setError("");
|
||||||
try {
|
try {
|
||||||
const next = await fetchEnrollTokens(includeExpired);
|
const next = await fetchEnrollTokens();
|
||||||
setTokens(next);
|
setTokens(next);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(String(err));
|
setError(String(err));
|
||||||
@@ -85,7 +77,7 @@ export function TokensPage() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void load();
|
void load();
|
||||||
}, [includeExpired]);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="grid gap-3 xl:grid-cols-2">
|
<section className="grid gap-3 xl:grid-cols-2">
|
||||||
@@ -102,21 +94,6 @@ export function TokensPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-3">
|
<CardContent className="space-y-3">
|
||||||
<label className="grid gap-1 text-sm text-muted-foreground">
|
|
||||||
<span>Include expired</span>
|
|
||||||
<Select
|
|
||||||
value={includeExpired ? "yes" : "no"}
|
|
||||||
onValueChange={(value) => setIncludeExpired(value === "yes")}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Choose option" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="no">No</SelectItem>
|
|
||||||
<SelectItem value="yes">Yes</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</label>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{activeCount} active, {tokens.length} shown
|
{activeCount} active, {tokens.length} shown
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ pub struct IssueEnrollTokenQuery {
|
|||||||
pub ttl_seconds: Option<u64>,
|
pub ttl_seconds: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct ListEnrollTokenQuery {
|
|
||||||
pub include_expired: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct EnrollTokenStatus {
|
pub struct EnrollTokenStatus {
|
||||||
pub enroll_token: String,
|
pub enroll_token: String,
|
||||||
@@ -200,10 +195,8 @@ pub async fn issue_enroll_token(
|
|||||||
|
|
||||||
pub async fn list_enroll_tokens(
|
pub async fn list_enroll_tokens(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Query(query): Query<ListEnrollTokenQuery>,
|
|
||||||
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
||||||
let include_expired = query.include_expired.unwrap_or(false);
|
match state.store.list_enroll_tokens().await {
|
||||||
match state.store.list_enroll_tokens(include_expired).await {
|
|
||||||
Ok(tokens) => {
|
Ok(tokens) => {
|
||||||
if let Err(err) = state
|
if let Err(err) = state
|
||||||
.store
|
.store
|
||||||
@@ -217,7 +210,6 @@ pub async fn list_enroll_tokens(
|
|||||||
latency_ms: None,
|
latency_ms: None,
|
||||||
message: "listed enroll tokens".into(),
|
message: "listed enroll tokens".into(),
|
||||||
metadata: serde_json::json!({
|
metadata: serde_json::json!({
|
||||||
"include_expired": include_expired,
|
|
||||||
"count": tokens.len(),
|
"count": tokens.len(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -160,9 +160,6 @@ pub struct ListEnrollTokensArgs {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub public_url: Option<String>,
|
pub public_url: Option<String>,
|
||||||
|
|
||||||
#[arg(long)]
|
|
||||||
pub include_expired: bool,
|
|
||||||
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub json: bool,
|
pub json: bool,
|
||||||
|
|
||||||
|
|||||||
@@ -74,10 +74,7 @@ pub async fn issue_enroll_token(args: IssueEnrollTokenArgs) -> Result<()> {
|
|||||||
pub async fn list_enroll_tokens(args: ListEnrollTokensArgs) -> Result<()> {
|
pub async fn list_enroll_tokens(args: ListEnrollTokensArgs) -> Result<()> {
|
||||||
let settings = config::resolve_list_enroll_token_settings(&args)?;
|
let settings = config::resolve_list_enroll_token_settings(&args)?;
|
||||||
if let Some(base) = settings.public_url.as_deref() {
|
if let Some(base) = settings.public_url.as_deref() {
|
||||||
let url = format!(
|
let url = format!("{}/api/v1/control/enroll-tokens", base);
|
||||||
"{}/api/v1/control/enroll-tokens?include_expired={}",
|
|
||||||
base, args.include_expired
|
|
||||||
);
|
|
||||||
let response = reqwest::get(&url)
|
let response = reqwest::get(&url)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to call {url}"))?;
|
.with_context(|| format!("failed to call {url}"))?;
|
||||||
@@ -118,7 +115,7 @@ pub async fn list_enroll_tokens(args: ListEnrollTokensArgs) -> Result<()> {
|
|||||||
settings.state_file.display()
|
settings.state_file.display()
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let tokens = store.list_enroll_tokens(args.include_expired).await?;
|
let tokens = store.list_enroll_tokens().await?;
|
||||||
if args.json {
|
if args.json {
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ impl Store {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_enroll_tokens(&self, include_expired: bool) -> Result<Vec<EnrollTokenInfo>> {
|
pub async fn list_enroll_tokens(&self) -> Result<Vec<EnrollTokenInfo>> {
|
||||||
let now = now_unix();
|
let now = now_unix();
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for item in self.enroll_tokens.iter() {
|
for item in self.enroll_tokens.iter() {
|
||||||
@@ -160,9 +160,6 @@ impl Store {
|
|||||||
let expires_at_unix =
|
let expires_at_unix =
|
||||||
decode_expiry(value.as_ref()).context("failed decoding token expiry")?;
|
decode_expiry(value.as_ref()).context("failed decoding token expiry")?;
|
||||||
let expired = expires_at_unix <= now;
|
let expired = expires_at_unix <= now;
|
||||||
if !include_expired && expired {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let enroll_token =
|
let enroll_token =
|
||||||
String::from_utf8(token.to_vec()).context("invalid utf-8 enroll token in db")?;
|
String::from_utf8(token.to_vec()).context("invalid utf-8 enroll token in db")?;
|
||||||
out.push(EnrollTokenInfo {
|
out.push(EnrollTokenInfo {
|
||||||
@@ -836,9 +833,11 @@ mod tests {
|
|||||||
assert!(cleared);
|
assert!(cleared);
|
||||||
|
|
||||||
let listed = store.list_agents_with_nicknames().await;
|
let listed = store.list_agents_with_nicknames().await;
|
||||||
assert!(listed
|
assert!(
|
||||||
.iter()
|
listed
|
||||||
.any(|(id, name)| id == &issued.agent_id && name.is_none()));
|
.iter()
|
||||||
|
.any(|(id, name)| id == &issued.agent_id && name.is_none())
|
||||||
|
);
|
||||||
|
|
||||||
cleanup_dir(&dir);
|
cleanup_dir(&dir);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user