fix: align workspace diagnostic contracts

This commit is contained in:
2026-08-04 00:37:57 +02:00
parent f6494fd8ef
commit 565e93a456
12 changed files with 346 additions and 42 deletions
+98 -10
View File
@@ -9,6 +9,7 @@ import {
createWorkspaceDiagnoser,
type DiagnosticAdapters,
} from "../src/workspaces/diagnostics.js";
import { resolveRuntimeBindings } from "../src/workspaces/bindings.js";
import type { RuntimeBindings } from "../src/workspaces/runtime-renderer.js";
import { parseWorkspaceYaml } from "../src/workspaces/schema.js";
@@ -56,6 +57,7 @@ diagnostics:
method: POST
path: /vector/diagnostic-probe
auth: bearer
response: { operation: operation }
`);
const writerWorkspace = parseWorkspaceYaml(`workspace:
@@ -88,6 +90,11 @@ semantic_index:
llm_policy:
allowed: [zai/glm-5.2]
diagnostics:
dwh_rest:
method: POST
path: /rpc/ping
auth: bearer
response: { database: database, schema: schema }
vector_rest:
metadata:
method: GET
@@ -98,6 +105,7 @@ diagnostics:
method: POST
path: /vector/diagnostic-probe
auth: bearer
response: { operation: operation }
`);
const bindings: RuntimeBindings = {
@@ -123,6 +131,7 @@ const bindings: RuntimeBindings = {
THT_WS_PSD_CLINICAL_VECTOR_TLS_CA_FILE: "/run/secrets/vector-ca",
},
},
vectorWriter: { transport: "rest_api", missing: [], values: {} },
embedding: {
transport: "rest_api",
missing: [],
@@ -142,9 +151,13 @@ const writerBindings: RuntimeBindings = {
values: {
THT_WS_PSD_CLINICAL_VECTOR_BASE_URL: "https://vector.example.test",
THT_WS_PSD_CLINICAL_VECTOR_API_KEY_FILE: "/run/secrets/vector-reader-key",
THT_WS_PSD_CLINICAL_VECTOR_WRITER_API_KEY_FILE: "/run/secrets/vector-writer-key",
},
},
vectorWriter: {
transport: "rest_api",
missing: [],
values: { THT_WS_PSD_CLINICAL_VECTOR_WRITER_API_KEY_FILE: "/run/secrets/vector-writer-key" },
},
};
function successfulAdapters(overrides: Partial<DiagnosticAdapters> = {}): DiagnosticAdapters {
@@ -448,6 +461,40 @@ test("requires a matching embedding model vector and removes its unique write pr
}));
});
test("passes the resolver's distinct vector-writer binding to the diagnoser", async () => {
const directory = await mkdtemp(join(tmpdir(), "thothii-diagnostic-bindings-"));
const readerKey = join(directory, "reader-key");
const writerKey = join(directory, "writer-key");
const dwhKey = join(directory, "dwh-key");
await Promise.all([
writeFile(readerKey, "reader\n", { mode: 0o600 }),
writeFile(writerKey, "writer\n", { mode: 0o600 }),
writeFile(dwhKey, "dwh\n", { mode: 0o600 }),
]);
const adapters = successfulAdapters();
try {
const resolved = resolveRuntimeBindings(writerWorkspace, {
THT_WS_PSD_CLINICAL_DWH_TRANSPORT: "rest_api",
THT_WS_PSD_CLINICAL_DWH_BASE_URL: "https://dwh.example.test",
THT_WS_PSD_CLINICAL_DWH_API_KEY_FILE: dwhKey,
THT_WS_PSD_CLINICAL_VECTOR_TRANSPORT: "rest_api",
THT_WS_PSD_CLINICAL_VECTOR_BASE_URL: "https://vector.example.test",
THT_WS_PSD_CLINICAL_VECTOR_API_KEY_FILE: readerKey,
THT_WS_PSD_CLINICAL_VECTOR_WRITER_API_KEY_FILE: writerKey,
THT_WS_PSD_CLINICAL_EMBEDDING_BASE_URL: "https://embedding.example.test",
}, [directory]);
await diagnose(adapters)(writerWorkspace, resolved, { writeProbe: true });
expect(resolved.vectorWriter.values).toEqual({
THT_WS_PSD_CLINICAL_VECTOR_WRITER_API_KEY_FILE: writerKey,
});
expect(adapters.writeDiagnosticRecord).toHaveBeenCalledWith(expect.objectContaining({ credentialFile: writerKey }));
} finally {
await rm(directory, { recursive: true, force: true });
}
});
test("keeps a reader-only workspace activatable without a vector write probe", async () => {
const adapters = successfulAdapters();
@@ -476,11 +523,8 @@ test("rejects a writer credential that aliases the reader credential", async ()
const adapters = successfulAdapters();
const aliasedBindings: RuntimeBindings = {
...writerBindings,
vector: { ...writerBindings.vector, values: {
...writerBindings.vector.values,
THT_WS_PSD_CLINICAL_VECTOR_API_KEY_FILE: readerKey,
THT_WS_PSD_CLINICAL_VECTOR_WRITER_API_KEY_FILE: writerAlias,
} },
vector: { ...writerBindings.vector, values: { ...writerBindings.vector.values, THT_WS_PSD_CLINICAL_VECTOR_API_KEY_FILE: readerKey } },
vectorWriter: { ...writerBindings.vectorWriter, values: { THT_WS_PSD_CLINICAL_VECTOR_WRITER_API_KEY_FILE: writerAlias } },
};
try {
@@ -555,6 +599,29 @@ test("requires an authenticated TLS database query before direct diagnostics suc
}
});
test("uses system trust for direct and SSH PostgreSQL diagnostics when no CA binding exists", async () => {
const directory = await mkdtemp(join(tmpdir(), "thothii-diagnostic-"));
const passwordFile = join(directory, "password");
await writeFile(passwordFile, "password\n", { mode: 0o600 });
const query = vi.fn(async () => ({ rows: [{ database: "warehouse", schema: "datawarehouse" }] }));
const connect = vi.fn(async () => ({ query, end: vi.fn(async () => undefined) }));
const adapter = createConcreteDiagnosticAdapters({ databaseClient: { connect } } as any);
try {
for (const transport of ["postgres_direct", "ssh_tunnel"] as const) {
await expect(adapter.probeConnector({
role: "dwh", transport, host: "127.0.0.1", port: 5432, user: "reader", credentialFile: passwordFile,
resource: { database: "warehouse", schema: "datawarehouse" }, timeoutMs: 5000,
signal: new AbortController().signal,
})).resolves.toMatchObject({ tlsVerified: true, authenticated: true });
}
expect(connect).toHaveBeenCalledTimes(2);
expect(connect).toHaveBeenNthCalledWith(1, expect.objectContaining({ tlsCaFile: undefined }));
expect(connect).toHaveBeenNthCalledWith(2, expect.objectContaining({ tlsCaFile: undefined }));
} finally {
await rm(directory, { recursive: true, force: true });
}
});
test("selects the vector index containing the declared vector column for direct metadata", async () => {
const directory = await mkdtemp(join(tmpdir(), "thothii-diagnostic-"));
const passwordFile = join(directory, "password");
@@ -597,20 +664,41 @@ test("applies declared auth modes and rejects private CA files across vector RES
const keyFile = join(directory, "api-key");
const caFile = join(directory, "ca.pem");
await Promise.all([writeFile(keyFile, "writer-key\n", { mode: 0o600 }), writeFile(caFile, "private-ca\n")]);
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ collection: "clinical_documents", dimensions: 768, distance: "cosine", model: "embed" }), { status: 200, headers: { "content-type": "application/json" } }));
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ collection: "clinical_documents", dimensions: 768, distance: "cosine", model: "embed", operation: "create" }), { status: 200, headers: { "content-type": "application/json" } }));
vi.stubGlobal("fetch", fetchSpy);
const adapter = createConcreteDiagnosticAdapters();
const signal = new AbortController().signal;
try {
await adapter.inspectVector({ transport: "rest_api", baseUrl: "https://vector.example.test", collection: "clinical_documents", timeoutMs: 1, signal, diagnostic: { method: "GET", path: "/metadata", auth: "none", response: { collection: "collection", dimensions: "dimensions", distance: "distance" } } });
await adapter.probeEmbedding({ baseUrl: "https://embed.example.test", model: "embed", timeoutMs: 1, signal, credentialFile: keyFile, diagnostic: { method: "POST", path: "/embed", auth: "x-api-key", response: { model: "model", dimensions: "dimensions" } } });
await adapter.writeDiagnosticRecord({ baseUrl: "https://vector.example.test", credentialFile: keyFile, collection: "clinical_documents", dimensions: 768, id: "diagnostic:test", timeoutMs: 1, signal, diagnostic: { method: "POST", path: "/probe", auth: "none" } });
expect(fetchSpy.mock.calls[0]?.[1]).toMatchObject({ headers: {} });
expect(fetchSpy.mock.calls[1]?.[1]).toMatchObject({ headers: { "x-api-key": "writer-key" } });
expect(fetchSpy.mock.calls[2]?.[1]).toMatchObject({ headers: expect.not.objectContaining({ authorization: expect.anything() }) });
await expect(adapter.inspectVector({ transport: "rest_api", baseUrl: "https://vector.example.test", credentialFile: keyFile, tlsCaFile: caFile, collection: "clinical_documents", timeoutMs: 1, signal, diagnostic: { method: "GET", path: "/metadata", auth: "bearer", response: { collection: "collection", dimensions: "dimensions", distance: "distance" } } })).rejects.toThrow("vector metadata adapter is unavailable");
await expect(adapter.probeEmbedding({ baseUrl: "https://embed.example.test", credentialFile: keyFile, tlsCaFile: caFile, model: "embed", timeoutMs: 1, signal, diagnostic: { method: "POST", path: "/embed", auth: "bearer", response: { model: "model", dimensions: "dimensions" } } })).rejects.toThrow("embedding probe failed");
await expect(adapter.removeDiagnosticRecord({ baseUrl: "https://vector.example.test", credentialFile: keyFile, tlsCaFile: caFile, collection: "clinical_documents", id: "diagnostic:test", dimensions: 768, timeoutMs: 1, signal, diagnostic: { method: "POST", path: "/probe", auth: "bearer" } })).rejects.toThrow("vector write adapter is unavailable");
await expect(adapter.removeDiagnosticRecord({ baseUrl: "https://vector.example.test", credentialFile: keyFile, tlsCaFile: caFile, collection: "clinical_documents", id: "diagnostic:test", dimensions: 768, timeoutMs: 1, signal, diagnostic: { method: "POST", path: "/probe", auth: "bearer", response: { operation: "operation" } } })).rejects.toThrow("vector write adapter is unavailable");
} finally {
vi.unstubAllGlobals();
await rm(directory, { recursive: true, force: true });
}
});
test("validates that the reversible writer response confirms each requested operation", async () => {
const directory = await mkdtemp(join(tmpdir(), "thothii-diagnostic-"));
const keyFile = join(directory, "writer-key");
await writeFile(keyFile, "writer\n", { mode: 0o600 });
const fetchSpy = vi.fn(async (_url: string, init: RequestInit) => new Response(JSON.stringify({
operation: JSON.parse(String(init.body)).operation === "create" ? "create" : "not-removed",
}), { status: 200, headers: { "content-type": "application/json" } }));
vi.stubGlobal("fetch", fetchSpy);
const request = {
baseUrl: "https://vector.example.test", credentialFile: keyFile, collection: "clinical_documents",
dimensions: 768, id: "diagnostic:test", timeoutMs: 5000, signal: new AbortController().signal,
diagnostic: { method: "POST" as const, path: "/probe", auth: "bearer" as const, response: { operation: "operation" } },
};
try {
const adapter = createConcreteDiagnosticAdapters();
await expect(adapter.writeDiagnosticRecord(request)).resolves.toBeUndefined();
await expect(adapter.removeDiagnosticRecord(request)).rejects.toThrow("vector write adapter is unavailable");
} finally {
vi.unstubAllGlobals();
await rm(directory, { recursive: true, force: true });