From 2deef3346319be58a8447ac2d464e59db75df86d Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Thu, 30 Jul 2026 14:16:27 +0800 Subject: [PATCH 1/2] ci: add provable-chain pre-publish gate (release.yml) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires a cross-package regression gate into the release pipeline so a broken provable chain fails BEFORE publish, not after. - examples/integration-smoke/provable-chain.mjs: self-contained end-to-end smoke over the freshly-built workspace (no LLM, no network). A task output is verified by @wasmagent/compliance (backed by @wasmagent/core VerificationPipeline+DeterministicVerifier), the verdict becomes signed AEP evidence via @wasmagent/aep, and the signature is verified; includes a tamper-evidence check. Adds @wasmagent/aep + @wasmagent/compliance as workspace:* deps of the smoke package so bare imports resolve to local builds. - run-all.mjs: register provable-chain.mjs in ORDER (cheap, no-IO — runs early). - release.yml: run the gate after Build and before npm auth/publish. A break (a verified task can no longer become signed, verifiable evidence) fails the release. Verified on VPS: CI-equivalent (frozen install + build + gate from repo root) exits 0 on a healthy chain; an injected signature break exits 1. The trust-passport link is intentionally excluded (external dep, not a workspace package, so a wasmagent-js pre-publish gate cannot guard it). Complements the after-publish canary in agent-golden-path. No changeset needed (examples/ + CI only, no publishable package source). --- .github/workflows/release.yml | 8 + bun.lock | 114 +++++++-------- examples/integration-smoke/package.json | 4 +- examples/integration-smoke/provable-chain.mjs | 138 ++++++++++++++++++ examples/integration-smoke/run-all.mjs | 1 + 5 files changed, 205 insertions(+), 60 deletions(-) create mode 100644 examples/integration-smoke/provable-chain.mjs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff741c5c..33eda53a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,6 +47,14 @@ jobs: - name: Build run: bun run build + # Pre-publish provable-chain gate: prove the core → compliance → AEP + # seam still holds on the freshly-built workspace BEFORE anything is + # published to npm. A break here (a verified task can no longer become + # signed, verifiable evidence) fails the release rather than shipping a + # broken chain. Runs against workspace builds, not published versions. + - name: Provable-chain pre-publish gate + run: bun examples/integration-smoke/provable-chain.mjs + - name: Set npm registry run: | echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc diff --git a/bun.lock b/bun.lock index 2ad88828..f750f015 100644 --- a/bun.lock +++ b/bun.lock @@ -20,7 +20,7 @@ }, "examples/a2a-interop": { "name": "wasmagent-example-a2a-interop", - "version": "0.0.30", + "version": "0.0.31", "dependencies": { "@wasmagent/a2a": "workspace:*", "@wasmagent/core": "workspace:*", @@ -28,7 +28,7 @@ }, "examples/aisdk-quickjs": { "name": "aisdk-quickjs", - "version": "0.1.11", + "version": "0.1.12", "dependencies": { "@ai-sdk/openai": "^1.0.0", "@jitl/quickjs-wasmfile-release-sync": "^0.31.0", @@ -53,7 +53,7 @@ }, "examples/basic-agent": { "name": "basic-agent", - "version": "0.1.31", + "version": "0.1.32", "dependencies": { "@anthropic-ai/sdk": "^0.37.0", "@wasmagent/core": "workspace:*", @@ -61,7 +61,7 @@ }, "examples/browser-screenshot": { "name": "example-browser-screenshot", - "version": "0.1.31", + "version": "0.1.32", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/model-anthropic": "workspace:*", @@ -73,7 +73,7 @@ }, "examples/chat-cards": { "name": "chat-cards", - "version": "0.1.12", + "version": "0.1.14", "dependencies": { "@terrastruct/d2": "^0.1.33", "@wasmagent/react": "workspace:*", @@ -94,7 +94,7 @@ }, "examples/claude-agent-quickjs": { "name": "claude-agent-quickjs", - "version": "0.1.10", + "version": "0.1.11", "dependencies": { "@jitl/quickjs-wasmfile-release-sync": "^0.31.0", "@wasmagent/claude-agent-sdk": "workspace:*", @@ -136,7 +136,7 @@ }, "examples/eval-suite": { "name": "example-eval-suite", - "version": "0.1.31", + "version": "0.1.32", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/model-anthropic": "workspace:*", @@ -144,10 +144,12 @@ }, "examples/integration-smoke": { "name": "wasmagent-integration-smoke", - "version": "0.0.32", + "version": "0.0.33", "dependencies": { + "@wasmagent/aep": "workspace:*", "@wasmagent/aisdk": "workspace:*", "@wasmagent/cli": "workspace:*", + "@wasmagent/compliance": "workspace:*", "@wasmagent/core": "workspace:*", "@wasmagent/devtools": "workspace:*", "@wasmagent/evals-runner": "workspace:*", @@ -165,7 +167,7 @@ }, "examples/kernel-only": { "name": "wasmagent-example-kernel-only", - "version": "0.0.11", + "version": "0.0.12", "dependencies": { "@jitl/quickjs-wasmfile-release-sync": "0.32.0", "@wasmagent/kernel-quickjs": "workspace:*", @@ -175,7 +177,7 @@ }, "examples/local-offline": { "name": "local-offline", - "version": "0.1.30", + "version": "0.1.31", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/kernel-quickjs": "workspace:*", @@ -184,7 +186,7 @@ }, "examples/mastra-quickjs": { "name": "mastra-quickjs", - "version": "0.1.11", + "version": "0.1.12", "dependencies": { "@jitl/quickjs-wasmfile-release-sync": "^0.31.0", "@wasmagent/kernel-quickjs": "workspace:*", @@ -203,7 +205,7 @@ }, "examples/mcp-memory-server": { "name": "@wasmagent-example/mcp-memory-server", - "version": "0.1.32", + "version": "0.1.33", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/mcp-server": "workspace:*", @@ -211,7 +213,7 @@ }, "examples/mcp-portal": { "name": "mcp-portal", - "version": "0.1.32", + "version": "0.1.33", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/mcp-server": "workspace:*", @@ -236,7 +238,7 @@ }, "examples/openai-agents-quickjs": { "name": "openai-agents-quickjs", - "version": "0.1.10", + "version": "0.1.11", "dependencies": { "@jitl/quickjs-wasmfile-release-sync": "^0.31.0", "@wasmagent/kernel-quickjs": "workspace:*", @@ -263,7 +265,7 @@ }, "examples/tool-calling-agent": { "name": "tool-calling-agent-example", - "version": "0.1.31", + "version": "0.1.32", "dependencies": { "@anthropic-ai/sdk": "^0.37.0", "@wasmagent/core": "workspace:*", @@ -272,7 +274,7 @@ }, "examples/tool-search-rag": { "name": "example-tool-search-rag", - "version": "0.1.31", + "version": "0.1.32", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/model-anthropic": "workspace:*", @@ -282,7 +284,7 @@ }, "packages/a2a": { "name": "@wasmagent/a2a", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "^1.0.3", }, @@ -294,7 +296,7 @@ }, "packages/aep": { "name": "@wasmagent/aep", - "version": "2.1.0", + "version": "2.3.0", "dependencies": { "@noble/ed25519": "^3.1.0", "zod": "^3.23.0", @@ -307,7 +309,7 @@ }, "packages/ag-ui": { "name": "@wasmagent/ag-ui", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -326,7 +328,7 @@ }, "packages/aisdk": { "name": "@wasmagent/aisdk", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -343,7 +345,7 @@ }, "packages/capability-compiler": { "name": "@wasmagent/capability-compiler", - "version": "1.7.7", + "version": "1.7.8", "dependencies": { "@wasmagent/core": "^1.7.0", }, @@ -355,7 +357,7 @@ }, "packages/claude-agent-sdk": { "name": "@wasmagent/claude-agent-sdk", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -374,7 +376,7 @@ }, "packages/cli": { "name": "@wasmagent/cli", - "version": "1.3.11", + "version": "1.3.12", "bin": { "wasmagent": "./dist/index.js", "wasmagent-cli": "./dist/index.js", @@ -420,7 +422,7 @@ }, "packages/compliance": { "name": "@wasmagent/compliance", - "version": "3.0.2", + "version": "3.1.0", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/protocol": "0.1.5", @@ -433,7 +435,7 @@ }, "packages/core": { "name": "@wasmagent/core", - "version": "3.2.0", + "version": "3.3.0", "dependencies": { "@wasmagent/agent-prompts": "workspace:*", "@wasmagent/protocol": "^0.1.5", @@ -456,7 +458,7 @@ }, "packages/devtools": { "name": "@wasmagent/devtools", - "version": "1.7.7", + "version": "1.7.8", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -479,7 +481,7 @@ }, "packages/eliza-rollout-plugin": { "name": "@wasmagent/eliza-rollout-plugin", - "version": "1.0.11", + "version": "1.0.12", "dependencies": { "@wasmagent/core": "^1.0.3", }, @@ -496,7 +498,7 @@ }, "packages/evals-runner": { "name": "@wasmagent/evals-runner", - "version": "1.10.7", + "version": "1.10.8", "bin": { "wasmagent-evals": "./dist/cli.js", }, @@ -514,7 +516,7 @@ }, "packages/kernel-pyodide": { "name": "@wasmagent/kernel-pyodide", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -528,7 +530,7 @@ }, "packages/kernel-quickjs": { "name": "@wasmagent/kernel-quickjs", - "version": "1.2.7", + "version": "1.2.8", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -550,7 +552,7 @@ }, "packages/kernel-remote": { "name": "@wasmagent/kernel-remote", - "version": "1.3.11", + "version": "1.3.12", "dependencies": { "@wasmagent/core": "^1.3.4", }, @@ -568,7 +570,7 @@ }, "packages/kernel-wasmtime": { "name": "@wasmagent/kernel-wasmtime", - "version": "1.19.7", + "version": "1.19.8", "dependencies": { "@seda-protocol/wasm-metering-ts": "^2.0.1", "@wasmagent/core": "workspace:*", @@ -581,7 +583,7 @@ }, "packages/mastra-sandbox": { "name": "@wasmagent/mastra-sandbox", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -603,7 +605,7 @@ }, "packages/mcp-firewall": { "name": "@wasmagent/mcp-firewall", - "version": "2.0.2", + "version": "2.0.3", "dependencies": { "@wasmagent/mcp-server": "^1.1.0", }, @@ -616,7 +618,7 @@ }, "packages/mcp-gateway": { "name": "@wasmagent/mcp-gateway", - "version": "0.1.7", + "version": "0.1.8", "dependencies": { "@wasmagent/mcp-firewall": "^1.1.0", }, @@ -649,7 +651,7 @@ }, "packages/mcp-server": { "name": "@wasmagent/mcp-server", - "version": "1.1.8", + "version": "1.1.9", "bin": { "wasmagent-mcp-server": "./dist/stdio.js", }, @@ -664,7 +666,7 @@ }, "packages/model-anthropic": { "name": "@wasmagent/model-anthropic", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -678,7 +680,7 @@ }, "packages/model-deepseek": { "name": "@wasmagent/model-deepseek", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -692,7 +694,7 @@ }, "packages/model-doubao": { "name": "@wasmagent/model-doubao", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -706,7 +708,7 @@ }, "packages/model-local": { "name": "@wasmagent/model-local", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/models": "workspace:*", @@ -724,7 +726,7 @@ }, "packages/model-minimax": { "name": "@wasmagent/model-minimax", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -739,7 +741,7 @@ }, "packages/model-moonshot": { "name": "@wasmagent/model-moonshot", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -753,7 +755,7 @@ }, "packages/model-openai": { "name": "@wasmagent/model-openai", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -768,7 +770,7 @@ }, "packages/model-qwen": { "name": "@wasmagent/model-qwen", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -782,7 +784,7 @@ }, "packages/model-zhipu": { "name": "@wasmagent/model-zhipu", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/models": "workspace:*", }, @@ -796,7 +798,7 @@ }, "packages/models": { "name": "@wasmagent/models", - "version": "2.0.3", + "version": "2.0.4", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -816,7 +818,7 @@ }, "packages/openai-agents": { "name": "@wasmagent/openai-agents", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -835,7 +837,7 @@ }, "packages/otel-exporter": { "name": "@wasmagent/otel-exporter", - "version": "2.0.0", + "version": "3.0.0", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -850,7 +852,7 @@ }, "packages/react": { "name": "@wasmagent/react", - "version": "1.3.11", + "version": "1.4.1", "dependencies": { "@wasmagent/core": "workspace:*", }, @@ -865,7 +867,7 @@ }, "packages/tools-browser": { "name": "@wasmagent/tools-browser", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "^1.0.3", "zod": "^3.23.0", @@ -884,7 +886,7 @@ }, "packages/tools-rag": { "name": "@wasmagent/tools-rag", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "^1.0.3", "zod": "^3.23.0", @@ -896,7 +898,7 @@ }, "packages/tools-web": { "name": "@wasmagent/tools-web", - "version": "1.0.10", + "version": "1.0.11", "dependencies": { "@wasmagent/core": "^1.0.3", "zod": "^3.23.0", @@ -944,7 +946,7 @@ }, "tests/integration": { "name": "@wasmagent/integration-tests", - "version": "1.19.7", + "version": "1.19.8", "dependencies": { "@wasmagent/core": "workspace:*", "@wasmagent/kernel-quickjs": "workspace:*", @@ -3102,8 +3104,6 @@ "@wasmagent/ag-ui/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], - "@wasmagent/aisdk/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], - "@wasmagent/aisdk/ai": ["ai@4.3.19", "https://registry.npmmirror.com/ai/-/ai-4.3.19.tgz", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/react": "1.2.12", "@ai-sdk/ui-utils": "1.2.11", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q=="], "@wasmagent/aisdk/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -3136,8 +3136,6 @@ "@wasmagent/kernel-remote/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], - "@wasmagent/mastra-sandbox/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], - "@wasmagent/mcp-attestation/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], "@wasmagent/mcp-firewall/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], @@ -3148,8 +3146,6 @@ "@wasmagent/mcp-policy/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], - "@wasmagent/mcp-server/@types/node": ["@types/node@26.1.1", "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], - "@wasmagent/mcp-server/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@wasmagent/model-local/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], diff --git a/examples/integration-smoke/package.json b/examples/integration-smoke/package.json index 73cfa836..cc6d4a12 100644 --- a/examples/integration-smoke/package.json +++ b/examples/integration-smoke/package.json @@ -2,7 +2,7 @@ "name": "wasmagent-integration-smoke", "version": "0.0.33", "private": true, - "description": "Local-only end-to-end smoke scripts that drive the public package surface (A1/A2/A4/A5 etc.). NOT part of CI — run them by hand to verify a fresh build.", + "description": "Local-only end-to-end smoke scripts that drive the public package surface (A1/A2/A4/A5 etc.). NOT part of CI \u2014 run them by hand to verify a fresh build.", "type": "module", "scripts": { "all": "node run-all.mjs", @@ -21,8 +21,10 @@ "edge:evals": "bun edge-evals-runner.mjs" }, "dependencies": { + "@wasmagent/aep": "workspace:*", "@wasmagent/aisdk": "workspace:*", "@wasmagent/cli": "workspace:*", + "@wasmagent/compliance": "workspace:*", "@wasmagent/core": "workspace:*", "@wasmagent/devtools": "workspace:*", "@wasmagent/evals-runner": "workspace:*", diff --git a/examples/integration-smoke/provable-chain.mjs b/examples/integration-smoke/provable-chain.mjs new file mode 100644 index 00000000..dfda0388 --- /dev/null +++ b/examples/integration-smoke/provable-chain.mjs @@ -0,0 +1,138 @@ +/** + * Provable-chain smoke: the end-to-end "provable agent" pipeline across the + * freshly-built workspace packages, with NO external services and NO LLM. + * + * task output ──▶ @wasmagent/compliance (verify against a TaskSpec, backed + * by @wasmagent/core's VerificationPipeline) + * ──▶ @wasmagent/aep (record the step + the verifier result as + * signed AEP evidence, then verify the signature) + * + * This is the release gate for cross-package contract drift on the provable + * chain: if a change to @wasmagent/core, @wasmagent/compliance, or + * @wasmagent/aep breaks the seam that lets a verified task turn into signed, + * verifiable evidence, this script goes red BEFORE the packages are published. + * + * It imports bare `@wasmagent/*` specifiers, which bun resolves to the local + * workspace builds — so it exercises what is about to ship, not what is on npm. + * + * NOTE: the trust-passport link (@openagentaudit/passport) is intentionally + * NOT exercised here: it is an external published dependency, not a workspace + * package, so a wasmagent-js pre-publish gate cannot meaningfully guard it. + */ +import { DeterministicVerifier, VerificationPipeline } from "@wasmagent/core"; +import { ComplianceVerifier } from "@wasmagent/compliance"; +import { AEPEmitter, createLocalSignerFromSeed, verifyAEPRecord } from "@wasmagent/aep"; + +let failed = 0; +function ok(label) { + console.log(`✓ ${label}`); +} +function fail(label, detail) { + console.error(`✗ ${label}`, detail ?? ""); + failed++; +} + +// A minimal, self-contained TaskSpec: the produced object must contain the +// substring "approved" (a stand-in for a real compliance constraint). This +// uses the DeterministicVerifier's `file_contains` method against the object +// exposed as "object.json" by ComplianceVerifier.verifyObject. +const taskSpec = { + id: "provable-chain.smoke.v1", + intent: "produce_compliant_decision", + language: "en", + constraints: [ + { + id: "must-be-approved", + description: 'decision object must contain "approved"', + verify_method: "file_contains", + arg: "approved", + path: "object.json", + level: "hard", + priority: 100, + category: "content", + }, + ], + priority_hierarchy: ["system_policy", "user_explicit_constraints"], +}; + +// ── 1. A compliant task output passes compliance; a non-compliant one fails. +// Proves core's VerificationPipeline + DeterministicVerifier + compliance +// enrichment agree on a verdict. + +let compliantResult; +{ + const compliant = { decision: "approved", reason: "vendor on whitelist" }; + const nonCompliant = { decision: "blocked", reason: "budget exceeded" }; + + compliantResult = await ComplianceVerifier.verifyObject(compliant, taskSpec); + const badResult = await ComplianceVerifier.verifyObject(nonCompliant, taskSpec); + + if (!compliantResult.ok) { + fail("compliance: compliant object should pass", compliantResult.violations); + } else if (compliantResult.passing_constraint_ids.length !== 1) { + fail("compliance: expected 1 passing constraint", compliantResult.passing_constraint_ids); + } else { + ok("compliance: compliant object passes, non-compliant fails"); + } + + if (badResult.ok) { + fail("compliance: non-compliant object should fail", badResult); + } else if (!badResult.violations.some((v) => v.constraint_id === "must-be-approved")) { + fail("compliance: expected must-be-approved violation", badResult.violations); + } +} + +// ── 2. The compliance verdict becomes SIGNED AEP evidence that verifies. +// Proves the compliance→AEP seam: a VerifierResult built from a +// ComplianceVerificationResult round-trips through emit()+verifyAEPRecord. + +{ + const seed = "deadbeef".repeat(8); // 64 hex chars — deterministic test key + const signer = createLocalSignerFromSeed(seed, "provable-chain-smoke-key"); + const emitter = new AEPEmitter({ run_id: "provable-chain-smoke-run", signer }); + + // The task step that produced the decision. + emitter.addAction({ tool_name: "make_decision", state_changing: false }); + // Bridge: the compliance result → an AEP verifier result. + emitter.addVerifierResult({ + verifier_id: taskSpec.id, + passed: compliantResult.ok, + score: compliantResult.ok ? 1 : 0, + claim_ids: compliantResult.passing_constraint_ids, + }); + + const record = await emitter.emit(1_700_000_000_000); + if (record.verifier_results.length !== 1) { + fail("aep: expected 1 verifier_result on the record", record.verifier_results); + } else if (!record.verifier_results[0].passed) { + fail("aep: verifier_result should reflect a passing compliance run", record.verifier_results); + } else if (record.actions.length !== 1) { + fail("aep: expected 1 action on the record", record.actions); + } else { + ok("aep: signed record carries the action + compliance verifier result"); + } + + const publicKey = await signer.getPublicKey(); + const valid = await verifyAEPRecord(record, publicKey); + if (!valid) { + fail("aep: signature verification failed on freshly emitted record"); + } else { + ok("aep: emitted record verifies against its signer public key"); + } + + // Tamper-evidence: mutating the record must break verification. + const tampered = { ...record, run_id: "tampered-run" }; + const tamperedValid = await verifyAEPRecord(tampered, publicKey); + if (tamperedValid) { + fail("aep: tampered record should NOT verify"); + } else { + ok("aep: tampered record is rejected (tamper-evident)"); + } +} + +if (failed > 0) { + console.error(`\n[provable-chain] ${failed} CHECK(S) FAILED`); + process.exit(1); +} +console.log(`\n[provable-chain] all checks passed`); +process.exit(0); diff --git a/examples/integration-smoke/run-all.mjs b/examples/integration-smoke/run-all.mjs index 5b5ac68b..2380a9a4 100644 --- a/examples/integration-smoke/run-all.mjs +++ b/examples/integration-smoke/run-all.mjs @@ -28,6 +28,7 @@ const here = dirname(fileURLToPath(import.meta.url)); // We pin the order so the cheap, no-IO scripts run first — quick failure // signal — and the heavyweight (Studio HTTP, MCP protocol) come last. const ORDER = [ + "provable-chain.mjs", "a5-openai-compat.mjs", "cross-kernel.mjs", "edge-capability-boundaries.mjs", From 274615ffda30c3fd4fff3ee679415ccc7cfefafa Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Thu, 30 Jul 2026 14:17:27 +0800 Subject: [PATCH 2/2] docs: restore em-dash and mark provable-chain as a CI gate in smoke pkg description --- examples/integration-smoke/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/integration-smoke/package.json b/examples/integration-smoke/package.json index cc6d4a12..732660d9 100644 --- a/examples/integration-smoke/package.json +++ b/examples/integration-smoke/package.json @@ -2,7 +2,7 @@ "name": "wasmagent-integration-smoke", "version": "0.0.33", "private": true, - "description": "Local-only end-to-end smoke scripts that drive the public package surface (A1/A2/A4/A5 etc.). NOT part of CI \u2014 run them by hand to verify a fresh build.", + "description": "End-to-end smoke scripts that drive the public package surface (A1/A2/A4/A5 etc.). Most are local-only (run by hand to verify a fresh build); provable-chain.mjs is also run as a pre-publish gate in release.yml.", "type": "module", "scripts": { "all": "node run-all.mjs",