test: strengthen evidence runtime handoff coverage
This commit is contained in:
@@ -141,7 +141,7 @@ async function fixture(workspaceSource = filesystemWorkspace) {
|
|||||||
};
|
};
|
||||||
for (const [name, value] of Object.entries(environment)) vi.stubEnv(name, value);
|
for (const [name, value] of Object.entries(environment)) vi.stubEnv(name, value);
|
||||||
vi.stubEnv("THT_HOME", join(root, "home"));
|
vi.stubEnv("THT_HOME", join(root, "home"));
|
||||||
return { root, dataRoot, secretRoot, registry, registryConfig, revision };
|
return { root, source, dataRoot, secretRoot, registry, registryConfig, revision };
|
||||||
}
|
}
|
||||||
|
|
||||||
function runnerFor(f: Awaited<ReturnType<typeof fixture>>): ThtRunner {
|
function runnerFor(f: Awaited<ReturnType<typeof fixture>>): ThtRunner {
|
||||||
@@ -234,6 +234,52 @@ test("separate runtime leases hand off byte-identical revision Evidence configs
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("real Evidence-content-only commit changes runtime identity and root with identical descriptor YAML", async () => {
|
||||||
|
const f = await fixture();
|
||||||
|
const runner = runnerFor(f);
|
||||||
|
const first = runner.acquireWorkspaceRuntime(f.revision.snapshotPath);
|
||||||
|
const descriptorBefore = readFileSync(f.revision.snapshotPath, "utf8");
|
||||||
|
writeFileSync(
|
||||||
|
join(f.source, "workspace-content", "psd-clinical", "evidence", "guide.md"),
|
||||||
|
"# Content-only revision two\n",
|
||||||
|
);
|
||||||
|
await git(f.source, ["add", "workspace-content/psd-clinical/evidence/guide.md"]);
|
||||||
|
await git(f.source, ["commit", "-m", "Update Evidence content only"]);
|
||||||
|
await git(f.source, ["push", "origin", "main"]);
|
||||||
|
await f.registry.pull();
|
||||||
|
const current = (await f.registry.list())[0];
|
||||||
|
const second = runner.acquireWorkspaceRuntime(current.snapshotPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
expect(current.commit).not.toBe(f.revision.commit);
|
||||||
|
expect(current.blob).toBe(f.revision.blob);
|
||||||
|
expect(readFileSync(current.snapshotPath, "utf8")).toBe(descriptorBefore);
|
||||||
|
const firstRendered = parse(readFileSync(first.path, "utf8"));
|
||||||
|
const secondRendered = parse(readFileSync(second.path, "utf8"));
|
||||||
|
expect(firstRendered.runtime_identity.workspace_revision).toBe(f.revision.commit);
|
||||||
|
expect(secondRendered.runtime_identity.workspace_revision).toBe(current.commit);
|
||||||
|
expect(secondRendered.evidence.sources[0].root).toBe(join(
|
||||||
|
f.registryConfig.root,
|
||||||
|
"snapshots",
|
||||||
|
current.commit,
|
||||||
|
"workspace-content",
|
||||||
|
"psd-clinical",
|
||||||
|
"evidence",
|
||||||
|
));
|
||||||
|
expect(secondRendered.evidence.sources[0].root).not.toBe(firstRendered.evidence.sources[0].root);
|
||||||
|
|
||||||
|
for (const lease of [first, second]) {
|
||||||
|
await expect(runFile(thtBin, ["config", "check", "-c", lease.path], {
|
||||||
|
cwd: harnessDir,
|
||||||
|
env: { ...process.env, THT_HOME: join(f.root, "home") },
|
||||||
|
})).resolves.toBeDefined();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
first.release();
|
||||||
|
second.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("signed HTTP Evidence resolves its file binding and config check never captures its contents", async () => {
|
test("signed HTTP Evidence resolves its file binding and config check never captures its contents", async () => {
|
||||||
const f = await fixture(evidenceWorkspace(` type: http
|
const f = await fixture(evidenceWorkspace(` type: http
|
||||||
uris: [https://evidence.example.test/guide.md]
|
uris: [https://evidence.example.test/guide.md]
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { expect, test } from "vitest";
|
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { afterEach, expect, test } from "vitest";
|
||||||
import { parse } from "yaml";
|
import { parse } from "yaml";
|
||||||
import {
|
import {
|
||||||
renderRuntimeConfig,
|
renderRuntimeConfig,
|
||||||
@@ -300,6 +303,20 @@ test("renders REST bindings through the legacy rest sections without secret valu
|
|||||||
expect(yaml).not.toContain("\n api_key: ");
|
expect(yaml).not.toContain("\n api_key: ");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const evidenceSecretRoots: string[] = [];
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
evidenceSecretRoots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
function evidenceSecretFile(name: string, contents: string): string {
|
||||||
|
const root = mkdtempSync(join(tmpdir(), "tht-renderer-evidence-secret-"));
|
||||||
|
evidenceSecretRoots.push(root);
|
||||||
|
const path = join(root, name);
|
||||||
|
writeFileSync(path, contents, { mode: 0o600 });
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
function evidenceWorkspace(source: Record<string, unknown>, policy?: Record<string, unknown>) {
|
function evidenceWorkspace(source: Record<string, unknown>, policy?: Record<string, unknown>) {
|
||||||
return parseWorkspaceYaml(`${canonicalEvidenceWorkspace}\nevidence:\n source: ${JSON.stringify(source)}${
|
return parseWorkspaceYaml(`${canonicalEvidenceWorkspace}\nevidence:\n source: ${JSON.stringify(source)}${
|
||||||
policy === undefined ? "" : `\n policy: ${JSON.stringify(policy)}`
|
policy === undefined ? "" : `\n policy: ${JSON.stringify(policy)}`
|
||||||
@@ -410,7 +427,8 @@ test("renders public HTTP Evidence with exact fractional-second timeouts and eve
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("renders signed HTTP Evidence as provenance plus a validated file path only", () => {
|
test("renders signed HTTP Evidence as provenance plus a validated file path only", () => {
|
||||||
const signedFile = "/run/secrets/evidence-signed-urls.json";
|
const canary = "SIGNED-URL-CANARY-CONTENT";
|
||||||
|
const signedFile = evidenceSecretFile("evidence-signed-urls.json", canary);
|
||||||
const yaml = evidenceRender({
|
const yaml = evidenceRender({
|
||||||
type: "http",
|
type: "http",
|
||||||
uris: [
|
uris: [
|
||||||
@@ -437,7 +455,7 @@ test("renders signed HTTP Evidence as provenance plus a validated file path only
|
|||||||
allow_private_hosts: false,
|
allow_private_hosts: false,
|
||||||
max_cache_bytes: 67_108_864,
|
max_cache_bytes: 67_108_864,
|
||||||
}]);
|
}]);
|
||||||
expect(yaml).not.toContain("SIGNED-URL-CANARY-CONTENT");
|
expect(yaml).not.toContain(canary);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders ambient S3 Evidence without credential keys", () => {
|
test("renders ambient S3 Evidence without credential keys", () => {
|
||||||
@@ -465,7 +483,13 @@ test("renders ambient S3 Evidence without credential keys", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("renders static S3 Evidence with endpoint policy, limits, and file paths but no contents", () => {
|
test("renders static S3 Evidence with endpoint policy, limits, and file paths but no contents", () => {
|
||||||
const yaml = evidenceRender({
|
const accessCanary = "ACCESS-CANARY-CONTENT";
|
||||||
|
const secretCanary = "SECRET-CANARY-CONTENT";
|
||||||
|
const tokenCanary = "TOKEN-CANARY-CONTENT";
|
||||||
|
const accessFile = evidenceSecretFile("evidence-access", accessCanary);
|
||||||
|
const secretFile = evidenceSecretFile("evidence-secret", secretCanary);
|
||||||
|
const tokenFile = evidenceSecretFile("evidence-token", tokenCanary);
|
||||||
|
const source = {
|
||||||
type: "s3",
|
type: "s3",
|
||||||
uri: "s3://clinical-evidence/published/",
|
uri: "s3://clinical-evidence/published/",
|
||||||
credentials: "static_files",
|
credentials: "static_files",
|
||||||
@@ -478,14 +502,13 @@ test("renders static S3 Evidence with endpoint policy, limits, and file paths bu
|
|||||||
max_objects: 33,
|
max_objects: 33,
|
||||||
max_pages: 4,
|
max_pages: 4,
|
||||||
page_size: 5,
|
page_size: 5,
|
||||||
}, {
|
};
|
||||||
missing: [],
|
const values = {
|
||||||
values: {
|
THT_WS_PSD_CLINICAL_EVIDENCE_ACCESS_KEY_FILE: accessFile,
|
||||||
THT_WS_PSD_CLINICAL_EVIDENCE_ACCESS_KEY_FILE: "/run/secrets/evidence-access",
|
THT_WS_PSD_CLINICAL_EVIDENCE_SECRET_KEY_FILE: secretFile,
|
||||||
THT_WS_PSD_CLINICAL_EVIDENCE_SECRET_KEY_FILE: "/run/secrets/evidence-secret",
|
THT_WS_PSD_CLINICAL_EVIDENCE_SESSION_TOKEN_FILE: tokenFile,
|
||||||
THT_WS_PSD_CLINICAL_EVIDENCE_SESSION_TOKEN_FILE: "/run/secrets/evidence-token",
|
};
|
||||||
},
|
const yaml = evidenceRender(source, { missing: [], values });
|
||||||
});
|
|
||||||
|
|
||||||
expect(parse(yaml).evidence.sources).toEqual([{
|
expect(parse(yaml).evidence.sources).toEqual([{
|
||||||
type: "s3",
|
type: "s3",
|
||||||
@@ -493,9 +516,9 @@ test("renders static S3 Evidence with endpoint policy, limits, and file paths bu
|
|||||||
prefix: "published/",
|
prefix: "published/",
|
||||||
endpoint_url: "http://minio.internal:9000/",
|
endpoint_url: "http://minio.internal:9000/",
|
||||||
region: "eu-central-1",
|
region: "eu-central-1",
|
||||||
access_key_file: "/run/secrets/evidence-access",
|
access_key_file: accessFile,
|
||||||
secret_key_file: "/run/secrets/evidence-secret",
|
secret_key_file: secretFile,
|
||||||
session_token_file: "/run/secrets/evidence-token",
|
session_token_file: tokenFile,
|
||||||
trusted_endpoint: true,
|
trusted_endpoint: true,
|
||||||
allow_private_endpoint: true,
|
allow_private_endpoint: true,
|
||||||
allow_insecure_endpoint: true,
|
allow_insecure_endpoint: true,
|
||||||
@@ -504,9 +527,19 @@ test("renders static S3 Evidence with endpoint policy, limits, and file paths bu
|
|||||||
max_pages: 4,
|
max_pages: 4,
|
||||||
page_size: 5,
|
page_size: 5,
|
||||||
}]);
|
}]);
|
||||||
expect(yaml).not.toContain("ACCESS-CANARY-CONTENT");
|
expect(yaml).not.toContain(accessCanary);
|
||||||
expect(yaml).not.toContain("SECRET-CANARY-CONTENT");
|
expect(yaml).not.toContain(secretCanary);
|
||||||
expect(yaml).not.toContain("TOKEN-CANARY-CONTENT");
|
expect(yaml).not.toContain(tokenCanary);
|
||||||
|
|
||||||
|
const withoutToken = parse(evidenceRender(source, {
|
||||||
|
missing: [],
|
||||||
|
values: {
|
||||||
|
THT_WS_PSD_CLINICAL_EVIDENCE_ACCESS_KEY_FILE: accessFile,
|
||||||
|
THT_WS_PSD_CLINICAL_EVIDENCE_SECRET_KEY_FILE: secretFile,
|
||||||
|
},
|
||||||
|
})).evidence.sources[0];
|
||||||
|
expect(withoutToken).toMatchObject({ access_key_file: accessFile, secret_key_file: secretFile });
|
||||||
|
expect(withoutToken).not.toHaveProperty("session_token_file");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("omits Evidence configuration and policy when the descriptor has no Evidence", () => {
|
test("omits Evidence configuration and policy when the descriptor has no Evidence", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user