From e29770c26b4ba7a4906074f1349fb36c6be494cb Mon Sep 17 00:00:00 2001 From: bobby Date: Sat, 27 Jun 2026 19:08:22 -0400 Subject: [PATCH] prx-5yp: adopt @bounded-systems/seam-check for the extractability test assertSeam (prod: @bounded-systems/policy + cas + anchored-chain; default ambient). Test allowlist keeps the test-only anchored-chain-sqlite + node:fs edges. Test-only. Co-Authored-By: Claude Opus 4.8 (1M context) --- bun.lock | 3 + package.json | 1 + src/__tests__/extractability.test.ts | 127 +++++---------------------- 3 files changed, 24 insertions(+), 107 deletions(-) diff --git a/bun.lock b/bun.lock index f229ee3..5e7ea9d 100644 --- a/bun.lock +++ b/bun.lock @@ -11,6 +11,7 @@ "@bounded-systems/policy": "npm:@jsr/bounded-systems__policy@^0.2.1", }, "devDependencies": { + "@bounded-systems/seam-check": "npm:@jsr/bounded-systems__seam-check@^0.1.0", "@types/bun": "^1.3.14", "typescript": "^6.0.3", }, @@ -25,6 +26,8 @@ "@bounded-systems/policy": ["@jsr/bounded-systems__policy@0.2.1", "https://npm.jsr.io/~/11/@jsr/bounded-systems__policy/0.2.1.tgz", {}, "sha512-5ppqxSi1rmo10S07M1zOCGGCWkRkXhXWWQG4XFcGLER+GPbptuitixcUPnMyXMgly8Kc+k8prJWU6nrh/L+X3g=="], + "@bounded-systems/seam-check": ["@jsr/bounded-systems__seam-check@0.1.0", "https://npm.jsr.io/~/11/@jsr/bounded-systems__seam-check/0.1.0.tgz", {}, "sha512-nFzH7o19uIBF7BfJrly668AkynjdZ99Qk6pVRoOsf7/9M5vtKK7emI+B2jDFMSMyqZvVuILWKXz7tFs2vD1/LA=="], + "@jsr/bounded-systems__anchored-chain": ["@jsr/bounded-systems__anchored-chain@0.2.2", "https://npm.jsr.io/~/11/@jsr/bounded-systems__anchored-chain/0.2.2.tgz", { "dependencies": { "@jsr/bounded-systems__cas": "^0.1.2" } }, "sha512-Pi8b+9ocSWqcuSjW0R1CaRjI2i6J22yWmludPie1/dUuV5Uwyx7JHVlg/4cbKPqVKUJsQzgBWtWRva0oc8LO4Q=="], "@jsr/bounded-systems__cas": ["@jsr/bounded-systems__cas@0.1.2", "https://npm.jsr.io/~/11/@jsr/bounded-systems__cas/0.1.2.tgz", {}, "sha512-Pp1MWl5KJL30HMLqFAZ+g62IYH9g5xpDDNUdRDgsdomnMamXnubg+yyg4N1elqaupa6Q7A/cmlaRtqP8KHu4eA=="], diff --git a/package.json b/package.json index 41a01e5..6ae9b63 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "prepublishOnly": "bun run build" }, "devDependencies": { + "@bounded-systems/seam-check": "npm:@jsr/bounded-systems__seam-check@^0.1.0", "@types/bun": "^1.3.14", "typescript": "^6.0.3" }, diff --git a/src/__tests__/extractability.test.ts b/src/__tests__/extractability.test.ts index 6a87506..0e67167 100644 --- a/src/__tests__/extractability.test.ts +++ b/src/__tests__/extractability.test.ts @@ -1,111 +1,24 @@ -import { describe, expect, test } from "bun:test"; -import { readdirSync, readFileSync, statSync } from "node:fs"; -import { dirname, join, relative, resolve } from "node:path"; +import { test } from "bun:test"; +import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; -const HERE = dirname(fileURLToPath(import.meta.url)); -const MODULE_ROOT = resolve(HERE, ".."); - -// The slack read surface is a standalone package. At slack .2 (the port + -// types skeleton) the prod files import nothing but their own siblings. Later -// tasks of epic prx-zes widen this allowlist deliberately: -// .3 policy → @bounded-systems/policy (the gate) -// .5 core → @bounded-systems/cas (content-addressing) -// .6 provenance → @bounded-systems/anchored-chain -// .8 CLI xport → @bounded-systems/proc (the sanctioned spawn seam) -// Each widening is a reviewed edge, not a silent reach. Notably absent forever: -// @bounded-systems/auth — this package never RESOLVES a credential or touches a -// secret. It may CONTAIN scope logic (slackScopedKeymaker) but only wraps an -// opaque, structurally-typed base keymaker whose closure holds the token; the -// secret never enters this package. The composition root supplies the base. -const PROD_ALLOWLIST = new Set([ - "@bounded-systems/policy", // .3 — the policy gate - "@bounded-systems/cas", // .5 — content-addressing - "@bounded-systems/anchored-chain", // .6 — the provenance ledger -]); - -const TEST_ALLOWLIST = new Set([ - ...PROD_ALLOWLIST, - "bun:test", - "node:fs", - "node:path", - "node:url", - "@bounded-systems/slack", - // .6 provenance tests exercise the bridge against a real store - "@bounded-systems/anchored-chain-sqlite", -]); - -const IMPORT_RE = - /(?:^|\n)\s*(?:import|export)\s+(?:type\s+)?(?:[^'"`;]*?\s+from\s+)?['"]([^'"]+)['"]/g; - -function listTsFiles(dir: string): string[] { - const out: string[] = []; - for (const entry of readdirSync(dir)) { - const full = join(dir, entry); - if (statSync(full).isDirectory()) { - out.push(...listTsFiles(full)); - } else if (entry.endsWith(".ts")) { - out.push(full); - } - } - return out; -} - -function isInModuleImport(spec: string): boolean { - return spec.startsWith("."); -} - -describe("slack read-surface extractability", () => { - test("core files import only the reviewed substrate allowlist", () => { - const violations: Array<{ file: string; spec: string }> = []; - for (const file of listTsFiles(MODULE_ROOT)) { - const isTest = file.includes("/__tests__/"); - const allowlist = isTest ? TEST_ALLOWLIST : PROD_ALLOWLIST; - const source = readFileSync(file, "utf8"); - for (const match of source.matchAll(IMPORT_RE)) { - const spec = match[1]!; - if (isInModuleImport(spec)) continue; - if (allowlist.has(spec)) continue; - violations.push({ file: relative(MODULE_ROOT, file), spec }); - } - } - expect(violations).toEqual([]); - }); -}); - -// The keymaker separation, enforced structurally: prod files must NEVER read -// ambient env/auth or spawn external tools. A transport is a pure mechanism -// handed a minted key; authority enters only via that key. This guard holds for -// the life of the package — adapters route spawning through @bounded-systems/proc, -// never raw child_process, and never reach for process.env. -// -// SCOPE OF THIS GUARANTEE: this is a SOURCE-LEVEL LINT at the in-process Bun -// layer, not a runtime sandbox. It catches *accidental* ambient reach in our own -// source; it cannot stop malicious or transitive in-process code from touching -// env/spawn (no syscall gate, no memory isolation). Real in-process enforcement -// = SES/hardened-JS Compartments (no runtime swap), Deno --allow-* (GH-1836), or -// the WASI component model. Note prx ALSO isolates at the agent layer: under -// `--vm` the whole agent runs in a Lima microVM. Isolation is a layered profile, -// not a single tier. See [[prx-capability-enforcement-level]]. -const FORBIDDEN_AMBIENT: ReadonlyArray = [ - [/\bchild_process\b/, "child_process"], - [/\bspawnSync\b|\bBun\.spawn\b|\bexecSync\b|\bexecFileSync\b/, "process spawn"], - [/\bDeno\.Command\b/, "Deno subprocess"], - [/\bprocess\.env\b|\bBun\.env\b/, "ambient env / auth"], -]; - -describe("no hidden ambient dependencies", () => { - test("prod files never spawn external tools or read ambient env/auth", () => { - const offenders: Array<{ file: string; what: string }> = []; - for (const file of listTsFiles(MODULE_ROOT)) { - if (file.includes("/__tests__/")) continue; - const source = readFileSync(file, "utf8"); - for (const [re, what] of FORBIDDEN_AMBIENT) { - if (re.test(source)) { - offenders.push({ file: relative(MODULE_ROOT, file), what }); - } - } - } - expect(offenders).toEqual([]); +import { assertSeam } from "@bounded-systems/seam-check"; + +const SRC = resolve(dirname(fileURLToPath(import.meta.url)), ".."); + +// @bounded-systems/slack: policy-gated, provenance-tracked Slack read surface. +// Prod files touch the policy gate, cas content-addressing, and the +// anchored-chain ledger only. The harness proves that edge and the no-ambient +// thesis; tests additionally exercise the anchored-chain-sqlite store. +test("@bounded-systems/slack upholds its seam claim", () => { + assertSeam({ + root: SRC, + prod: ["@bounded-systems/policy", "@bounded-systems/cas", "@bounded-systems/anchored-chain"], + test: [ + "@bounded-systems/slack", + "@bounded-systems/seam-check", + "@bounded-systems/anchored-chain-sqlite", + "node:fs", + ], }); });