Files
ThothII/backend/scripts/verify-workspace-descriptor-files.test.mjs
T

980 lines
36 KiB
JavaScript

import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import test from "node:test";
import { extractScriptDocuments, verifyEntries } from "./verify-workspace-descriptor-files.mjs";
const repositoryRoot = fileURLToPath(new URL("../..", import.meta.url));
const canonicalDescriptor = await readFile(join(repositoryRoot, "deploy/workspaces/example.yaml"), "utf8");
async function fixture(t) {
const root = await mkdtemp(join(tmpdir(), "thoth-workspace-yaml-verifier-"));
t.after(() => rm(root, { recursive: true, force: true }));
return root;
}
async function put(root, path, content) {
await mkdir(dirname(join(root, path)), { recursive: true });
await writeFile(join(root, path), content);
}
function entry(kind, path) {
return { kind, path };
}
function bashN(root, path) {
execFileSync("/bin/bash", ["-n", join(root, path)], { stdio: "pipe" });
}
function replaceWorkspaceKeys(source, workspaceKey, schemaLine) {
return source
.replace(/^workspace:$/m, workspaceKey)
.replace(/^ schema_version: 4$/m, schemaLine);
}
test("production parser accepts semantic v4 with quoted Unicode/tagged keys and spacing", async (t) => {
const root = await fixture(t);
const unicode = replaceWorkspaceKeys(
canonicalDescriptor,
'"\\u0077orkspace" :',
' "\\u0073chema_version" : 4',
);
const tagged = replaceWorkspaceKeys(
canonicalDescriptor,
"!!str workspace :",
" !!str schema_version : 4",
);
await put(root, "deploy/workspaces/unicode.yaml", unicode);
await put(root, "deploy/workspaces/tagged.yaml", tagged);
await verifyEntries({
root,
entries: [
entry("workspace_descriptor", "deploy/workspaces/unicode.yaml"),
entry("workspace_descriptor", "deploy/workspaces/tagged.yaml"),
],
});
});
test("production parser rejects fancy keys with every non-v4 or ambiguous value", async (t) => {
const invalid = [
["unicode-v2", '"\\u0077orkspace" :', ' "\\u0073chema_version" : 2'],
["unicode-v3", '"\\u0077orkspace" :', ' "\\u0073chema_version" : 3'],
["tagged-leading-zero", "!!str workspace :", " !!str schema_version : 03"],
["hexadecimal", "workspace :", " schema_version : 0x3"],
["multiline", "workspace :", " schema_version : >\n 4"],
["duplicate", "workspace :", " schema_version : 4\n schema_version: 4"],
["inline", "workspace: { schema_version: 4 }", " schema_version: 4"],
];
for (const [name, workspaceKey, schemaLine] of invalid) {
await t.test(name, async () => {
const root = await mkdtemp(join(tmpdir(), `thoth-workspace-yaml-${name}-`));
try {
const source = replaceWorkspaceKeys(canonicalDescriptor, workspaceKey, schemaLine);
const path = `deploy/workspaces/${name}.yaml`;
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("workspace_descriptor", path)] }),
/workspace descriptor/i,
);
} finally {
await rm(root, { recursive: true, force: true });
}
});
}
});
test("Bash embedded workspace mappings are rejected while tracked-fixture-only bundles pass", async (t) => {
const root = await fixture(t);
const validScript = [
"#!/usr/bin/env bash",
"cat <<'WORKSPACE_YAML'",
canonicalDescriptor.trimEnd(),
"WORKSPACE_YAML",
"cat <<'BUNDLE_YAML'",
"bundle:",
" name: deploy",
"schema_version: 1",
"job:",
" state: operational",
"BUNDLE_YAML",
"",
].join("\n");
await put(root, "scripts/operator-smoke.sh", validScript);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", "scripts/operator-smoke.sh")] }),
/embedded workspace descriptor/i,
);
const bundleScript = validScript.replace(canonicalDescriptor.trimEnd(), "job:\n name: deploy");
await put(root, "scripts/operator-smoke.sh", bundleScript);
await verifyEntries({
root,
entries: [entry("deployment_script", "scripts/operator-smoke.sh")],
});
});
test("PowerShell embedded workspace mappings are rejected while bundle-only strings pass", async (t) => {
const root = await fixture(t);
const source = [
"$workspace = @'",
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 0x2").trimEnd(),
"'@",
'$bundle = @"',
"bundle:",
" schema_version: 1",
'"@',
"",
].join("\n");
await put(root, "scripts/operator.ps1", source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", "scripts/operator.ps1")] }),
/workspace descriptor/i,
);
});
test("workspace descriptor family entries require a top-level workspace", async (t) => {
const root = await fixture(t);
await put(root, "scripts/fixtures/workspace-registry-future.yaml", "bundle:\n schema_version: 4\n");
await assert.rejects(
verifyEntries({
root,
entries: [entry("workspace_descriptor", "scripts/fixtures/workspace-registry-future.yaml")],
}),
/top-level workspace/i,
);
});
test("script scalar workspace remains a bundle even with descriptor-like siblings", async (t) => {
const root = await fixture(t);
const path = "scripts/job-smoke.sh";
const job = [
"#!/usr/bin/env bash",
"cat <<'JOB-YAML'",
"job: refresh",
"workspace: analytics",
"schema_version: 2",
"state: operational",
"JOB-YAML",
"",
].join("\n");
await put(root, path, job);
bashN(root, path);
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
const bundles = [
job.replace("job: refresh", "dwh:\n engine: postgres"),
job.replace("job: refresh", "evidence:\n source: bundle"),
];
for (const bundle of bundles) {
await put(root, path, bundle);
bashN(root, path);
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
}
});
test("standalone descriptor files require workspace to be a mapping", async (t) => {
const root = await fixture(t);
const path = "scripts/fixtures/workspace-registry-scalar.yaml";
await put(root, path, "workspace: analytics\nschema_version: 4\n");
await assert.rejects(
verifyEntries({ root, entries: [entry("workspace_descriptor", path)] }),
/workspace.*mapping/i,
);
});
test("Bash extractor supports hyphen, digit, escaped delimiters, and tab stripping", async (t) => {
const root = await fixture(t);
const cases = [
{
name: "hyphen-v2",
opener: "cat <<'WORKSPACE-YAML'",
delimiter: "WORKSPACE-YAML",
descriptor: canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2"),
rejected: true,
},
{
name: "digit-v4",
opener: "cat <<2YAML",
delimiter: "2YAML",
descriptor: canonicalDescriptor,
rejected: true,
},
{
name: "escaped-v2",
opener: "cat <<WORKSPACE\\-YAML",
delimiter: "WORKSPACE-YAML",
descriptor: canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2"),
rejected: true,
},
{
name: "tab-strip-v4",
opener: "cat <<-'TAB-YAML'",
delimiter: "\tTAB-YAML",
descriptor: canonicalDescriptor.split("\n").map((line) => `\t${line}`).join("\n"),
rejected: true,
},
];
for (const item of cases) {
await t.test(item.name, async () => {
const path = `scripts/${item.name}-smoke.sh`;
const source = ["#!/usr/bin/env bash", item.opener, item.descriptor.trimEnd(), item.delimiter, ""].join("\n");
await put(root, path, source);
bashN(root, path);
const verification = verifyEntries({ root, entries: [entry("deployment_script", path)] });
if (item.rejected) await assert.rejects(verification, /workspace descriptor/i);
else await verification;
});
}
});
test("unsupported Bash heredoc opener fails closed while a bundle heredoc stays allowed", async (t) => {
const root = await fixture(t);
const unsupportedPath = "scripts/unsupported-smoke.sh";
const unsupported = [
"#!/usr/bin/env bash",
"cat <<$DELIMITER",
canonicalDescriptor.trimEnd(),
"$DELIMITER",
"",
].join("\n");
await put(root, unsupportedPath, unsupported);
bashN(root, unsupportedPath);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", unsupportedPath)] }),
/unsupported Bash heredoc opener/i,
);
const bundlePath = "scripts/bundle-smoke.sh";
const bundle = [
"#!/usr/bin/env bash",
"cat <<'BUNDLE-YAML'",
"job: refresh",
"workspace: analytics",
"schema_version: 1",
"state: operational",
"BUNDLE-YAML",
"",
].join("\n");
await put(root, bundlePath, bundle);
bashN(root, bundlePath);
await verifyEntries({ root, entries: [entry("deployment_script", bundlePath)] });
});
test("non-stripping heredoc close requires an exact physical delimiter line", async (t) => {
const root = await fixture(t);
const path = "scripts/trailing-close-smoke.sh";
const source = [
"#!/usr/bin/env bash",
"cat <<'---'",
"--- ",
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
"---",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/workspace descriptor/i,
);
});
test("delimiter-like body lines remain content until a real exact close", async (t) => {
const root = await fixture(t);
const path = "scripts/delimiter-content-smoke.sh";
const source = [
"#!/usr/bin/env bash",
"cat <<'END'",
"END ",
" END",
"job: refresh",
"workspace: analytics",
"schema_version: 1",
"END",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
const [candidate] = extractScriptDocuments(source, path);
assert.match(candidate.source, /^END \n END\n/u);
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
});
test("double-quoted non-special backslash is preserved in the delimiter", async (t) => {
const root = await fixture(t);
const path = "scripts/double-quoted-nonspecial-smoke.sh";
const source = [
"#!/usr/bin/env bash",
'cat <<"\\---"',
"---",
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
"\\---",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
assert.match(execFileSync("/bin/bash", [join(root, path)], { encoding: "utf8" }), /schema_version: 2/u);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/workspace descriptor/i,
);
});
test("double-quoted delimiter quote removal matches Bash special escapes", async (t) => {
const root = await fixture(t);
const cases = [
["dollar", 'cat <<"DOL\\$LAR"', "DOL$LAR"],
["backtick", 'cat <<"TIC\\`K"', "TIC`K"],
["quote", 'cat <<"QUO\\\"TE"', 'QUO"TE'],
["backslash", 'cat <<"SLA\\\\SH"', "SLA\\SH"],
["newline", 'cat <<"LINE\\\nBREAK"', "LINEBREAK"],
["nonspecial", 'cat <<"NON\\-SPECIAL"', "NON\\-SPECIAL"],
];
for (const [name, opener, close] of cases) {
const path = `scripts/double-quoted-${name}-smoke.sh`;
const source = ["#!/usr/bin/env bash", opener, "job: refresh", close, ""].join("\n");
await put(root, path, source);
bashN(root, path);
assert.equal(execFileSync("/bin/bash", [join(root, path)], { encoding: "utf8" }), "job: refresh\n");
assert.equal(extractScriptDocuments(source, path)[0].source, "job: refresh\n");
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
}
});
test("split heredoc operator continuation cannot bypass v2 validation", async (t) => {
const root = await fixture(t);
const path = "scripts/split-operator-smoke.sh";
const source = [
"#!/usr/bin/env bash",
"cat <\\",
"<'YAML'",
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
"YAML",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
assert.match(execFileSync("/bin/bash", [join(root, path)], { encoding: "utf8" }), /schema_version: 2/u);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/workspace descriptor/i,
);
});
test("multiple opener continuations are joined before heredoc discovery", async (t) => {
const root = await fixture(t);
const path = "scripts/multiple-continuation-smoke.sh";
const source = [
"#!/usr/bin/env bash",
"cat \\",
"<\\",
"<'YAML'",
"job: refresh",
"workspace: analytics",
"YAML",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
assert.equal(
execFileSync("/bin/bash", [join(root, path)], { encoding: "utf8" }),
"job: refresh\nworkspace: analytics\n",
);
const [candidate] = extractScriptDocuments(source, path);
assert.equal(candidate.label, `${path}:5 Bash heredoc`);
assert.equal(candidate.source, "job: refresh\nworkspace: analytics\n");
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
});
test("backslash-newline inside single quotes is not removed", async (t) => {
const root = await fixture(t);
const path = "scripts/single-quoted-noncontinuation-smoke.sh";
const source = [
"#!/usr/bin/env bash",
"printf '%s' 'literal\\",
"continued'",
"cat <<'YAML'",
"job: refresh",
"workspace: analytics",
"YAML",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
assert.equal(
execFileSync("/bin/bash", [join(root, path)], { encoding: "utf8" }),
"literal\\\ncontinuedjob: refresh\nworkspace: analytics\n",
);
const [candidate] = extractScriptDocuments(source, path);
assert.equal(candidate.label, `${path}:5 Bash heredoc`);
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
});
test("PowerShell comment backslash cannot hide a following v2 here-string", async (t) => {
const root = await fixture(t);
const path = "scripts/powershell-comment-smoke.ps1";
const source = [
"# harmless PowerShell comment \\",
"$workspace = @'",
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
"'@",
"",
].join("\n");
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/workspace descriptor/i,
);
});
test("PowerShell dialect accepts normal v4 and non-workspace bundle here-strings", async (t) => {
const root = await fixture(t);
const path = "scripts/powershell-valid-smoke.ps1";
const source = [
"$workspace = @'",
canonicalDescriptor.trimEnd(),
"'@",
"$bundle = @'",
"evidence:",
" source: bundle",
"schema_version: 2",
"'@",
"",
].join("\n");
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/embedded workspace descriptor/i,
);
const bundleOnly = [
"$bundle = @'",
"evidence:",
" source: bundle",
"schema_version: 2",
"'@",
"",
].join("\n");
await put(root, path, bundleOnly);
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
});
test("unknown deployment script dialect fails closed", async (t) => {
const root = await fixture(t);
const path = "scripts/operator-smoke.cmd";
await put(root, path, "echo harmless\n");
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/unknown deployment script dialect/i,
);
});
test("PowerShell cast and concatenation openers cannot hide embedded descriptors", async (t) => {
const root = await fixture(t);
for (const [name, opener] of [["cast", "[string]@'"], ["concat", "+@'"]]) {
const path = `scripts/powershell-${name}-smoke.ps1`;
const source = [opener, canonicalDescriptor.trimEnd(), "'@", ""].join("\n");
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/embedded workspace descriptor/i,
);
}
});
test("expandable YAML interpolation that can hide a workspace descriptor fails closed", async (t) => {
const root = await fixture(t);
const cases = [
["braced-key", "${key}:\n schema_version: 4"],
["plain-key", "$key:\n schema_version: 4"],
["quoted-key", '"$key" :\n schema_version: 4'],
["subexpression-key", "$($key):\n schema_version: 4"],
["version", "workspace:\n schema_version: $version"],
];
for (const [name, body] of cases) {
const path = `scripts/powershell-interpolation-${name}.ps1`;
await put(root, path, [`$yaml = @\"`, body, `\"@`, ""].join("\n"));
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/interpolation|embedded workspace descriptor/i,
);
}
});
test("Bash heredoc discovery ignores quoted, comment, here-string, and arithmetic tokens", async (t) => {
const root = await fixture(t);
const path = "scripts/bash-lexer-smoke.sh";
const source = [
"#!/usr/bin/env bash",
`printf '%s\\n' \"cat <<'QUOTED'\"`,
`printf '%s\\n' 'cat <<\"SINGLE\"'`,
"# cat <<'COMMENT'",
"value=$((1 << 2))",
`cat <<< \"not a heredoc\"`,
"cat <<'YAML'",
"job: refresh",
"YAML",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
const extracted = extractScriptDocuments(source, path);
assert.equal(extracted.length, 1);
assert.equal(extracted[0].source, "job: refresh\n");
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
});
test("UTF-8 decoding is fatal but literal replacement characters are valid text", async (t) => {
const root = await fixture(t);
const validPath = "deploy/workspaces/replacement.yaml";
await put(root, validPath, `${canonicalDescriptor}# literal replacement: �\n`);
await verifyEntries({ root, entries: [entry("workspace_descriptor", validPath)] });
const invalidPath = "deploy/workspaces/malformed.yaml";
await mkdir(dirname(join(root, invalidPath)), { recursive: true });
await writeFile(join(root, invalidPath), Buffer.concat([Buffer.from(canonicalDescriptor), Buffer.from([0xff])]));
await assert.rejects(
verifyEntries({ root, entries: [entry("workspace_descriptor", invalidPath)] }),
/valid UTF-8/i,
);
});
test("unmarked expandable Bash YAML cannot generate descriptor keys or values at runtime", async (t) => {
const root = await fixture(t);
const cases = [
["quoted", '"$key" :'],
["command", "$(printf workspace):"],
["braced", "${key}:"],
["plain", "$key:"],
];
for (const [name, generatedKey] of cases) {
const path = `scripts/bash-dynamic-${name}.sh`;
const source = [
"#!/usr/bin/env bash",
"key=workspace",
"cat <<YAML",
generatedKey,
" schema_version: 4",
"YAML",
"",
].join("\n");
await put(root, path, source);
bashN(root, path);
assert.match(execFileSync("/bin/bash", [join(root, path)], { encoding: "utf8" }), /workspace/u);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/exact-content reviewed allowlist/i,
);
}
const valuePath = "scripts/bash-dynamic-value.sh";
const valueSource = [
"#!/usr/bin/env bash",
"version=3",
"cat <<YAML",
"workspace:",
" schema_version: $version",
"YAML",
"",
].join("\n");
await put(root, valuePath, valueSource);
bashN(root, valuePath);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", valuePath)] }),
/exact-content reviewed allowlist/i,
);
});
test("an in-band marker cannot authorize expandable content", async (t) => {
const root = await fixture(t);
for (const [path, source] of [
["scripts/fake-marker.sh", [
"#!/usr/bin/env bash",
"# schema-v4-only: expandable-nonworkspace",
"cat <<YAML",
"${DESCRIPTOR}",
"YAML",
"",
].join("\n")],
["scripts/fake-marker.ps1", [
"# schema-v4-only: expandable-nonworkspace",
'$yaml = @"',
"$descriptor",
'"@',
"",
].join("\n")],
]) {
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/exact-content reviewed allowlist/,
);
}
});
test("current exact reviewed expandable blocks pass only at their trusted paths", async (t) => {
const reviewedPaths = [
"scripts/test-server-pi-state-topology.sh",
"scripts/test-vector-backup-restore-safety.sh",
"scripts/test-windows-clone-contract.ps1",
"scripts/unified-deployment-smoke.sh",
"scripts/vector-backup.sh",
"scripts/vector-restore.sh",
];
await verifyEntries({
root: repositoryRoot,
entries: reviewedPaths.map((path) => entry("deployment_script", path)),
});
});
test("PowerShell tokenizer ignores opener text in comments and ordinary strings", async (t) => {
const root = await fixture(t);
const path = "scripts/powershell-lexical-context.ps1";
const source = [
"# example @'",
'\"example @\'\"',
"'example @\"'",
"<# block @'",
"still @\" #>",
"$cast = [string]@'",
"job: cast",
"'@",
"$concat = $cast +@'",
"job: concat",
"'@",
"",
].join("\n");
await put(root, path, source);
const extracted = extractScriptDocuments(source, path);
assert.equal(extracted.length, 2);
assert.deepEqual(extracted.map((item) => item.source), ["job: cast\n", "job: concat\n"]);
await verifyEntries({ root, entries: [entry("deployment_script", path)] });
});
test("policy text rejects NUL and prescribed symbol substrings but permits lower-camel legacy identifiers", async (t) => {
const root = await fixture(t);
await put(root, "backend/src/nul.ts", Buffer.from("safe\0WorkspaceV2"));
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", "backend/src/nul.ts")] }), /NUL byte/);
for (const [name, text] of [
["compat", "type X = WorkspaceV2Compat;"],
["mixed-prescribed", "type X = wOrKsPaCeV2;"],
["lower-deprecated", "type X = deprecatedV2Descriptor;"],
["upper-function", "WRITEMIGRATEDWORKSPACE(value);"],
["adapter", "type X = LegacyWorkspaceAdapter;"],
["lower", "type X = legacyworkspace;"],
["mixed", "type X = LeGaCyWoRkSpAcE;"],
]) {
const path = `backend/src/${name}.ts`;
await put(root, path, text);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /forbidden/);
}
await put(root, "backend/src/allowed.ts", "const legacyWorkspacePath = value;");
await verifyEntries({ root, entries: [entry("policy_text", "backend/src/allowed.ts")] });
});
test("revision-state structural scan permits only the exact historical decoder occurrence", async (t) => {
const root = await fixture(t);
const registry = "backend/src/workspaces/registry.ts";
await put(root, registry, 'if (revision.state !== "operational") return;\n');
await verifyEntries({ root, entries: [entry("policy_text", registry)] });
const variants = [
'if (revision.state !== "operational") return;\nif (revision["state"] === value) return;\n',
'if (workspaceRevision\n .state === value) return;\n',
"if (selectedWorkspace [ 'state' ] === value) return;\n",
];
for (let index = 0; index < variants.length; index += 1) {
const path = index === 0 ? registry : `frontend/src/revision-${index}.ts`;
await put(root, path, variants[index]);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/);
}
});
test("complete descriptors supplied only through Bash or PowerShell variables require exact review", async (t) => {
const root = await fixture(t);
const cases = [
["scripts/variable-descriptor.sh", ["#!/usr/bin/env bash", "cat <<YAML", "${DESCRIPTOR}", "YAML", ""].join("\n")],
["scripts/variable-descriptor.ps1", ['$yaml = @"', "$descriptor", '"@', ""].join("\n")],
];
for (const [path, source] of cases) {
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/exact-content reviewed allowlist/,
);
}
});
test("all Bash and PowerShell positional or special dollar expansions fail without exact review", async (t) => {
const root = await fixture(t);
const cases = [
["scripts/positional.sh", "cat <<YAML\n$1\nYAML\n"],
["scripts/all-args.sh", "cat <<YAML\n$@\nYAML\n"],
["scripts/positional.ps1", '$yaml = @"\n$1\n"@\n'],
];
for (const [path, source] of cases) {
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/exact-content reviewed allowlist/,
);
}
});
test("PowerShell backtick escapes hash and quote tokens without hiding a later real here-string", async (t) => {
const root = await fixture(t);
for (const [name, prefix] of [
["escaped-hash", "Write-Output `# harmless"],
["escaped-quote", 'Write-Output `" harmless'],
]) {
const path = `scripts/${name}.ps1`;
const source = [prefix, "$yaml = @'", "workspace:", " schema_version: 2", "'@", ""].join("\n");
await put(root, path, source);
assert.equal(extractScriptDocuments(source, path).length, 1);
await assert.rejects(
verifyEntries({ root, entries: [entry("deployment_script", path)] }),
/embedded workspace descriptor/,
);
}
});
test("TypeScript AST rejects comment-separated and destructured revision state", async (t) => {
const root = await fixture(t);
for (const [index, source] of [
"const value = revision /*legacy*/ . state;",
"const { state } = revision;",
"const { state: oldState } = selectedWorkspace;",
].entries()) {
const path = `frontend/src/ast-revision-${index}.ts`;
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/);
}
const registry = "backend/src/workspaces/registry.ts";
await put(root, registry, 'if (revision.state !== "operational") return;\nconst { state } = revision;\n');
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", registry)] }), /revision-state/);
await put(root, "backend/src/unrelated.ts", "const { state } = lease; const jobState = job.state;");
await verifyEntries({ root, entries: [entry("policy_text", "backend/src/unrelated.ts")] });
});
test("AST recognizes semantic state keys in every revision destructuring form", async (t) => {
const root = await fixture(t);
const cases = [
["backend/src/computed.mts", 'const { ["state"]: oldState } = revision;'],
["frontend/src/renamed.cts", 'const { "state": oldState = fallback } = workspaceRevision;'],
["backend/scripts/template.TS", 'const { [`state`]: oldState } = selectedWorkspace;'],
["scripts/parameter.txt", 'function read({ state: oldState = fallback } = revision) {}'],
["scripts/assignment.sh", '({ state } = workspaceRevision);'],
["scripts/computed-assignment.data", '({ ["state"]: oldState = fallback } = selectedWorkspace);'],
];
for (const [path, source] of cases) {
await put(root, path, source);
await assert.rejects(
verifyEntries({ root, entries: [entry("policy_text", path)] }),
/revision-state/,
path,
);
}
const registry = "backend/src/workspaces/registry.ts";
await put(root, registry, [
'if (revision.state !== "operational") return;',
'function read({ ["state"]: oldState } = revision) {}',
"",
].join("\n"));
await assert.rejects(
verifyEntries({ root, entries: [entry("policy_text", registry)] }),
/revision-state/,
);
});
test("tolerant all-suffix AST scan ignores strings/comments and unrelated state", async (t) => {
const root = await fixture(t);
const path = "scripts/arbitrary.weird";
await put(root, path, [
'// const { state } = revision;',
'"revision.state";',
"'({ [\\\"state\\\"]: oldState } = selectedWorkspace)';",
"const { state } = lease;",
"const jobState = job.state;",
"record.state = 'ready';",
"",
].join("\n"));
await verifyEntries({ root, entries: [entry("policy_text", path)] });
});
test("computed revision destructuring keys fold parentheses assertions templates and string concatenation", async (t) => {
const root = await fixture(t);
const cases = [
["backend/src/paren.ts", 'const { [("state")]: oldState } = revision;'],
["backend/src/concat.ts", 'const { ["st" + "ate"]: oldState } = workspaceRevision;'],
["frontend/src/template.ts", 'const { [`st${"ate"}`]: oldState } = selectedWorkspace;'],
["scripts/assertion.data", 'const { [("st" as string) + (`ate` satisfies string)]: oldState } = revision;'],
["scripts/assignment.txt", '({ ["st" + "ate"]: oldState } = selectedWorkspace);'],
];
for (const [path, source] of cases) {
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/, path);
}
const registry = "backend/src/workspaces/registry.ts";
for (const injected of [
'const { [("state")]: oldState } = revision;',
'({ ["st" + "ate"]: oldState } = revision);',
]) {
await put(root, registry, `if (revision.state !== "operational") return;\n${injected}\n`);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", registry)] }), /revision-state/);
}
});
test("polyglot masking and JSX syntax prevent comment and string false positives", async (t) => {
const root = await fixture(t);
const passing = [
["backend/scripts/comment.py", '# revision.state\nvalue = "revision.state"\ntext = """selectedWorkspace.state"""\n'],
["scripts/comment.ps1", '# revision.state\n<# workspaceRevision.state #>\n$value = "revision.state"\n'],
["scripts/comment.sh", '# revision.state\nprintf \'%s\\n\' "selectedWorkspace.state"\n'],
["frontend/src/content.tsx", 'export const view = <div>revision.state</div>;'],
["frontend/src/attribute.tsx", 'export const view = <div title="revision.state" />;'],
["frontend/src/expression.tsx", 'export const view = <div>{"revision.state"}</div>;'],
["scripts/arbitrary.data", 'title: "revision.state"\n# const { state } = revision\nlease:\n state: ready\n'],
];
for (const [path, source] of passing) {
await put(root, path, source);
await verifyEntries({ root, entries: [entry("policy_text", path)] });
}
for (const [path, source] of [
["scripts/code.txt", "const { state } = revision;"],
["scripts/code.data", '({ ["st" + "ate"]: oldState } = workspaceRevision);'],
]) {
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/);
}
});
test("rest bindings and dynamic computed keys are not semantic state-property access", async (t) => {
const root = await fixture(t);
const cases = [
["backend/src/rest.ts", "const { ...state } = revision;"],
["frontend/src/renamed.ts", "const { other: state } = workspaceRevision;"],
["scripts/dynamic.txt", "const { [state]: value } = selectedWorkspace;"],
["scripts/dynamic-assignment.data", "({ [state]: value } = revision);"],
["scripts/spread-assignment.data", "({ ...state } = workspaceRevision);"],
];
for (const [path, source] of cases) {
await put(root, path, source);
await verifyEntries({ root, entries: [entry("policy_text", path)] });
}
});
test("polyglot code remains structural across shell Python PowerShell YAML TSX and JSX", async (t) => {
const root = await fixture(t);
const failing = [
["scripts/code.sh", "value=revision.state\n"],
["scripts/code.ps1", "$value = workspaceRevision.state\n"],
["backend/scripts/code.py", "value = selectedWorkspace.state\n"],
["scripts/code.yaml", "value: revision.state\n"],
["frontend/src/code.tsx", "export const view = <div>{revision.state}</div>;"],
["frontend/src/code.jsx", "export const view = <div>{workspaceRevision.state}</div>;"],
];
for (const [path, source] of failing) {
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/, path);
}
});
test("PowerShell executable subexpressions expose dollar-prefixed revision access", async (t) => {
const root = await fixture(t);
const failing = [
["scripts/ps-property.ps1", 'Write-Output "revision: $($revision.state)"\n'],
["scripts/ps-element.ps1", 'Write-Output "$($workspaceRevision[\'state\'])"\n'],
["scripts/ps-workspace.ps1", '$value = $workspaceRevision.state\n'],
["scripts/ps-nested.ps1", 'Write-Output "$($($revision.state))"\n'],
];
for (const [path, source] of failing) {
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/, path);
}
const passing = [
'# $revision.state\nWrite-Output "revision.state"\n',
"Write-Output '$selectedWorkspace[\"state\"]'\n",
];
for (let index = 0; index < passing.length; index += 1) {
const path = `scripts/ps-literal-${index}.ps1`;
await put(root, path, passing[index]);
await verifyEntries({ root, entries: [entry("policy_text", path)] });
}
});
test("Python f-string fields expose revision access while literal text remains masked", async (t) => {
const root = await fixture(t);
const failing = [
["backend/scripts/f-property.py", 'value = f"{revision.state}"\n'],
["backend/scripts/fr-element.py", 'value = fr"{workspaceRevision[\'state\']}"\n'],
["backend/scripts/rf-element.py", 'value = rf"prefix {selectedWorkspace[\"state\"]}"\n'],
];
for (const [path, source] of failing) {
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/, path);
}
const passing = [
'value = f"revision.state"\n',
'value = f"{{revision.state}}"\n',
'value = "revision.state"\n',
'value = r"workspaceRevision.state"\n',
'value = """selectedWorkspace.state"""\n',
'value = r"""revision.state"""\n',
];
for (let index = 0; index < passing.length; index += 1) {
const path = `backend/scripts/python-literal-${index}.py`;
await put(root, path, passing[index]);
await verifyEntries({ root, entries: [entry("policy_text", path)] });
}
});
test("Bash masking preserves parameter trimming and executable command consumers", async (t) => {
const root = await fixture(t);
const failing = [
["scripts/trim.sh", "trimmed=${value#prefix}; old=revision.state\n"],
["scripts/base.sh", "base=${path##*/}; old=workspaceRevision.state\n"],
["scripts/backtick.sh", "old=`echo revision.state`\n"],
["scripts/quoted-backtick.sh", 'echo "old: `echo revision.state`"\n'],
["scripts/jq.sh", "jq '.revision.state' snapshot.json\n"],
["scripts/substitution.sh", 'echo "$(echo revision.state)"\n'],
];
for (const [path, source] of failing) {
await put(root, path, source);
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/, path);
}
await put(root, "scripts/echo.sh", 'echo "revision.state"\n# workspaceRevision.state\n');
await verifyEntries({ root, entries: [entry("policy_text", "scripts/echo.sh")] });
await put(root, "scripts/literal.yaml", '# revision.state\nvalue: "selectedWorkspace.state"\n');
await verifyEntries({ root, entries: [entry("policy_text", "scripts/literal.yaml")] });
});
test("YAML keeps URL slashes as data rather than a false line comment", async (t) => {
const root = await fixture(t);
const path = "scripts/url.yaml";
await put(root, path, "url: https://host/x; old: selectedWorkspace.state\n");
await assert.rejects(verifyEntries({ root, entries: [entry("policy_text", path)] }), /revision-state/);
});