feat: bind evidence credentials through local files
This commit is contained in:
@@ -2797,3 +2797,99 @@ test("POST /sessions bootstrap failure emits only a fixed recovery message", asy
|
||||
expect(clientOutput).not.toContain("DO_NOT_LEAK");
|
||||
expect(clientOutput).not.toContain("/srv/private/model-key");
|
||||
});
|
||||
|
||||
|
||||
test.each([
|
||||
{ mode: "missing signed Evidence file", evidence: true, safe: false, expectedStatus: 409, reachesReadiness: false },
|
||||
{ mode: "safe signed Evidence file", evidence: true, safe: true, expectedStatus: 503, reachesReadiness: true },
|
||||
{ mode: "no Evidence descriptor", evidence: false, safe: false, expectedStatus: 503, reachesReadiness: true },
|
||||
])("real buildApp admission handles $mode before Pi spawn", async ({
|
||||
evidence, safe, expectedStatus, reachesReadiness,
|
||||
}) => {
|
||||
const root = mkdtempSync(path.join(tmpdir(), "thoth-evidence-admission-"));
|
||||
const signedFile = path.join(root, "signed-urls.json");
|
||||
writeFileSync(signedFile, '["CANARY-SIGNED-QUERY"]');
|
||||
const variable = "THT_WS_PSD_CLINICAL_EVIDENCE_SIGNED_URLS_FILE";
|
||||
const previous = {
|
||||
transport: process.env.THT_WS_PSD_CLINICAL_DWH_TRANSPORT,
|
||||
baseUrl: process.env.THT_WS_PSD_CLINICAL_DWH_BASE_URL,
|
||||
signed: process.env[variable],
|
||||
};
|
||||
process.env.THT_WS_PSD_CLINICAL_DWH_TRANSPORT = "rest_api";
|
||||
process.env.THT_WS_PSD_CLINICAL_DWH_BASE_URL = "https://dwh.example.test";
|
||||
if (safe) process.env[variable] = signedFile;
|
||||
else delete process.env[variable];
|
||||
|
||||
const descriptor = {
|
||||
...operationalWorkspace("psd-clinical"),
|
||||
dwh: {
|
||||
...operationalWorkspace("psd-clinical").dwh,
|
||||
supported_transports: ["rest_api"],
|
||||
},
|
||||
diagnostics: {
|
||||
dwh_rest: {
|
||||
method: "GET", path: "/health", auth: "none",
|
||||
response: { database: "database", schema: "schema" },
|
||||
},
|
||||
},
|
||||
...(evidence ? {
|
||||
evidence: {
|
||||
source: {
|
||||
type: "http",
|
||||
uris: ["https://evidence.example.test/guide.md"],
|
||||
authentication: "signed_urls_file",
|
||||
connect_timeout_ms: 5_000,
|
||||
read_timeout_ms: 30_000,
|
||||
max_bytes: 10 * 1024 * 1024,
|
||||
max_redirects: 5,
|
||||
allow_private_hosts: false,
|
||||
max_cache_bytes: 64 * 1024 * 1024,
|
||||
},
|
||||
policy: { max_chunk_chars: 4_000, retain_published_generations: 3 },
|
||||
},
|
||||
} : {}),
|
||||
} as any;
|
||||
const canonicalBefore = JSON.stringify(descriptor);
|
||||
const ensure = vi.fn(async () => ({ ok: false, code: "workspace_not_activatable" as const }));
|
||||
const createFor = vi.fn();
|
||||
const abort = vi.fn(async () => {});
|
||||
const revision = {
|
||||
id: "psd-clinical", commit: "a".repeat(40), blob: "b".repeat(40),
|
||||
snapshotPath: `/data/workspace-registry/snapshots/${"a".repeat(40)}/psd-clinical.yaml`,
|
||||
state: "operational" as const,
|
||||
};
|
||||
|
||||
try {
|
||||
const app = buildRealApp(loadConfig({
|
||||
THT_HARNESS_DIR: "../harness",
|
||||
THT_WORKSPACE_SECRET_ROOTS: root,
|
||||
}), {
|
||||
thtRunner: { sessionNew: vi.fn(), searchPack: async () => {} } as any,
|
||||
readiness: { ensure } as any,
|
||||
mgr: { get: () => undefined, createFor } as any,
|
||||
getSettings: () => ({ workspace: "psd-clinical" }) as any,
|
||||
workspaceRegistry: {
|
||||
acquireSessionRevision: vi.fn(async () => ({
|
||||
workspace: descriptor, revision, abort, markPersisted: vi.fn(async () => {}),
|
||||
})),
|
||||
} as any,
|
||||
});
|
||||
const response = await app.inject({ method: "POST", url: "/sessions", payload: { question: "q" } });
|
||||
|
||||
expect(response.statusCode).toBe(expectedStatus);
|
||||
expect(ensure).toHaveBeenCalledTimes(reachesReadiness ? 1 : 0);
|
||||
expect(createFor).not.toHaveBeenCalled();
|
||||
expect(JSON.stringify(descriptor)).toBe(canonicalBefore);
|
||||
expect(revision.commit).toBe("a".repeat(40));
|
||||
expect(response.body).not.toContain("CANARY-SIGNED-QUERY");
|
||||
} finally {
|
||||
const restore = (name: string, value: string | undefined) => {
|
||||
if (value === undefined) delete process.env[name];
|
||||
else process.env[name] = value;
|
||||
};
|
||||
restore("THT_WS_PSD_CLINICAL_DWH_TRANSPORT", previous.transport);
|
||||
restore("THT_WS_PSD_CLINICAL_DWH_BASE_URL", previous.baseUrl);
|
||||
restore(variable, previous.signed);
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { chmodSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, expect, test } from "vitest";
|
||||
import { resolveBinding, resolveRuntimeBindings } from "../src/workspaces/bindings.js";
|
||||
import { resolveBinding, resolveEvidenceBinding, resolveRuntimeBindings, supportsSessionRuntime } from "../src/workspaces/bindings.js";
|
||||
import { parseWorkspaceYaml } from "../src/workspaces/schema.js";
|
||||
|
||||
const workspace = parseWorkspaceYaml(`workspace:
|
||||
@@ -254,3 +254,118 @@ test("schema v3 ignores external semantic binding variables and reports only DWH
|
||||
expect(bindings.vector.values).toEqual({});
|
||||
expect(bindings.embedding.values).toEqual({});
|
||||
});
|
||||
|
||||
|
||||
function withEvidence(source: Record<string, unknown>) {
|
||||
return parseWorkspaceYaml(`workspace:
|
||||
schema_version: 3
|
||||
id: psd-clinical
|
||||
name: Policlinico San Donato
|
||||
language: it
|
||||
dwh:
|
||||
engine: postgres
|
||||
database: postgres
|
||||
schema: datawarehouse
|
||||
supported_transports: [postgres_direct]
|
||||
semantic_index:
|
||||
vector_store: { engine: qdrant, collection: psd-clinical, dimensions: 1024, distance: cosine }
|
||||
embedding: { provider: ollama_internal, model: qwen3-embedding:0.6b, dimensions: 1024 }
|
||||
llm_policy: { allowed: [zai/glm-5.2] }
|
||||
evidence:
|
||||
source: ${JSON.stringify(source)}
|
||||
`);
|
||||
}
|
||||
|
||||
const evidenceVariable = (suffix: string) => `THT_WS_PSD_CLINICAL_EVIDENCE_${suffix}`;
|
||||
|
||||
test.each([
|
||||
{ type: "filesystem", uri: "workspace-content/psd-clinical/evidence" },
|
||||
{ type: "http", uris: ["https://evidence.example.test/guide.md"], authentication: "none" },
|
||||
{ type: "s3", uri: "s3://clinical-evidence/published/", credentials: "ambient" },
|
||||
])("does not resolve Evidence variables for $type modes without file credentials", (source) => {
|
||||
expect(resolveEvidenceBinding(withEvidence(source), {
|
||||
[evidenceVariable("SIGNED_URLS_FILE")]: "/CANARY/http",
|
||||
[evidenceVariable("ACCESS_KEY_FILE")]: "/CANARY/access",
|
||||
}, ["/run/secrets"])).toEqual({ values: {}, missing: [] });
|
||||
});
|
||||
|
||||
test("requires only a safe HTTP signed-URL file and never reads its contents", () => {
|
||||
const signed = secretPath("evidence-signed-urls");
|
||||
writeFileSync(signed.path, "CANARY-SIGNED-URL-CONTENT");
|
||||
const source = withEvidence({
|
||||
type: "http",
|
||||
uris: ["https://evidence.example.test/guide.md"],
|
||||
authentication: "signed_urls_file",
|
||||
});
|
||||
const variable = evidenceVariable("SIGNED_URLS_FILE");
|
||||
|
||||
expect(resolveEvidenceBinding(source, {}, [signed.root]).missing).toEqual([variable]);
|
||||
const resolved = resolveEvidenceBinding(source, {
|
||||
[variable]: signed.path,
|
||||
[evidenceVariable("ACCESS_KEY_FILE")]: signed.path,
|
||||
}, [signed.root]);
|
||||
expect(resolved).toEqual({ values: { [variable]: signed.path }, missing: [] });
|
||||
expect(JSON.stringify(resolved)).not.toContain("CANARY-SIGNED-URL-CONTENT");
|
||||
});
|
||||
|
||||
test("requires S3 access and secret files together while accepting an optional safe session token", () => {
|
||||
const access = secretPath("evidence-access");
|
||||
const secret = secretPath("evidence-secret");
|
||||
const token = secretPath("evidence-token");
|
||||
const source = withEvidence({
|
||||
type: "s3", uri: "s3://clinical-evidence/published/", credentials: "static_files",
|
||||
});
|
||||
const env = {
|
||||
[evidenceVariable("ACCESS_KEY_FILE")]: access.path,
|
||||
[evidenceVariable("SECRET_KEY_FILE")]: secret.path,
|
||||
[evidenceVariable("SESSION_TOKEN_FILE")]: token.path,
|
||||
[evidenceVariable("SIGNED_URLS_FILE")]: access.path,
|
||||
};
|
||||
|
||||
expect(resolveEvidenceBinding(source, {
|
||||
[evidenceVariable("ACCESS_KEY_FILE")]: access.path,
|
||||
}, [access.root]).missing).toEqual([evidenceVariable("SECRET_KEY_FILE")]);
|
||||
expect(resolveEvidenceBinding(source, env, [access.root, secret.root, token.root])).toEqual({
|
||||
values: {
|
||||
[evidenceVariable("ACCESS_KEY_FILE")]: access.path,
|
||||
[evidenceVariable("SECRET_KEY_FILE")]: secret.path,
|
||||
[evidenceVariable("SESSION_TOKEN_FILE")]: token.path,
|
||||
},
|
||||
missing: [],
|
||||
});
|
||||
});
|
||||
|
||||
test("rejects relative, missing, directory, unreadable, and escaping symlink Evidence paths", () => {
|
||||
const allowed = secretPath("valid");
|
||||
const outside = secretPath("outside");
|
||||
const directory = join(allowed.root, "directory");
|
||||
mkdirSync(directory);
|
||||
const link = join(allowed.root, "escape");
|
||||
symlinkSync(outside.path, link);
|
||||
const unreadable = join(allowed.root, "unreadable");
|
||||
writeFileSync(unreadable, "secret");
|
||||
chmodSync(unreadable, 0o000);
|
||||
const source = withEvidence({
|
||||
type: "http", uris: ["https://evidence.example.test/guide.md"], authentication: "signed_urls_file",
|
||||
});
|
||||
const variable = evidenceVariable("SIGNED_URLS_FILE");
|
||||
|
||||
for (const path of ["relative", join(allowed.root, "missing"), directory, unreadable, link]) {
|
||||
expect(resolveEvidenceBinding(source, { [variable]: path }, [allowed.root])).toEqual({
|
||||
values: {}, missing: [variable],
|
||||
});
|
||||
}
|
||||
chmodSync(unreadable, 0o600);
|
||||
});
|
||||
|
||||
test("includes Evidence binding completeness in session runtime support without changing v3 compatibility", () => {
|
||||
const unsigned = resolveRuntimeBindings(workspaceV3, {}, ["/run/secrets"]);
|
||||
expect(unsigned.evidence).toEqual({ values: {}, missing: [] });
|
||||
expect(supportsSessionRuntime(unsigned)).toBe(true);
|
||||
|
||||
const signed = resolveRuntimeBindings(withEvidence({
|
||||
type: "http", uris: ["https://evidence.example.test/guide.md"], authentication: "signed_urls_file",
|
||||
}), {}, ["/run/secrets"]);
|
||||
expect(signed.evidence.missing).toEqual([evidenceVariable("SIGNED_URLS_FILE")]);
|
||||
expect(supportsSessionRuntime(signed)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -190,6 +190,7 @@ llm_policy:
|
||||
missing: [],
|
||||
values: { THT_WS_PSD_CLINICAL_EMBEDDING_BASE_URL: "https://embedding.internal" },
|
||||
},
|
||||
evidence: { missing: [], values: {} },
|
||||
};
|
||||
|
||||
const writerVariables = buildInstallationContract(writerWorkspace).variables
|
||||
@@ -326,3 +327,61 @@ test("v3 installation contract omits external vector and embedding bindings", ()
|
||||
expect(names.some((name) => name.includes("_EMBEDDING_"))).toBe(false);
|
||||
expect(renderWorkspaceDocs(workspaceV3).markdown).not.toContain("Embedding service");
|
||||
});
|
||||
|
||||
|
||||
test.each([
|
||||
{
|
||||
mode: "signed HTTP",
|
||||
source: {
|
||||
type: "http", uris: ["https://evidence.example.test/guide.md"],
|
||||
authentication: "signed_urls_file",
|
||||
},
|
||||
expected: ["THT_WS_PSD_CLINICAL_EVIDENCE_SIGNED_URLS_FILE"],
|
||||
},
|
||||
{
|
||||
mode: "static S3",
|
||||
source: { type: "s3", uri: "s3://clinical-evidence/published/", credentials: "static_files" },
|
||||
expected: [
|
||||
"THT_WS_PSD_CLINICAL_EVIDENCE_ACCESS_KEY_FILE",
|
||||
"THT_WS_PSD_CLINICAL_EVIDENCE_SECRET_KEY_FILE",
|
||||
"THT_WS_PSD_CLINICAL_EVIDENCE_SESSION_TOKEN_FILE",
|
||||
],
|
||||
},
|
||||
])("generates source-specific $mode Evidence file bindings", ({ source, expected }) => {
|
||||
const descriptor = parseWorkspaceYaml(`${renderWorkspaceWithoutEvidence()}evidence:\n source: ${JSON.stringify(source)}\n`);
|
||||
const contract = buildInstallationContract(descriptor);
|
||||
const evidence = contract.variables.filter((variable) => variable.role === "EVIDENCE");
|
||||
|
||||
expect(contract.namespace).toBe("PSD_CLINICAL");
|
||||
expect(evidence.map((variable) => variable.name)).toEqual(expected);
|
||||
expect(evidence.every((variable) => variable.secret)).toBe(true);
|
||||
expect(renderWorkspaceDocs(descriptor).envExample).not.toContain("CANARY-SECRET");
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ type: "filesystem", uri: "workspace-content/psd-clinical/evidence" },
|
||||
{ type: "http", uris: ["https://evidence.example.test/guide.md"], authentication: "none" },
|
||||
{ type: "s3", uri: "s3://clinical-evidence/published/", credentials: "ambient" },
|
||||
])("omits Evidence installation variables for $type modes without file credentials", (source) => {
|
||||
const descriptor = parseWorkspaceYaml(`${renderWorkspaceWithoutEvidence()}evidence:\n source: ${JSON.stringify(source)}\n`);
|
||||
expect(buildInstallationContract(descriptor).variables.some((variable) => variable.role === "EVIDENCE"))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
function renderWorkspaceWithoutEvidence(): string {
|
||||
return `workspace:
|
||||
schema_version: 3
|
||||
id: psd-clinical
|
||||
name: Policlinico San Donato
|
||||
language: it
|
||||
dwh:
|
||||
engine: postgres
|
||||
database: postgres
|
||||
schema: datawarehouse
|
||||
supported_transports: [postgres_direct]
|
||||
semantic_index:
|
||||
vector_store: { engine: qdrant, collection: psd-clinical, dimensions: 1024, distance: cosine }
|
||||
embedding: { provider: ollama_internal, model: qwen3-embedding:0.6b, dimensions: 1024 }
|
||||
llm_policy: { allowed: [zai/glm-5.2] }
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ const bindings: RuntimeBindings = {
|
||||
THT_WS_PSD_CLINICAL_EMBEDDING_TLS_CA_FILE: "/run/secrets/embedding-ca",
|
||||
},
|
||||
},
|
||||
evidence: { missing: [], values: {} },
|
||||
};
|
||||
|
||||
const writerBindings: RuntimeBindings = {
|
||||
@@ -190,6 +191,7 @@ const bindingsV3: RuntimeBindings = {
|
||||
vector: { transport: "rest_api", missing: [], values: {} },
|
||||
vectorWriter: { transport: "rest_api", missing: [], values: {} },
|
||||
embedding: { transport: "rest_api", missing: [], values: {} },
|
||||
evidence: { missing: [], values: {} },
|
||||
};
|
||||
|
||||
function successfulAdapters(overrides: Partial<DiagnosticAdapters> = {}): DiagnosticAdapters {
|
||||
@@ -960,3 +962,55 @@ test("attempts bounded cleanup when a timed-out write may already have created t
|
||||
expect(adapters.removeDiagnosticRecord).toHaveBeenCalledOnce();
|
||||
expect(result.activatable).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
test.each([
|
||||
{
|
||||
source: {
|
||||
type: "http", uris: ["https://evidence.example.test/guide.md"],
|
||||
authentication: "signed_urls_file",
|
||||
},
|
||||
field: "evidence.source.authentication",
|
||||
variable: "THT_WS_PSD_CLINICAL_EVIDENCE_SIGNED_URLS_FILE",
|
||||
},
|
||||
{
|
||||
source: { type: "s3", uri: "s3://clinical-evidence/published/", credentials: "static_files" },
|
||||
field: "evidence.source.credentials",
|
||||
variable: "THT_WS_PSD_CLINICAL_EVIDENCE_ACCESS_KEY_FILE",
|
||||
},
|
||||
])("reports sanitized v3 Evidence binding diagnostics for $field", async ({ source, field, variable }) => {
|
||||
const descriptor = parseWorkspaceYaml(`${renderEvidenceWorkspace()}evidence:\n source: ${JSON.stringify(source)}\n`);
|
||||
const resolved: RuntimeBindings = {
|
||||
...resolveRuntimeBindings(descriptor, {
|
||||
[variable]: "CANARY-UNSAFE-RELATIVE-PATH",
|
||||
}, ["/run/secrets"]),
|
||||
dwh: bindings.dwh,
|
||||
};
|
||||
const result = await createProductionWorkspaceDiagnoser(5_000)(descriptor, resolved, { writeProbe: false });
|
||||
|
||||
expect(result).toEqual({
|
||||
activatable: false,
|
||||
diagnostics: expect.arrayContaining([expect.objectContaining({
|
||||
code: "binding_missing", field, variable,
|
||||
})]),
|
||||
});
|
||||
expect(JSON.stringify(result)).not.toContain("CANARY-UNSAFE-RELATIVE-PATH");
|
||||
});
|
||||
|
||||
function renderEvidenceWorkspace(): string {
|
||||
return `workspace:
|
||||
schema_version: 3
|
||||
id: psd-clinical
|
||||
name: Policlinico San Donato
|
||||
language: it
|
||||
dwh:
|
||||
engine: postgres
|
||||
database: warehouse
|
||||
schema: datawarehouse
|
||||
supported_transports: [postgres_direct]
|
||||
semantic_index:
|
||||
vector_store: { engine: qdrant, collection: psd-clinical, dimensions: 1024, distance: cosine }
|
||||
embedding: { provider: ollama_internal, model: qwen3-embedding:0.6b, dimensions: 1024 }
|
||||
llm_policy: { allowed: [zai/glm-5.2] }
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user