fix: close evidence credential disclosure gaps
This commit is contained in:
@@ -2800,15 +2800,19 @@ test("POST /sessions bootstrap failure emits only a fixed recovery message", asy
|
||||
|
||||
|
||||
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 },
|
||||
{ mode: "missing signed Evidence file", evidence: true, binding: "missing", expectedStatus: 409, reachesReadiness: false },
|
||||
{ mode: "unsafe signed Evidence file", evidence: true, binding: "unsafe", expectedStatus: 409, reachesReadiness: false },
|
||||
{ mode: "safe signed Evidence file", evidence: true, binding: "safe", expectedStatus: 503, reachesReadiness: true },
|
||||
{ mode: "no Evidence descriptor", evidence: false, binding: "missing", expectedStatus: 503, reachesReadiness: true },
|
||||
])("real buildApp admission handles $mode before Pi spawn", async ({
|
||||
evidence, safe, expectedStatus, reachesReadiness,
|
||||
evidence, binding, expectedStatus, reachesReadiness,
|
||||
}) => {
|
||||
const root = mkdtempSync(path.join(tmpdir(), "thoth-evidence-admission-"));
|
||||
const unsafeRoot = mkdtempSync(path.join(tmpdir(), "thoth-evidence-unsafe-"));
|
||||
const signedFile = path.join(root, "signed-urls.json");
|
||||
const unsafeFile = path.join(unsafeRoot, "signed-urls.json");
|
||||
writeFileSync(signedFile, '["CANARY-SIGNED-QUERY"]');
|
||||
writeFileSync(unsafeFile, '["CANARY-UNSAFE-SIGNED-QUERY"]');
|
||||
const variable = "THT_WS_PSD_CLINICAL_EVIDENCE_SIGNED_URLS_FILE";
|
||||
const previous = {
|
||||
transport: process.env.THT_WS_PSD_CLINICAL_DWH_TRANSPORT,
|
||||
@@ -2817,7 +2821,8 @@ test.each([
|
||||
};
|
||||
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;
|
||||
if (binding === "safe") process.env[variable] = signedFile;
|
||||
else if (binding === "unsafe") process.env[variable] = unsafeFile;
|
||||
else delete process.env[variable];
|
||||
|
||||
const descriptor = {
|
||||
@@ -2882,6 +2887,7 @@ test.each([
|
||||
expect(JSON.stringify(descriptor)).toBe(canonicalBefore);
|
||||
expect(revision.commit).toBe("a".repeat(40));
|
||||
expect(response.body).not.toContain("CANARY-SIGNED-QUERY");
|
||||
expect(response.body).not.toContain("CANARY-UNSAFE-SIGNED-QUERY");
|
||||
} finally {
|
||||
const restore = (name: string, value: string | undefined) => {
|
||||
if (value === undefined) delete process.env[name];
|
||||
@@ -2891,5 +2897,6 @@ test.each([
|
||||
restore("THT_WS_PSD_CLINICAL_DWH_BASE_URL", previous.baseUrl);
|
||||
restore(variable, previous.signed);
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
rmSync(unsafeRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { expect, test, vi } from "vitest";
|
||||
import yazl from "yazl";
|
||||
import { buildApp } from "../src/app.js";
|
||||
import { loadConfig } from "../src/config.js";
|
||||
import { createProductionWorkspaceDiagnoser } from "../src/workspaces/diagnostics.js";
|
||||
import { WorkspaceRegistryError } from "../src/workspaces/git-repository.js";
|
||||
import type { WorkspaceRegistry, WorkspaceRevision } from "../src/workspaces/registry.js";
|
||||
import { renderWorkspaceDocs, serializeWorkspaceYaml, type CanonicalWorkspace, type WorkspaceV2 } from "../src/workspaces/schema.js";
|
||||
@@ -283,6 +284,51 @@ test("runs diagnostics for a schema v3 workspace without external semantic bindi
|
||||
}), { writeProbe: false });
|
||||
});
|
||||
|
||||
test("reports missing Evidence binding through the real test route without changing registry revision", async () => {
|
||||
const evidenceWorkspace: CanonicalWorkspace = {
|
||||
...workspace,
|
||||
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 },
|
||||
},
|
||||
};
|
||||
const read = vi.fn(async () => ({ workspace: evidenceWorkspace, revision }));
|
||||
const registry = registryFake({ read });
|
||||
const app = appFor(registry, createProductionWorkspaceDiagnoser(100));
|
||||
const variable = "THT_WS_PSD_CLINICAL_EVIDENCE_SIGNED_URLS_FILE";
|
||||
const previous = process.env[variable];
|
||||
delete process.env[variable];
|
||||
|
||||
try {
|
||||
const res = await app.inject({ method: "POST", url: "/workspaces/psd-clinical/test", payload: {} });
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
const body = res.json();
|
||||
expect(body.activatable).toBe(false);
|
||||
expect(body.diagnostics).toEqual(expect.arrayContaining([expect.objectContaining({
|
||||
code: "binding_missing",
|
||||
field: "evidence.source.authentication",
|
||||
variable,
|
||||
})]));
|
||||
expect(read).toHaveBeenCalledTimes(1);
|
||||
expect(registry.publish).not.toHaveBeenCalled();
|
||||
expect(revision).toMatchObject({ commit: "a".repeat(40), blob: "b".repeat(40) });
|
||||
} finally {
|
||||
if (previous === undefined) delete process.env[variable];
|
||||
else process.env[variable] = previous;
|
||||
}
|
||||
});
|
||||
|
||||
test("returns a 409 field conflict instead of overwriting a changed workspace", async () => {
|
||||
const conflict = Object.assign(
|
||||
new WorkspaceRegistryError("workspace_conflict", "Workspace has changed"),
|
||||
|
||||
@@ -123,6 +123,7 @@ const directBindings: RuntimeBindings = {
|
||||
missing: [],
|
||||
values: { THT_WS_PSD_CLINICAL_EMBEDDING_BASE_URL: "http://embedding.internal:11434" },
|
||||
},
|
||||
evidence: { missing: [], values: {} },
|
||||
};
|
||||
|
||||
test("runtime support stays fail-closed for either SSH connector", () => {
|
||||
|
||||
Reference in New Issue
Block a user