Files
yoi/web/workspace/tests/runtime-management.test.ts

489 lines
14 KiB
TypeScript

declare const Deno: {
test(name: string, fn: () => void | Promise<void>): void;
};
import {
createRemoteRuntime,
parseRuntimeRemovalOperationResponse,
parseRuntimeTrustConflict,
parseRuntimeTrustKeyRevealResponse,
parseWorkspaceRuntimeDetail,
parseWorkspaceRuntimeList,
previewRuntimePublicKeyFingerprint,
removeRemoteRuntime,
revokeRuntimeTrustKey,
RuntimeRemovalAttempt,
RuntimeTrustConflictError,
RuntimeTrustRouteFence,
updateRemoteRuntime,
} from "../src/lib/workspace/api/runtime-management.ts";
function assert(condition: unknown, message: string): asserts condition {
if (!condition) throw new Error(message);
}
function assertThrows(operation: () => unknown, expected: string): void {
try {
operation();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
if (message.includes(expected)) return;
throw new Error(
`expected error containing ${expected}, received ${message}`,
);
}
throw new Error("expected operation to throw");
}
function runtime() {
return {
management: {
built_in: false,
config_managed: true,
removable: false,
endpoint_configured: true,
token_ref_configured: false,
binding: {
state: "verified",
connection_state: "verified",
revision: 3,
workspace_key_id: "WK-1",
workspace_key_generation: 1,
verification: {
verified_at: "2026-09-01T13:00:00Z",
last_checked_at: "2026-09-01T13:00:00Z",
last_outcome: "verified",
binding_revision: 3,
workspace_key_id: "WK-1",
workspace_identity_revision: 1,
workspace_trust_generation: 1,
runtime_public_key_fingerprint: "SHA256:current",
runtime_identity_revision: 1,
},
},
},
runtime_id: "arcadia",
label: "Arcadia",
kind: "remote",
status: "started",
source: {
kind: "remote_http",
status: "active",
identity_authority: "server_runtime_configuration",
note: "Configured by Server authority",
},
host_ids: ["host-a"],
worker_creation_available: true,
os: "linux",
arch: "x86_64",
diagnostics: [],
};
}
function detail() {
return {
workspace_id: "workspace-a",
runtime: runtime(),
endpoint: "https://runtime.example.test",
trust_key: {
status: "active",
fingerprint: "SHA256:current",
revision: 3,
created_at: "2026-09-01T12:00:00Z",
updated_at: "2026-09-01T13:00:00Z",
revoked_at: null,
},
recent_audit: [{
action: "created",
actor_account_id: "account-a",
old_fingerprint: null,
new_fingerprint: "SHA256:current",
revision: 3,
at: "2026-09-01T13:00:00Z",
}],
};
}
Deno.test("Runtime list and detail parsers return generated Runtime DTO shapes", () => {
const list = parseWorkspaceRuntimeList({
workspace_id: "workspace-a",
limit: 200,
items: [runtime()],
source: "workspace-control-plane",
diagnostics: [],
});
assert(
list.items[0]?.runtime_id === "arcadia",
"Runtime ID was not preserved",
);
assert(
list.items[0]?.management.binding?.state === "verified",
"binding state was not preserved",
);
const parsed = parseWorkspaceRuntimeDetail(detail());
assert(
parsed.trust_key.revision === 3,
"revision was not preserved as a safe integer",
);
assert(
parsed.recent_audit[0]?.revision === 3,
"audit revision was not normalized",
);
});
Deno.test("Runtime list parser accepts the built-in Runtime's internal binding", () => {
const embedded = runtime();
embedded.runtime_id = "embedded";
embedded.label = "Embedded Runtime";
embedded.kind = "embedded";
embedded.management.built_in = true;
embedded.management.endpoint_configured = false;
const binding = embedded.management.binding as Partial<
typeof embedded.management.binding
>;
delete binding.workspace_key_id;
delete binding.workspace_key_generation;
delete binding.verification;
const list = parseWorkspaceRuntimeList({
workspace_id: "workspace-a",
limit: 200,
items: [embedded],
source: "workspace-control-plane",
diagnostics: [],
});
assert(
list.items[0]?.management.binding?.connection_state === "verified",
"built-in Runtime binding was not preserved",
);
});
Deno.test("Runtime management parser rejects Workspace identity bindings without key metadata", () => {
const payload = detail();
const binding = payload.runtime.management.binding as Partial<
typeof payload.runtime.management.binding
>;
delete binding.workspace_key_id;
delete binding.workspace_key_generation;
binding.state = "configured";
assertThrows(
() => parseWorkspaceRuntimeDetail(payload),
"requires Workspace signing key identity metadata",
);
});
Deno.test("Runtime validators reject unknown object keys and enum variants", () => {
assertThrows(
() => parseWorkspaceRuntimeDetail({ ...detail(), head_tree: "stale" }),
"head_tree is not part",
);
const futureSource = structuredClone(detail());
futureSource.runtime.source.kind = "future_transport";
assertThrows(
() => parseWorkspaceRuntimeDetail(futureSource),
"contains an unknown enum value",
);
assertThrows(
() =>
parseRuntimeTrustConflict({
error: "future_conflict",
message: "conflict",
current_revision: 4,
current_fingerprint: "SHA256:new",
}),
"contains an unknown enum value",
);
});
Deno.test("Runtime validators reject unsafe revisions and bounded collection overflow", () => {
const unsafeRevision = structuredClone(detail());
unsafeRevision.trust_key.revision = Number.MAX_SAFE_INTEGER + 1;
assertThrows(
() => parseWorkspaceRuntimeDetail(unsafeRevision),
"must be a safe integer",
);
const tooMuchAudit = structuredClone(detail());
tooMuchAudit.recent_audit = Array.from(
{ length: 21 },
() => structuredClone(detail().recent_audit[0]),
);
assertThrows(
() => parseWorkspaceRuntimeDetail(tooMuchAudit),
"must contain at most 20 items",
);
const tooManyItems = Array.from({ length: 201 }, () => runtime());
assertThrows(
() =>
parseWorkspaceRuntimeList({
workspace_id: "workspace-a",
limit: 200,
items: tooManyItems,
source: "workspace-control-plane",
diagnostics: [],
}),
"must contain at most 200 items",
);
});
Deno.test("Runtime detail rejects unbounded strings and incoherent trust state", () => {
assertThrows(
() =>
parseRuntimeTrustKeyRevealResponse({
public_key: "x".repeat(16 * 1024 + 1),
}),
"must be at most 16384 UTF-8 bytes",
);
const activeWithoutFingerprint = structuredClone(detail()) as Record<
string,
unknown
>;
(activeWithoutFingerprint.trust_key as Record<string, unknown>).fingerprint =
null;
assertThrows(
() => parseWorkspaceRuntimeDetail(activeWithoutFingerprint),
"must include fingerprint",
);
});
Deno.test("mismatched revoke fingerprint never sends a request", async () => {
let requests = 0;
const fetchImpl: typeof fetch = () => {
requests += 1;
return Promise.reject(new Error("request must not be sent"));
};
let rejected = false;
try {
await revokeRuntimeTrustKey(
"workspace-a",
"runtime-a",
{ expected_revision: 3 },
"sha256:current",
"sha256:different",
fetchImpl,
);
} catch (error) {
rejected = error instanceof Error &&
error.message.includes("current fingerprint exactly");
}
assert(rejected, "mismatched fingerprint should be rejected locally");
assert(requests === 0, "mismatched fingerprint sent a revoke request");
});
Deno.test("Runtime metadata update never sends public key authority", async () => {
let requestedUrl = "";
let requestedMethod = "";
let requestedBody: unknown = null;
const fetchImpl = ((input: string | URL | Request, init?: RequestInit) => {
requestedUrl = String(input);
requestedMethod = init?.method ?? "GET";
requestedBody = JSON.parse(String(init?.body));
return Promise.resolve(Response.json(detail()));
}) as typeof fetch;
await updateRemoteRuntime(
"workspace-a",
"arcadia",
{
display_name: "Updated Runtime",
endpoint: "https://runtime.example.test/v2",
},
fetchImpl,
);
assert(
requestedUrl === "/api/w/workspace-a/runtimes/arcadia",
`unexpected update URL: ${requestedUrl}`,
);
assert(requestedMethod === "POST", "Runtime update must use POST");
assert(
JSON.stringify(requestedBody) ===
JSON.stringify({
display_name: "Updated Runtime",
endpoint: "https://runtime.example.test/v2",
}),
`unexpected update body: ${JSON.stringify(requestedBody)}`,
);
const body = requestedBody as Record<string, unknown>;
assert(!("public_bundle" in body), "metadata update sent public_bundle");
assert(!("public_key" in body), "metadata update sent public_key");
});
Deno.test("Runtime removal attempt retains its id across response-loss retry", async () => {
const attempt = new RuntimeRemovalAttempt();
const operationIds: string[] = [];
let calls = 0;
const submit = async () => {
const operationId = attempt.operationId(() => "stable-removal-operation");
operationIds.push(operationId);
const operation = await removeRemoteRuntime(
"workspace-a",
"runtime-a",
{ operation_id: operationId, expected_binding_revision: 4 },
() => {
calls += 1;
if (calls === 1) return Promise.reject(new Error("response lost"));
return Promise.resolve(Response.json({
operation_id: operationId,
workspace_id: "workspace-a",
runtime_id: "runtime-a",
state: "succeeded",
binding_removed: true,
runtime_registration_removed: true,
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-01T00:00:01Z",
completed_at: "2026-01-01T00:00:01Z",
}));
},
);
attempt.complete(operation.operation_id);
};
try {
await submit();
throw new Error("expected response-loss retry to fail");
} catch (error) {
assert(
error instanceof Error && error.message.includes("response lost"),
`unexpected response-loss error: ${String(error)}`,
);
}
await submit();
assert(
operationIds.length === 2 &&
operationIds.every((id) => id === "stable-removal-operation"),
`response-loss retry changed operation id: ${operationIds.join(",")}`,
);
assert(
attempt.operationId(() => "next-removal-operation") ===
"next-removal-operation",
"authoritative success did not clear the completed operation id",
);
});
Deno.test("Runtime removal uses the Workspace-scoped operation route", async () => {
let requestedUrl = "";
let requestedMethod = "";
let requestedBody: unknown = null;
const fetchImpl = ((input: string | URL | Request, init?: RequestInit) => {
requestedUrl = String(input);
requestedMethod = init?.method ?? "GET";
requestedBody = JSON.parse(String(init?.body));
return Promise.resolve(Response.json({
operation_id: "remove-runtime-a",
workspace_id: "workspace a",
runtime_id: "runtime/a",
state: "succeeded",
binding_removed: true,
runtime_registration_removed: true,
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-01T00:00:01Z",
completed_at: "2026-01-01T00:00:01Z",
}));
}) as typeof fetch;
const operation = await removeRemoteRuntime(
"workspace a",
"runtime/a",
{ operation_id: "remove-runtime-a", expected_binding_revision: 7 },
fetchImpl,
);
assert(
requestedUrl === "/api/w/workspace%20a/runtimes/runtime%2Fa",
`unexpected removal URL: ${requestedUrl}`,
);
assert(requestedMethod === "DELETE", "Runtime removal must use DELETE");
assert(
JSON.stringify(requestedBody) === JSON.stringify({
operation_id: "remove-runtime-a",
expected_binding_revision: 7,
}),
"Runtime removal request body drifted",
);
assert(operation.state === "succeeded", "Runtime removal did not complete");
assertThrows(
() =>
parseRuntimeRemovalOperationResponse({
...operation,
unknown: "rejected",
}),
"not part of the wire contract",
);
});
Deno.test("Runtime route fence rejects a delayed reveal from the prior Runtime", async () => {
const fence = new RuntimeTrustRouteFence();
fence.enter("runtime-a");
const operation = fence.capture("runtime-a");
let renderedKey: string | null = null;
let resolveReveal!: (key: string) => void;
const delayedReveal = new Promise<string>((resolve) => {
resolveReveal = resolve;
}).then((key) => {
if (fence.isCurrent(operation, "runtime-b")) renderedKey = key;
});
fence.enter("runtime-b");
resolveReveal("runtime-a-public-key");
await delayedReveal;
assert(
renderedKey === null,
"Runtime A key rendered after navigating to Runtime B",
);
});
Deno.test("Runtime public key preview matches the Server fingerprint contract", async () => {
const fingerprint = await previewRuntimePublicKeyFingerprint(
"yoi-ed25519-pub:v1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
);
assert(
fingerprint ===
"sha256:66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925",
"fingerprint preview drifted from the Server SHA-256 contract",
);
});
Deno.test("Runtime create surfaces bounded Settings error details", async () => {
const fetchImpl = (() =>
Promise.resolve(
new Response(
JSON.stringify({
error: "remote_runtime_endpoint_not_allowed",
details: "Runtime endpoint must use public https egress",
}),
{ status: 400, headers: { "content-type": "application/json" } },
),
)) as typeof fetch;
try {
await createRemoteRuntime(
"workspace-a",
{
public_bundle: {
identity_id: "runtime-a",
public_key: "yoi-ed25519-pub:v1:test",
},
display_name: null,
endpoint: "https://runtime.example",
expected_revision: null,
},
fetchImpl,
);
throw new Error("expected create to reject");
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
assert(
message === "Runtime endpoint must use public https egress",
`unexpected create error: ${message}`,
);
}
});