Skip to main content
Version: 1.0.0

Verify a handler supply chain

Bind the compiled AIR, manifest, actual handler, dependency lockfile and declared local data by digest. Detect changes before dispatch, without treating a digest as evidence that code is safe. Prerequisites: Touba, Node.js 24 and npm.

Create the isolated project​

Terminal
mkdir -p supply-chain-demo
cd supply-chain-demo
mkdir -p handlers vendor
npm init -y
node --input-type=module -e 'import {execFileSync} from "node:child_process"; import {copyFileSync} from "node:fs"; const v=JSON.parse(execFileSync("touba",["version","--json"],{encoding:"utf8"})); copyFileSync(v.distribution.sdk_archive,"vendor/touba-sdk.tgz");'
npm install --offline --ignore-scripts --save-exact ./vendor/touba-sdk.tgz
source.tb
module examples.supply_chain

tool ReadCatalogue
description "Read the local catalogue from the reviewed project file."
gives Text
requires filesystem_read

strategy RunCatalogue
gives Text
uses ReadCatalogue
do
ReadCatalogue
into catalogue
give catalogue
catalogue.json
{"datasets":[{"id":"parks","title":"Public parks"}]}
handlers/read.mjs
import { readFile } from "node:fs/promises";
import { defineTool } from "@touba/sdk";
await defineTool({ toolRef: "tool:examples.supply_chain/ReadCatalogue",
inputSignature: [], outputType: "builtin:Text", requiredGrants: ["filesystem_read"],
run: async () => (await readFile("catalogue.json", "utf8")).trim(),
});
configure.mjs
import { writeFileSync } from "node:fs";
writeFileSync("touba.manifest.json", JSON.stringify({ manifest_version: "touba-manifest-v1", bindings: {
"tool:examples.supply_chain/ReadCatalogue": {
handler: { kind: "process", command: process.execPath, args: ["handlers/read.mjs"], cwd: "." },
grants: ["filesystem_read"], secrets: [], effect_contract: { kind: "none" },
timeout_ms: 10000, max_payload_bytes: 65536,
},
} }, null, 2));

Generate, check and deliberately invalidate the lock​

The generator hashes the actual files and leaves the original lock pending review. The script first proves that requiring a review rejects this lock. It then runs the handler and records the assertions in an automated report. A separate lock declares this narrow automated check with a tool reviewer. It does not claim a human security review, signed identity or production approval. Your deployment policy must require the actual reviews appropriate to your environment.

Every drift test restores its own isolated file. Neither the original lock nor its digests are silently rewritten to make a failed check pass.

exercise.mjs
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { readFileSync, writeFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { TOUBA_SDK_METADATA } from "@touba/sdk";
function cli(args, expected = 0) {
const child = spawnSync("touba", args, { encoding: "utf8" });
assert.equal(child.status, expected, child.stderr || child.stdout);
return JSON.parse(child.stdout);
}
const write = (path, value) => writeFileSync(path, JSON.stringify(value, null, 2) + "\n");
const digest = path => ({ kind: "sha256", value: createHash("sha256").update(readFileSync(path)).digest("hex") });
cli(["supply-chain", "generate", "--air", "program.air.json", "--manifest", "touba.manifest.json",
"--out", "touba.lock.json", "--file", "catalogue.json", "--file", "vendor/touba-sdk.tgz",
"--sdk-metadata-json", JSON.stringify(TOUBA_SDK_METADATA)]);
const baseline = JSON.parse(readFileSync("touba.lock.json", "utf8"));
assert.equal(baseline.review.status, "pending");
const validate = (lock, expected, flags = []) => cli(["supply-chain", "validate", "--lock", lock,
"--air", "program.air.json", "--manifest", "touba.manifest.json", "--output", "json", ...flags], expected);
const pending = validate("touba.lock.json", 1, ["--strict", "--require-review"]);
assert.ok(pending.diagnostics.some(item => item.code === "SupplyChainReviewNotApproved"));
const run = (lock, expected) => cli(["run", "program.air.json", "--entry", "strategy:examples.supply_chain/RunCatalogue",
"--manifest", "touba.manifest.json", "--supply-chain-lock", lock, "--require-supply-chain-lock", "--output", "json"], expected);
const direct = cli(["run", "program.air.json", "--entry", "strategy:examples.supply_chain/RunCatalogue",
"--manifest", "touba.manifest.json", "--output", "json"]);
assert.equal(direct.result, readFileSync("catalogue.json", "utf8").trim());
write("automated-check.json", { scope: "isolated tutorial: actual catalogue read, expected value, pending-review refusal",
checked_at: new Date().toISOString(), result: "passed", security_review: false });
const checked = structuredClone(baseline);
checked.review = { status: "approved", reviewed_at: new Date().toISOString(),
reviewers: [{ kind: "tool", id: "tutorial:automated-check", role: "isolated-functional-check" }],
evidence: [{ kind: "validation_report", path: "automated-check.json", digest: digest("automated-check.json") }] };
write("automated.checked.lock.json", checked);
assert.equal(validate("automated.checked.lock.json", 0, ["--strict", "--require-review"]).status, "ok");
assert.equal(run("automated.checked.lock.json", 0).result, direct.result);
function variant(name, mutate, code) {
const value = structuredClone(checked); mutate(value); const file = name + ".lock.json"; write(file, value);
const report = validate(file, 1, ["--strict", "--require-review"]);
assert.ok(report.diagnostics.some(item => item.code === code), JSON.stringify(report));
}
variant("protocol", lock => { lock.handlers[0].sdk.protocol = "unsupported-protocol"; }, "HandlerSdkUnsupported");
variant("package", lock => { delete lock.handlers[0].handler_package; }, "HandlerPackageUnknown");
variant("rejected", lock => { lock.review.status = "rejected"; }, "SupplyChainReviewRejected");
for (const [file, code] of [["handlers/read.mjs", "HandlerChanged"],
["package-lock.json", "HandlerDependencyArtifactChanged"], ["automated-check.json", "SupplyChainReviewEvidenceChanged"]]) {
const original = readFileSync(file);
try {
writeFileSync(file, Buffer.concat([original, Buffer.from("\n ")]));
const report = validate("automated.checked.lock.json", 1, ["--strict", "--require-review"]);
assert.ok(report.diagnostics.some(item => item.code === code), JSON.stringify(report));
const refused = run("automated.checked.lock.json", 1);
assert.equal(refused.status, "failure");
assert.ok(!refused.trace.events.some(event => event.kind === "tool_binding_authorized"));
} finally { writeFileSync(file, original); }
}
assert.equal(JSON.parse(readFileSync("touba.lock.json", "utf8")).review.status, "pending");
console.log("LOCK_DIGEST_PROTOCOL_PACKAGE_REVIEW_AND_DRIFT_CHECKS_OK");
Terminal
node configure.mjs
touba compile source.tb --out program.air.json
node exercise.mjs
touba inspect --supply-chain touba.lock.json

The script prints LOCK_DIGEST_PROTOCOL_PACKAGE_REVIEW_AND_DRIFT_CHECKS_OK. The runtime manifest still grants authority; the lock only constrains artifact identity and declared review state. The generator follows static local JavaScript and Python imports; --file adds other resources. Third-party dependencies remain described by their lockfiles. See the supply-chain guide for inventory details.