Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/decisions/ci-utility.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,12 @@ binding unavailable. Current `dist` bytes never substitute for source inputs.
Other generated artifacts, external assets and temporary readers remain unknown
until their own bindings are validated.

Generated CSS/theme and inclusion self-tests use raw Git blobs from the
independently pinned audited revision for their positive producer controls.
They test actual current producer bytes separately: legitimate audit drift
requires fresh proof and does not redefine the positive fixture. The locked
offline compiler and installed-asset byte/mode controls remain runtime proof.

The native diagram SVG/PNG/PDF fixture has a separate finite operation binding.
The host launches each engine's native producer in a separate network-disabled,
read-only-root Docker container, using the existing pinned Playwright image's
Expand Down
14 changes: 14 additions & 0 deletions tests/frozen-generated-source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import assert from "node:assert/strict";
import {resolve} from "node:path";

// Delivered main before #2370 owns these audited producer bytes. Read raw Git
// blobs offline: neither HEAD, worktree files nor archive substitution owns a
// frozen positive. CI checks out full history; absent history is a hard failure.
const owner = "498270fbdc4ef2788fdd3babb259b647d77f6c77";
export function frozenGeneratedSource(file: string): string {
const child = Bun.spawnSync(["git", "show", `${owner}:${file}`], {
cwd: resolve(import.meta.dir, ".."), stdout: "pipe", stderr: "pipe",
});
assert.equal(child.exitCode, 0, "FROZEN_GENERATED_SOURCE_OWNER_AVAILABLE_OFFLINE");
return child.stdout.toString("utf8");
}
16 changes: 14 additions & 2 deletions tests/generated-build-inputs.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {frozenGeneratedSource} from "./frozen-generated-source";
import { afterEach, expect, test } from "bun:test";
import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
Expand All @@ -10,7 +11,7 @@ const producer=["scripts/build.ts","scripts/build-receipt.ts","scripts/build-rep
function fixture(){
const root=mkdtempSync(join(tmpdir(),"generated-css-"));roots.push(root);
const write=(file:string,bytes:string)=>{mkdirSync(dirname(join(root,file)),{recursive:true});writeFileSync(join(root,file),bytes);};
for(const file of producer)write(file,readFileSync(join(repo,file),"utf8"));
for(const file of producer)write(file,frozenGeneratedSource(file));
write("packages/ui-react/src/styles.css",".marker{color:red}");write("packages/ui-react/package.json",'{}');
return {root,write};
}
Expand Down Expand Up @@ -46,7 +47,7 @@ test("locked offline Tailwind CLI really derives changed bytes from owned styles

test("only audited filesystem reader commands bind the generated stylesheet cwd",()=>{
const {root,write}=fixture();const owner="packages/ui-kit/tests/visual/form-browser.ts";
const original=readFileSync(join(repo,owner),"utf8");write(owner,original);
const original=frozenGeneratedSource(owner);write(owner,original);
expect(generatedCssReadInputs(root,owner,"../ui-react/dist/styles.css")?.entry).toBe("packages/ui-react/src/styles.css");
expect(generatedCssReadInputs(root,owner,"../../outside/styles.css")).toBeUndefined();
expect(generatedCssReadInputs(root,"other.ts","../ui-react/dist/styles.css")).toBeUndefined();
Expand All @@ -56,3 +57,14 @@ test("only audited filesystem reader commands bind the generated stylesheet cwd"
expect(generatedCssReadInputs(root,owner,"../ui-react/dist/styles.css")).toBeUndefined();
expect(discoverInputClosure(root,[owner]).unresolved.some(value=>value.includes('readFile(resolve("../ui-react/dist/styles.css"), "utf8")'))).toBe(true);
});

// Keep real candidate drift separate from independently owned positives.
test("current producer bytes qualify only when they match the frozen audit",()=>{
for(const file of producer){
const {root,write}=fixture(),current=readFileSync(join(repo,file),"utf8");
write(file,current);
const binding=generatedCssInputs(root,"packages/ui-react/dist/styles.css");
if(current===frozenGeneratedSource(file)) expect(binding?.entry,"UNCHANGED_PRODUCER_RETAINS_BINDING").toBe("packages/ui-react/src/styles.css");
else expect(binding,"CURRENT_PRODUCER_DRIFT_REQUIRES_FRESH_PROOF").toBeUndefined();
}
});
3 changes: 2 additions & 1 deletion tests/generated-theme-inputs.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {frozenGeneratedSource} from "./frozen-generated-source";
import {afterEach,expect,test} from "bun:test";
import {cpSync,mkdirSync,mkdtempSync,readFileSync,readdirSync,rmSync,symlinkSync,writeFileSync} from "node:fs";
import {tmpdir} from "node:os";
Expand All @@ -7,7 +8,7 @@ import {generatedThemeInputs} from "../scripts/generated-theme-inputs";
const repo=resolve(import.meta.dir,".."),roots:string[]=[],owner="packages/ui-kit/tests/visual/dictation-motion.ts",caller="packages/ui-kit/vitest.config.ts",entry="packages/ui-kit/tests/visual/dictation-theme.css";
const producers=["scripts/build.ts","scripts/build-receipt.ts","scripts/build-repeat-observation.ts","scripts/bin-modes.ts","scripts/publishable-packages.ts","scripts/workspace-lease.mjs","scripts/ci-proof.ts","scripts/check-pr.ts","scripts/ci-runner.ts",".github/workflows/ci.yml","package.json","bun.lock","packages/ui-react/src/theme.css","packages/ui-react/package.json"];
afterEach(()=>{for(const root of roots.splice(0))rmSync(root,{recursive:true,force:true});});
function fixture(){const root=mkdtempSync(join(tmpdir(),"generated-theme-"));roots.push(root);const write=(file:string,text:string)=>{mkdirSync(dirname(join(root,file)),{recursive:true});writeFileSync(join(root,file),text);};for(const file of [...producers,owner,caller,entry])write(file,readFileSync(join(repo,file),"utf8"));symlinkSync(join(repo,"node_modules"),join(root,"node_modules"),"dir");return{root,write};}
function fixture(){const root=mkdtempSync(join(tmpdir(),"generated-theme-"));roots.push(root);const write=(file:string,text:string)=>{mkdirSync(dirname(join(root,file)),{recursive:true});writeFileSync(join(root,file),text);};for(const file of [...producers,owner,caller,entry])write(file,frozenGeneratedSource(file));symlinkSync(join(repo,"node_modules"),join(root,"node_modules"),"dir");return{root,write};}
test("temporary theme output binds the audited command, copied theme and installed compiler",()=>{
const {root}=fixture(),files=[owner,caller],bound=generatedThemeInputs(root,files,browserImporters(root,files));
expect(bound?.css).toEqual([entry,"packages/ui-react/src/theme.css"]);
Expand Down
5 changes: 3 additions & 2 deletions tests/inclusion-inputs.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {frozenGeneratedSource} from "./frozen-generated-source";
import { afterEach, expect, test } from "bun:test";
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { chmodSync, mkdirSync, mkdtempSync, readdirSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { inclusionInputs } from "../scripts/inclusion-inputs";
Expand Down Expand Up @@ -82,7 +83,7 @@ test("validated installed asset bytes and mode join immutable source fingerprint
for(const entry of readdirSync(installed)) if(entry!=="axe-core") symlinkSync(join(installed,entry),join(root,"node_modules",entry),"dir");
const owner="packages/ui-react/tests/browser/offline/cold-capture/commands.ts";
for(const file of [owner,"scripts/build.ts","scripts/build-receipt.ts","scripts/build-repeat-observation.ts","scripts/bin-modes.ts","scripts/publishable-packages.ts","scripts/workspace-lease.mjs","scripts/ci-proof.ts","scripts/check-pr.ts","scripts/ci-runner.ts",".github/workflows/ci.yml","package.json","packages/ui-react/package.json","packages/ui-kit/package.json"])
write(root,file,readFileSync(resolve(import.meta.dir,"..",file),"utf8"));
write(root,file,frozenGeneratedSource(file));
write(root,spec,`import "../../../ui-react/tests/browser/offline/cold-capture/commands.ts";`);
write(root,"node_modules/axe-core/package.json",JSON.stringify({name:"axe-core",version:"4.13.0"}));write(root,"node_modules/axe-core/axe.min.js","owned asset before");commit(root);
const initial=inclusionInputs(root,"layout",inventory,"fixed-runner").fingerprint;
Expand Down
Loading