mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-23 06:10:02 +08:00
- Enforce oxlint and oxfmt for owned JavaScript and TypeScript with independent CI checks. - Preserve compiler import boundaries and protected fixtures while cleaning up lint findings. - Standardize source formatting and validate import, fixture, and embedded-source protections.
125 lines
5.8 KiB
TypeScript
125 lines
5.8 KiB
TypeScript
/* --provenance-sources (EXPERIMENTAL): the provenance-assisted static
|
|
* compilation pipeline, offline — the fixture manifest
|
|
* (SCRIPTC_PROVENANCE_MANIFEST) stands in for the live attestation +
|
|
* source fetch, so these tests exercise everything AFTER the network:
|
|
* source-entry mapping, the registry chokepoints (preflight edges, tsgo
|
|
* "paths", the npm-import bypass), the @__PURE__ dead-const elision, the
|
|
* per-package attribution, and the island fallback notes.
|
|
*
|
|
* The differential contract is the thesis itself: the binary compiled
|
|
* from the ATTESTED SOURCE (static, no island) must byte-match the
|
|
* binary island-running the PUBLISHED dist — and both must byte-match
|
|
* Node running the published package.
|
|
*/
|
|
import { execFile } from "node:child_process";
|
|
import { mkdirSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { afterEach, describe, expect, test } from "vitest";
|
|
import {
|
|
analyze,
|
|
compile,
|
|
resolveProvenanceSources,
|
|
setProvenanceSources,
|
|
} from "@scriptc/compiler";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
const repoRoot = join(import.meta.dirname, "../..");
|
|
const fixtureDir = join(repoRoot, "tests/fixtures/provenance");
|
|
const entry = join(fixtureDir, "cases/greet/main.ts");
|
|
/* Suite-flavor segment: the plain and SCRIPTC_SAN=1 suites both run these
|
|
* same (unsanitized) builds and may run concurrently — the suite lock is
|
|
* per flavor — so they must never share a build dir. */
|
|
const flavor = process.env["SCRIPTC_SAN"] === "1" ? "san" : "plain";
|
|
const outDir = join(repoRoot, "node_modules/.cache/scriptc-tests/provenance", flavor);
|
|
|
|
const EXPECTED = "hello, world\nHELLO, COMPILER!\nhello, chain!\n";
|
|
|
|
async function buildAndRun(name: string, dynamic: boolean, program = entry): Promise<string> {
|
|
mkdirSync(outDir, { recursive: true });
|
|
const outPath = join(outDir, name);
|
|
// Pinned: the provenance thesis compares a source-static binary against
|
|
// a dist-island binary — holding both on the C lane keeps that byte
|
|
// comparison about PROVENANCE, never about which backend each build drew.
|
|
const result = await compile(program, { outPath, outDir, dynamic, backend: "llvm" });
|
|
if (!result.ok) {
|
|
throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n"));
|
|
}
|
|
const { stdout } = await execFileAsync(outPath, [], { encoding: "utf8" });
|
|
return stdout;
|
|
}
|
|
|
|
afterEach(() => {
|
|
setProvenanceSources(null);
|
|
delete process.env["SCRIPTC_PROVENANCE_MANIFEST"];
|
|
});
|
|
|
|
describe("provenance sources", () => {
|
|
test("attested source compiles STATIC and byte-matches the island's published dist", async () => {
|
|
// Flag off: the published dist embeds in the island (--dynamic).
|
|
const island = await buildAndRun("greet-island", true);
|
|
expect(island).toBe(EXPECTED);
|
|
|
|
// Flag on: the manifest maps greeter to its source tree; the driver
|
|
// compiles WITHOUT --dynamic — possible only because the source
|
|
// became program modules (a bare npm import would fence a static
|
|
// build), which IS the assertion that nothing islanded.
|
|
process.env["SCRIPTC_PROVENANCE_MANIFEST"] = join(fixtureDir, "manifest.json");
|
|
const sources = await resolveProvenanceSources(entry);
|
|
expect(sources.packages).toHaveLength(1);
|
|
const pkg = sources.packages[0]!;
|
|
expect(pkg.name).toBe("greeter");
|
|
expect(pkg.version).toBe("1.2.3");
|
|
expect(pkg.entries["greeter"]).toMatch(/attested-src\/greeter\/src\/index\.ts$/);
|
|
setProvenanceSources(sources);
|
|
const fromSource = await buildAndRun("greet-static", false);
|
|
expect(fromSource).toBe(island);
|
|
});
|
|
|
|
test("maps a published dist/esm subpath to its unmodified TypeScript source", async () => {
|
|
const subpathEntry = join(fixtureDir, "cases/echo/main.ts");
|
|
const node = await execFileAsync("node", [subpathEntry], { encoding: "utf8" });
|
|
process.env["SCRIPTC_PROVENANCE_MANIFEST"] = join(fixtureDir, "manifest.json");
|
|
const sources = await resolveProvenanceSources(subpathEntry);
|
|
expect(sources.packages[0]?.entries["greeter/echo"]).toMatch(
|
|
/attested-src\/greeter\/src\/echo\.ts$/,
|
|
);
|
|
setProvenanceSources(sources);
|
|
expect(await buildAndRun("echo-static", false, subpathEntry)).toBe(node.stdout);
|
|
});
|
|
|
|
test("per-package attribution counts the source static; the @__PURE__ dead const elides", async () => {
|
|
process.env["SCRIPTC_PROVENANCE_MANIFEST"] = join(fixtureDir, "manifest.json");
|
|
setProvenanceSources(await resolveProvenanceSources(entry));
|
|
const { coverage } = analyze(entry);
|
|
expect(coverage.preflightFailed).toBe(false);
|
|
// No blockers anywhere: the dead const elided instead of fencing.
|
|
expect(coverage.diagnostics).toHaveLength(0);
|
|
expect(coverage.provenanceElided ?? []).toHaveLength(1);
|
|
expect(coverage.provenanceElided![0]!.message).toContain("'Legacy'");
|
|
// Attribution: every counted statement of the greeter source is
|
|
// static (the elided declaration never counts — it lowers to nothing).
|
|
const srcStats = [...(coverage.statsByFile ?? [])].filter(([f]) =>
|
|
f.includes("attested-src/greeter/"),
|
|
);
|
|
expect(srcStats.length).toBeGreaterThan(0);
|
|
for (const [, s] of srcStats) {
|
|
expect(s.failed).toBe(0);
|
|
expect(s.island).toBe(0);
|
|
}
|
|
});
|
|
|
|
test("an unmappable package falls back to the island with a note, never a failure", async () => {
|
|
process.env["SCRIPTC_PROVENANCE_MANIFEST"] = join(fixtureDir, "manifest-broken.json");
|
|
const sources = await resolveProvenanceSources(entry);
|
|
expect(sources.packages).toHaveLength(0);
|
|
expect(sources.notes).toHaveLength(1);
|
|
expect(sources.notes[0]).toContain("greeter");
|
|
expect(sources.notes[0]).toContain("island path used");
|
|
setProvenanceSources(sources);
|
|
// The island path still works under the flag — the fallback contract.
|
|
const island = await buildAndRun("greet-fallback", true);
|
|
expect(island).toBe(EXPECTED);
|
|
});
|
|
});
|