feat: unify installation model catalog
This commit is contained in:
@@ -1195,13 +1195,8 @@ export async function executeChecks({ checks, failAt, recorder } = {}) {
|
||||
|
||||
function baseWorkspace(id, evidenceSource) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P1 ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P1 ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "postgres", schema: "public", supported_transports: ["postgres_direct"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ async function validateDistFiles(repo,files){const dist=join(repo,"backend","dis
|
||||
|
||||
export async function readManualOwnership({repositoryRoot=defaultRepositoryRoot}={}){const repo=realpathSync(repositoryRoot),root=fixedManualRoot(repo);noSymlinkExisting(repo,root);let rootEntry,ownershipEntry;try{rootEntry=await lstat(root);ownershipEntry=await lstat(join(root,"ownership.json"));}catch{throw new Error("manual ownership is missing");}if(!rootEntry.isDirectory()||rootEntry.isSymbolicLink()||await realpath(root)!==root||!ownershipEntry.isFile()||ownershipEntry.isSymbolicLink())throw new Error("manual ownership is unsafe");let value;try{value=JSON.parse(await readFile(join(root,"ownership.json"),"utf8"));}catch{throw new Error("manual ownership is malformed");}const baseValid=value.schemaVersion===1&&value.kind==="p1-manual-acceptance"&&HEX64.test(value.nonce??"")&&value.repositoryRoot===repo&&value.root===root&&value.status==="PENDING"&&["PREPARING","READY"].includes(value.stage)&&value.listener?.host===HOST&&value.listener?.port===PORT&&value.listener?.state==="stopped"&&typeof value.createdAt==="string"&&validEntrypoint(value.entrypoint,repo)&&validDistManifest(value.distManifest,root)&&JSON.stringify(value.resources)===JSON.stringify([root,{kind:"fastify",host:HOST,port:PORT}]);const readyLog=value.backendLog?.path===join(root,"logs/backend.log")&&Number.isSafeInteger(value.backendLog?.dev)&&Number.isSafeInteger(value.backendLog?.ino);if(!baseValid||(value.stage==="READY"?!readyLog:value.backendLog!==null))throw new Error("manual ownership identity mismatch");return value;}
|
||||
async function run(executable,argv,options={}){return await exec(executable,argv,{...options,maxBuffer:2*1024*1024,encoding:"utf8"});}
|
||||
function descriptor(id,source){return{workspace:{schema_version:3,id,name:`P1 ${id}`,language:"en"},dwh:{engine:"postgres",database:"postgres",schema:"public",supported_transports:["postgres_direct"]},semantic_index:{vector_store:{engine:"qdrant",collection:id,dimensions:1024,distance:"cosine"},embedding:{provider:"ollama_internal",model:"qwen3-embedding:0.6b",dimensions:1024}},llm_policy:{allowed:["zai/glm-5.2"]},evidence:{source,policy:{max_chunk_chars:4000,retain_published_generations:3}}};}
|
||||
function descriptor(id,source){return{workspace:{schema_version:4,id,name:`P1 ${id}`,language:"en"},dwh:{engine:"postgres",database:"postgres",schema:"public",supported_transports:["postgres_direct"]},evidence:{source,policy:{max_chunk_chars:4000,retain_published_generations:3}}};}
|
||||
function descriptors(){return[descriptor("p1-filesystem",{type:"filesystem",uri:"workspace-content/p1-filesystem/evidence",patterns:["**/*.md"],max_bytes:10485760}),descriptor("p1-http",{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}),descriptor("p1-s3",{type:"s3",uri:"s3://p1-evidence/published/",endpoint_url:"https://s3.example.test/",region:"eu-west-1",credentials:"static_files",trusted_endpoint:true,allow_private_endpoint:false,allow_insecure_endpoint:false,max_bytes:12345,max_objects:33,max_pages:4,page_size:5})];}
|
||||
function quote(value){return `'${String(value).replaceAll("'",`'"'"'`)}'`;}
|
||||
async function checkPrerequisites(repo){for(const path of ["scripts/p1-acceptance.sh","scripts/test-p1-acceptance.sh","backend/scripts/p1-acceptance.mjs","backend/dist/server.js"]){try{await access(join(repo,path));}catch{throw new Error(`Task 8 prerequisite is missing: ${path}`);}}for(const command of ["node","npm","git","curl","unzip","zipinfo","lsof","python3"]){try{await run(command,[command==="unzip"||command==="lsof"?"-v":command==="zipinfo"?"-h":"--version"]);}catch{throw new Error(`missing prerequisite: ${command}`);}}const tht=join(repo,"harness",".venv","bin","tht");try{await access(tht,constants.X_OK);}catch{throw new Error("missing prerequisite: harness/.venv/bin/tht");}}
|
||||
|
||||
@@ -403,7 +403,7 @@ test("generated render command validates saved responses and owned snapshot befo
|
||||
});
|
||||
|
||||
const renderSnapshotYaml=`workspace:
|
||||
schema_version: 3
|
||||
schema_version: 4
|
||||
id: p1-filesystem
|
||||
name: P1 filesystem
|
||||
language: en
|
||||
@@ -412,11 +412,6 @@ dwh:
|
||||
database: postgres
|
||||
schema: public
|
||||
supported_transports: [postgres_direct]
|
||||
semantic_index:
|
||||
vector_store: {engine: qdrant, collection: p1-filesystem, dimensions: 1024, distance: cosine}
|
||||
embedding: {provider: ollama_internal, model: qwen3-embedding:0.6b, dimensions: 1024}
|
||||
llm_policy:
|
||||
allowed: [zai/glm-5.2]
|
||||
evidence:
|
||||
source: {type: filesystem, uri: workspace-content/p1-filesystem/evidence, patterns: ["**/*.md"], max_bytes: 10485760}
|
||||
policy: {max_chunk_chars: 4000, retain_published_generations: 3}
|
||||
|
||||
@@ -16,7 +16,7 @@ async function fixture() {
|
||||
await writeFile(join(root,"installation/base.yaml"),"{}\n");
|
||||
const secret=join(root,"fixture-secrets/dwh-password"); await writeFile(secret,"not-inspected",{mode:0o600});
|
||||
await writeFile(snapshot,`workspace:
|
||||
schema_version: 3
|
||||
schema_version: 4
|
||||
id: p1-filesystem
|
||||
name: P1 filesystem
|
||||
language: en
|
||||
@@ -25,11 +25,6 @@ dwh:
|
||||
database: postgres
|
||||
schema: public
|
||||
supported_transports: [postgres_direct]
|
||||
semantic_index:
|
||||
vector_store: {engine: qdrant, collection: p1-filesystem, dimensions: 1024, distance: cosine}
|
||||
embedding: {provider: ollama_internal, model: qwen3-embedding:0.6b, dimensions: 1024}
|
||||
llm_policy:
|
||||
allowed: [zai/glm-5.2]
|
||||
evidence:
|
||||
source: {type: filesystem, uri: workspace-content/p1-filesystem/evidence, patterns: ["**/*.md"], max_bytes: 10485760}
|
||||
policy: {max_chunk_chars: 4000, retain_published_generations: 3}
|
||||
@@ -61,7 +56,7 @@ test("renderer refuses snapshot manifest head, digest, and expected-digest tampe
|
||||
|
||||
test("renderer refuses a missing or malformed snapshot manifest",async()=>{ const f=await fixture(); const output=join(f.root,"rendered/nomanifest.yaml"); await rm(f.manifestPath); await assert.rejects(call(f,{outputPath:output}),/snapshot manifest.*(missing|unbounded|unsafe)/); await writeFile(f.manifestPath,"{not json"); await assert.rejects(call(f,{outputPath:output}),/snapshot manifest.*malformed/); await assert.rejects(lstat(output)); assert.deepEqual(await runtimeLeases(f),[]); });
|
||||
|
||||
test("renderer rejects a regular snapshot replacement against its manifest",async()=>{ const f=await fixture(); const output=join(f.root,"rendered/replaced.yaml"); await assert.rejects(call(f,{outputPath:output,beforePublish:async()=>{await writeFile(f.snapshot,"workspace:\n schema_version: 3\n id: p1-filesystem\n name: replaced\n")}}),/snapshot content changed/); await assert.rejects(lstat(output)); });
|
||||
test("renderer rejects a regular snapshot replacement against its manifest",async()=>{ const f=await fixture(); const output=join(f.root,"rendered/replaced.yaml"); await assert.rejects(call(f,{outputPath:output,beforePublish:async()=>{await writeFile(f.snapshot,"workspace:\n schema_version: 4\n id: p1-filesystem\n name: replaced\n")}}),/snapshot content changed/); await assert.rejects(lstat(output)); });
|
||||
|
||||
test("renderer anchors publication when rendered parent is concurrently swapped", async()=>{
|
||||
const f=await fixture(),output=join(f.root,"rendered/raced.yaml"),moved=join(f.root,"rendered-moved"),outside=join(f.repo,"outside-rendered"); await mkdir(outside);
|
||||
|
||||
@@ -328,13 +328,8 @@ async function tht(ctx, argv, options = {}) {
|
||||
function namespace(id) { return id.toUpperCase().replaceAll("-", "_"); }
|
||||
function baseWorkspace(id, evidenceSource) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P1.1 ${id}`, description: `Catalog entry for ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P1.1 ${id}`, description: `Catalog entry for ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "postgres", schema: "public", supported_transports: ["postgres_direct"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -81,13 +81,8 @@ async function git(executable, argv, options = {}) {
|
||||
function namespace(id) { return id.toUpperCase().replaceAll("-", "_"); }
|
||||
function baseWorkspace(id, evidenceSource) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P1.1 ${id}`, description: `Catalog entry for ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P1.1 ${id}`, description: `Catalog entry for ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "postgres", schema: "public", supported_transports: ["postgres_direct"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -375,16 +375,11 @@ function installationProjectName(installationPath) {
|
||||
|
||||
function baseWorkspace(id, { dwhBaseUrl, evidenceSource }) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P2 ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P2 ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "warehouse", schema: "dw", supported_transports: ["rest_api"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
diagnostics: {
|
||||
dwh_rest: { method: "POST", path: "/rpc/ping", auth: "x-api-key", response: { database: "database", schema: "schema" } },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
...(evidenceSource ? { evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } } } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -376,16 +376,11 @@ function installationProjectName(installationPath) {
|
||||
|
||||
function baseWorkspace(id, { dwhBaseUrl, evidenceSource }) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P2 ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P2 ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "warehouse", schema: "dw", supported_transports: ["rest_api"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
diagnostics: {
|
||||
dwh_rest: { method: "POST", path: "/rpc/ping", auth: "x-api-key", response: { database: "database", schema: "schema" } },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
...(evidenceSource ? { evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } } } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -379,16 +379,11 @@ function installationProjectName(installationPath) {
|
||||
|
||||
function baseWorkspace(id, { dwhBaseUrl, evidenceSource }) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P2 ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P2 ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "warehouse", schema: "dw", supported_transports: ["rest_api"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
diagnostics: {
|
||||
dwh_rest: { method: "POST", path: "/rpc/ping", auth: "x-api-key", response: { database: "database", schema: "schema" } },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
...(evidenceSource ? { evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } } } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -374,16 +374,11 @@ function installationProjectName(installationPath) {
|
||||
|
||||
function baseWorkspace(id, { dwhBaseUrl, evidenceSource }) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P2 ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P2 ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "warehouse", schema: "dw", supported_transports: ["rest_api"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
diagnostics: {
|
||||
dwh_rest: { method: "POST", path: "/rpc/ping", auth: "x-api-key", response: { database: "database", schema: "schema" } },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
...(evidenceSource ? { evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } } } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -374,16 +374,11 @@ function installationProjectName(installationPath) {
|
||||
|
||||
function baseWorkspace(id, { dwhBaseUrl, evidenceSource }) {
|
||||
return {
|
||||
workspace: { schema_version: 3, id, name: `P2 ${id}`, language: "en" },
|
||||
workspace: { schema_version: 4, id, name: `P2 ${id}`, language: "en" },
|
||||
dwh: { engine: "postgres", database: "warehouse", schema: "dw", supported_transports: ["rest_api"] },
|
||||
semantic_index: {
|
||||
vector_store: { engine: "qdrant", collection: id, dimensions: 1024, distance: "cosine" },
|
||||
embedding: { provider: "ollama_internal", model: "qwen3-embedding:0.6b", dimensions: 1024 },
|
||||
},
|
||||
diagnostics: {
|
||||
dwh_rest: { method: "POST", path: "/rpc/ping", auth: "x-api-key", response: { database: "database", schema: "schema" } },
|
||||
},
|
||||
llm_policy: { allowed: ["zai/glm-5.2"] },
|
||||
...(evidenceSource ? { evidence: { source: evidenceSource, policy: { max_chunk_chars: 4000, retain_published_generations: 3 } } } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,11 +36,10 @@ const reviewedExpandableBlocks = new Map([
|
||||
{ sha256: "b903e5dae953ae1372f1a5276f12a92ed3dd632b897f3afe5e00c646d90a1b42", rationale: "Same reviewed block in the repository-required CRLF checkout representation." },
|
||||
]],
|
||||
["scripts/unified-deployment-smoke.sh", [
|
||||
{ sha256: "1d60bf140165a8fabfa0c3729e776136904717e67becf3e0ab68c70d8e37847e", rationale: "Generates reviewed Task 13 runtime configuration." },
|
||||
{ sha256: "36d3d8a2362dbdc4fad90948d6c227586d749f56b9a4bc5b6b5a91bcbec6407b", rationale: "Generates the reviewed local Task 13 Compose override." },
|
||||
{ sha256: "c556f7d910d0788e219b042957e6b307cb9925b43920c680535d0d3a6dcbdb25", rationale: "Generates the reviewed local Task 13 installation descriptor." },
|
||||
{ sha256: "b6c0826151b2c8b955399d1abf5b691cc8fe6b6454b17da000dde7ba3bc55d2d", rationale: "Generates the reviewed local Task 13 Compose override with normalized catalog mounts." },
|
||||
{ sha256: "24f69d12b8554aa2bebba455be99fde3e60743eef5a40fa2ef5b29397a477c03", rationale: "Generates the reviewed local Task 13 installation descriptor with its model catalog." },
|
||||
{ sha256: "526006fa6d48a8080b3834723630c64de5005a67243e944ebf1da15212b4d654", rationale: "Generates the reviewed server Task 13 Compose override." },
|
||||
{ sha256: "c57ae2205c21ead0c2015a353aaabb948fa4ddd9b78a2cdcdb71f48cf2db742d", rationale: "Generates the reviewed projected-auth server Task 13 installation descriptor." },
|
||||
{ sha256: "406ccead1967f642225c946fc4a23fe5b019c9764cc5153e1125876ade16ec90", rationale: "Generates the reviewed projected-auth server Task 13 installation descriptor with its model catalog." },
|
||||
]],
|
||||
["scripts/vector-backup.sh", [
|
||||
{ sha256: "571899db49dfdcec8107fbe1e0a86a61e7581979d3c4c248c20546843e275bcf", rationale: "Generates the reviewed backup manifest inside the helper command." },
|
||||
@@ -103,6 +102,7 @@ function isPolicyImplementationException(label, category) {
|
||||
]);
|
||||
if (implementations.has(label)) return true;
|
||||
if (category === "migration-marker" && new Set([
|
||||
"backend/src/workspaces/schema.ts",
|
||||
"scripts/workspace_descriptor_doc_contract.py",
|
||||
"scripts/test_workspace_descriptor_doc_contract.py",
|
||||
"backend/scripts/clean-dist.test.mjs",
|
||||
@@ -173,7 +173,7 @@ function validateWorkspaceSource(source, label, { requireWorkspace, expandable =
|
||||
try {
|
||||
parseWorkspaceYaml(source);
|
||||
} catch (error) {
|
||||
throw new Error(`${label}: workspace descriptor is not valid schema v3: ${error instanceof Error ? error.message : String(error)}`);
|
||||
throw new Error(`${label}: workspace descriptor is not valid schema v4: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,20 +33,20 @@ function bashN(root, path) {
|
||||
function replaceWorkspaceKeys(source, workspaceKey, schemaLine) {
|
||||
return source
|
||||
.replace(/^workspace:$/m, workspaceKey)
|
||||
.replace(/^ schema_version: 3$/m, schemaLine);
|
||||
.replace(/^ schema_version: 4$/m, schemaLine);
|
||||
}
|
||||
|
||||
test("production parser accepts semantic v3 with quoted Unicode/tagged keys and spacing", async (t) => {
|
||||
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" : 3',
|
||||
' "\\u0073chema_version" : 4',
|
||||
);
|
||||
const tagged = replaceWorkspaceKeys(
|
||||
canonicalDescriptor,
|
||||
"!!str workspace :",
|
||||
" !!str schema_version : 3",
|
||||
" !!str schema_version : 4",
|
||||
);
|
||||
await put(root, "deploy/workspaces/unicode.yaml", unicode);
|
||||
await put(root, "deploy/workspaces/tagged.yaml", tagged);
|
||||
@@ -59,14 +59,15 @@ test("production parser accepts semantic v3 with quoted Unicode/tagged keys and
|
||||
});
|
||||
});
|
||||
|
||||
test("production parser rejects fancy keys with every non-v3 or ambiguous value", async (t) => {
|
||||
test("production parser rejects fancy keys with every non-v4 or ambiguous value", async (t) => {
|
||||
const invalid = [
|
||||
["unicode-v2", '"\\u0077orkspace" :', ' "\\u0073chema_version" : 2'],
|
||||
["tagged-leading-zero", "!!str workspace :", " !!str schema_version : 02"],
|
||||
["hexadecimal", "workspace :", " schema_version : 0x2"],
|
||||
["multiline", "workspace :", " schema_version : >\n 3"],
|
||||
["duplicate", "workspace :", " schema_version : 3\n schema_version: 3"],
|
||||
["inline", "workspace: { schema_version: 3 }", " schema_version: 3"],
|
||||
["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 () => {
|
||||
@@ -120,7 +121,7 @@ test("PowerShell embedded workspace mappings are rejected while bundle-only stri
|
||||
const root = await fixture(t);
|
||||
const source = [
|
||||
"$workspace = @'",
|
||||
canonicalDescriptor.replace(" schema_version: 3", " schema_version: 0x2").trimEnd(),
|
||||
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 0x2").trimEnd(),
|
||||
"'@",
|
||||
'$bundle = @"',
|
||||
"bundle:",
|
||||
@@ -137,7 +138,7 @@ test("PowerShell embedded workspace mappings are rejected while bundle-only stri
|
||||
|
||||
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: 3\n");
|
||||
await put(root, "scripts/fixtures/workspace-registry-future.yaml", "bundle:\n schema_version: 4\n");
|
||||
await assert.rejects(
|
||||
verifyEntries({
|
||||
root,
|
||||
@@ -179,7 +180,7 @@ test("script scalar workspace remains a bundle even with descriptor-like sibling
|
||||
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: 3\n");
|
||||
await put(root, path, "workspace: analytics\nschema_version: 4\n");
|
||||
await assert.rejects(
|
||||
verifyEntries({ root, entries: [entry("workspace_descriptor", path)] }),
|
||||
/workspace.*mapping/i,
|
||||
@@ -193,11 +194,11 @@ test("Bash extractor supports hyphen, digit, escaped delimiters, and tab strippi
|
||||
name: "hyphen-v2",
|
||||
opener: "cat <<'WORKSPACE-YAML'",
|
||||
delimiter: "WORKSPACE-YAML",
|
||||
descriptor: canonicalDescriptor.replace(" schema_version: 3", " schema_version: 2"),
|
||||
descriptor: canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2"),
|
||||
rejected: true,
|
||||
},
|
||||
{
|
||||
name: "digit-v3",
|
||||
name: "digit-v4",
|
||||
opener: "cat <<2YAML",
|
||||
delimiter: "2YAML",
|
||||
descriptor: canonicalDescriptor,
|
||||
@@ -207,11 +208,11 @@ test("Bash extractor supports hyphen, digit, escaped delimiters, and tab strippi
|
||||
name: "escaped-v2",
|
||||
opener: "cat <<WORKSPACE\\-YAML",
|
||||
delimiter: "WORKSPACE-YAML",
|
||||
descriptor: canonicalDescriptor.replace(" schema_version: 3", " schema_version: 2"),
|
||||
descriptor: canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2"),
|
||||
rejected: true,
|
||||
},
|
||||
{
|
||||
name: "tab-strip-v3",
|
||||
name: "tab-strip-v4",
|
||||
opener: "cat <<-'TAB-YAML'",
|
||||
delimiter: "\tTAB-YAML",
|
||||
descriptor: canonicalDescriptor.split("\n").map((line) => `\t${line}`).join("\n"),
|
||||
@@ -272,7 +273,7 @@ test("non-stripping heredoc close requires an exact physical delimiter line", as
|
||||
"#!/usr/bin/env bash",
|
||||
"cat <<'---'",
|
||||
"--- ",
|
||||
canonicalDescriptor.replace(" schema_version: 3", " schema_version: 2").trimEnd(),
|
||||
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
|
||||
"---",
|
||||
"",
|
||||
].join("\n");
|
||||
@@ -313,7 +314,7 @@ test("double-quoted non-special backslash is preserved in the delimiter", async
|
||||
"#!/usr/bin/env bash",
|
||||
'cat <<"\\---"',
|
||||
"---",
|
||||
canonicalDescriptor.replace(" schema_version: 3", " schema_version: 2").trimEnd(),
|
||||
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
|
||||
"\\---",
|
||||
"",
|
||||
].join("\n");
|
||||
@@ -355,7 +356,7 @@ test("split heredoc operator continuation cannot bypass v2 validation", async (t
|
||||
"#!/usr/bin/env bash",
|
||||
"cat <\\",
|
||||
"<'YAML'",
|
||||
canonicalDescriptor.replace(" schema_version: 3", " schema_version: 2").trimEnd(),
|
||||
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
|
||||
"YAML",
|
||||
"",
|
||||
].join("\n");
|
||||
@@ -424,7 +425,7 @@ test("PowerShell comment backslash cannot hide a following v2 here-string", asyn
|
||||
const source = [
|
||||
"# harmless PowerShell comment \\",
|
||||
"$workspace = @'",
|
||||
canonicalDescriptor.replace(" schema_version: 3", " schema_version: 2").trimEnd(),
|
||||
canonicalDescriptor.replace(" schema_version: 4", " schema_version: 2").trimEnd(),
|
||||
"'@",
|
||||
"",
|
||||
].join("\n");
|
||||
@@ -435,7 +436,7 @@ test("PowerShell comment backslash cannot hide a following v2 here-string", asyn
|
||||
);
|
||||
});
|
||||
|
||||
test("PowerShell dialect accepts normal v3 and non-workspace bundle here-strings", async (t) => {
|
||||
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 = [
|
||||
@@ -494,10 +495,10 @@ test("PowerShell cast and concatenation openers cannot hide embedded descriptors
|
||||
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: 3"],
|
||||
["plain-key", "$key:\n schema_version: 3"],
|
||||
["quoted-key", '"$key" :\n schema_version: 3'],
|
||||
["subexpression-key", "$($key):\n schema_version: 3"],
|
||||
["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) {
|
||||
@@ -564,7 +565,7 @@ test("unmarked expandable Bash YAML cannot generate descriptor keys or values at
|
||||
"key=workspace",
|
||||
"cat <<YAML",
|
||||
generatedKey,
|
||||
" schema_version: 3",
|
||||
" schema_version: 4",
|
||||
"YAML",
|
||||
"",
|
||||
].join("\n");
|
||||
@@ -600,14 +601,14 @@ test("an in-band marker cannot authorize expandable content", async (t) => {
|
||||
for (const [path, source] of [
|
||||
["scripts/fake-marker.sh", [
|
||||
"#!/usr/bin/env bash",
|
||||
"# schema-v3-only: expandable-nonworkspace",
|
||||
"# schema-v4-only: expandable-nonworkspace",
|
||||
"cat <<YAML",
|
||||
"${DESCRIPTOR}",
|
||||
"YAML",
|
||||
"",
|
||||
].join("\n")],
|
||||
["scripts/fake-marker.ps1", [
|
||||
"# schema-v3-only: expandable-nonworkspace",
|
||||
"# schema-v4-only: expandable-nonworkspace",
|
||||
'$yaml = @"',
|
||||
"$descriptor",
|
||||
'"@',
|
||||
|
||||
Reference in New Issue
Block a user