feat: render revision-bound evidence configuration
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import {
|
||||
chmodSync, existsSync, mkdtempSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync,
|
||||
chmodSync, existsSync, mkdtempSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
@@ -42,6 +43,18 @@ llm_policy:
|
||||
allowed: [zai/glm-5.2]
|
||||
`;
|
||||
|
||||
const filesystemWorkspace = `${canonicalWorkspace}evidence:
|
||||
source:
|
||||
type: filesystem
|
||||
uri: workspace-content/psd-clinical/evidence
|
||||
`;
|
||||
|
||||
function evidenceWorkspace(source: string, policy = ""): string {
|
||||
return `${canonicalWorkspace}evidence:
|
||||
source:
|
||||
${source}${policy}`;
|
||||
}
|
||||
|
||||
const migrationRequiredWorkspace = canonicalWorkspace
|
||||
.replace("schema_version: 3", "schema_version: 2")
|
||||
.replace(
|
||||
@@ -63,7 +76,7 @@ async function git(cwd: string, args: string[]): Promise<string> {
|
||||
return (await runFile("git", args, { cwd })).stdout.trim();
|
||||
}
|
||||
|
||||
async function fixture(workspaceSource = canonicalWorkspace) {
|
||||
async function fixture(workspaceSource = filesystemWorkspace) {
|
||||
const root = mkdtempSync(join(tmpdir(), "tht-runtime-handoff-"));
|
||||
roots.push(root);
|
||||
const remote = join(root, "remote.git");
|
||||
@@ -78,14 +91,26 @@ async function fixture(workspaceSource = canonicalWorkspace) {
|
||||
await git(source, ["config", "user.email", "runtime-handoff@example.invalid"]);
|
||||
mkdirSync(join(source, "workspaces"));
|
||||
writeFileSync(join(source, "workspaces", "psd-clinical.yaml"), workspaceSource);
|
||||
await git(source, ["add", "workspaces/psd-clinical.yaml"]);
|
||||
const evidenceRoot = join(source, "workspace-content", "psd-clinical", "evidence");
|
||||
mkdirSync(evidenceRoot, { recursive: true });
|
||||
writeFileSync(join(evidenceRoot, "guide.md"), "# Immutable revision evidence\n");
|
||||
await git(source, ["add", "."]);
|
||||
await git(source, ["commit", "-m", "Canonical workspace"]);
|
||||
await git(source, ["remote", "add", "origin", remote]);
|
||||
await git(source, ["push", "origin", "main"]);
|
||||
mkdirSync(secretRoot);
|
||||
for (const name of ["dwh-password"]) {
|
||||
const secretContents: Record<string, string> = {
|
||||
"dwh-password": "dwh-password-value",
|
||||
"evidence-signed-urls.json": JSON.stringify([
|
||||
"https://evidence.example.test/guide.md?token=SIGNED-HANDOFF-CANARY",
|
||||
]),
|
||||
"evidence-access": "ACCESS-HANDOFF-CANARY",
|
||||
"evidence-secret": "SECRET-HANDOFF-CANARY",
|
||||
"evidence-token": "TOKEN-HANDOFF-CANARY",
|
||||
};
|
||||
for (const [name, contents] of Object.entries(secretContents)) {
|
||||
const path = join(secretRoot, name);
|
||||
writeFileSync(path, `${name}-value`, { mode: 0o600 });
|
||||
writeFileSync(path, contents, { mode: 0o600 });
|
||||
chmodSync(path, 0o600);
|
||||
}
|
||||
mkdirSync(dataRoot);
|
||||
@@ -109,10 +134,14 @@ async function fixture(workspaceSource = canonicalWorkspace) {
|
||||
THT_WS_PSD_CLINICAL_DWH_PORT: "5432",
|
||||
THT_WS_PSD_CLINICAL_DWH_USER: "reader",
|
||||
THT_WS_PSD_CLINICAL_DWH_PASSWORD_FILE: join(secretRoot, "dwh-password"),
|
||||
THT_WS_PSD_CLINICAL_EVIDENCE_SIGNED_URLS_FILE: join(secretRoot, "evidence-signed-urls.json"),
|
||||
THT_WS_PSD_CLINICAL_EVIDENCE_ACCESS_KEY_FILE: join(secretRoot, "evidence-access"),
|
||||
THT_WS_PSD_CLINICAL_EVIDENCE_SECRET_KEY_FILE: join(secretRoot, "evidence-secret"),
|
||||
THT_WS_PSD_CLINICAL_EVIDENCE_SESSION_TOKEN_FILE: join(secretRoot, "evidence-token"),
|
||||
};
|
||||
for (const [name, value] of Object.entries(environment)) vi.stubEnv(name, value);
|
||||
vi.stubEnv("THT_HOME", join(root, "home"));
|
||||
return { root, dataRoot, registry, registryConfig, revision };
|
||||
return { root, dataRoot, secretRoot, registry, registryConfig, revision };
|
||||
}
|
||||
|
||||
function runnerFor(f: Awaited<ReturnType<typeof fixture>>): ThtRunner {
|
||||
@@ -148,30 +177,160 @@ test("real schema-v3 registry revision loads through ThtRunner and the harness c
|
||||
expect(readdirSync(join(f.registryConfig.root, "snapshots", "runtime"))).toEqual([]);
|
||||
});
|
||||
|
||||
test("separate runtime leases hand off one stable logical workspace identity", async () => {
|
||||
test("separate runtime leases hand off byte-identical revision Evidence configs accepted by tht", async () => {
|
||||
const f = await fixture();
|
||||
const runner = runnerFor(f);
|
||||
const first = runner.acquireWorkspaceRuntime(f.revision.snapshotPath);
|
||||
const second = runner.acquireWorkspaceRuntime(f.revision.snapshotPath);
|
||||
const expectedRoot = join(
|
||||
f.registryConfig.root,
|
||||
"snapshots",
|
||||
f.revision.commit,
|
||||
"workspace-content",
|
||||
"psd-clinical",
|
||||
"evidence",
|
||||
);
|
||||
|
||||
try {
|
||||
expect(first.path).not.toBe(second.path);
|
||||
expect(parse(readFileSync(first.path, "utf8")).runtime_identity).toEqual({
|
||||
const firstYaml = readFileSync(first.path, "utf8");
|
||||
const secondYaml = readFileSync(second.path, "utf8");
|
||||
expect(secondYaml).toBe(firstYaml);
|
||||
expect(parse(firstYaml).runtime_identity).toEqual({
|
||||
workspace_id: "psd-clinical",
|
||||
workspace_revision: f.revision.commit,
|
||||
source_identity: "workspace://psd-clinical",
|
||||
});
|
||||
expect(parse(readFileSync(second.path, "utf8")).runtime_identity).toEqual({
|
||||
workspace_id: "psd-clinical",
|
||||
workspace_revision: f.revision.commit,
|
||||
source_identity: "workspace://psd-clinical",
|
||||
expect(parse(firstYaml).evidence).toEqual({
|
||||
sources: [{
|
||||
type: "filesystem",
|
||||
root: expectedRoot,
|
||||
patterns: ["**/*.md"],
|
||||
max_bytes: 10_485_760,
|
||||
}],
|
||||
});
|
||||
expect(parse(firstYaml).vector).toEqual({
|
||||
max_chunk_chars: 4_000,
|
||||
retain_published_generations: 3,
|
||||
});
|
||||
expect(expectedRoot).not.toContain(join(f.registryConfig.root, "repo"));
|
||||
|
||||
for (const lease of [first, second]) {
|
||||
const checked = await runFile(thtBin, ["config", "check", "-c", lease.path], {
|
||||
cwd: harnessDir,
|
||||
env: { ...process.env, THT_HOME: join(f.root, "home") },
|
||||
});
|
||||
expect(`${checked.stdout}${checked.stderr}`).not.toContain("HANDOFF-CANARY");
|
||||
}
|
||||
|
||||
first.release();
|
||||
expect(existsSync(first.path)).toBe(false);
|
||||
expect(existsSync(second.path)).toBe(true);
|
||||
second.release();
|
||||
expect(existsSync(second.path)).toBe(false);
|
||||
} finally {
|
||||
first.release();
|
||||
second.release();
|
||||
}
|
||||
});
|
||||
|
||||
test("signed HTTP Evidence resolves its file binding and config check never captures its contents", async () => {
|
||||
const f = await fixture(evidenceWorkspace(` type: http
|
||||
uris: [https://evidence.example.test/guide.md]
|
||||
authentication: signed_urls_file
|
||||
connect_timeout_ms: 1250
|
||||
read_timeout_ms: 30001
|
||||
max_bytes: 12345
|
||||
max_redirects: 2
|
||||
allow_private_hosts: false
|
||||
max_cache_bytes: 67890
|
||||
`));
|
||||
const runner = runnerFor(f);
|
||||
const lease = runner.acquireWorkspaceRuntime(f.revision.snapshotPath);
|
||||
try {
|
||||
const yaml = readFileSync(lease.path, "utf8");
|
||||
expect(parse(yaml).evidence.sources).toEqual([{
|
||||
type: "http",
|
||||
provenance_urls: ["https://evidence.example.test/guide.md"],
|
||||
signed_urls_file: realpathSync(join(f.secretRoot, "evidence-signed-urls.json")),
|
||||
connect_timeout: 1.25,
|
||||
read_timeout: 30.001,
|
||||
max_bytes: 12_345,
|
||||
max_redirects: 2,
|
||||
allow_private_hosts: false,
|
||||
max_cache_bytes: 67_890,
|
||||
}]);
|
||||
expect(yaml).not.toContain("SIGNED-HANDOFF-CANARY");
|
||||
|
||||
const checked = await runFile(thtBin, ["config", "check", "-c", lease.path], {
|
||||
cwd: harnessDir,
|
||||
env: { ...process.env, THT_HOME: join(f.root, "home") },
|
||||
});
|
||||
expect(`${checked.stdout}${checked.stderr}`).not.toContain("SIGNED-HANDOFF-CANARY");
|
||||
} finally {
|
||||
lease.release();
|
||||
}
|
||||
});
|
||||
|
||||
test("static S3 Evidence resolves only configured secret-root file paths", async () => {
|
||||
const f = await fixture(evidenceWorkspace(` type: s3
|
||||
uri: s3://clinical-evidence/published/
|
||||
endpoint_url: https://s3.example.test/
|
||||
region: eu-west-1
|
||||
credentials: static_files
|
||||
trusted_endpoint: true
|
||||
allow_private_endpoint: true
|
||||
allow_insecure_endpoint: false
|
||||
max_bytes: 222
|
||||
max_objects: 33
|
||||
max_pages: 4
|
||||
page_size: 5
|
||||
`, ` policy:
|
||||
max_chunk_chars: 2500
|
||||
retain_published_generations: 7
|
||||
`));
|
||||
const runner = runnerFor(f);
|
||||
const lease = runner.acquireWorkspaceRuntime(f.revision.snapshotPath);
|
||||
try {
|
||||
const yaml = readFileSync(lease.path, "utf8");
|
||||
expect(parse(yaml).evidence.sources).toEqual([{
|
||||
type: "s3",
|
||||
bucket: "clinical-evidence",
|
||||
prefix: "published/",
|
||||
endpoint_url: "https://s3.example.test/",
|
||||
region: "eu-west-1",
|
||||
access_key_file: realpathSync(join(f.secretRoot, "evidence-access")),
|
||||
secret_key_file: realpathSync(join(f.secretRoot, "evidence-secret")),
|
||||
session_token_file: realpathSync(join(f.secretRoot, "evidence-token")),
|
||||
trusted_endpoint: true,
|
||||
allow_private_endpoint: true,
|
||||
allow_insecure_endpoint: false,
|
||||
max_bytes: 222,
|
||||
max_objects: 33,
|
||||
max_pages: 4,
|
||||
page_size: 5,
|
||||
}]);
|
||||
expect(parse(yaml).vector).toEqual({
|
||||
max_chunk_chars: 2_500,
|
||||
retain_published_generations: 7,
|
||||
});
|
||||
for (const canary of ["ACCESS-HANDOFF-CANARY", "SECRET-HANDOFF-CANARY", "TOKEN-HANDOFF-CANARY"]) {
|
||||
expect(yaml).not.toContain(canary);
|
||||
}
|
||||
|
||||
const checked = await runFile(thtBin, ["config", "check", "-c", lease.path], {
|
||||
cwd: harnessDir,
|
||||
env: { ...process.env, THT_HOME: join(f.root, "home") },
|
||||
});
|
||||
const output = `${checked.stdout}${checked.stderr}`;
|
||||
for (const canary of ["ACCESS-HANDOFF-CANARY", "SECRET-HANDOFF-CANARY", "TOKEN-HANDOFF-CANARY"]) {
|
||||
expect(output).not.toContain(canary);
|
||||
}
|
||||
} finally {
|
||||
lease.release();
|
||||
}
|
||||
});
|
||||
|
||||
test("ThtRunner refuses to render a migration-required registry snapshot", async () => {
|
||||
const f = await fixture(migrationRequiredWorkspace);
|
||||
const runner = runnerFor(f);
|
||||
|
||||
Reference in New Issue
Block a user