Public dry run dryrun-20b59dc46b72

Source commit: 20b59dc46b72103c2f8a516c692b5cc3d54fab19

Public tree identity: sha256:aaa5ac7b58b2a0d23c6b11e5f76324bf3839ca1f62653a83deb736932adcfbd9
This commit is contained in:
Disasmer release dry run 2026-07-14 10:08:15 +02:00
commit 2bef715211
221 changed files with 79792 additions and 0 deletions

83
scripts/acceptance-cli-first.sh Executable file
View file

@ -0,0 +1,83 @@
#!/usr/bin/env bash
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo"
if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_E2E:-}" == "1" ]]; then
echo "CLI-first acceptance does not run final public-release e2e; unset DISASMER_PUBLIC_RELEASE_DRYRUN_E2E" >&2
exit 1
fi
if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL:-}" == "1" ]]; then
echo "CLI-first acceptance does not run final public-release evidence; unset DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL" >&2
exit 1
fi
node scripts/acceptance-report.js cli-first
node scripts/cli-first-contract-smoke.js
node scripts/acceptance-report-smoke.js
node scripts/acceptance-doc-contract-smoke.js
node scripts/acceptance-environment-contract-smoke.js
node scripts/acceptance-evidence-contract-smoke.js
node scripts/code-size-guard.js
node scripts/public-private-boundary-smoke.js
node scripts/release-blocker-smoke.js
node scripts/resource-metering-contract-smoke.js
node scripts/hostile-input-contract-smoke.js
node scripts/tenant-isolation-contract-smoke.js
node scripts/public-story-contract-smoke.js
if [[ "${DISASMER_CLI_FIRST_PREPARE_PUBLIC_RELEASE:-1}" == "1" ]]; then
node scripts/prepare-public-release-dryrun.js
fi
node scripts/public-release-dryrun-contract-smoke.js
node scripts/public-browser-login-contract-smoke.js
node scripts/self-hosted-coordinator-smoke.js
if [[ "${DISASMER_CLI_HAPPY_PATH_LIVE:-}" == "1" ]]; then
node scripts/cli-happy-path-live-smoke.js
fi
node scripts/public-local-demo-matrix-smoke.js
scripts/release-source-scan.sh
cargo fmt --all --check
cargo test --workspace
cargo build --workspace --bins
node scripts/docs-smoke.js
node scripts/cli-output-mode-smoke.js
node scripts/cli-login-smoke.js
node scripts/cli-error-exit-smoke.js
node scripts/cli-browser-login-flow-smoke.js
node scripts/cli-install-smoke.js
node scripts/user-session-token-boundary-smoke.js
node scripts/sdk-spawn-runtime-smoke.js
node scripts/node-lifecycle-contract-smoke.js
node scripts/wasmtime-node-smoke.js
node scripts/wasmtime-assignment-smoke.js
if command -v podman >/dev/null 2>&1; then
node scripts/podman-backend-smoke.js
elif command -v nix >/dev/null 2>&1; then
nix shell nixpkgs#podman --command node scripts/podman-backend-smoke.js
else
node scripts/podman-backend-smoke.js
fi
node scripts/vscode-extension-smoke.js
node scripts/vscode-f5-smoke.js
node scripts/node-attach-smoke.js
node scripts/cli-local-run-smoke.js
node scripts/artifact-download-smoke.js
node scripts/artifact-export-smoke.js
node scripts/operator-panel-smoke.js
node scripts/source-preparation-smoke.js
node scripts/scheduler-placement-smoke.js
node scripts/windows-best-effort-smoke.js
node scripts/windows-validation-contract-smoke.js
node scripts/quic-smoke.js
node scripts/dap-smoke.js
node scripts/flagship-demo-smoke.js
if [[ "${DISASMER_CLI_FIRST_INCLUDE_PRIVATE:-0}" == "1" ]]; then
scripts/acceptance-private.sh
fi

View file

@ -0,0 +1,205 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const {
assertPreFinalOrFinalLedger,
} = require("./phase3-ledger");
const repo = path.resolve(__dirname, "..");
if (
fs.existsSync(path.join(repo, "DISASMER_PUBLIC_TREE.json")) &&
!fs.existsSync(path.join(repo, "acceptance_criteria.md"))
) {
console.log(
"Acceptance doc contract smoke skipped: root acceptance markdown is filtered from this public tree"
);
process.exit(0);
}
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function criterionLines(source) {
return source
.split(/\r?\n/)
.filter((line) => /^- \[[ x]\] \*\*/.test(line));
}
function assertEveryCriterionHasStatus(source, name) {
const lines = criterionLines(source);
assert(lines.length > 0, `${name} must contain acceptance criteria`);
for (const line of lines) {
assert.match(
line,
/^- \[[ x]\] \*\*(Passed|Partial|Open|Postponed)(?: \([^)]+\))?:\*\*/,
`${name} criterion lacks an explicit status prefix: ${line}`
);
}
}
function assertNoOpenCriteria(source, name) {
const open = criterionLines(source).filter((line) => /\*\*Open(?::| \()/.test(line));
assert.deepStrictEqual(open, [], `${name} still has Open criteria`);
}
function assertPhase3CriterionHeadingsHaveStatus(source, name) {
const headings = source
.split(/\r?\n/)
.filter((line) => /^## /.test(line) && /P3-[A-Z]+-\d{3}:/.test(line));
assert(headings.length > 0, `${name} must contain Phase 3 criteria`);
for (const line of headings) {
assert.match(
line,
/^## \*\*(Passed|Partial|Open|Postponed):\*\* P3-[A-Z]+-\d{3}:/,
`${name} criterion heading lacks an explicit status prefix: ${line}`
);
}
assertPreFinalOrFinalLedger(source);
}
const phase2 = read("acceptance_criteria_phase2.md");
const base = read("acceptance_criteria.md");
const cliFirst = read("cli_acceptance_criteria.md");
const website = read("website_mvp_inventory.md");
const phase3 = read("phase_3_acceptance_criteria.md");
const docsSmoke = read("scripts/docs-smoke.js");
const releaseBlockerSmoke = read("scripts/release-blocker-smoke.js");
const publicAcceptance = read("scripts/acceptance-public.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
const cliFirstAcceptance = read("scripts/acceptance-cli-first.sh");
const publicSplit = read("scripts/verify-public-split.sh");
assert.match(
phase2,
/phase 2 superset of `acceptance_criteria\.md`/,
"phase 2 criteria must declare that they are a superset of the base criteria"
);
assert.match(
phase2,
/Existing `acceptance_criteria\.md` remains required unless it conflicts with this stricter release document; this document wins in conflicts/,
"phase 2 criteria must keep base acceptance criteria required unless stricter phase 2 criteria conflict"
);
assert.match(
phase2,
/- \[x\] \*\*Passed:\*\* Existing `acceptance_criteria\.md` remains required unless it conflicts with this stricter release document; this document wins in conflicts\./,
"phase 2 cross-document requirement must be marked passed only when this guard is wired"
);
assert.match(
phase3,
/Canonical Phase 3 gate:[\s\S]*active Phase 3 acceptance document/,
"phase 3 criteria must declare itself as the canonical current gate"
);
assert.match(
phase3,
/Important reading note:[\s\S]*not necessarily always mean adding code/,
"phase 3 criteria must keep the no-automatic-code-work disclaimer at the top"
);
assert.match(
phase3,
/Every criterion heading below is prefixed with \*\*Passed\*\*, \*\*Partial\*\*, or \*\*Open\*\*/,
"phase 3 criteria must explain the explicit status-prefix convention"
);
assertPhase3CriterionHeadingsHaveStatus(phase3, "phase_3_acceptance_criteria.md");
for (const [source, name] of [
[base, "acceptance_criteria.md"],
[phase2, "acceptance_criteria_phase2.md"],
[cliFirst, "cli_acceptance_criteria.md"],
]) {
assertEveryCriterionHasStatus(source, name);
assertNoOpenCriteria(source, name);
assert.match(
source,
/Design-document references to billing, paid plans, or plan flags are future metadata placeholders; they do not require MVP/,
`${name} must keep billing/paid-plan placeholders outside MVP implementation scope`
);
assert.match(
source,
/not the canonical Phase 3 release gate; current Phase 3 status and release verification live in `phase_3_acceptance_criteria\.md`/,
`${name} must point current Phase 3 status to phase_3_acceptance_criteria.md`
);
}
assertEveryCriterionHasStatus(website, "website_mvp_inventory.md");
assert.match(
website,
/private hosted website addendum to `acceptance_criteria\.md`, `acceptance_criteria_phase2\.md`, and `cli_acceptance_criteria\.md`/,
"website acceptance criteria must declare itself as the private hosted website addendum"
);
assert.match(
website,
/barebones functional HTML with no CSS/,
"website acceptance criteria must keep the MVP website barebones with no CSS"
);
assert.match(
website,
/Billing is not part of the MVP[\s\S]*Design-document references to billing, paid plans, or plan flags are future metadata placeholders; they do not require MVP website routes/,
"website acceptance criteria must keep billing and paid-plan placeholders outside MVP website scope"
);
assert.match(
website,
/- \[ \] \*\*Open:\*\* The private hosted website acceptance gate exists and exercises the barebones website through `disasmer\.michelpaulissen\.com`/,
"website acceptance criteria must leave the private website deployment gate explicit and open"
);
assert.match(
website,
/not the canonical Phase 3 release gate; current Phase 3 status and release verification live in `phase_3_acceptance_criteria\.md`/,
"website acceptance criteria must point current Phase 3 status to phase_3_acceptance_criteria.md"
);
for (const file of [
"MVP.md",
"acceptance_criteria.md",
"acceptance_criteria_phase2.md",
"cli_acceptance_criteria.md",
"website_mvp_inventory.md",
"phase_3_acceptance_criteria.md",
]) {
assert(
docsSmoke.includes(`"${file}"`),
`docs smoke must include ${file} as user-facing acceptance context`
);
}
assert(
releaseBlockerSmoke.includes('const phase2 = read("acceptance_criteria_phase2.md")'),
"release-blocker smoke must read phase 2 acceptance criteria"
);
assert(
releaseBlockerSmoke.includes('const base = read("acceptance_criteria.md")'),
"release-blocker smoke must read base acceptance criteria"
);
for (const [source, name] of [
[base, "acceptance_criteria.md"],
[phase2, "acceptance_criteria_phase2.md"],
]) {
for (const [label, pattern] of [
["MVP selected locals", /selected (?:top-level )?locals|selected real source locals/],
["MVP task args", /task arguments|task args/],
["MVP handle inspection", /Artifact.*SourceSnapshot.*Blob|Disasmer handles/],
["MVP stdout stderr", /stdout\/stderr/],
["MVP unavailable locals", /cannot be inspected|unavailable-local/],
["MVP required DAP surface", /initialize[\s\S]*launch.*attach[\s\S]*setBreakpoints[\s\S]*configurationDone[\s\S]*threads[\s\S]*stackTrace[\s\S]*scopes[\s\S]*variables[\s\S]*continue[\s\S]*pause/],
]) {
assert.match(source, pattern, `${name} must include MVP debugging criterion: ${label}`);
}
}
for (const [scriptName, script] of [
["public acceptance", publicAcceptance],
["private acceptance", privateAcceptance],
["CLI-first acceptance", cliFirstAcceptance],
["public split", publicSplit],
]) {
assert(
script.includes("node scripts/acceptance-doc-contract-smoke.js"),
`${scriptName} must run acceptance-doc-contract-smoke.js`
);
}
console.log("Acceptance doc contract smoke passed");

View file

@ -0,0 +1,262 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function maybeRead(relativePath) {
const absolute = path.join(repo, relativePath);
if (!fs.existsSync(absolute)) return null;
return fs.readFileSync(absolute, "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing acceptance environment evidence: ${name}`);
}
function expectIncludes(source, name, text) {
assert(source.includes(text), `missing acceptance environment evidence: ${name}`);
}
const publicAcceptance = read("scripts/acceptance-public.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const acceptanceReport = read("scripts/acceptance-report.js");
const acceptanceReportSmoke = read("scripts/acceptance-report-smoke.js");
const readme = read("README.md");
const windowsWorkflow = read(".forgejo/workflows/windows-validation.yml");
const publicDryrunServiceSmoke = maybeRead("private/hosted-policy/scripts/public-release-dryrun-service-smoke.js");
const publicDryrunDeployPrep = maybeRead("private/hosted-policy/scripts/prepare-public-release-dryrun-deployment.js");
const publicDryrunSystemd = maybeRead("private/hosted-policy/deploy/disasmer-public-release-dryrun.service");
const publicDryrunRunbook = maybeRead("private/hosted-policy/deploy/README.md");
const hostedClientCompatSmoke = maybeRead("private/hosted-policy/scripts/hosted-client-compat-smoke.js");
const hostedService = maybeRead("private/hosted-policy/src/bin/disasmer-hosted-service.rs");
const hostedStartup = maybeRead(
"private/hosted-policy/src/bin/disasmer-hosted-service/startup.rs"
);
const hostedOperatorAuth = maybeRead(
"private/hosted-policy/src/bin/disasmer-hosted-service/operator_auth.rs"
);
const publicDryrunE2e = read("scripts/public-release-dryrun-e2e.js");
const finalDryrunEvidence = read("scripts/public-release-dryrun-final-evidence.js");
for (const [name, script] of [
["public acceptance", publicAcceptance],
["private acceptance", privateAcceptance],
]) {
expect(script, `${name} writes acceptance environment report first`, /node scripts\/acceptance-report\.js (public|private)[\s\S]*node scripts\/acceptance-report-smoke\.js/);
expectIncludes(
script,
`${name} runs acceptance environment contract`,
"node scripts/acceptance-environment-contract-smoke.js"
);
}
for (const [name, script] of [
["public acceptance", publicAcceptance],
["public split", publicSplit],
]) {
for (const smoke of [
"scripts/wasmtime-assignment-smoke.js",
"scripts/node-attach-smoke.js",
"scripts/cli-local-run-smoke.js",
"scripts/vscode-f5-smoke.js",
"scripts/dap-smoke.js",
"scripts/artifact-download-smoke.js",
"scripts/artifact-export-smoke.js",
"scripts/public-local-demo-matrix-smoke.js",
]) {
assert(script.includes(`node ${smoke}`), `${name} must run ${smoke}`);
}
}
expectIncludes(publicAcceptance, "public gate runs rootless Podman backend smoke", "node scripts/podman-backend-smoke.js");
expectIncludes(publicAcceptance, "public gate runs Wasmtime node smoke", "node scripts/wasmtime-node-smoke.js");
expectIncludes(privateAcceptance, "private gate runs hosted deployment smoke", "node private/hosted-policy/scripts/hosted-deployment-smoke.js");
expectIncludes(privateAcceptance, "private gate prepares public dry-run deployment bundle", "node private/hosted-policy/scripts/prepare-public-release-dryrun-deployment.js");
expectIncludes(privateAcceptance, "private gate runs hosted Client compatibility smoke", "node private/hosted-policy/scripts/hosted-client-compat-smoke.js");
expectIncludes(privateAcceptance, "private gate runs standalone Core coordinator smoke", "node scripts/self-hosted-coordinator-smoke.js");
expectIncludes(privateAcceptance, "private gate runs Postgres durable smoke", "node private/hosted-policy/scripts/postgres-durable-smoke.js");
expectIncludes(privateAcceptance, "private gate can run public release dry-run service smoke", "node private/hosted-policy/scripts/public-release-dryrun-service-smoke.js");
expectIncludes(privateAcceptance, "public release dry-run service smoke is env gated", "DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR");
expectIncludes(privateAcceptance, "private gate runs hosted policy cargo tests", "cargo test --manifest-path private/hosted-policy/Cargo.toml");
expectIncludes(publicAcceptance, "public gate can run final dry-run evidence verifier", "node scripts/public-release-dryrun-final-evidence.js");
expectIncludes(publicAcceptance, "public gate can run public release dry-run e2e", "node scripts/public-release-dryrun-e2e.js");
expectIncludes(publicAcceptance, "public release dry-run e2e is env gated", "DISASMER_PUBLIC_RELEASE_DRYRUN_E2E");
expectIncludes(privateAcceptance, "private gate can run final dry-run evidence verifier", "node scripts/public-release-dryrun-final-evidence.js");
expectIncludes(publicAcceptance, "public final dry-run verifier is env gated", "DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL");
expectIncludes(privateAcceptance, "private final dry-run verifier is env gated", "DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL");
expect(publicSplit, "public split excludes private modules", /--exclude='\.\/private'/);
expect(publicSplit, "public split excludes experiments", /--exclude='\.\/experiments'/);
expect(publicSplit, "public split tests copied workspace", /cargo test --workspace --manifest-path "\$tmp_dir\/Cargo\.toml"/);
expect(publicSplit, "public split builds copied workspace binaries", /cargo build --workspace --bins --manifest-path "\$tmp_dir\/Cargo\.toml"/);
expectIncludes(
publicSplit,
"public split runs acceptance environment contract from copied tree",
'(cd "$tmp_dir" && node scripts/acceptance-environment-contract-smoke.js)'
);
for (const [name, pattern] of [
["commit SHA fallback", /process\.env\.DISASMER_ACCEPTANCE_COMMIT \|\| commandOutput\("git", \["rev-parse", "HEAD"\]\)/],
["tree status", /tree_status: \(commandOutput\("git", \["status", "--short"\]\) \|\| ""\)[\s\S]*\.filter\(Boolean\)/],
["OS report", /platform: os\.platform\(\)[\s\S]*kernel: os\.release\(\)/],
["Rust report", /rustc: commandOutput\("rustc", \["--version"\]\)/],
["Node report", /version: process\.version/],
["Podman report", /function podmanReport\(\)/],
["Postgres report", /postgres: \{[\s\S]*commandOutput\("postgres", \["--version"\]\) \|\|[\s\S]*commandOutput\("psql", \["--version"\]\)/],
["browser harness report", /browser_harness:/],
["VS Code harness report", /vscode_harness:/],
["Windows validation report", /windows_validation: process\.env\.DISASMER_WINDOWS_VALIDATION \|\| "not-run"/],
]) {
expect(acceptanceReport, name, pattern);
}
for (const [name, pattern] of [
["acceptance report validates Podman incomplete state", /assertPodmanReport/],
["acceptance report validates Windows not-run", /assertReport\(runReport\(mode\), mode, "not-run"\)/],
["acceptance report validates Windows runner mode", /DISASMER_WINDOWS_VALIDATION: "forgejo-windows-runner"/],
]) {
expect(acceptanceReportSmoke, name, pattern);
}
expect(readme, "README documents public acceptance script", /scripts\/acceptance-public\.sh/);
expect(readme, "README documents private acceptance script", /scripts\/acceptance-private\.sh/);
expect(readme, "README documents rootless Podman incomplete handling", /Podman backend behavior is marked `incomplete`/);
expect(readme, "README documents Postgres discovery in environment report", /Podman\/Postgres discovery/);
expect(readme, "README documents manual Windows validation", /manual `Windows validation`\s+workflow/);
expect(windowsWorkflow, "Windows workflow is manual", /workflow_dispatch/);
expect(windowsWorkflow, "Windows workflow uses intermittent Windows runner", /runs-on:\s*windows/);
expect(windowsWorkflow, "Windows workflow writes acceptance report", /node scripts\/acceptance-report\.js windows/);
if (publicDryrunServiceSmoke && publicDryrunDeployPrep && publicDryrunSystemd && publicDryrunRunbook) {
for (const [name, pattern] of [
["service smoke requires external service address", /DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR is required/],
["service smoke requires browser test driver", /DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND/],
["service smoke loads release manifest", /public-release-manifest\.json/],
["service smoke rejects stale release manifest", /manifest\.source_commit[\s\S]*expectedCommit/],
["service smoke records source commit", /source_commit: release\.sourceCommit/],
["service smoke records release name", /release_name: release\.releaseName/],
["service smoke connects through public domain", /addr\.host[\s\S]*serviceHost/],
["service smoke verifies DNS state", /\["not-published", "published"\]\.includes\(dnsPublicationState\)/],
["service smoke begins a server-owned OIDC login", /type: "begin_oidc_browser_login"/],
["service smoke polls with opaque credentials", /type: "poll_oidc_browser_login"[\s\S]*transaction_id[\s\S]*polling_secret/],
["service smoke rejects missing hosted callback completion", /timed out waiting for the hosted OIDC callback/],
["service smoke reads server-created project", /type: "list_projects"/],
["service smoke enrolls signed node", /type: "create_node_enrollment_grant"[\s\S]*exchange_node_enrollment_grant/],
["service smoke starts session-authorized process", /type: "start_process"/],
["service smoke reports signed node capabilities", /signedNodeRequest[\s\S]*report_node_capabilities/],
["service smoke reads authorized debug state", /type: "debug_attach"/],
["service smoke aborts its probe process", /type: "abort_process"/],
["service smoke records private hosted coordinator", /coordinator_implementation:[\s\S]*"hosted-policy-coordinator"/],
["service smoke writes evidence report", /public-release-dryrun-service\.json/],
]) {
expect(publicDryrunServiceSmoke, name, pattern);
}
for (const [name, source, pattern] of [
["deployment prep builds hosted service release", publicDryrunDeployPrep, /cargo"[\s\S]*"build"[\s\S]*"--release"[\s\S]*"private\/hosted-policy\/Cargo\.toml"[\s\S]*"disasmer-hosted-service"/],
["deployment prep stages systemd unit", publicDryrunDeployPrep, /disasmer-public-release-dryrun\.service/],
["deployment prep writes manifest", publicDryrunDeployPrep, /deployment-manifest\.json/],
["deployment prep records private hosted coordinator", publicDryrunDeployPrep, /coordinator_implementation:[\s\S]*"hosted-policy-coordinator"/],
["deployment prep records service address", publicDryrunDeployPrep, /service_addr:[\s\S]*`\$\{serviceHost\}:\$\{servicePort\}`/],
["deployment prep records DNS state", publicDryrunDeployPrep, /dns_publication_state: dnsPublicationState/],
["deployment prep records service smoke command", publicDryrunDeployPrep, /public-release-dryrun-service-smoke\.js/],
["systemd keeps hosted HTTP upstream on loopback", publicDryrunSystemd, /--listen 127\.0\.0\.1:9080/],
["systemd loads root-owned operator credentials", publicDryrunSystemd, /EnvironmentFile=\/etc\/disasmer-public-release-dryrun\/operator\.env/],
["systemd avoids privileged port capability", publicDryrunSystemd, /NoNewPrivileges=true/],
["systemd uses dedicated user", publicDryrunSystemd, /User=disasmer[\s\S]*Group=disasmer/],
["runbook says externally reachable", publicDryrunRunbook, /externally reachable host/],
["runbook documents DNS pending fallback", publicDryrunRunbook, /Until the `disasmer\.michelpaulissen\.com` DNS record is deployed/],
["runbook gives hosts entry", publicDryrunRunbook, /<deployment-ip> disasmer\.michelpaulissen\.com/],
["runbook separates authority vocabulary", publicDryrunRunbook, /Client and signed Node protocols[\s\S]*Identity boundary[\s\S]*Operator boundary/],
["runbook documents operator credential", publicDryrunRunbook, /DISASMER_HOSTED_OPERATOR_TOKEN/],
]) {
expect(source, name, pattern);
}
}
if (hostedClientCompatSmoke && hostedService && hostedStartup && hostedOperatorAuth) {
const hostedServiceSecurity = `${hostedService}\n${hostedStartup}\n${hostedOperatorAuth}`;
for (const [name, pattern] of [
["hosted service embeds core coordinator runtime", /core_coordinator: CoordinatorService/],
["hosted service parses the unified identity, operator, and client protocol", /decode_incoming_request/],
["hosted service delegates client requests", /handle_client_request/],
["hosted service routes decoded client requests to Core", /IncomingRequest::Client\(request\)/],
["hosted service requires replay-resistant operator envelope proofs", /hosted_operator_request[\s\S]*HostedOperatorAuth[\s\S]*replay_nonces[\s\S]*verify_request[\s\S]*hosted_operator_request_proof_from_token_digest/],
["hosted service issues the authenticated Core CLI session", /core_coordinator[\s\S]*\.issue_cli_session/],
["hosted service creates the authenticated default project through Core", /AuthenticatedCoordinatorRequest::CreateProject/],
]) {
expect(hostedServiceSecurity, name, pattern);
}
for (const [name, pattern] of [
["compat smoke starts hosted service", /disasmer-hosted-service/],
["compat smoke creates hosted project", /type: "create_project"/],
["compat smoke creates session-authorized enrollment grant", /type: "create_node_enrollment_grant"/],
["compat smoke runs public CLI attach", /"disasmer-cli"[\s\S]*"node"[\s\S]*"attach"/],
["compat smoke verifies public enrollment exchange", /node_enrollment_exchanged/],
["compat smoke runs public CLI browser login", /"login"[\s\S]*"--browser"[\s\S]*DISASMER_BROWSER_OPEN_COMMAND/],
["compat smoke derives hosted scope", /const session = login\.coordinator_response\.session/],
["compat smoke rejects forged identity", /forged_unsigned_project/],
["compat smoke rejects an actually expired hosted session", /DISASMER_HOSTED_CLI_SESSION_TTL_SECONDS[\s\S]*expired; run disasmer login --browser again/],
["compat smoke denies cross-tenant task-event reads", /crossTenantTaskEventsDenied[\s\S]*type: "list_task_events"[\s\S]*vp-victim/],
["compat smoke writes evidence report", /hosted-client-compat\.json/],
]) {
expect(hostedClientCompatSmoke, name, pattern);
}
}
for (const [name, pattern] of [
["e2e runner requires explicit opt-in", /DISASMER_PUBLIC_RELEASE_DRYRUN_E2E/],
["e2e runner requires the honestly reset pre-final ledger", /assertPreFinalLedger\(readPhase3Ledger\(repo\)\)/],
["e2e runner requires public domain service address", /serviceAddr[\s\S]*serviceHost/],
["e2e runner downloads release assets", /downloadReleaseAssets/],
["e2e runner verifies release checksums", /verifyChecksums/],
["e2e runner clones public repo", /git"[\s\S]*"clone"[\s\S]*publicRepositoryUrl/],
["e2e runner uses default hosted coordinator", /defaultLoginPlan\.coordinator[\s\S]*serviceEndpoint/],
["e2e runner uses server-owned browser login", /DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND[\s\S]*DISASMER_BROWSER_OPEN_COMMAND/],
["e2e runner attaches user node", /node"[\s\S]*"attach"/],
["e2e runner starts public worker runtime", /workerArgs[\s\S]*"--worker"[\s\S]*cp\.spawn\(disasmerNode/],
["e2e runner launches released product through CLI", /"run"[\s\S]*"build"[\s\S]*runReport\.status[\s\S]*main_launched/],
["standalone Core proof launches a real Wasm TaskSpec", /type: "launch_task"[\s\S]*task_spec:[\s\S]*kind: "coordinator_node_wasm"[\s\S]*bundle_digest: manifest\.bundle_digest/],
["e2e runner verifies public assignment polling", /worker_assignment_poll_protocol/],
["e2e runner validates standalone Core coordinator", /validateStandaloneCoreCoordinator/],
["e2e runner records standalone Core coordinator", /core_coordinator_implementation/],
["e2e runner verifies task events", /list_task_events/],
["e2e runner creates artifact download link", /create_artifact_download_link/],
["e2e runner verifies VS Code debugger", /vscode-f5-smoke\.js/],
["e2e runner writes e2e report", /public-release-dryrun-e2e\.json/],
]) {
expect(publicDryrunE2e, name, pattern);
}
for (const [name, pattern] of [
["final verifier requires public release manifest", /public-release-manifest\.json/],
["final verifier requires Forgejo release evidence", /public-release-dryrun-forgejo-release\.json/],
["final verifier requires deployment manifest", /deployment-manifest\.json/],
["final verifier requires service smoke evidence", /public-release-dryrun-service\.json/],
["final verifier requires all 191 Phase 3 criteria passed", /assertFinalLedger\(readPhase3Ledger\(repo\)\)/],
["final verifier requires current service smoke source", /service\.source_commit[\s\S]*manifest\.source_commit/],
["final verifier requires current service smoke release", /service\.release_name[\s\S]*manifest\.release_name/],
["final verifier requires hosted Client compatibility evidence", /hosted-client-compat\.json/],
["final verifier requires current Client compatibility source", /compat\.source_commit[\s\S]*manifest\.source_commit/],
["final verifier requires current Client compatibility release", /compat\.release_name[\s\S]*manifest\.release_name/],
["final verifier requires Core coordinator compatibility evidence", /core-coordinator-compat\.json/],
["final verifier requires current public coordinator source", /coreCoordinator\.source_commit[\s\S]*manifest\.source_commit/],
["final verifier requires current public coordinator release", /coreCoordinator\.release_name[\s\S]*manifest\.release_name/],
["final verifier requires public e2e evidence", /public-release-dryrun-e2e\.json/],
["final verifier records both coordinator validations", /coordinator_validation/],
["final verifier writes final evidence", /public-release-dryrun-final\.json/],
]) {
expect(finalDryrunEvidence, name, pattern);
}
console.log("Acceptance environment contract smoke passed");

File diff suppressed because it is too large Load diff

39
scripts/acceptance-private.sh Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo"
node scripts/acceptance-report.js private
node scripts/acceptance-report-smoke.js
node scripts/acceptance-doc-contract-smoke.js
node scripts/acceptance-environment-contract-smoke.js
node scripts/acceptance-evidence-contract-smoke.js
node private/hosted-policy/scripts/phase3-live-infra-contract-smoke.js
node scripts/code-size-guard.js
node scripts/public-private-boundary-smoke.js
node scripts/release-blocker-smoke.js
node scripts/resource-metering-contract-smoke.js
node scripts/hostile-input-contract-smoke.js
node scripts/tenant-isolation-contract-smoke.js
node scripts/cli-error-exit-smoke.js
scripts/release-source-scan.sh
cargo test --manifest-path private/hosted-policy/Cargo.toml
node private/hosted-policy/scripts/hosted-signup-contract-smoke.js
node private/hosted-policy/scripts/prepare-public-release-dryrun-deployment.js
node private/hosted-policy/scripts/hosted-deployment-smoke.js
node private/hosted-policy/scripts/hosted-client-compat-smoke.js
node scripts/self-hosted-coordinator-smoke.js
if command -v podman >/dev/null 2>&1; then
node private/hosted-policy/scripts/postgres-durable-smoke.js
elif command -v nix >/dev/null 2>&1; then
nix shell nixpkgs#podman --command node private/hosted-policy/scripts/postgres-durable-smoke.js
else
node private/hosted-policy/scripts/postgres-durable-smoke.js
fi
if [[ -n "${DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR:-}" ]]; then
node private/hosted-policy/scripts/public-release-dryrun-service-smoke.js
fi
if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL:-}" == "1" ]]; then
node scripts/public-release-dryrun-final-evidence.js
fi

72
scripts/acceptance-public.sh Executable file
View file

@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo"
node scripts/acceptance-report.js public
node scripts/acceptance-report-smoke.js
node scripts/acceptance-doc-contract-smoke.js
node scripts/acceptance-environment-contract-smoke.js
node scripts/acceptance-evidence-contract-smoke.js
node scripts/code-size-guard.js
node scripts/public-private-boundary-smoke.js
node scripts/release-blocker-smoke.js
node scripts/resource-metering-contract-smoke.js
node scripts/hostile-input-contract-smoke.js
node scripts/tenant-isolation-contract-smoke.js
node scripts/public-story-contract-smoke.js
node scripts/public-release-dryrun-contract-smoke.js
node scripts/public-browser-login-contract-smoke.js
node scripts/self-hosted-coordinator-smoke.js
node scripts/public-local-demo-matrix-smoke.js
scripts/release-source-scan.sh
node scripts/prepare-public-release-dryrun.js
if [[ "${DISASMER_PUBLIC_RELEASE_PREFLIGHT:-}" == "1" ]]; then
node scripts/public-release-dryrun-preflight.js
fi
if [[ -n "${DISASMER_FORGEJO_TOKEN:-}" ]]; then
node scripts/publish-public-release-dryrun.js
fi
if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_E2E:-}" == "1" ]]; then
node scripts/public-release-dryrun-e2e.js
fi
if [[ "${DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL:-}" == "1" ]]; then
node scripts/public-release-dryrun-final-evidence.js
fi
cargo fmt --all --check
cargo test --workspace
cargo build --workspace --bins
node scripts/docs-smoke.js
node scripts/cli-output-mode-smoke.js
node scripts/cli-login-smoke.js
node scripts/cli-error-exit-smoke.js
node scripts/cli-browser-login-flow-smoke.js
node scripts/cli-install-smoke.js
node scripts/user-session-token-boundary-smoke.js
node scripts/sdk-spawn-runtime-smoke.js
node scripts/node-lifecycle-contract-smoke.js
node scripts/wasmtime-node-smoke.js
node scripts/wasmtime-assignment-smoke.js
if command -v podman >/dev/null 2>&1; then
node scripts/podman-backend-smoke.js
elif command -v nix >/dev/null 2>&1; then
nix shell nixpkgs#podman --command node scripts/podman-backend-smoke.js
else
node scripts/podman-backend-smoke.js
fi
node scripts/vscode-extension-smoke.js
node scripts/vscode-f5-smoke.js
node scripts/node-attach-smoke.js
node scripts/cli-local-run-smoke.js
node scripts/artifact-download-smoke.js
node scripts/artifact-export-smoke.js
node scripts/operator-panel-smoke.js
node scripts/source-preparation-smoke.js
node scripts/scheduler-placement-smoke.js
node scripts/windows-best-effort-smoke.js
node scripts/windows-validation-contract-smoke.js
node scripts/quic-smoke.js
node scripts/dap-smoke.js
node scripts/flagship-demo-smoke.js
scripts/verify-public-split.sh

View file

@ -0,0 +1,113 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function runReport(mode, env = {}) {
const output = cp.execFileSync(
"node",
["scripts/acceptance-report.js", mode],
{
cwd: repo,
encoding: "utf8",
env: { ...process.env, ...env },
}
);
const report = JSON.parse(output);
const persistedPath = path.join(
repo,
"target",
"acceptance",
`${mode}-environment.json`
);
const persisted = JSON.parse(fs.readFileSync(persistedPath, "utf8"));
assert.deepStrictEqual(persisted, report, `${mode} report was not persisted`);
return report;
}
function assertString(value, name) {
assert.strictEqual(typeof value, "string", `${name} must be a string`);
assert(value.length > 0, `${name} must not be empty`);
}
function assertNullableString(value, name) {
if (value === null) return;
assertString(value, name);
}
function assertPodmanReport(podman) {
assert(podman && typeof podman === "object", "podman report must be an object");
assert(
["available", "incomplete"].includes(podman.status),
"podman.status must be available or incomplete"
);
assertNullableString(podman.version, "podman.version");
assertNullableString(podman.rootless, "podman.rootless");
assertNullableString(podman.incomplete_reason, "podman.incomplete_reason");
if (podman.status === "available") {
assertString(podman.version, "podman.version");
assert.strictEqual(podman.rootless, "true");
assert.strictEqual(podman.incomplete_reason, null);
} else {
assertString(podman.incomplete_reason, "podman.incomplete_reason");
}
}
function assertReport(report, mode, expectedWindowsValidation) {
assert.strictEqual(report.kind, "disasmer_acceptance_environment");
assert.strictEqual(report.mode, mode);
assert.match(report.generated_at, /^\d{4}-\d{2}-\d{2}T/);
assert.match(report.commit, /^[0-9a-f]{40}$/);
assert(Array.isArray(report.tree_status), "tree_status must be an array");
assertString(report.os.platform, "os.platform");
assertString(report.os.release, "os.release");
assertString(report.os.kernel, "os.kernel");
assertString(report.os.arch, "os.arch");
assertString(report.rust.rustc, "rust.rustc");
assertString(report.rust.cargo, "rust.cargo");
assertString(report.node.version, "node.version");
assert(report.node.version.startsWith("v"), "node.version must be Node.js style");
assertPodmanReport(report.podman);
assertNullableString(report.postgres.version, "postgres.version");
assertNullableString(report.browser_harness.version, "browser_harness.version");
assertNullableString(report.browser_harness.command, "browser_harness.command");
assertString(report.browser_harness.configured, "browser_harness.configured");
assert(Array.isArray(report.vscode_harness.smokes), "vscode smokes must be listed");
assert(
report.vscode_harness.smokes.includes("scripts/vscode-extension-smoke.js"),
"VS Code extension smoke must be recorded"
);
assert(
report.vscode_harness.smokes.includes("scripts/vscode-f5-smoke.js"),
"VS Code F5 smoke must be recorded"
);
assertString(report.vscode_harness.engine, "vscode_harness.engine");
assertString(
report.vscode_harness.extension_version,
"vscode_harness.extension_version"
);
assert.strictEqual(report.windows_validation, expectedWindowsValidation);
}
for (const mode of ["public", "private"]) {
assertReport(runReport(mode), mode, "not-run");
}
assertReport(
runReport("windows", {
DISASMER_WINDOWS_VALIDATION: "forgejo-windows-runner",
}),
"windows",
"forgejo-windows-runner"
);
console.log("Acceptance report smoke passed");

139
scripts/acceptance-report.js Executable file
View file

@ -0,0 +1,139 @@
#!/usr/bin/env node
const cp = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const mode = process.argv[2] || "public";
function commandOutput(command, args = []) {
try {
return cp
.execFileSync(command, args, {
cwd: repo,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"]
})
.trim();
} catch (_) {
return null;
}
}
function packageJson() {
return JSON.parse(
fs.readFileSync(path.join(repo, "vscode-extension/package.json"), "utf8")
);
}
function firstCommandOutput(candidates) {
for (const [command, args] of candidates) {
const output = commandOutput(command, args);
if (output) {
return { command, version: output };
}
}
return null;
}
function podmanReport() {
const version = commandOutput("podman", ["--version"]);
if (!version) {
return {
status: "incomplete",
version: null,
rootless: null,
incomplete_reason: "podman command is unavailable"
};
}
const rootless = commandOutput("podman", [
"info",
"--format",
"{{.Host.Security.Rootless}}"
]);
if (!rootless) {
return {
status: "incomplete",
version,
rootless: null,
incomplete_reason: "podman info did not report rootless status"
};
}
if (rootless !== "true") {
return {
status: "incomplete",
version,
rootless,
incomplete_reason: "podman is not running in rootless mode"
};
}
return {
status: "available",
version,
rootless,
incomplete_reason: null
};
}
const extensionPackage = packageJson();
const sourceCommit =
process.env.DISASMER_ACCEPTANCE_COMMIT || commandOutput("git", ["rev-parse", "HEAD"]);
const browserVersion = firstCommandOutput([
["chromium", ["--version"]],
["chromium-browser", ["--version"]],
["google-chrome", ["--version"]],
["firefox", ["--version"]]
]);
const report = {
kind: "disasmer_acceptance_environment",
mode,
commit: sourceCommit,
tree_status: (commandOutput("git", ["status", "--short"]) || "")
.split("\n")
.filter(Boolean),
generated_at: new Date().toISOString(),
os: {
platform: os.platform(),
release: os.release(),
kernel: os.release(),
arch: os.arch()
},
rust: {
rustc: commandOutput("rustc", ["--version"]),
cargo: commandOutput("cargo", ["--version"])
},
node: {
version: process.version
},
podman: podmanReport(),
postgres: {
version:
commandOutput("postgres", ["--version"]) ||
commandOutput("psql", ["--version"])
},
browser_harness: {
version: browserVersion && browserVersion.version,
command: browserVersion && browserVersion.command,
configured: process.env.DISASMER_BROWSER_HARNESS || "not-configured"
},
vscode_harness: {
smokes: [
"scripts/vscode-extension-smoke.js",
"scripts/vscode-f5-smoke.js"
],
engine: extensionPackage.engines && extensionPackage.engines.vscode,
extension_version: extensionPackage.version
},
windows_validation: process.env.DISASMER_WINDOWS_VALIDATION || "not-run"
};
const outDir = path.join(repo, "target/acceptance");
fs.mkdirSync(outDir, { recursive: true });
fs.writeFileSync(
path.join(outDir, `${mode}-environment.json`),
`${JSON.stringify(report, null, 2)}\n`
);
console.log(JSON.stringify(report, null, 2));

95
scripts/agent-signing.js Normal file
View file

@ -0,0 +1,95 @@
const crypto = require("crypto");
const { nodeIdentity, signedRequestPayloadDigest } = require("./node-signing");
function agentIdentity(seedPrefix, agent) {
const identity = nodeIdentity(seedPrefix, agent);
return {
...identity,
publicKeyFingerprint: `sha256:${crypto
.createHash("sha256")
.update(identity.publicKey)
.digest("hex")}`,
};
}
function agentWorkflowSignatureMessage({
tenant,
project,
agent,
requestKind,
process: processId,
task = "",
payloadDigest,
nonce,
issuedAtEpochSeconds,
}) {
const parts = [
"disasmer-agent-workflow-signature:v2",
tenant,
project,
agent,
requestKind,
processId,
task,
payloadDigest,
nonce,
String(issuedAtEpochSeconds),
];
return Buffer.concat(
parts.flatMap((part) => [
Buffer.from(`${Buffer.byteLength(part)}:`),
Buffer.from(part),
Buffer.from("\n"),
])
);
}
function signedAgentWorkflowProof(identity, request, options = {}) {
const nonce =
options.nonce ||
`${request.type}-${process.pid}-${Date.now()}-${crypto
.randomBytes(8)
.toString("hex")}`;
const issuedAtEpochSeconds =
options.issuedAtEpochSeconds || Math.floor(Date.now() / 1000);
const signature = crypto.sign(
null,
agentWorkflowSignatureMessage({
tenant: request.tenant,
project: request.project,
agent: request.actor_agent,
requestKind: request.type,
process: request.process,
task: request.task || "",
payloadDigest: signedRequestPayloadDigest(request),
nonce,
issuedAtEpochSeconds,
}),
identity.privateKeyObject
);
return {
nonce,
issued_at_epoch_seconds: issuedAtEpochSeconds,
signature: `ed25519:${signature.toString("base64")}`,
};
}
function signedAgentWorkflowRequest(identity, request, options = {}) {
const unsignedRequest = {
...request,
agent_public_key_fingerprint:
options.publicKeyFingerprint || identity.publicKeyFingerprint,
};
return {
...unsignedRequest,
agent_signature: signedAgentWorkflowProof(identity, unsignedRequest, options),
};
}
module.exports = {
agentIdentity,
agentWorkflowSignatureMessage,
signedAgentWorkflowProof,
signedAgentWorkflowRequest,
};

View file

@ -0,0 +1,401 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const os = require("os");
const path = require("path");
const { nodeIdentity, signedNodeRequest } = require("./node-signing");
const {
ensureRootlessPodman,
flagshipNodeCapabilities,
launchFlagship,
repo,
runFlagshipWorker,
send,
waitForJsonLine,
} = require("./real-flagship-harness");
const downloadNode = "node-download";
const downloadNodeIdentity = nodeIdentity("artifact-download-smoke", downloadNode);
const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
async function downloadRetainedBytes(addr, link, artifact, expectedSize) {
const chunks = [];
let offset = 0;
for (let attempt = 0; attempt < 500; attempt += 1) {
const response = await send(addr, {
type: "open_artifact_download_stream",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
token_digest: link.link.scoped_token_digest,
chunk_bytes: 256 * 1024,
});
assert.strictEqual(response.type, "artifact_download_stream");
if (!response.content_bytes_available) {
assert.strictEqual(response.content_source, "retaining_node_reverse_stream_pending");
await delay(10);
continue;
}
assert.strictEqual(response.content_source, "retaining_node_reverse_stream");
assert.strictEqual(response.content_offset, offset);
const bytes = Buffer.from(response.content_base64, "base64");
assert.strictEqual(response.streamed_bytes, bytes.length);
chunks.push(bytes);
offset += bytes.length;
if (response.content_eof) {
const content = Buffer.concat(chunks);
assert.strictEqual(content.length, expectedSize);
return { content, response };
}
}
throw new Error("timed out waiting for retained artifact reverse stream");
}
function downloadNodeCapabilities() {
return flagshipNodeCapabilities();
}
(async () => {
ensureRootlessPodman();
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback",
],
{ cwd: repo }
);
let worker;
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
worker = await runFlagshipWorker(addr, downloadNode, downloadNodeIdentity);
const workerReady = await worker.ready;
assert.strictEqual(workerReady.node_status, "ready");
assert.strictEqual(workerReady.mode, "worker");
const { compileEvent, packageEvent, process: virtualProcess } = await launchFlagship(addr);
assert.strictEqual(compileEvent.status_code, 0);
assert.strictEqual(packageEvent.status_code, 0);
assert.deepStrictEqual(compileEvent.result, {
Artifact: {
id: compileEvent.artifact_path.slice("/vfs/artifacts/".length),
digest: compileEvent.artifact_digest,
size_bytes: compileEvent.artifact_size_bytes,
},
});
assert.deepStrictEqual(packageEvent.result, {
Artifact: {
id: packageEvent.artifact_path.slice("/vfs/artifacts/".length),
digest: packageEvent.artifact_digest,
size_bytes: packageEvent.artifact_size_bytes,
},
});
assert.ok(compileEvent.artifact_size_bytes > 0);
assert.ok(packageEvent.artifact_size_bytes > compileEvent.artifact_size_bytes);
assert.match(compileEvent.artifact_digest, /^sha256:[0-9a-f]{64}$/);
assert.match(packageEvent.artifact_digest, /^sha256:[0-9a-f]{64}$/);
const artifactPath = packageEvent.artifact_path;
assert.match(artifactPath, /^\/vfs\/artifacts\/release\.tar-[0-9a-f]{64}$/);
const artifact = artifactPath.slice("/vfs/artifacts/".length);
const disconnectedReport = await send(addr, signedNodeRequest(downloadNode, downloadNodeIdentity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: downloadNode,
capabilities: downloadNodeCapabilities(),
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [artifact],
direct_connectivity: false,
online: true,
}));
assert.strictEqual(disconnectedReport.type, "node_capabilities_recorded");
const disconnectedLink = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
ttl_seconds: 60,
});
assert.strictEqual(disconnectedLink.type, "artifact_download_link");
const connectedReport = await send(addr, signedNodeRequest(downloadNode, downloadNodeIdentity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: downloadNode,
capabilities: downloadNodeCapabilities(),
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [artifact],
direct_connectivity: true,
online: true,
}));
assert.strictEqual(connectedReport.type, "node_capabilities_recorded");
const link = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
ttl_seconds: 60,
});
assert.strictEqual(link.type, "artifact_download_link");
assert.strictEqual(link.link.tenant, "tenant");
assert.strictEqual(link.link.project, "project");
assert.strictEqual(link.link.process, virtualProcess);
assert.deepStrictEqual(link.link.actor, { User: "user" });
assert.match(link.link.policy_context_digest, /^sha256:[0-9a-f]{64}$/);
assert.ok(link.link.expires_at_epoch_seconds > Math.floor(Date.now() / 1000));
assert.ok(link.link.expires_at_epoch_seconds <= Math.floor(Date.now() / 1000) + 60);
assert.ok(
link.link.url_path.endsWith(
`/artifacts/tenant/project/${virtualProcess}/${artifact}`
)
);
assert.deepStrictEqual(link.link.source, { RetainedNode: "node-download" });
const crossTenant = await send(addr, {
type: "create_artifact_download_link",
tenant: "other",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
ttl_seconds: 60,
});
assert.strictEqual(crossTenant.type, "error");
assert.match(crossTenant.message, /tenant mismatch/);
const crossProject = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "other-project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
ttl_seconds: 60,
});
assert.strictEqual(crossProject.type, "error");
assert.match(crossProject.message, /project mismatch/);
const crossTenantOpen = await send(addr, {
type: "open_artifact_download_stream",
tenant: "other",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
token_digest: link.link.scoped_token_digest,
chunk_bytes: 1,
});
assert.strictEqual(crossTenantOpen.type, "error");
assert.match(crossTenantOpen.message, /tenant mismatch/);
const crossProjectOpen = await send(addr, {
type: "open_artifact_download_stream",
tenant: "tenant",
project: "other-project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
token_digest: link.link.scoped_token_digest,
chunk_bytes: 1,
});
assert.strictEqual(crossProjectOpen.type, "error");
assert.match(crossProjectOpen.message, /project mismatch/);
const guessed = await send(addr, {
type: "open_artifact_download_stream",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
token_digest: "sha256:guessed",
chunk_bytes: 1,
});
assert.strictEqual(guessed.type, "error");
assert.match(guessed.message, /token is invalid/);
const crossActorOpen = await send(addr, {
type: "open_artifact_download_stream",
tenant: "tenant",
project: "project",
actor_user: "other-user",
artifact,
max_bytes: 1024 * 1024,
token_digest: link.link.scoped_token_digest,
chunk_bytes: 1,
});
assert.strictEqual(crossActorOpen.type, "error");
assert.match(crossActorOpen.message, /token is invalid/);
const downloaded = await downloadRetainedBytes(
addr,
link,
artifact,
packageEvent.artifact_size_bytes,
);
const downloadedDigest = `sha256:${crypto
.createHash("sha256")
.update(downloaded.content)
.digest("hex")}`;
assert.strictEqual(downloadedDigest, packageEvent.artifact_digest);
const inspect = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-release-"));
try {
const archive = path.join(inspect, "release.tar");
fs.writeFileSync(archive, downloaded.content);
const listing = cp.execFileSync("tar", ["-tf", archive], { encoding: "utf8" });
assert.strictEqual(listing.trim(), "hello-disasmer");
cp.execFileSync("tar", ["-xf", archive, "-C", inspect]);
fs.chmodSync(path.join(inspect, "hello-disasmer"), 0o755);
assert.strictEqual(
cp.execFileSync(path.join(inspect, "hello-disasmer"), { encoding: "utf8" }),
"hello from a real Disasmer build\n"
);
} finally {
fs.rmSync(inspect, { recursive: true, force: true });
}
const cliDownloadDirectory = fs.mkdtempSync(
path.join(os.tmpdir(), "disasmer-cli-download-")
);
try {
const cliDownloadPath = path.join(cliDownloadDirectory, "release.tar");
const cliDownload = JSON.parse(
cp.execFileSync(
"cargo",
[
"run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--",
"artifact", "download", artifact,
"--to", cliDownloadPath,
"--max-bytes", "1048576",
"--coordinator", `disasmer+tcp://${addr.host}:${addr.port}`,
"--tenant", "tenant",
"--project-id", "project",
"--user", "user",
"--json",
],
{ cwd: repo, env: process.env, encoding: "utf8" }
)
);
assert.strictEqual(cliDownload.command, "artifact download");
assert.strictEqual(cliDownload.local_download.status, "local_bytes_written");
assert.strictEqual(
cliDownload.local_download.verified_digest,
packageEvent.artifact_digest
);
assert.strictEqual(
`sha256:${crypto
.createHash("sha256")
.update(fs.readFileSync(cliDownloadPath))
.digest("hex")}`,
packageEvent.artifact_digest
);
} finally {
fs.rmSync(cliDownloadDirectory, { recursive: true, force: true });
}
assert.strictEqual(downloaded.response.content_eof, true);
assert.strictEqual(
downloaded.response.charged_download_bytes,
packageEvent.artifact_size_bytes
);
assert.strictEqual(downloaded.response.link.artifact, artifact);
const crossActorRevoke = await send(addr, {
type: "revoke_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "other-user",
artifact,
token_digest: link.link.scoped_token_digest,
});
assert.strictEqual(crossActorRevoke.type, "error");
assert.match(crossActorRevoke.message, /token is invalid/);
const revoked = await send(addr, {
type: "revoke_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
token_digest: link.link.scoped_token_digest,
});
assert.strictEqual(revoked.type, "artifact_download_link_revoked");
assert.strictEqual(revoked.link.scoped_token_digest, link.link.scoped_token_digest);
const revokedOpen = await send(addr, {
type: "open_artifact_download_stream",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
token_digest: link.link.scoped_token_digest,
chunk_bytes: 1,
});
assert.strictEqual(revokedOpen.type, "error");
assert.match(revokedOpen.message, /revoked/);
const gcReport = await send(addr, signedNodeRequest(downloadNode, downloadNodeIdentity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: downloadNode,
capabilities: downloadNodeCapabilities(),
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: false,
online: true,
}));
assert.strictEqual(gcReport.type, "node_capabilities_recorded");
const collectedLink = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
max_bytes: 1024 * 1024,
ttl_seconds: 60,
});
assert.strictEqual(collectedLink.type, "error");
assert.match(collectedLink.message, /unavailable from current retention/);
} finally {
worker?.child.kill("SIGTERM");
coordinator.kill("SIGTERM");
}
console.log("Artifact download smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,262 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const { nodeIdentity, signedNodeRequest } = require("./node-signing");
const {
ensureRootlessPodman,
flagshipNodeCapabilities,
launchFlagship,
repo,
runFlagshipWorker,
send,
waitForJsonLine,
} = require("./real-flagship-harness");
const sourceNode = "node-export-source";
const sourceIdentity = nodeIdentity("artifact-export-smoke", sourceNode);
function nodeCapabilities() {
return flagshipNodeCapabilities();
}
function runJson(command, args, options = {}) {
return new Promise((resolve, reject) => {
const child = cp.spawn(command, args, { cwd: repo, ...options });
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.once("error", reject);
child.once("exit", (code) => {
if (code !== 0) {
reject(
new Error(
`${command} ${args.join(" ")} failed with code ${code}\n${stderr}\n${stdout}`
)
);
return;
}
try {
resolve(JSON.parse(stdout));
} catch (error) {
reject(new Error(`${command} did not return JSON\n${stdout}\n${error.message}`));
}
});
});
}
async function reportNode(
addr,
node,
identity,
{ directConnectivity = true, online = true, artifacts = [] } = {}
) {
const response = await send(addr, signedNodeRequest(node, identity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node,
capabilities: nodeCapabilities(),
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: artifacts,
direct_connectivity: directConnectivity,
online,
}));
assert.strictEqual(response.type, "node_capabilities_recorded");
assert.strictEqual(response.node, node);
}
(async () => {
ensureRootlessPodman();
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback",
],
{ cwd: repo }
);
let worker;
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
worker = await runFlagshipWorker(addr, sourceNode, sourceIdentity);
const workerReady = await worker.ready;
assert.strictEqual(workerReady.node_status, "ready");
assert.strictEqual(workerReady.mode, "worker");
const firstNodeTaskCompletion = waitForJsonLine(worker.child);
const { compileEvent, process: virtualProcess } = await launchFlagship(addr);
const workerCompletion = await firstNodeTaskCompletion;
assert.strictEqual(workerCompletion.node_status, "completed");
assert.strictEqual(
workerCompletion.task_assignment_response.task_spec.task_definition,
"prepare_source"
);
assert.strictEqual(
workerCompletion.virtual_thread,
workerCompletion.task_assignment_response.task_spec.task_instance
);
assert.strictEqual(compileEvent.status_code, 0);
assert.match(
compileEvent.artifact_path,
/^\/vfs\/artifacts\/hello-disasmer-[0-9a-f]{64}$/
);
const artifact = compileEvent.artifact_path.slice("/vfs/artifacts/".length);
await reportNode(addr, sourceNode, sourceIdentity, {
artifacts: [artifact],
});
const receiverIdentity = nodeIdentity("artifact-export-smoke", "node-export-receiver");
const attachedReceiver = await send(addr, {
type: "attach_node",
tenant: "tenant",
project: "project",
node: "node-export-receiver",
public_key: receiverIdentity.publicKey,
});
assert.strictEqual(attachedReceiver.type, "node_attached");
await reportNode(addr, "node-export-receiver", receiverIdentity);
const exportPlan = await send(addr, {
type: "export_artifact_to_node",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
receiver_node: "node-export-receiver",
direct_connectivity: true,
failure_reason: "",
});
assert.strictEqual(exportPlan.type, "artifact_export_plan");
assert.strictEqual(exportPlan.source_node, "node-export-source");
assert.strictEqual(exportPlan.receiver_node, "node-export-receiver");
assert.strictEqual(exportPlan.plan.transport, "NativeQuic");
assert.strictEqual(exportPlan.plan.scope.tenant, "tenant");
assert.strictEqual(exportPlan.plan.scope.project, "project");
assert.strictEqual(exportPlan.plan.scope.process, virtualProcess);
assert.deepStrictEqual(exportPlan.plan.scope.object, { Artifact: artifact });
assert.strictEqual(exportPlan.plan.source.node, "node-export-source");
assert.strictEqual(exportPlan.plan.destination.node, "node-export-receiver");
assert.strictEqual(exportPlan.plan.coordinator_assisted_rendezvous, true);
assert.strictEqual(exportPlan.plan.coordinator_bulk_relay_allowed, false);
assert.match(exportPlan.plan.authorization_digest, /^sha256:[0-9a-f]{64}$/);
assert.strictEqual(exportPlan.artifact_size_bytes, compileEvent.artifact_size_bytes);
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-artifact-export-"));
const exportPath = path.join(temp, "hello-disasmer");
const cliExport = await runJson("cargo", [
"run",
"-q",
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
"artifact",
"export",
"--coordinator",
`${addr.host}:${addr.port}`,
"--tenant",
"tenant",
"--project-id",
"project",
"--user",
"user",
"--json",
artifact,
"--receiver-node",
"node-export-receiver",
"--to",
exportPath,
]);
assert.strictEqual(cliExport.command, "artifact export");
assert.strictEqual(cliExport.export_plan.local_bytes_written_by_cli, true);
assert.strictEqual(cliExport.export_plan.local_export_status, "local_bytes_written");
assert.strictEqual(
cliExport.export_plan.bytes_written,
compileEvent.artifact_size_bytes
);
assert.strictEqual(cliExport.local_export.stream.content_material_returned_in_report, false);
assert.strictEqual(
cliExport.local_export.verified_digest,
compileEvent.artifact_digest
);
fs.chmodSync(exportPath, 0o755);
assert.strictEqual(
cp.execFileSync(exportPath, { encoding: "utf8" }),
"hello from a real Disasmer build\n"
);
const crossTenant = await send(addr, {
type: "export_artifact_to_node",
tenant: "other",
project: "project",
actor_user: "user",
artifact,
receiver_node: "node-export-receiver",
direct_connectivity: true,
failure_reason: "",
});
assert.strictEqual(crossTenant.type, "error");
assert.match(crossTenant.message, /tenant mismatch/);
const failedDirect = await send(addr, {
type: "export_artifact_to_node",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
receiver_node: "node-export-receiver",
direct_connectivity: false,
failure_reason: "nat traversal failed",
});
assert.strictEqual(failedDirect.type, "error");
assert.match(failedDirect.message, /nat traversal failed/);
assert.match(failedDirect.message, /coordinator bulk relay is disabled/);
await reportNode(addr, "node-export-receiver", receiverIdentity, { online: false });
const offlineReceiver = await send(addr, {
type: "export_artifact_to_node",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact,
receiver_node: "node-export-receiver",
direct_connectivity: true,
failure_reason: "",
});
assert.strictEqual(offlineReceiver.type, "error");
assert.match(offlineReceiver.message, /offline/);
} finally {
worker?.child.kill("SIGTERM");
coordinator.kill("SIGTERM");
}
console.log("Artifact export smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,223 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const net = require("net");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const tmp = path.join(repo, "target", "acceptance", "tmp", "cli-browser-login-flow");
const project = path.join(tmp, "project");
fs.rmSync(tmp, { recursive: true, force: true });
fs.mkdirSync(project, { recursive: true });
function writeOpener() {
const opener = path.join(tmp, "browser-opener.js");
const trace = path.join(tmp, "browser-opener.log");
fs.writeFileSync(
opener,
`#!/usr/bin/env node
const fs = require("fs");
const trace = ${JSON.stringify(trace)};
const loginUrl = new URL(process.argv[2]);
const state = loginUrl.searchParams.get("state");
const nonce = loginUrl.searchParams.get("nonce");
const challenge = loginUrl.searchParams.get("code_challenge");
if (loginUrl.protocol !== "https:" || !state || !nonce || !challenge) {
fs.appendFileSync(trace, "missing server-owned OIDC parameters\\n");
process.exit(1);
}
fs.appendFileSync(trace, "server-owned browser transaction\\n");
// Model a real browser/opener that remains alive after the CLI transaction.
// Its descriptors must not keep the invoking CLI process open.
setTimeout(() => process.exit(0), 5000);
`
);
fs.chmodSync(opener, 0o755);
return opener;
}
function startCoordinator() {
return new Promise((resolve, reject) => {
const requests = [];
const server = net.createServer((socket) => {
let buffered = "";
socket.on("data", (chunk) => {
buffered += chunk.toString("utf8");
while (buffered.includes("\n")) {
const newline = buffered.indexOf("\n");
const line = buffered.slice(0, newline);
buffered = buffered.slice(newline + 1);
const envelope = JSON.parse(line);
requests.push(envelope);
assert.strictEqual(envelope.type, "coordinator_request");
assert.strictEqual(envelope.protocol_version, 1);
assert.strictEqual(envelope.authentication.kind, "none");
const request = envelope.payload;
if (requests.length === 1) {
assert.strictEqual(envelope.request_id, "cli-1");
assert.strictEqual(envelope.operation, "begin_oidc_browser_login");
assert.deepStrictEqual(request, {
type: "begin_oidc_browser_login",
requested_project: "project-smoke",
});
socket.write(
`${JSON.stringify({
type: "oidc_browser_login_started",
transaction_id: "login-transaction",
polling_secret: "opaque-polling-secret",
authorization_url:
"https://auth.michelpaulissen.com/application/o/authorize/?state=server-state&nonce=server-nonce&code_challenge=server-pkce&code_challenge_method=S256&redirect_uri=https%3A%2F%2Fdisasmer.michelpaulissen.com%2Fauth%2Fcallback",
expires_at_epoch_seconds: 1800000000,
})}\n`
);
continue;
}
assert.strictEqual(envelope.request_id, "cli-2");
assert.strictEqual(envelope.operation, "poll_oidc_browser_login");
assert.deepStrictEqual(request, {
type: "poll_oidc_browser_login",
transaction_id: "login-transaction",
polling_secret: "opaque-polling-secret",
});
socket.end(
`${JSON.stringify({
type: "oidc_browser_session",
session: {
tenant: "tenant-smoke",
project: "project-smoke",
user: "user-smoke",
cli_session_credential_kind: "CliDeviceSession",
cli_session_secret: "scoped-cli-session-secret",
expires_at_epoch_seconds: 1800000000,
provider_tokens_sent_to_nodes: false,
},
})}\n`
);
server.close();
}
});
});
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
const address = server.address();
resolve({
url: `${address.address}:${address.port}`,
requests,
close: () =>
new Promise((closeResolve) => {
if (!server.listening) closeResolve();
else server.close(() => closeResolve());
}),
});
});
});
}
function runDisasmer(args, env) {
return new Promise((resolve, reject) => {
const child = cp.spawn(
"cargo",
[
"run",
"-q",
"--manifest-path",
path.join(repo, "Cargo.toml"),
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
...args,
],
{ cwd: project, env, stdio: ["ignore", "pipe", "pipe"] }
);
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => (stdout += chunk.toString("utf8")));
child.stderr.on("data", (chunk) => (stderr += chunk.toString("utf8")));
child.once("error", reject);
child.once("close", (code) => {
if (code === 0) resolve(stdout);
else reject(new Error(`disasmer exited ${code}\n${stderr}\n${stdout}`));
});
});
}
(async () => {
const opener = writeOpener();
const coordinator = await startCoordinator();
try {
const loginStarted = Date.now();
const report = JSON.parse(
await runDisasmer(
[
"login",
"--browser",
"--json",
"--coordinator",
coordinator.url,
"--project-id",
"project-smoke",
],
{
...process.env,
DISASMER_BROWSER_OPEN_COMMAND: opener,
DISASMER_BROWSER_LOGIN_TIMEOUT_SECONDS: "5",
}
)
);
assert(
Date.now() - loginStarted < 3000,
"a long-lived browser opener must not keep CLI output pipes or login completion open"
);
assert.strictEqual(report.plan.coordinator, coordinator.url);
assert.strictEqual(report.boundary.cli_contacted_coordinator, true);
assert.strictEqual(report.boundary.scoped_cli_session_received, true);
assert.strictEqual(report.boundary.local_cli_session_file_written, true);
assert.strictEqual(report.boundary.provider_tokens_persisted_locally, false);
assert.strictEqual(report.boundary.provider_tokens_exposed_to_cli, false);
assert.strictEqual(report.boundary.provider_tokens_sent_to_nodes, false);
assert.strictEqual(report.boundary.coordinator_session_requests, 2);
assert.strictEqual(coordinator.requests.length, 2);
const sessionFile = path.join(project, ".disasmer", "session.json");
const sessionText = fs.readFileSync(sessionFile, "utf8");
const session = JSON.parse(sessionText);
assert.strictEqual(session.kind, "human");
assert.strictEqual(session.coordinator, coordinator.url);
assert.strictEqual(session.tenant, "tenant-smoke");
assert.strictEqual(session.project, "project-smoke");
assert.strictEqual(session.user, "user-smoke");
assert.strictEqual(session.cli_session_credential_kind, "CliDeviceSession");
assert.strictEqual(session.token_expiry_posture, "expires_at");
assert.strictEqual(session.expires_at, "1800000000");
assert.strictEqual(session.provider_tokens_exposed_to_cli, false);
assert.strictEqual(session.provider_tokens_sent_to_nodes, false);
assert.doesNotMatch(
sessionText,
/access_token|refresh_token|id_token|provider-secret|authorization_code|Bearer/
);
const authStatus = JSON.parse(
await runDisasmer(["auth", "status", "--json"], process.env)
);
assert.strictEqual(authStatus.active_coordinator, coordinator.url);
assert.strictEqual(authStatus.principal, "user-smoke");
assert.strictEqual(authStatus.tenant, "tenant-smoke");
assert.strictEqual(authStatus.project, "project-smoke");
assert.strictEqual(authStatus.session.kind, "human");
assert.strictEqual(authStatus.session.source, "session_file");
assert.strictEqual(authStatus.session.provider_tokens_exposed_to_cli, false);
assert.strictEqual(authStatus.session.provider_tokens_exposed_to_nodes, false);
} finally {
await coordinator.close();
}
console.log("CLI browser login flow smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

365
scripts/cli-error-exit-smoke.js Executable file
View file

@ -0,0 +1,365 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const http = require("http");
const os = require("os");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const project = path.join(repo, "examples/launch-build-demo");
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-cli-error-"));
function runDisasmer(args) {
return new Promise((resolve) => {
const child = cp.spawn(
"cargo",
["run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--", ...args],
{
cwd: repo,
stdio: ["ignore", "pipe", "pipe"],
}
);
let stdout = "";
let stderr = "";
child.stdout.setEncoding("utf8");
child.stderr.setEncoding("utf8");
child.stdout.on("data", (chunk) => {
stdout += chunk;
});
child.stderr.on("data", (chunk) => {
stderr += chunk;
});
child.on("close", (code, signal) => {
resolve({ code, signal, stdout, stderr });
});
});
}
async function runWithOneCoordinatorResponse(buildArgs, response) {
let request = "";
const server = http.createServer((incoming, outgoing) => {
incoming.setEncoding("utf8");
incoming.on("data", (chunk) => {
request += chunk;
});
incoming.on("end", () => {
outgoing.writeHead(200, { "content-type": "application/json" });
outgoing.end(JSON.stringify(response));
server.close();
});
});
const address = await new Promise((resolve) => {
server.listen(0, "127.0.0.1", () => resolve(server.address()));
});
const coordinator = `http://${address.address}:${address.port}`;
const result = await runDisasmer(buildArgs(coordinator));
return { request, result };
}
async function main() {
const environmentProject = path.join(tempRoot, "missing-env-project");
fs.mkdirSync(path.join(environmentProject, "src"), { recursive: true });
fs.writeFileSync(
path.join(environmentProject, "Cargo.toml"),
"[package]\nname = \"missing-env-project\"\nversion = \"0.1.0\"\nedition = \"2021\"\n"
);
fs.writeFileSync(
path.join(environmentProject, "src", "main.rs"),
"fn main() { let _target = env!(\"linux\"); }\n"
);
const environmentFailure = await runDisasmer([
"build",
"--project",
environmentProject,
"--json",
]);
assert.strictEqual(environmentFailure.signal, null, environmentFailure.stderr);
assert.strictEqual(environmentFailure.code, 26, environmentFailure.stderr);
const environmentReport = JSON.parse(environmentFailure.stdout);
assert.strictEqual(environmentReport.status, "blocked_before_schedule");
assert.strictEqual(environmentReport.scheduled_work, false);
assert.strictEqual(environmentReport.machine_error.category, "environment");
assert.strictEqual(
environmentReport.machine_error.process_exit_code_applied,
true
);
assert(
environmentReport.machine_error.next_actions.includes("disasmer inspect")
);
assert.strictEqual(environmentReport.diagnostics[0].code, "missing_environment");
const nonInteractive = await runDisasmer([
"run",
"build",
"--project",
project,
"--non-interactive",
"--json",
]);
assert.strictEqual(nonInteractive.signal, null, nonInteractive.stderr);
assert.strictEqual(nonInteractive.code, 20, nonInteractive.stderr);
assert.doesNotMatch(nonInteractive.stderr, /Opening Disasmer browser login/);
const nonInteractiveReport = JSON.parse(nonInteractive.stdout);
assert.strictEqual(nonInteractiveReport.status, "authentication_required");
assert.strictEqual(nonInteractiveReport.non_interactive, true);
assert.strictEqual(nonInteractiveReport.browser_opened, false);
assert.strictEqual(nonInteractiveReport.machine_error.category, "authentication");
assert.strictEqual(nonInteractiveReport.machine_error.stable_exit_code, 20);
assert.strictEqual(
nonInteractiveReport.machine_error.process_exit_code_applied,
true
);
assert(
nonInteractiveReport.machine_error.next_actions.includes(
"pass --local to run against local services"
)
);
let request = "";
const server = http.createServer((incoming, outgoing) => {
incoming.setEncoding("utf8");
incoming.on("data", (chunk) => {
request += chunk;
});
incoming.on("end", () => {
outgoing.writeHead(200, { "content-type": "application/json" });
outgoing.end(
JSON.stringify({
type: "error",
message: "quota unavailable: resource limit exceeded for api_calls",
})
);
server.close();
});
});
const address = await new Promise((resolve) => {
server.listen(0, "127.0.0.1", () => resolve(server.address()));
});
const coordinator = `http://${address.address}:${address.port}`;
const result = await runDisasmer([
"run",
"build",
"--project",
project,
"--coordinator",
coordinator,
"--json",
]);
assert.strictEqual(result.signal, null, result.stderr);
assert.strictEqual(result.code, 22, result.stderr);
assert.match(request, /"type":"start_process"/);
const report = JSON.parse(result.stdout);
assert.strictEqual(report.status, "coordinator_rejected");
assert.strictEqual(report.run_start.machine_error.category, "quota");
assert.strictEqual(report.run_start.machine_error.resource_category, "api_calls");
assert.strictEqual(report.run_start.machine_error.community_tier_language, true);
assert.strictEqual(
report.run_start.machine_error.community_tier_label,
"community tier"
);
assert.doesNotMatch(result.stdout, new RegExp(["free", "tier"].join(" "), "i"));
assert.strictEqual(
report.run_start.machine_error.private_abuse_heuristics_exposed,
false
);
assert.strictEqual(report.run_start.machine_error.stable_exit_code, 22);
assert.strictEqual(
report.run_start.machine_error.process_exit_code_applied,
true
);
assert(
report.run_start.machine_error.next_actions.includes("disasmer quota status")
);
const capabilityFailure = await runWithOneCoordinatorResponse(
(coordinator) => [
"run",
"build",
"--project",
project,
"--coordinator",
coordinator,
"--json",
],
{
type: "error",
message:
"scheduler placement failed: no capable node for placement: missing capability Command",
}
);
assert.strictEqual(capabilityFailure.result.signal, null, capabilityFailure.result.stderr);
assert.strictEqual(capabilityFailure.result.code, 24, capabilityFailure.result.stderr);
assert.match(capabilityFailure.request, /"type":"start_process"/);
const capabilityReport = JSON.parse(capabilityFailure.result.stdout);
assert.strictEqual(
capabilityReport.run_start.machine_error.category,
"capability"
);
assert.strictEqual(
capabilityReport.run_start.machine_error.process_exit_code_applied,
true
);
assert(
capabilityReport.run_start.machine_error.next_actions.includes(
"attach a node with the required capabilities"
)
);
const nodePolicyFailure = await runWithOneCoordinatorResponse(
(coordinator) => [
"run",
"build",
"--project",
project,
"--coordinator",
coordinator,
"--json",
],
{
type: "error",
message: "node policy denied native command execution",
}
);
assert.strictEqual(nodePolicyFailure.result.signal, null, nodePolicyFailure.result.stderr);
assert.strictEqual(nodePolicyFailure.result.code, 23, nodePolicyFailure.result.stderr);
assert.match(nodePolicyFailure.request, /"type":"start_process"/);
const nodePolicyReport = JSON.parse(nodePolicyFailure.result.stdout);
assert.strictEqual(
nodePolicyReport.run_start.machine_error.category,
"policy"
);
assert.strictEqual(
nodePolicyReport.run_start.machine_error.process_exit_code_applied,
true
);
assert(
nodePolicyReport.run_start.machine_error.next_actions.includes(
"check coordinator policy for this action"
)
);
const programFailure = await runWithOneCoordinatorResponse(
(coordinator) => [
"task",
"list",
"--coordinator",
coordinator,
"--json",
],
{
type: "task_events",
events: [
{
process: "vp-current",
task: "compile",
terminal_state: "failed",
environment: "linux",
node: "node-linux",
status_code: 1,
stderr_tail: "task exited with status 1",
},
],
}
);
assert.strictEqual(programFailure.result.signal, null, programFailure.result.stderr);
assert.strictEqual(programFailure.result.code, 0, programFailure.result.stderr);
assert.match(programFailure.request, /"type":"list_task_events"/);
const programReport = JSON.parse(programFailure.result.stdout);
assert.strictEqual(programReport.tasks[0].machine_error.category, "program");
assert.strictEqual(programReport.tasks[0].machine_error.stable_exit_code, 27);
assert(
programReport.tasks[0].machine_error.next_actions.includes("disasmer logs")
);
const artifactDownload = await runWithOneCoordinatorResponse(
(coordinator) => [
"artifact",
"download",
"app.txt",
"--coordinator",
coordinator,
"--json",
],
{
type: "artifact_download_denied",
message: "artifact download unauthorized for project",
}
);
assert.strictEqual(artifactDownload.result.signal, null, artifactDownload.result.stderr);
assert.strictEqual(artifactDownload.result.code, 21, artifactDownload.result.stderr);
assert.match(artifactDownload.request, /"type":"create_artifact_download_link"/);
const artifactDownloadReport = JSON.parse(artifactDownload.result.stdout);
assert.strictEqual(
artifactDownloadReport.download_session.machine_error.category,
"authorization"
);
assert.strictEqual(
artifactDownloadReport.download_session.machine_error.process_exit_code_applied,
true
);
const artifactExport = await runWithOneCoordinatorResponse(
(coordinator) => [
"artifact",
"export",
"app.txt",
"--to",
path.join(project, "target", "blocked-artifact.txt"),
"--coordinator",
coordinator,
"--json",
],
{
type: "artifact_export_unavailable",
message: "direct connectivity unavailable for artifact export",
}
);
assert.strictEqual(artifactExport.result.signal, null, artifactExport.result.stderr);
assert.strictEqual(artifactExport.result.code, 25, artifactExport.result.stderr);
assert.match(artifactExport.request, /"type":"export_artifact_to_node"/);
const artifactExportReport = JSON.parse(artifactExport.result.stdout);
assert.strictEqual(
artifactExportReport.export_plan.machine_error.category,
"connectivity"
);
assert.strictEqual(
artifactExportReport.export_plan.machine_error.process_exit_code_applied,
true
);
const confirmation = await runDisasmer([
"process",
"cancel",
"--coordinator",
"127.0.0.1:9",
"--json",
]);
assert.strictEqual(confirmation.signal, null, confirmation.stderr);
assert.strictEqual(confirmation.code, 23, confirmation.stderr);
const confirmationReport = JSON.parse(confirmation.stdout);
assert.strictEqual(confirmationReport.status, "confirmation_required");
assert.strictEqual(confirmationReport.coordinator_request_sent, false);
assert.strictEqual(confirmationReport.machine_error.category, "policy");
assert.strictEqual(
confirmationReport.machine_error.process_exit_code_applied,
true
);
assert(
confirmationReport.next_actions.some((action) => action.includes("--yes"))
);
}
main()
.then(() => {
console.log("CLI error exit smoke passed");
})
.catch((error) => {
console.error(error);
process.exit(1);
});

View file

@ -0,0 +1,773 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
const fullPath = path.join(repo, relativePath);
if (!fs.existsSync(fullPath)) {
if (fs.existsSync(path.join(repo, "DISASMER_PUBLIC_TREE.json"))) {
console.log(
`CLI-first contract smoke skipped: ${relativePath} is filtered from this public tree`
);
process.exit(0);
}
throw new Error(`${relativePath} is missing`);
}
return fs.readFileSync(fullPath, "utf8");
}
function readRustTree(relativePath) {
const root = path.join(repo, relativePath);
const sourcePaths = [];
function visit(directory) {
for (const entry of fs
.readdirSync(directory, { withFileTypes: true })
.sort((left, right) => left.name.localeCompare(right.name))) {
const fullPath = path.join(directory, entry.name);
if (entry.isDirectory()) {
visit(fullPath);
} else if (entry.isFile() && entry.name.endsWith(".rs")) {
sourcePaths.push(fullPath);
}
}
}
visit(root);
const priority = (filePath) => {
const name = path.basename(filePath);
if (name === "main.rs" || name === "service.rs") return 0;
if (name === "lib.rs") return 1;
if (name === "protocol.rs") return 2;
if (name === "tests.rs") return 100;
return 10;
};
sourcePaths.sort(
(left, right) =>
priority(left) - priority(right) || left.localeCompare(right)
);
return sourcePaths
.map((filePath) => fs.readFileSync(filePath, "utf8"))
.join("\n");
}
function criterionLines(source) {
return source
.split(/\r?\n/)
.filter((line) => /^- \[[ x]\] \*\*/.test(line));
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing CLI-first contract evidence: ${name}`);
}
const criteria = read("cli_acceptance_criteria.md");
// Phase 3 deliberately split the former CLI and coordinator mega-files into
// focused modules. Contract evidence therefore follows the complete source
// trees instead of assuming every implementation and test still lives in one
// entrypoint file.
const cli = readRustTree("crates/disasmer-cli/src");
const coordinator = readRustTree("crates/disasmer-coordinator/src");
const coordinatorLib = read("crates/disasmer-coordinator/src/lib.rs");
const cliFirstAcceptance = read("scripts/acceptance-cli-first.sh");
const outputModeSmoke = read("scripts/cli-output-mode-smoke.js");
const errorExitSmoke = read("scripts/cli-error-exit-smoke.js");
const browserLoginFlowSmoke = read("scripts/cli-browser-login-flow-smoke.js");
const nodeAttachSmoke = read("scripts/node-attach-smoke.js");
const dapSmoke = read("scripts/dap-smoke.js");
const cliHappyPathSmoke = read("scripts/cli-happy-path-live-smoke.js");
expect(criteria, "header", /^# Disasmer CLI-First MVP Acceptance Criteria/m);
expect(
criteria,
"addendum status",
/\*\*Status:\*\* CLI-first addendum to `acceptance_criteria\.md` and `acceptance_criteria_phase2\.md`/
);
expect(
criteria,
"website exception",
/hosted account creation as the only intentional private website exception/
);
expect(
criteria,
"no duplicate work note",
/does not automatically mean new product code, a new feature, or even actual implementation work is required/
);
expect(
criteria,
"future hosted business non-goal",
/billing, paid-plan checkout, team\/org management, provider setup wizards, secret-manager UI, full support tooling, broad moderation consoles, and durable account\/business-process management are intentionally outside this CLI-first MVP slice/
);
expect(
criteria,
"billing plan flags are placeholders",
/Design-document references to billing, paid plans, or plan flags are future metadata placeholders; they do not require MVP CLI commands, coordinator routes, schemas, migrations, website controls, or service logic/
);
expect(
criteria,
"hosted signup remains private Authentik-backed flow",
/Hosted account creation is available only through the private hosted identity flow, backed by Authentik[\s\S]*first-login account\/project creation stays inside/
);
expect(
criteria,
"hosted signup provider and password policy criteria",
/approved external identity-provider requirement[\s\S]*disasmer_native_password_signup_allowed: false/
);
expect(
criteria,
"hosted provider normalization criteria",
/Google sign-in may be treated as OIDC; GitHub sign-in is OAuth2 social login[\s\S]*normalizes Google as `google_oidc` and GitHub as `github_oauth2` from an Authentik-issued OIDC session[\s\S]*does not consume provider-specific tokens directly/
);
expect(
criteria,
"hosted CLI cannot create accounts directly",
/The CLI cannot create a hosted account directly[\s\S]*parser coverage rejects `disasmer signup`, `disasmer account create`, and `disasmer login --create-account`/
);
expect(
criteria,
"hosted safe claim failure criteria",
/If identity is ambiguous, missing required claims, unverified where required, or blocked by policy[\s\S]*exactly one approved external identity provider[\s\S]*stable subject[\s\S]*verified email/
);
expect(
criteria,
"hosted signup sanitized failure criteria",
/Signup failures do not disclose moderation, abuse-scoring, or allow\/deny internals[\s\S]*stripping issuer, allowlist, abuse-score, moderation-note, and provider-secret details/
);
expect(
criteria,
"hosted account state privacy criteria",
/Account suspension, deletion, manual review, and abuse handling are private hosted-admin concerns[\s\S]*public CLI displays clear suspended, disabled, deleted, and manual-review status[\s\S]*strips private moderation\/signup details/
);
const lines = criterionLines(criteria);
assert(lines.length > 0, "CLI-first criteria must contain criteria lines");
for (const line of lines) {
assert.match(
line,
/^- \[[ x]\] \*\*(Passed|Partial|Open|Postponed)(?: \([^)]+\))?:\*\*/,
`CLI-first criterion lacks an explicit status prefix: ${line}`
);
}
const openCriteria = lines.filter((line) => /\*\*Open(?::| \()/.test(line));
assert.deepStrictEqual(
openCriteria,
[],
"CLI-first criteria should not leave Open items once the non-e2e gate exists; remaining unfinished facts stay Partial"
);
expect(
criteria,
"CLI-first non-e2e gate wording",
/scripts\/acceptance-cli-first\.sh[\s\S]*scripts\/cli-happy-path-live-smoke\.js[\s\S]*live hosted coordinator/
);
expect(
cliFirstAcceptance,
"CLI-first gate can run live happy path when explicitly enabled",
/DISASMER_CLI_HAPPY_PATH_LIVE[\s\S]*cli-happy-path-live-smoke\.js/
);
for (const [name, pattern] of [
["happy path uses released binaries", /disasmer-public-binaries-/],
["happy path completes server-owned browser login", /DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND[\s\S]*DISASMER_BROWSER_OPEN_COMMAND/],
["happy path initializes project", /"project"[\s\S]*"init"/],
["happy path inspects project", /"inspect"[\s\S]*"--project"/],
["happy path enrolls node", /"node"[\s\S]*"enroll"/],
["happy path attaches node", /"node"[\s\S]*"attach"/],
["happy path starts worker", /--worker/],
["happy path runs build", /"run"[\s\S]*"build"/],
["happy path checks logs", /"logs"/],
["happy path checks artifacts", /"artifact"[\s\S]*"list"/],
["happy path downloads artifact", /"artifact"[\s\S]*"download"/],
["happy path restarts process", /"process"[\s\S]*"restart"/],
["happy path cancels process", /"process"[\s\S]*"cancel"/],
["happy path writes evidence", /cli-happy-path-live\.json/],
]) {
expect(cliHappyPathSmoke, name, pattern);
}
expect(
criteria,
"artifact export explicit local byte write",
/artifact export <id> --to <path>` writes bytes[\s\S]*explicit bounded download stream[\s\S]*complete staged content is available/
);
expect(
criteria,
"artifact download grant disclosure criteria",
/artifact download <id>` creates a secure[\s\S]*explicit artifact-download grant disclosure[\s\S]*Download links or sessions are not guessable public URLs[\s\S]*guessable_public_url: false[\s\S]*cross-tenant no-reuse[\s\S]*unauthorized-project no-reuse[\s\S]*Every command that grants[\s\S]*artifact download ability[\s\S]*grant_disclosures/
);
expect(
criteria,
"locality failure safe guidance",
/If direct transfer or locality assumptions fail[\s\S]*connectivity-category safe failures[\s\S]*coordinator bulk relay was not used/
);
expect(
criteria,
"mutating commands require confirmation",
/Mutating or dangerous commands support `--yes`[\s\S]*confirmation-required safe failure[\s\S]*do not send coordinator requests/
);
expect(
criteria,
"log redaction criteria",
/Logs are capped, truncated honestly[\s\S]*preserve byte counts and truncation flags[\s\S]*Secret-like values are redacted[\s\S]*common token\/password\/bearer patterns/
);
expect(
criteria,
"doctor node readiness criteria",
/`disasmer doctor` reports missing local dependencies[\s\S]*explicit node readiness summary[\s\S]*missing local dependencies[\s\S]*node next actions/
);
expect(
criteria,
"admin bootstrap self-hosted sequence criteria",
/admin bootstrap now reports a CLI-only self-hosted sequence[\s\S]*node enrollment\/attach[\s\S]*quota status[\s\S]*node revoke/
);
expect(
criteria,
"quota resource-category criteria",
/Hitting a quota produces a clear error[\s\S]*resource category[\s\S]*private abuse heuristics[\s\S]*quota machine errors now extract the resource category/
);
expect(
criteria,
"quota before work criteria",
/Quotas are checked before expensive work starts[\s\S]*workflow spawns now charge `Spawn` before coordinator-side process\/task state is created or queued[\s\S]*debug, artifact-download, and rendezvous metering/
);
expect(
criteria,
"community tier CLI wording criteria",
/Community tier language is used instead of "free[ -]tier" in user-facing CLI output/
);
expect(
criteria,
"DAP launch-critical surface criteria",
/launch-critical DAP surface required by the MVP[\s\S]*`initialize`[\s\S]*`source`[\s\S]*`next`\/step-over[\s\S]*`restartFrame`/
);
expect(
criteria,
"DAP variables experience criteria",
/normal debugger variables path exposes the MVP debugging experience[\s\S]*selected source locals around Disasmer API calls[\s\S]*runtime-captured Wasmtime frame locals/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance report",
/node scripts\/acceptance-report\.js cli-first/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance refuses final e2e",
/DISASMER_PUBLIC_RELEASE_DRYRUN_E2E[\s\S]*does not run final public-release e2e/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance refuses final evidence",
/DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL[\s\S]*does not run final public-release evidence/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance composes public API contracts",
/node scripts\/cli-output-mode-smoke\.js[\s\S]*node scripts\/cli-login-smoke\.js[\s\S]*node scripts\/cli-error-exit-smoke\.js[\s\S]*node scripts\/cli-browser-login-flow-smoke\.js/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance composes service boundary checks",
/node scripts\/wasmtime-assignment-smoke\.js[\s\S]*node scripts\/cli-local-run-smoke\.js/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance composes self-hosted checks",
/node scripts\/self-hosted-coordinator-smoke\.js/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance composes debug and artifact checks",
/node scripts\/vscode-f5-smoke\.js[\s\S]*node scripts\/artifact-download-smoke\.js[\s\S]*node scripts\/artifact-export-smoke\.js/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance composes DAP checks",
/node scripts\/dap-smoke\.js/
);
expect(
cliFirstAcceptance,
"CLI-first acceptance can include private hosted gate",
/DISASMER_CLI_FIRST_INCLUDE_PRIVATE[\s\S]*scripts\/acceptance-private\.sh/
);
assert.doesNotMatch(
cliFirstAcceptance,
/node scripts\/public-release-dryrun-e2e\.js|node scripts\/public-release-dryrun-final-evidence\.js/,
"CLI-first non-e2e gate must not invoke final public release e2e or final evidence verifier"
);
for (const [name, pattern] of [
["top-level version metadata", /#\[command\([\s\S]*name = "disasmer"[\s\S]*version[\s\S]*arg_required_else_help = true[\s\S]*\)\]/],
["top-level primary workflow help", /after_help = "Primary workflow:[\s\S]*disasmer login --browser[\s\S]*disasmer node attach; disasmer-node --worker[\s\S]*Disasmer: Launch Virtual Process[\s\S]*Hosted account creation happens in the browser login flow\."/],
["top-level logout command", /enum Commands[\s\S]*Logout\(AuthLogoutArgs\)[\s\S]*Auth \{/],
["login non-interactive flag", /struct LoginArgs[\s\S]*non_interactive: bool/],
["run non-interactive flag", /struct RunArgs[\s\S]*non_interactive: bool/],
["stored CLI session model", /struct StoredCliSession[\s\S]*cli_session_credential_kind[\s\S]*provider_tokens_exposed_to_cli[\s\S]*provider_tokens_sent_to_nodes/],
["read CLI session helper", /fn read_cli_session\(project: &Path\) -> Result<Option<StoredCliSession>>/],
["write CLI session helper", /fn write_cli_session\(project: &Path, session: &StoredCliSession\) -> Result<PathBuf>/],
["session source fallback", /fn session_from_sources\(project: &Path\) -> Result<CliSession>[\s\S]*read_cli_session\(project\)\?\.is_some\(\)/],
["browser login writes local CLI session", /local_cli_session_file_written[\s\S]*write_cli_session\(&cwd, &stored_session\)\?/],
["browser login does not persist provider tokens", /provider_tokens_persisted_locally:\s*false/],
["non-interactive auth report", /fn non_interactive_auth_machine_error[\s\S]*browser_opened[\s\S]*false/],
["human report renderer", /fn human_report\(value: &Value\) -> String/],
["shared report emitter", /fn emit_report<T: Serialize>\(report: &T, json_output: bool\) -> Result<\(\)>/],
["doctor command", /Doctor\(DoctorArgs\)/],
["doctor node readiness summary", /fn node_readiness_summary[\s\S]*ready_to_attach[\s\S]*explicit_attach_required[\s\S]*missing_local_dependencies[\s\S]*next_actions/],
["auth status command", /enum AuthCommands[\s\S]*Status\(AuthStatusArgs\)/],
["auth logout command", /enum AuthCommands[\s\S]*Logout\(AuthLogoutArgs\)/],
["key lifecycle commands", /enum KeyCommands[\s\S]*Add\(KeyAddArgs\)[\s\S]*List\(KeyListArgs\)[\s\S]*Revoke\(KeyRevokeArgs\)/],
["project commands", /enum ProjectCommands[\s\S]*Init\(ProjectInitArgs\)[\s\S]*Status\(ProjectStatusArgs\)[\s\S]*List\(ProjectListArgs\)[\s\S]*Select\(ProjectSelectArgs\)/],
["inspect command", /Inspect\(BundleInspectArgs\)/],
["build command", /Build\(BuildArgs\)/],
["node lifecycle commands", /enum NodeCommands[\s\S]*Attach\(AttachArgs\)[\s\S]*Enroll\(NodeEnrollArgs\)[\s\S]*List\(NodeListArgs\)[\s\S]*Status\(NodeStatusArgs\)[\s\S]*Revoke\(NodeRevokeArgs\)/],
["process commands", /enum ProcessCommands[\s\S]*Status\(ProcessStatusArgs\)[\s\S]*Restart\(ProcessRestartArgs\)[\s\S]*Cancel\(ProcessCancelArgs\)/],
["task lifecycle commands", /enum TaskCommands[\s\S]*List\(TaskListArgs\)[\s\S]*Restart\(TaskRestartArgs\)/],
["logs command", /Logs\(LogsArgs\)/],
["artifact commands", /enum ArtifactCommands[\s\S]*List\(ArtifactListArgs\)[\s\S]*Download\(ArtifactDownloadArgs\)[\s\S]*Export\(ArtifactExportArgs\)/],
["DAP command", /Dap\(DapArgs\)/],
["debug attach command", /enum DebugCommands[\s\S]*Attach\(DebugAttachArgs\)/],
["quota command", /enum QuotaCommands[\s\S]*Status\(QuotaStatusArgs\)/],
["admin commands", /enum AdminCommands[\s\S]*Status\(AdminStatusArgs\)[\s\S]*Bootstrap\(AdminBootstrapArgs\)[\s\S]*RevokeNode\(NodeRevokeArgs\)[\s\S]*StopProcess\(ProcessCancelArgs\)[\s\S]*SuspendTenant\(AdminSuspendTenantArgs\)/],
]) {
expect(cli, name, pattern);
}
for (const [name, pattern] of [
["CLI parse coverage", /fn cli_first_mvp_command_surface_parses\(\)/],
["CLI primary workflow help coverage", /fn top_level_help_exposes_primary_workflow_without_auth\(\)/],
["CLI non-interactive run auth coverage", /fn non_interactive_run_without_session_requires_explicit_auth_or_local\(\)/],
["CLI non-interactive browser login coverage", /fn browser_login_non_interactive_fails_before_opening_browser\(\)/],
["CLI stored browser session coverage", /fn stored_browser_login_session_omits_provider_token_values\(\)/],
["CLI auth status session-file coverage", /fn auth_status_reads_stored_cli_session_without_provider_tokens\(\)/],
["CLI auth status account privacy coverage", /fn auth_status_queries_coordinator_account_state_without_private_moderation_details\(\)/],
["CLI version coverage", /fn top_level_version_is_available\(\)/],
["CLI JSON parse coverage", /fn cli_first_json_mode_parses_for_primary_commands\(\)/],
["CLI human output coverage", /fn human_report_is_text_not_json\(\)/],
["CLI key lifecycle coverage", /fn key_lifecycle_reports_project_scoped_agent_credentials\(\)/],
["CLI agent workflow actor coverage", /fn run_with_agent_public_key_sends_attributable_workflow_actor\(\)/],
["CLI node revoke coverage", /fn node_revoke_reports_scoped_credential_revocation\(\)/],
["CLI admin public API coverage", /fn admin_status_and_suspend_use_public_coordinator_api\(\)/],
["CLI admin bootstrap coverage", /fn admin_bootstrap_reports_self_hosted_cli_only_path\(\)/],
["CLI debug attach coverage", /fn debug_attach_reports_public_authorization\(\)/],
["doctor unchecked reachability coverage", /fn doctor_reports_unchecked_coordinator_reachability_without_config\(\)/],
["doctor ping reachability coverage", /fn doctor_pings_configured_coordinator\(\)/],
["project local config coverage", /fn project_init_select_and_status_use_local_project_config\(\)/],
["project init public create coverage", /fn project_init_uses_public_create_before_writing_local_config\(\)/],
["project public API list/select coverage", /fn project_list_and_select_use_public_api_without_website\(\)/],
["project coordinator status coverage", /fn project_status_queries_public_coordinator_state\(\)/],
["run coordinator active-process coverage", /fn run_contacts_configured_coordinator_and_reports_active_process_conflicts\(\)/],
["CLI error classifier coverage", /fn cli_error_classifier_distinguishes_mvp_failure_categories\(\)/],
["CLI command exit-code coverage", /fn command_report_exit_code_marks_command_failures_only\(\)/],
["CLI top-level logout alias coverage", /fn top_level_logout_alias_removes_only_cli_session_state\(\)/],
["CLI confirmation gate helper", /fn confirmation_required_report[\s\S]*coordinator_request_sent[\s\S]*confirmation_required/],
["CLI mutating confirmation coverage", /fn mutating_commands_require_yes_before_side_effects\(\)/],
["CLI run rejection category coverage", /fn run_rejection_reports_machine_readable_error_category\(\)/],
["CLI locality failure classifier", /fn classify_cli_error_message\(message: &str\)[\s\S]*message_mentions_locality_failure\(&message\)[\s\S]*return "connectivity"/],
["CLI locality failure report helper", /fn task_locality_failure_from_reason\(reason: &Value\) -> Value[\s\S]*coordinator_bulk_relay_used[\s\S]*safe_next_actions/],
["CLI locality failure human output", /fn push_task_locality_failures\(lines: &mut Vec<String>, tasks: &\[Value\]\)[\s\S]*locality \{task_name\}/],
["node attach auto-detection coverage", /fn node_attach_detects_and_accepts_capability_overrides\(\)[\s\S]*detection\.auto_detected[\s\S]*command_backend[\s\S]*source_provider_backends/],
["node attach grant disclosure coverage", /fn node_attach_discloses_dangerous_capability_grants\(\)/],
["node enroll public API grant coverage", /fn node_enroll_reports_short_lived_public_api_grant\(\)/],
["quota local status coverage", /fn quota_status_uses_project_config_and_generic_public_limits\(\)/],
["quota coordinator usage coverage", /fn quota_status_queries_public_coordinator_usage\(\)/],
["task event summary coverage", /fn process_task_log_and_artifact_reports_summarize_task_events\(\)/],
["task locality failure summary coverage", /fn process_task_log_and_artifact_reports_summarize_task_events\(\)[\s\S]*source snapshot unavailable and direct connectivity unavailable[\s\S]*locality_failure/],
["log secret redaction coverage", /fn log_and_task_reports_redact_secret_like_values\(\)/],
["artifact download/export report coverage", /fn artifact_download_and_export_reports_expose_safe_session_boundaries\(\)/],
["process control report coverage", /fn process_restart_cancel_and_abort_reports_expose_control_boundaries\(\)/],
["task restart report coverage", /fn task_restart_reports_clean_boundary_requirements\(\)/],
["build no full repo upload coverage", /fn build_command_reuses_bundle_inspection_without_full_repo_upload\(\)/],
["bundle rebuild restart compatibility coverage", /fn bundle_rebuild_after_source_edit_keeps_restart_compatibility_contract\(\)/],
["inspect missing environment coverage", /fn bundle_inspect_reports_missing_environment_references_before_schedule\(\)/],
["inspect source provider override coverage", /fn bundle_inspect_reports_source_provider_overrides_before_schedule\(\)/],
["build missing environment gate coverage", /fn build_blocks_before_schedule_on_missing_environment_reference\(\)/],
["safe coordinator-required plans", /fn node_enroll_and_process_commands_have_safe_plan_without_coordinator\(\)/],
]) {
expect(cli, name, pattern);
}
expect(
browserLoginFlowSmoke,
"browser login smoke checks session file",
/provider_tokens_persisted_locally[\s\S]*path\.join\(project, "\.disasmer", "session\.json"\)[\s\S]*\["auth", "status", "--json"\]/
);
expect(
browserLoginFlowSmoke,
"browser login smoke rejects provider token persistence",
/assert\.doesNotMatch\([\s\S]*access_token\|refresh_token\|id_token/
);
expect(
nodeAttachSmoke,
"node attach smoke verifies auto-detection evidence",
/plan\.detection\.auto_detected[\s\S]*plan\.detection\.command_backend[\s\S]*source_provider_backends/
);
expect(
nodeAttachSmoke,
"node attach smoke verifies policy-limited grant disclosures",
/grant_disclosures\.length > 0[\s\S]*coordinator_policy_limited === true[\s\S]*native_command_execution[\s\S]*source_access/
);
for (const [name, pattern] of [
["DAP smoke verifies source request", /client\.send\("source"[\s\S]*assert\.match\(source\.content, \/build_main\//],
["DAP smoke rejects synthetic source stepping", /client\.send\("next"[\s\S]*client\.failure\(step, "next"\)[\s\S]*source stepping is not yet available[\s\S]*synthetic step/],
["DAP smoke verifies DAP variables scopes", /Source Locals[\s\S]*Wasm Frame Locals[\s\S]*Task Args and Handles[\s\S]*Disasmer Runtime/],
["DAP smoke reports unavailable source locals truthfully", /unavailable-local-diagnostic[\s\S]*cannot be inspected/],
["DAP smoke reports unavailable Wasm frame locals truthfully", /wasm-local-diagnostic[\s\S]*did not report inspectable Wasm frame locals/],
["DAP smoke verifies real local-services all-stop", /runtimeBackend: "local-services"[\s\S]*allThreadsStopped, true[\s\S]*confirmed by every active participant/],
["DAP smoke verifies coordinator checkpoint refusal", /client\.send\("restartFrame"[\s\S]*checkpoint boundary\|still active[\s\S]*whole virtual-process restart/],
]) {
expect(dapSmoke, name, pattern);
}
expect(
coordinator,
"coordinator whole-process cancellation coverage",
/fn service_cancels_whole_process_and_blocks_new_task_launches\(\)/
);
expect(
coordinator,
"coordinator single active process coverage",
/fn service_rejects_second_active_process_unless_restarting_same_process\(\)/
);
expect(
coordinator,
"coordinator agent key lifecycle coverage",
/fn service_manages_project_scoped_agent_public_keys\(\)/
);
expect(
coordinator,
"coordinator agent workflow dispatch coverage",
/fn service_runs_agent_workflows_with_scoped_key_attribution\(\)/
);
expect(
coordinator,
"coordinator agent workflow authorization",
/authorize_agent_project_run\([\s\S]*project:run/
);
expect(
coordinator,
"coordinator agent workflow actor fields",
/pub struct WorkflowActor[\s\S]*agent: Option<AgentId>[\s\S]*public_key_fingerprint: Option<Digest>[\s\S]*authenticated_without_browser/
);
expect(
coordinator,
"coordinator node revoke coverage",
/fn service_revokes_node_credentials_and_live_descriptors\(\)/
);
expect(
coordinator,
"coordinator public admin suspension coverage",
/fn service_reports_and_enforces_public_admin_tenant_suspension\(\)/
);
expect(
coordinator,
"coordinator debug attach coverage",
/fn service_authorizes_debug_attach_through_public_api\(\)/
);
expect(
coordinator,
"coordinator task restart boundary coverage",
/fn service_reports_task_restart_boundary_through_public_api\(\)/
);
for (const [name, pattern] of [
["task completion placement field", /pub struct TaskCompletionEvent[\s\S]*placement: Option<Placement>/],
["task placement state", /task_placements/],
["task completion retains placement", /event\.placement = self\.task_placements\.remove/],
]) {
expect(coordinator, `coordinator task events retain placement reasons: ${name}`, pattern);
}
expect(
coordinator,
"coordinator workflow spawn metering",
/struct MeterKey[\s\S]*kind: LimitKind[\s\S]*window: u64[\s\S]*fn can_charge_workflow_spawn[\s\S]*self\.can_charge\(tenant, project, LimitKind::Spawn, 1, now_epoch_seconds\)[\s\S]*fn charge_workflow_spawn[\s\S]*self\.charge\(tenant, project, LimitKind::Spawn, 1, now_epoch_seconds\)[\s\S]*charged_spawns/
);
expect(
coordinator,
"coordinator spawn quota before work coverage",
/fn service_checks_spawn_quota_before_process_or_task_work_starts\(\)[\s\S]*quota\.set_workflow_limits\(ResourceLimits[\s\S]*LimitKind::Spawn[\s\S]*compile-linux-denied[\s\S]*active_tasks\.contains[\s\S]*other-project[\s\S]*fn project_quota_resets_at_the_configured_window_boundary\(\)[\s\S]*set_server_time\(59\)[\s\S]*set_server_time\(60\)/
);
expect(
coordinator,
"public debug operation audit event",
/pub struct DebugAuditEvent[\s\S]*charged_debug_read_bytes[\s\S]*used_debug_read_bytes/
);
expect(
coordinator,
"public debug operation metering",
/record_debug_audit_event\([\s\S]*charge_debug_read\([\s\S]*&tenant[\s\S]*&project[\s\S]*DEBUG_CONTROL_READ_BYTES[\s\S]*used_debug_read_bytes\(&tenant, &project, now_epoch_seconds\)/
);
expect(
cli,
"CLI surfaces debug audit and quota fields",
/debug_reads_quota_limited[\s\S]*charged_debug_read_bytes[\s\S]*used_debug_read_bytes/
);
expect(
cli,
"CLI sends agent workflow actor fields",
/fn add_workflow_actor_fields[\s\S]*actor_agent[\s\S]*agent_public_key_fingerprint/
);
expect(
cli,
"CLI exposes node attach detection evidence",
/struct NodeAttachDetectionEvidence[\s\S]*command_backend[\s\S]*container_backend[\s\S]*source_provider_backends[\s\S]*manual_capability_overrides[\s\S]*os_arch_capabilities_require_manual_flags/
);
expect(
cli,
"CLI renders node attach detection evidence",
/fn push_node_attach_detection[\s\S]*command backend[\s\S]*container backend[\s\S]*source providers[\s\S]*capability overrides/
);
expect(
cli,
"CLI exposes node attach grant disclosures",
/struct CapabilityGrantDisclosure[\s\S]*coordinator_policy_limited[\s\S]*fn capability_grant_disclosures/
);
expect(
cli,
"CLI exposes artifact download grant disclosures",
/fn artifact_download_grant_disclosures[\s\S]*"grant": "artifact_download"[\s\S]*"coordinator_policy_limited": true[\s\S]*"authorization_required": true[\s\S]*"guessable_public_url": false[\s\S]*"cross_tenant_reuse_allowed": false[\s\S]*"unauthorized_project_reuse_allowed": false/
);
expect(
cli,
"CLI exposes normalized node enrollment grants",
/fn node_enroll_report[\s\S]*create_node_enrollment_grant[\s\S]*enrollment_grant[\s\S]*private_website_required[\s\S]*fn node_enrollment_grant_summary[\s\S]*short_lived[\s\S]*node_credentials_separate_from_user_session/
);
expect(
cli,
"CLI exposes task placement reasons",
/fn task_summaries[\s\S]*node_placement[\s\S]*reasons[\s\S]*explanation_available/
);
expect(
cli,
"CLI project init report current-directory link",
/fn project_init_report[\s\S]*current_directory_link[\s\S]*links_current_directory[\s\S]*safe_defaults[\s\S]*coordinator_create_before_local_write/
);
expect(
cli,
"CLI project init writes config after public create",
/let coordinator_response = if let Some\(coordinator\)[\s\S]*"type": "create_project"[\s\S]*coordinator_session_requests = session\.requests\(\)[\s\S]*write_project_config\(&cwd, &config\)\?/
);
expect(
cli,
"CLI project init renders current-directory link",
/current_directory_link[\s\S]*current directory linked: true[\s\S]*current directory config/
);
expect(
cli,
"CLI project list/select report public API boundary",
/fn project_list_report[\s\S]*public_coordinator_api[\s\S]*private_website_required[\s\S]*fn project_select_report[\s\S]*project_config_written[\s\S]*private_website_required/
);
expect(
cli,
"CLI project select writes config after coordinator response",
/fn project_select_report[\s\S]*let coordinator_response = if let Some\(coordinator\)[\s\S]*let request = authenticated_or_local_trusted_request\([\s\S]*"type": "select_project"[\s\S]*Some\(session\.request\(request\)\?\)[\s\S]*write_project_config\(&cwd, &config\)\?/
);
expect(
cli,
"CLI renders task placement reasons",
/fn push_task_placement_reasons[\s\S]*placement \{task_name\}: \{node\}/
);
expect(
cli,
"CLI redacts secret-like log values",
/fn log_entries[\s\S]*redact_secret_like_text[\s\S]*secret_like_values_redacted[\s\S]*redacted_fields[\s\S]*fn redact_secret_like_text[\s\S]*access_token=[\s\S]*password=[\s\S]*bearer /
);
expect(
cli,
"CLI classifies machine-readable error categories",
/fn classify_cli_error_message[\s\S]*"authentication"[\s\S]*"authorization"[\s\S]*"quota"[\s\S]*"policy"[\s\S]*"capability"[\s\S]*"connectivity"[\s\S]*"environment"[\s\S]*"program"/
);
expect(
cli,
"CLI exposes quota machine-error posture",
/fn cli_error_summary_for_category[\s\S]*resource_category[\s\S]*quota_error_resource_category[\s\S]*community_tier_language[\s\S]*community_tier_label[\s\S]*private_abuse_heuristics_exposed[\s\S]*fn quota_error_resource_category[\s\S]*resource limit exceeded for /
);
expect(
coordinator,
"coordinator exposes sanitized auth status API",
/AuthStatus \{[\s\S]*tenant: String[\s\S]*project: String[\s\S]*actor_user: String[\s\S]*AuthStatus \{[\s\S]*account_status: String[\s\S]*suspended: bool[\s\S]*disabled: bool[\s\S]*private_moderation_details_exposed: bool[\s\S]*signup_failure_details_exposed: bool/
);
expect(
cli,
"CLI auth status queries public account state",
/fn coordinator_auth_status_summary[\s\S]*"type": "auth_status"[\s\S]*"private_moderation_details_exposed": false[\s\S]*"signup_failure_details_exposed": false/
);
expect(
cli,
"CLI auth status does not expose raw private moderation response fields",
/fn auth_status_queries_coordinator_account_state_without_private_moderation_details[\s\S]*abuse_score[\s\S]*moderation_notes[\s\S]*!serialized\.contains\("abuse_score"\)[\s\S]*!serialized\.contains\("moderation_notes"\)/
);
expect(
cli,
"CLI auth status reports inactive account states safely",
/fn auth_status_reports_disabled_deleted_and_manual_review_safely[\s\S]*account_status[\s\S]*disabled[\s\S]*deleted[\s\S]*manual_review[\s\S]*!serialized\.contains\("signup_policy_trace"\)/
);
expect(
coordinatorLib,
"coordinator summarizes private account policy state safely",
/fn tenant_disabled\(&self, tenant: &TenantId\) -> bool[\s\S]*tenant:disabled[\s\S]*fn tenant_deleted\(&self, tenant: &TenantId\) -> bool[\s\S]*tenant:deleted[\s\S]*fn tenant_manual_review\(&self, tenant: &TenantId\) -> bool[\s\S]*tenant:manual_review[\s\S]*fn account_policy_state\(&self, tenant: &TenantId\) -> AccountPolicyState[\s\S]*"deleted"[\s\S]*"disabled"[\s\S]*"manual_review"[\s\S]*"account or tenant is pending hosted review"/
);
expect(
cli,
"CLI renders sanitized account status",
/coordinator_account_status[\s\S]*account status checked: \{checked\}[\s\S]*account status[\s\S]*private moderation details exposed/
);
expect(
cli,
"CLI renders community tier wording",
/push_string_field\(&mut lines, value, "quota_tier", "quota tier"\)[\s\S]*community_tier_label[\s\S]*quota tier: \{tier\}/
);
assert.doesNotMatch(cli, /free[- ]tier/i, "CLI source should use community tier wording");
expect(
cli,
"CLI reports stable error-code contract",
/fn cli_error_exit_code[\s\S]*"authentication" => 20[\s\S]*"authorization" => 21[\s\S]*"quota" => 22[\s\S]*"policy" => 23[\s\S]*"capability" => 24[\s\S]*"connectivity" => 25[\s\S]*"environment" => 26[\s\S]*"program" => 27/
);
expect(
cli,
"CLI attaches machine errors to run and task reports",
/run_start_summary[\s\S]*"machine_error": machine_error/
);
expect(
cli,
"CLI attaches machine errors to task failures",
/task_failure_machine_error[\s\S]*cli_error_summary_with_default/
);
expect(
cli,
"CLI applies process exit code after printing command failure report",
/fn emit_report<T: Serialize>[\s\S]*apply_command_report_exit_code[\s\S]*std::process::exit\(exit_code\)[\s\S]*fn human_report/
);
expect(
cli,
"CLI applies artifact nested failure exit codes",
/fn apply_command_report_exit_code[\s\S]*"\/download_session\/machine_error"[\s\S]*"\/export_plan\/machine_error"[\s\S]*"\/local_export\/machine_error"[\s\S]*"\/local_export\/download_session\/machine_error"[\s\S]*"\/local_export\/stream\/machine_error"/
);
expect(
cli,
"CLI wraps fallible main with classified exit",
/fn main\(\)[\s\S]*cli_error_summary\(&message\)[\s\S]*std::process::exit\(exit_code\)/
);
expect(
cli,
"CLI parses dangerous capability overrides",
/"host-filesystem"[\s\S]*Capability::HostFilesystem[\s\S]*"network"[\s\S]*Capability::Network[\s\S]*"secrets"[\s\S]*Capability::Secrets/
);
expect(
cli,
"CLI exposes source provider diagnostics",
/source_provider_statuses[\s\S]*source_provider_selection[\s\S]*source_provider_unsupported/
);
expect(
cli,
"CLI exposes environment pre-schedule diagnostics",
/environment_diagnostics_for_inputs[\s\S]*diagnose_environment_references[\s\S]*missing_environment/
);
expect(
cli,
"CLI bundle metadata exposes MVP build facets",
/BundleIdentityInputs[\s\S]*entrypoints[\s\S]*default_entrypoint[\s\S]*source_transfer_policy[\s\S]*wasm_source_proxy_digest[\s\S]*task_abi_digest/
);
expect(
cli,
"CLI bundle coverage verifies Dockerfile and debug metadata",
/fn bundle_inspect_discovers_environments_selected_inputs_and_source_providers\(\)[\s\S]*envs\/docker\/Dockerfile[\s\S]*task_metadata[\s\S]*source_metadata[\s\S]*debug_metadata/
);
expect(
cli,
"CLI build coverage verifies inspectable metadata",
/fn build_command_reuses_bundle_inspection_without_full_repo_upload\(\)[\s\S]*wasm_code[\s\S]*task_metadata[\s\S]*source_metadata[\s\S]*debug_metadata/
);
expect(
cli,
"CLI build coverage verifies large input handle posture",
/large_input_policy[\s\S]*selected_inputs_are_content_digests[\s\S]*selected_input_bytes_included[\s\S]*silent_task_argument_serialization[\s\S]*supported_handle_types/
);
expect(
cli,
"CLI bundle coverage verifies restart compatibility metadata",
/restart_compatibility[\s\S]*source_edits_can_restart_from_clean_task_boundary[\s\S]*requires_clean_checkpoint_boundary[\s\S]*compares_task_abi[\s\S]*incompatible_changes_require_whole_process_restart/
);
expect(
cli,
"CLI blocks build before scheduling unsafe inputs",
/blocked_before_schedule[\s\S]*scheduled_work[\s\S]*false/
);
expect(
cli,
"CLI artifact export writes explicit local bytes from stream content",
/fn artifact_export_local_write_followup[\s\S]*open_artifact_download_stream[\s\S]*content_base64[\s\S]*std::fs::write/
);
expect(
cli,
"CLI artifact export keeps content out of reports",
/fn artifact_stream_summary[\s\S]*content_material_returned_in_report[\s\S]*false/
);
expect(
cli,
"CLI artifact export carries download grant disclosure",
/fn artifact_export_local_write_followup[\s\S]*artifact_download_grant_disclosures[\s\S]*"grant_disclosures": grant_disclosures/
);
expect(
cli,
"CLI exposes admin bootstrap self-hosted path",
/fn admin_bootstrap_report[\s\S]*self_hosted_cli_only[\s\S]*bootstrap_sequence[\s\S]*create_node_enrollment_grant[\s\S]*attach_worker_node[\s\S]*inspect_status_logs_artifacts[\s\S]*revoke_access/
);
expect(
coordinator,
"coordinator reverse-streams verified retained artifact bytes through a bounded spool",
/struct ArtifactReverseTransfer[\s\S]*spool: tempfile::NamedTempFile[\s\S]*received_bytes: u64[\s\S]*delivered_offset: u64[\s\S]*handle_open_artifact_download_stream[\s\S]*read_exact\(&mut content\)[\s\S]*charge_download\([\s\S]*delivered_offset = end[\s\S]*BASE64_STANDARD\.encode\(content\)/
);
for (const [name, pattern] of [
["agent --json flag", /struct AgentEnrollArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
["bundle inspect --json flag", /struct BundleInspectArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
["build --json flag", /struct BuildArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
["run --json flag", /struct RunArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
["node attach --json flag", /struct AttachArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
["DAP plan --json flag", /struct DapArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
["shared scope --json flag", /struct CliScopeArgs[\s\S]*#\[arg\(long\)\]\s*json: bool/],
]) {
expect(cli, name, pattern);
}
for (const [name, pattern] of [
["human default assertion", /default output should be human-readable text, not JSON/],
[
"login plan JSON mode",
/"login",\s*"--plan",\s*"--coordinator",\s*"https:\/\/coord\.example\.test",\s*"--json"/,
],
["doctor human mode", /\["doctor"\]/],
["doctor reachability JSON mode", /doctorJson\.coordinator_reachability\.status/],
["doctor node readiness JSON mode", /doctorJson\.node_readiness_summary\.status[\s\S]*explicit_attach_required[\s\S]*missing_local_dependencies/],
["bundle inspect JSON mode", /\["bundle", "inspect", "--project", project, "--json"\]/],
["bundle inspect large input JSON mode", /large_input_policy[\s\S]*SourceSnapshot/],
["bundle inspect restart compatibility JSON mode", /restart_compatibility[\s\S]*source_edits_can_restart_from_clean_task_boundary/],
["auth expiry posture", /token_expiry_posture[\s\S]*expires_at/],
]) {
expect(outputModeSmoke, name, pattern);
}
for (const [name, pattern] of [
["environment build rejection exit code", /environmentFailure[\s\S]*assert\.strictEqual\(environmentFailure\.code, 26/],
["environment rejection machine category", /environmentReport\.machine_error\.category, "environment"/],
["fake coordinator quota rejection", /quota unavailable: resource limit exceeded for api_calls/],
["run uses JSON mode", /"run"[\s\S]*"--json"/],
["actual quota exit code", /assert\.strictEqual\(result\.code, 22/],
["actual quota resource-category assertion", /machine_error\.resource_category, "api_calls"/],
["actual quota community-tier label assertion", /machine_error\.community_tier_label,[\s\S]*"community tier"/],
["actual quota abuse-heuristics assertion", /machine_error\.private_abuse_heuristics_exposed,[\s\S]*false/],
["capability rejection exit code", /capabilityFailure[\s\S]*assert\.strictEqual\(capabilityFailure\.result\.code, 24/],
["capability rejection next action", /attach a node with the required capabilities/],
["node policy rejection exit code", /nodePolicyFailure[\s\S]*assert\.strictEqual\(nodePolicyFailure\.result\.code, 23/],
["node policy rejection next action", /check coordinator policy for this action/],
["program task failure category", /programReport\.tasks\[0\]\.machine_error\.category, "program"/],
["artifact download rejection exit code", /artifactDownload[\s\S]*assert\.strictEqual\(artifactDownload\.result\.code, 21/],
["artifact export rejection exit code", /artifactExport[\s\S]*assert\.strictEqual\(artifactExport\.result\.code, 25/],
["exit-code application in JSON", /process_exit_code_applied[\s\S]*true/],
]) {
expect(errorExitSmoke, name, pattern);
}
console.log("CLI-first contract smoke passed");

File diff suppressed because it is too large Load diff

61
scripts/cli-install-smoke.js Executable file
View file

@ -0,0 +1,61 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-cli-install-"));
const installRoot = path.join(temp, "install");
const targetDir =
process.env.DISASMER_CLI_INSTALL_CARGO_TARGET_DIR ||
process.env.CARGO_TARGET_DIR ||
path.join(repo, "target");
const project = path.join(repo, "examples/launch-build-demo");
const binName = process.platform === "win32" ? "disasmer.exe" : "disasmer";
const installedBin = path.join(installRoot, "bin", binName);
try {
cp.execFileSync(
"cargo",
[
"install",
"--path",
"crates/disasmer-cli",
"--bin",
"disasmer",
"--root",
installRoot,
"--debug"
],
{
cwd: repo,
env: {
...process.env,
CARGO_TARGET_DIR: targetDir
},
stdio: "inherit"
}
);
assert(fs.existsSync(installedBin), "installed disasmer binary must exist");
const inspection = JSON.parse(
cp.execFileSync(
installedBin,
["bundle", "inspect", "--project", project, "--json"],
{ cwd: repo, encoding: "utf8" }
)
);
assert.strictEqual(inspection.project, project);
assert.strictEqual(inspection.metadata.embeds_full_container_images, false);
assert(inspection.metadata.environments.some((env) => env.name === "linux"));
assert(inspection.metadata.selected_inputs.some((input) => input.path === "src/build.rs"));
} finally {
fs.rmSync(temp, { recursive: true, force: true });
}
console.log("CLI install smoke passed");

269
scripts/cli-local-run-smoke.js Executable file
View file

@ -0,0 +1,269 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const { configurePodmanTestEnvironment } = require("./podman-test-env");
const repo = path.resolve(__dirname, "..");
configurePodmanTestEnvironment(repo);
if (
!process.env.DISASMER_PODMAN_NIX_SHELL &&
cp.spawnSync("podman", ["--version"], { stdio: "ignore" }).status !== 0 &&
cp.spawnSync("nix", ["--version"], { stdio: "ignore" }).status === 0
) {
cp.execFileSync(
"nix",
["shell", "nixpkgs#podman", "--command", "node", __filename],
{
cwd: repo,
env: {
...process.env,
DISASMER_PODMAN_NIX_SHELL: "1",
},
stdio: "inherit",
}
);
process.exit(0);
}
const project = path.join(repo, "examples/launch-build-demo");
cp.execFileSync(
"cargo",
["build", "-q", "-p", "disasmer-node", "--bin", "disasmer-node"],
{ cwd: repo, stdio: "inherit" }
);
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function runCli(args, env = {}) {
return new Promise((resolve, reject) => {
const child = cp.spawn(
"cargo",
["run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--", ...args],
{
cwd: repo,
env: {
...process.env,
...env
}
}
);
const cliPid = child.pid;
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.on("exit", (code) => {
if (code !== 0) {
reject(new Error(`CLI run failed with code ${code}\n${stderr}`));
return;
}
try {
resolve({ pid: cliPid, report: JSON.parse(stdout) });
} catch (error) {
reject(new Error(`CLI output was not JSON: ${stdout}\n${error.stack || error.message}`));
}
});
});
}
(async () => {
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback"
],
{ cwd: repo }
);
assert(Number.isInteger(coordinator.pid));
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const { pid: cliPid, report } = await runCli([
"run",
"--coordinator",
`${addr.host}:${addr.port}`,
"--project",
project,
"--json",
]);
assert(Number.isInteger(cliPid));
assert.notStrictEqual(cliPid, coordinator.pid);
assert.strictEqual(report.plan.entry, "build");
assert.deepStrictEqual(report.plan.session, "Anonymous");
assert.strictEqual(report.boundary.cli_process_started_node_process, true);
assert.strictEqual(report.boundary.cli_process_started_coordinator_process, false);
assert(Number.isInteger(report.boundary.spawned_node_process_id));
assert.notStrictEqual(report.boundary.spawned_node_process_id, cliPid);
assert.notStrictEqual(report.boundary.spawned_node_process_id, coordinator.pid);
assert.strictEqual(report.boundary.node_session_requests, 0);
assert.strictEqual(report.node_report.node_status, "completed");
assert.strictEqual(report.node_report.execution_substrate, "wasm");
assert.strictEqual(report.node_report.task_spawn_host_import, true);
assert.strictEqual(
report.node_report.pre_node_process_status.processes.length,
1
);
assert.deepStrictEqual(
report.node_report.pre_node_process_status.processes[0].connected_nodes,
[]
);
assert.strictEqual(
report.node_report.pre_node_process_status.processes[0].main_state,
"running"
);
assert.strictEqual(
report.node_report.pre_node_process_status.processes[0].main_wait_state,
"waiting_for_node",
"the coordinator must expose that the capless main is parked on placement before a node exists"
);
assert.strictEqual(
report.node_report.pre_node_process_status.processes[0].main_task_instance,
report.node_report.run.task_instance
);
assert.strictEqual(report.node_report.run.status, "main_launched");
assert.strictEqual(report.node_report.join.type, "task_joined");
const process = report.node_report.run.process;
assert.strictEqual(process, "vp-current");
const events = await send(addr, {
type: "list_task_events",
tenant: "tenant",
project: "project",
actor_user: "user",
process
});
assert.strictEqual(events.type, "task_events");
assert(events.events.length >= 4);
assert(
events.events
.filter((event) => event.executor === "node")
.every((event) => event.node === "node-cli-local")
);
assert(
events.events.some(
(event) =>
event.executor === "coordinator_main" &&
event.node === "coordinator-main"
)
);
assert(events.events.every((event) => event.process === process));
assert.deepStrictEqual(
new Set(events.events.map((event) => event.task_definition)),
new Set([
report.node_report.run.task_definition,
"prepare_source",
"compile_linux",
"package_release",
])
);
assert.strictEqual(
new Set(events.events.map((event) => event.task)).size,
events.events.length,
"every live task event must retain its unique instance identity"
);
assert(
events.events.some(
(event) => event.task === report.node_report.run.task_instance
)
);
assert(events.events.some((event) => event.task.endsWith(":child:1")));
assert(events.events.some((event) => event.task.endsWith(":child:2")));
assert(events.events.some((event) => event.task.endsWith(":child:3")));
assert(events.events.some((event) => event.artifact_path));
} finally {
coordinator.kill("SIGTERM");
}
const { pid: autoCliPid, report: autoReport } = await runCli([
"run",
"--local",
"--project",
project,
"--json",
]);
assert(Number.isInteger(autoCliPid));
assert.strictEqual(autoReport.plan.entry, "build");
assert.deepStrictEqual(autoReport.plan.coordinator, "LocalOnly");
assert.deepStrictEqual(autoReport.plan.session, "Anonymous");
assert.strictEqual(autoReport.boundary.cli_process_started_node_process, true);
assert.strictEqual(autoReport.boundary.cli_process_started_coordinator_process, true);
assert.match(autoReport.boundary.coordinator_address, /^127\.0\.0\.1:\d+$/);
assert(Number.isInteger(autoReport.boundary.coordinator_process_id));
assert(Number.isInteger(autoReport.boundary.spawned_node_process_id));
assert.notStrictEqual(autoReport.boundary.coordinator_process_id, autoCliPid);
assert.notStrictEqual(autoReport.boundary.spawned_node_process_id, autoCliPid);
assert.notStrictEqual(
autoReport.boundary.spawned_node_process_id,
autoReport.boundary.coordinator_process_id
);
assert.strictEqual(autoReport.boundary.node_session_requests, 0);
assert.strictEqual(autoReport.node_report.node_status, "completed");
assert.strictEqual(autoReport.node_report.execution_substrate, "wasm");
assert.strictEqual(autoReport.node_report.task_spawn_host_import, true);
assert.strictEqual(autoReport.node_report.run.status, "main_launched");
assert.strictEqual(autoReport.node_report.join.type, "task_joined");
console.log("CLI local run smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,72 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const coordinator = "https://coord.example.test";
const defaultHostedCoordinatorEndpoint = "https://disasmer.michelpaulissen.com";
function disasmer(args) {
return JSON.parse(
cp.execFileSync(
"cargo",
["run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--", ...args],
{ cwd: repo, encoding: "utf8" }
)
);
}
function disasmerRaw(args, env = {}) {
return cp.spawnSync(
"cargo",
["run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--", ...args],
{
cwd: repo,
encoding: "utf8",
env: {
...process.env,
...env,
},
}
);
}
const browser = disasmer(["login", "--plan", "--coordinator", coordinator, "--json"]);
assert.strictEqual(browser.coordinator, coordinator);
assert(browser.human_flow.Browser, "browser login should be available for human users");
assert.strictEqual(browser.human_flow.Browser.authorization_url, null);
assert.strictEqual(browser.human_flow.Browser.server_owns_state, true);
assert.strictEqual(browser.human_flow.Browser.server_owns_nonce, true);
assert.strictEqual(browser.human_flow.Browser.pkce_required, true);
assert.strictEqual(browser.human_flow.Browser.hosted_callback, true);
assert.strictEqual(browser.human_flow.Browser.cli_receives_provider_authorization_code, false);
assert.strictEqual(browser.human_flow.Browser.cli_submits_identity_claims, false);
const defaultBrowser = disasmer(["login", "--plan", "--json"]);
assert.strictEqual(defaultBrowser.coordinator, defaultHostedCoordinatorEndpoint);
assert(defaultBrowser.human_flow.Browser);
const nonInteractiveBrowser = disasmerRaw(
["login", "--browser", "--non-interactive", "--coordinator", coordinator, "--json"],
{
DISASMER_BROWSER_OPEN_COMMAND:
"node -e 'require(\"fs\").writeFileSync(\"/tmp/disasmer-browser-should-not-open\", \"opened\")'",
}
);
assert.strictEqual(nonInteractiveBrowser.status, 20, nonInteractiveBrowser.stderr);
assert.doesNotMatch(nonInteractiveBrowser.stderr, /Opening Disasmer browser login/);
const nonInteractiveReport = JSON.parse(nonInteractiveBrowser.stdout);
assert.strictEqual(nonInteractiveReport.status, "authentication_required");
assert.strictEqual(nonInteractiveReport.non_interactive, true);
assert.strictEqual(nonInteractiveReport.browser_opened, false);
assert.strictEqual(nonInteractiveReport.machine_error.category, "authentication");
assert.strictEqual(nonInteractiveReport.machine_error.stable_exit_code, 20);
assert(
nonInteractiveReport.machine_error.next_actions.includes(
"rerun without --non-interactive to open the browser"
)
);
console.log("CLI login smoke passed");

View file

@ -0,0 +1,182 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const project = path.join(repo, "examples/launch-build-demo");
const isolatedCwd = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-cli-output-"));
function disasmer(args, env = {}, cwd = repo) {
return cp.execFileSync(
"cargo",
[
"run",
"-q",
"--manifest-path",
path.join(repo, "Cargo.toml"),
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
...args,
],
{
cwd,
encoding: "utf8",
env: {
...process.env,
...env,
},
}
);
}
function json(args, env, cwd) {
return JSON.parse(disasmer(args, env, cwd));
}
function assertHuman(name, output, requiredPatterns) {
assert(
!output.trimStart().startsWith("{"),
`${name} default output should be human-readable text, not JSON`
);
for (const pattern of requiredPatterns) {
assert.match(output, pattern, `${name} human output missing ${pattern}`);
}
}
const helpHuman = disasmer(["help"]);
assertHuman("help", helpHuman, [
/Primary workflow:/,
/disasmer login --browser/,
/disasmer project init/,
/disasmer node attach; disasmer-node --worker/,
/Disasmer: Launch Virtual Process/,
/Hosted account creation happens in the browser login flow/,
/--json/,
]);
const loginHuman = disasmer([
"login",
"--plan",
"--coordinator",
"https://coord.example.test",
]);
assertHuman("login", loginHuman, [
/Disasmer login/,
/flow: browser/,
]);
const loginJson = json([
"login",
"--plan",
"--coordinator",
"https://coord.example.test",
"--json",
]);
assert.strictEqual(loginJson.coordinator, "https://coord.example.test");
assert(loginJson.human_flow.Browser);
assert.strictEqual(loginJson.human_flow.Browser.hosted_callback, true);
assert.strictEqual(loginJson.human_flow.Browser.cli_submits_identity_claims, false);
const doctorHuman = disasmer(["doctor"]);
assertHuman("doctor", doctorHuman, [
/Disasmer doctor/,
/coordinator reachability: not_configured/,
/dependencies:/,
/auth:/,
/node capabilities:/,
/node readiness: (ready_to_attach|local_dependencies_missing|limited_capabilities)/,
/node next:/,
]);
const doctorJson = json(["doctor", "--json"]);
assert.strictEqual(doctorJson.coordinator_reachability.checked, false);
assert.strictEqual(doctorJson.coordinator_reachability.status, "not_configured");
assert(
["ready_to_attach", "local_dependencies_missing", "limited_capabilities"].includes(
doctorJson.node_readiness_summary.status
)
);
assert.strictEqual(doctorJson.node_readiness_summary.explicit_attach_required, true);
assert.strictEqual(
doctorJson.node_readiness_summary.command_execution_capability,
true
);
assert(Array.isArray(doctorJson.node_readiness_summary.missing_local_dependencies));
assert(doctorJson.node_readiness_summary.next_actions.length >= 2);
const authJson = json(["auth", "status", "--json"], {
DISASMER_TOKEN: "token",
DISASMER_TOKEN_EXPIRES_AT: "2026-07-04T00:00:00Z",
}, isolatedCwd);
assert.strictEqual(authJson.session.kind, "human");
assert.strictEqual(authJson.session.token_expiry_posture, "expires_at");
assert.strictEqual(authJson.session.expires_at, "2026-07-04T00:00:00Z");
assert.strictEqual(authJson.coordinator_account_status.checked, false);
assert.strictEqual(authJson.coordinator_account_status.account_status, "unknown");
assert.strictEqual(
authJson.coordinator_account_status.private_moderation_details_exposed,
false
);
const inspectHuman = disasmer(["bundle", "inspect", "--project", project]);
assertHuman("bundle inspect", inspectHuman, [
/Disasmer bundle inspect/,
/bundle: sha256:/,
/environments:/,
]);
const inspectJson = json(["bundle", "inspect", "--project", project, "--json"]);
assert.strictEqual(inspectJson.project, project);
assert.match(inspectJson.metadata.identity, /^sha256:/);
assert.match(inspectJson.metadata.wasm_code, /^sha256:/);
assert.strictEqual(inspectJson.metadata.task_metadata.default_entrypoint, "build");
assert.deepStrictEqual(inspectJson.metadata.task_metadata.entrypoints, [
"build",
"fail",
"restart",
]);
assert.strictEqual(
inspectJson.metadata.source_metadata.transfer_policy.coordinator_receives_source_bytes_by_default,
false
);
assert.strictEqual(
inspectJson.metadata.source_metadata.transfer_policy.default_full_repo_tarball,
false
);
assert.strictEqual(inspectJson.metadata.debug_metadata.dap_virtual_process, true);
assert.strictEqual(
inspectJson.metadata.large_input_policy.selected_inputs_are_content_digests,
true
);
assert.strictEqual(inspectJson.metadata.large_input_policy.selected_input_bytes_included, false);
assert.strictEqual(inspectJson.metadata.large_input_policy.full_repository_bytes_included, false);
assert.strictEqual(
inspectJson.metadata.large_input_policy.silent_task_argument_serialization,
false
);
assert(inspectJson.metadata.large_input_policy.supported_handle_types.includes("SourceSnapshot"));
assert.strictEqual(
inspectJson.metadata.restart_compatibility.source_edits_can_restart_from_clean_task_boundary,
true
);
assert.strictEqual(
inspectJson.metadata.restart_compatibility.requires_clean_checkpoint_boundary,
true
);
assert.strictEqual(
inspectJson.metadata.restart_compatibility.compares_task_abi,
inspectJson.metadata.task_metadata.task_abi
);
assert.strictEqual(
inspectJson.metadata.restart_compatibility.incompatible_changes_require_whole_process_restart,
true
);
console.log("CLI output mode smoke passed");

View file

@ -0,0 +1,86 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const maxProductionLines = 1000;
const ignoredDirs = new Set([".git", ".cache", ".local", "target", "node_modules"]);
const rootIgnoredDirs = new Set(["experiments"]);
function isTestRustFile(relativePath) {
const normalized = relativePath.split(path.sep).join("/");
return (
normalized.endsWith("/tests.rs") ||
normalized.includes("/tests/") ||
normalized.endsWith("_test.rs")
);
}
function lineCount(source) {
return source.endsWith("\n")
? source.split("\n").length - 1
: source.split("\n").length;
}
function productionSource(source) {
// A trailing cfg(test) module is not compiled into the product and therefore
// is not production business logic. Keeping it next to the implementation is
// useful when it exercises private invariants; count only the source before
// that explicitly test-only suffix.
const testModule = /^#\[cfg\(test\)\]\r?\nmod\s+[A-Za-z_][A-Za-z0-9_]*\s*\{/m.exec(source);
return testModule ? source.slice(0, testModule.index) : source;
}
function walk(directory, results = []) {
const entries = fs.readdirSync(directory, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(directory, entry.name);
const relativePath = path.relative(repo, fullPath);
if (entry.isDirectory()) {
if (ignoredDirs.has(entry.name)) continue;
if (!relativePath.includes(path.sep) && rootIgnoredDirs.has(entry.name)) continue;
walk(fullPath, results);
continue;
}
if (entry.isFile() && entry.name.endsWith(".rs")) {
results.push(relativePath);
}
}
return results;
}
const oversizedProductionFiles = [];
const oversizedTestFiles = [];
for (const relativePath of walk(repo)) {
const source = fs.readFileSync(path.join(repo, relativePath), "utf8");
const testOnlyFile = isTestRustFile(relativePath);
const lines = lineCount(testOnlyFile ? source : productionSource(source));
if (lines <= maxProductionLines) continue;
const entry = { path: relativePath, lines };
if (testOnlyFile) {
oversizedTestFiles.push(entry);
} else {
oversizedProductionFiles.push(entry);
}
}
assert.deepStrictEqual(
oversizedProductionFiles,
[],
`production Rust files must stay at or below ${maxProductionLines} lines; split business logic before adding more code`
);
if (oversizedTestFiles.length > 0) {
console.log(
`Code-size guard ignored ${oversizedTestFiles.length} oversized test-only Rust file(s): ${oversizedTestFiles
.map((entry) => `${entry.path} (${entry.lines})`)
.join(", ")}`
);
}
console.log("Code-size guard passed");

View file

@ -0,0 +1,43 @@
let requestId = 0;
function coordinatorWireRequest(payload, prefix = "acceptance") {
if (payload && payload.type === "coordinator_request") return payload;
if (!payload || typeof payload.type !== "string" || !payload.type.trim()) {
throw new Error("coordinator payload must have a non-empty type");
}
requestId += 1;
return {
type: "coordinator_request",
protocol_version: 1,
request_id: `${prefix}-${process.pid}-${requestId}`,
operation: payload.type,
authentication: authenticationMetadata(payload),
payload,
};
}
function authenticationMetadata(payload) {
if (payload.type === "authenticated") {
return {
kind: "cli_session",
session: true,
request_operation: payload.request?.type || "unknown",
};
}
if (payload.type === "signed_node" || payload.node_signature) {
return { kind: "node_signature", node: payload.node || null };
}
if (payload.agent_signature) {
return {
kind: "agent_signature",
agent: payload.actor_agent || null,
fingerprint: payload.agent_public_key_fingerprint || null,
};
}
if (payload.admin_token) {
return { kind: "admin_credential" };
}
return { kind: "none" };
}
module.exports = { coordinatorWireRequest };

132
scripts/dap-client.js Normal file
View file

@ -0,0 +1,132 @@
const cp = require("child_process");
class DapClient {
constructor({
cwd = process.cwd(),
env = process.env,
command = "cargo",
args = [
"run",
"-q",
"-p",
"disasmer-dap",
"--bin",
"disasmer-debug-dap",
],
} = {}) {
this.child = cp.spawn(
command,
args,
{ cwd, env }
);
this.seq = 1;
this.buffer = Buffer.alloc(0);
this.messages = [];
this.waiters = [];
this.stderr = "";
this.child.stdout.on("data", (chunk) => {
this.buffer = Buffer.concat([this.buffer, chunk]);
this.parse();
});
this.child.stderr.on("data", (chunk) => {
this.stderr += chunk.toString();
});
this.child.on("exit", () => this.flushWaiters());
}
send(command, args = {}) {
const seq = this.seq++;
const message = { seq, type: "request", command, arguments: args };
const payload = Buffer.from(JSON.stringify(message));
this.child.stdin.write(`Content-Length: ${payload.length}\r\n\r\n`);
this.child.stdin.write(payload);
return seq;
}
async response(seq, command) {
const message = await this.waitFor(
(item) =>
item.type === "response" &&
item.request_seq === seq &&
item.command === command
);
if (!message.success) {
throw new Error(
`DAP ${command} failed: ${message.message || JSON.stringify(message)}\nAdapter stderr:\n${this.stderr}`
);
}
return message;
}
async failure(seq, command) {
const message = await this.waitFor(
(item) =>
item.type === "response" &&
item.request_seq === seq &&
item.command === command
);
if (message.success) {
throw new Error(`DAP ${command} unexpectedly succeeded`);
}
return message;
}
waitFor(predicate, timeoutMs = 120000) {
const existing = this.messages.find(predicate);
if (existing) return Promise.resolve(existing);
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
this.child.kill("SIGKILL");
const recent = this.messages
.slice(-10)
.map((message) => JSON.stringify(message))
.join("\n");
reject(
new Error(
`timed out waiting for DAP message\nRecent DAP messages:\n${recent}\nAdapter stderr:\n${this.stderr}`
)
);
}, timeoutMs);
this.waiters.push({ predicate, resolve, timer });
});
}
parse() {
while (true) {
const headerEnd = this.buffer.indexOf("\r\n\r\n");
if (headerEnd < 0) return;
const header = this.buffer.slice(0, headerEnd).toString();
const match = header.match(/Content-Length: (\d+)/i);
if (!match) throw new Error(`bad DAP header: ${header}`);
const length = Number(match[1]);
const start = headerEnd + 4;
const end = start + length;
if (this.buffer.length < end) return;
const payload = this.buffer.slice(start, end).toString();
this.buffer = this.buffer.slice(end);
this.messages.push(JSON.parse(payload));
this.flushWaiters();
}
}
flushWaiters() {
for (const waiter of [...this.waiters]) {
const message = this.messages.find(waiter.predicate);
if (!message) continue;
clearTimeout(waiter.timer);
this.waiters.splice(this.waiters.indexOf(waiter), 1);
waiter.resolve(message);
}
}
async close() {
if (this.child.exitCode !== null) return;
const seq = this.send("disconnect");
await this.response(seq, "disconnect");
this.child.stdin.end();
}
}
module.exports = { DapClient };

363
scripts/dap-smoke.js Normal file
View file

@ -0,0 +1,363 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const { DapClient } = require("./dap-client");
(async () => {
const repo = path.resolve(__dirname, "..");
const project = path.join(repo, "examples/launch-build-demo");
const sourcePath = fs.realpathSync(path.join(project, "src/build.rs"));
const sourceLines = fs.readFileSync(sourcePath, "utf8").split(/\r?\n/);
const buildMainLine =
sourceLines.findIndex((line) => line.includes("pub async fn build_main()")) + 1;
assert(buildMainLine > 0, "flagship source must contain build_main");
const client = new DapClient();
try {
const initialize = client.send("initialize", {
adapterID: "disasmer",
linesStartAt1: true,
columnsStartAt1: true,
});
await client.response(initialize, "initialize");
const launch = client.send("launch", {
entry: "build",
project,
runtimeBackend: "local-services",
});
await client.response(launch, "launch");
await client.waitFor(
(message) => message.type === "event" && message.event === "initialized"
);
const breakpoints = client.send("setBreakpoints", {
source: { path: sourcePath },
breakpoints: [{ line: buildMainLine }],
});
const breakpointResponse = await client.response(
breakpoints,
"setBreakpoints"
);
assert.strictEqual(breakpointResponse.body.breakpoints.length, 1);
assert.strictEqual(breakpointResponse.body.breakpoints[0].verified, true);
const configurationDone = client.send("configurationDone");
await client.response(configurationDone, "configurationDone");
const stopped = await client.waitFor(
(message) =>
message.type === "event" &&
message.event === "stopped" &&
message.body.reason === "breakpoint"
);
assert.strictEqual(stopped.body.allThreadsStopped, true);
assert.match(stopped.body.description, /confirmed by every active participant/i);
const threadsRequest = client.send("threads");
const threads = (await client.response(threadsRequest, "threads")).body
.threads;
const mainThread = threads.find((thread) =>
thread.name.includes("build virtual process")
);
assert(mainThread, "the running Wasm entrypoint must be a DAP virtual thread");
assert.strictEqual(stopped.body.threadId, mainThread.id);
const stackRequest = client.send("stackTrace", {
threadId: mainThread.id,
startFrame: 0,
levels: 1,
});
const stack = (await client.response(stackRequest, "stackTrace")).body
.stackFrames;
assert.strictEqual(stack.length, 1);
assert.strictEqual(stack[0].line, buildMainLine);
assert.strictEqual(stack[0].source.path, sourcePath);
assert.match(stack[0].name, /build_main::wasm/);
assert.doesNotMatch(stack[0].name, /podman|cmd\.exe|powershell|pid|native child/i);
const sourceRequest = client.send("source", { source: stack[0].source });
const source = (await client.response(sourceRequest, "source")).body;
assert.match(source.content, /build_main/);
assert.match(source.mimeType, /rust/);
const scopesRequest = client.send("scopes", { frameId: stack[0].id });
const scopes = (await client.response(scopesRequest, "scopes")).body.scopes;
const localsScope = scopes.find((scope) => scope.name === "Source Locals");
const wasmScope = scopes.find((scope) => scope.name === "Wasm Frame Locals");
const argsScope = scopes.find(
(scope) => scope.name === "Task Args and Handles"
);
const runtimeScope = scopes.find(
(scope) => scope.name === "Disasmer Runtime"
);
assert(localsScope && wasmScope && argsScope && runtimeScope);
const localsRequest = client.send("variables", {
variablesReference: localsScope.variablesReference,
});
const locals = (await client.response(localsRequest, "variables")).body
.variables;
assert(
locals.some(
(variable) =>
variable.name === "unavailable-local-diagnostic" &&
String(variable.value).includes("cannot be inspected")
)
);
const wasmRequest = client.send("variables", {
variablesReference: wasmScope.variablesReference,
});
const wasmLocals = (await client.response(wasmRequest, "variables")).body
.variables;
assert.deepStrictEqual(
wasmLocals.map((variable) => variable.name),
["wasm-local-diagnostic"]
);
assert.match(wasmLocals[0].value, /did not report inspectable Wasm frame locals/);
const argsRequest = client.send("variables", {
variablesReference: argsScope.variablesReference,
});
const args = (await client.response(argsRequest, "variables")).body.variables;
assert.deepStrictEqual(
args.map((variable) => variable.name),
["runtime-boundary-diagnostic"]
);
assert.match(args[0].value, /reported no task arguments or handles/);
const runtimeRequest = client.send("variables", {
variablesReference: runtimeScope.variablesReference,
});
const runtime = (await client.response(runtimeRequest, "variables")).body
.variables;
const value = (name) => runtime.find((variable) => variable.name === name)?.value;
assert.strictEqual(value("runtime_backend"), "LocalServices");
assert.strictEqual(value("state"), "Frozen");
assert.strictEqual(value("debug_epoch"), 1);
assert.strictEqual(value("coordinator_task_events"), 0);
assert.match(
String(value("command_status")),
/frozen through local services at executing Wasm probe/
);
const step = client.send("next", { threadId: mainThread.id });
const stepFailure = await client.failure(step, "next");
assert.match(stepFailure.message, /source stepping is not yet available/i);
assert.match(stepFailure.message, /synthetic step/i);
const restart = client.send("restartFrame", { frameId: stack[0].id });
const restartFailure = await client.failure(restart, "restartFrame");
assert.match(restartFailure.message, /checkpoint boundary|still active/i);
const incompatibleRestart = client.send("restartFrame", {
frameId: stack[0].id,
sourceCompatibility: "incompatible",
});
const incompatibleFailure = await client.failure(
incompatibleRestart,
"restartFrame"
);
assert.match(incompatibleFailure.message, /incompatible source edit/i);
assert.match(incompatibleFailure.message, /whole virtual-process restart/i);
await client.close();
} catch (error) {
if (client.child.exitCode === null) client.child.kill("SIGKILL");
throw error;
}
const failMainLine =
sourceLines.findIndex((line) => line.includes("pub async fn fail_main()")) + 1;
assert(failMainLine > 0, "flagship source must contain fail_main");
const taskTrapLine =
sourceLines.findIndex((line) => line.includes("fn task_trap(")) + 1;
assert(taskTrapLine > 0, "flagship source must contain task_trap");
const restartClient = new DapClient();
try {
const initialize = restartClient.send("initialize", {
adapterID: "disasmer",
linesStartAt1: true,
columnsStartAt1: true,
});
await restartClient.response(initialize, "initialize");
const launch = restartClient.send("launch", {
entry: "fail",
project,
runtimeBackend: "local-services",
});
await restartClient.response(launch, "launch");
await restartClient.waitFor(
(message) => message.type === "event" && message.event === "initialized"
);
const breakpoints = restartClient.send("setBreakpoints", {
source: { path: sourcePath },
breakpoints: [{ line: failMainLine }, { line: taskTrapLine }],
});
const breakpointResponse = await restartClient.response(
breakpoints,
"setBreakpoints"
);
assert.deepStrictEqual(
breakpointResponse.body.breakpoints.map((breakpoint) => breakpoint.verified),
[true, true]
);
const configurationDone = restartClient.send("configurationDone");
await restartClient.response(configurationDone, "configurationDone");
const initialStop = await restartClient.waitFor(
(message) =>
message.type === "event" &&
message.event === "stopped" &&
message.body.reason === "breakpoint"
);
assert.strictEqual(initialStop.body.allThreadsStopped, true);
const threadsRequest = restartClient.send("threads");
const threads = (
await restartClient.response(threadsRequest, "threads")
).body.threads;
const failThread = threads.find(
(thread) => thread.id === initialStop.body.threadId
);
assert(failThread, "failed entrypoint must remain a virtual task thread");
const stackRequest = restartClient.send("stackTrace", {
threadId: failThread.id,
startFrame: 0,
levels: 1,
});
const failedStack = (
await restartClient.response(stackRequest, "stackTrace")
).body.stackFrames;
assert.strictEqual(failedStack[0].line, failMainLine);
const continueRequest = restartClient.send("continue", {
threadId: failThread.id,
});
await restartClient.response(continueRequest, "continue");
const childStop = await restartClient.waitFor(
(message) =>
message.seq > initialStop.seq &&
message.type === "event" &&
message.event === "stopped" &&
message.body.reason === "breakpoint",
70000
);
assert.strictEqual(childStop.body.allThreadsStopped, true);
const childThreadsRequest = restartClient.send("threads");
const childThreads = (
await restartClient.response(childThreadsRequest, "threads")
).body.threads;
const childThread = childThreads.find(
(thread) => thread.id === childStop.body.threadId
);
assert(childThread, "executing child task must become a DAP virtual thread");
assert.notStrictEqual(childThread.id, failThread.id);
assert.match(childThread.name, /task trap/i);
const childStackRequest = restartClient.send("stackTrace", {
threadId: childThread.id,
startFrame: 0,
levels: 1,
});
const childStack = (
await restartClient.response(childStackRequest, "stackTrace")
).body.stackFrames;
assert.strictEqual(childStack[0].line, taskTrapLine);
assert.match(childStack[0].name, /task_trap::wasm/);
const childScopesRequest = restartClient.send("scopes", {
frameId: childStack[0].id,
});
const childScopes = (
await restartClient.response(childScopesRequest, "scopes")
).body.scopes;
const childArgsScope = childScopes.find(
(scope) => scope.name === "Task Args and Handles"
);
assert(childArgsScope, "child task argument scope must be present");
const childArgsRequest = restartClient.send("variables", {
variablesReference: childArgsScope.variablesReference,
});
const childArgs = (
await restartClient.response(childArgsRequest, "variables")
).body.variables;
assert(
childArgs.some(
(variable) =>
variable.name === "arg_0" &&
/SmallJson\(Number\(0\)\)/.test(String(variable.value))
),
"child task argument must come from the frozen node participant"
);
const parentScopesRequest = restartClient.send("scopes", {
frameId: failedStack[0].id,
});
const parentScopes = (
await restartClient.response(parentScopesRequest, "scopes")
).body.scopes;
const parentArgsScope = parentScopes.find(
(scope) => scope.name === "Task Args and Handles"
);
const parentArgsRequest = restartClient.send("variables", {
variablesReference: parentArgsScope.variablesReference,
});
const parentArgs = (
await restartClient.response(parentArgsRequest, "variables")
).body.variables;
assert(
parentArgs.some(
(variable) =>
/^task_handle_\d+$/.test(variable.name) &&
/definition=task_trap instance=ti:.*:child:\d+ state=active/.test(
variable.value
) &&
variable.type === "runtime-handle"
),
"parent task handle must come from its live Wasm host registry"
);
const continueChildRequest = restartClient.send("continue", {
threadId: childThread.id,
});
await restartClient.response(continueChildRequest, "continue");
await restartClient.waitFor(
(message) =>
message.seq > childStop.seq &&
message.type === "event" &&
message.event === "terminated"
);
const restartRequest = restartClient.send("restartFrame", {
frameId: failedStack[0].id,
});
await restartClient.response(restartRequest, "restartFrame");
const restartedStop = await restartClient.waitFor(
(message) =>
message.type === "event" &&
message.event === "stopped" &&
/Restarted main from the rebuilt bundle/.test(message.body.description)
);
assert.strictEqual(restartedStop.body.allThreadsStopped, true);
const restartedStackRequest = restartClient.send("stackTrace", {
threadId: restartedStop.body.threadId,
startFrame: 0,
levels: 1,
});
const restartedStack = (
await restartClient.response(restartedStackRequest, "stackTrace")
).body.stackFrames;
assert.strictEqual(restartedStack[0].line, failMainLine);
await restartClient.close();
} catch (error) {
if (restartClient.child.exitCode === null) restartClient.child.kill("SIGKILL");
throw error;
}
console.log("DAP smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

413
scripts/docs-smoke.js Normal file
View file

@ -0,0 +1,413 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const readmePath = path.join(repo, "README.md");
const filteredPublicTree = fs.existsSync(path.join(repo, "DISASMER_PUBLIC_TREE.json"));
if (!fs.existsSync(readmePath)) throw new Error("README.md is missing");
const readme = fs.readFileSync(readmePath, "utf8");
const canonicalPublicDocs = [
"architecture.md",
"security.md",
"task-abi.md",
"artifacts.md",
"debugging.md",
"self-hosting.md",
];
for (const file of canonicalPublicDocs) {
const documentationPath = path.join(repo, "docs", file);
assert(
fs.existsSync(documentationPath),
`canonical public documentation is missing docs/${file}`
);
assert(
fs.readFileSync(documentationPath, "utf8").trim().length > 400,
`canonical public documentation docs/${file} is unexpectedly empty`
);
}
if (filteredPublicTree) {
assert.match(readme, /^# Disasmer/m, "filtered public README must identify the product");
assert.match(readme, /## Quickstart/, "filtered public README must retain the quickstart");
assert.match(
readme,
/docs\/architecture\.md/,
"filtered public README must link canonical public documentation"
);
assert.match(
readme,
/cargo install --path crates\/disasmer-cli --bin disasmer/,
"filtered public README must retain CLI installation"
);
assert.doesNotMatch(
readme,
/DISASMER_PUBLISH_PUBLIC_TREE|DISASMER_FORGEJO_TOKEN|public-release-manifest\.json|public-release-dryrun-e2e\.json/,
"filtered public README must not expose release-internal dry-run mechanics"
);
console.log("Docs smoke passed for filtered public product README");
process.exit(0);
}
const dryrunDoc = fs.readFileSync(
path.join(repo, "public_release_dryrun.md"),
"utf8"
);
const userFacingDocs = [
"README.md",
"public_release_dryrun.md",
"MVP.md",
"acceptance_criteria.md",
"acceptance_criteria_phase2.md",
"cli_acceptance_criteria.md",
"website_mvp_inventory.md",
"phase_3_acceptance_criteria.md",
].map((file) => [file, fs.readFileSync(path.join(repo, file), "utf8")]);
const publicAcceptance = fs.readFileSync(
path.join(repo, "scripts/acceptance-public.sh"),
"utf8"
);
const publicSplit = fs.readFileSync(
path.join(repo, "scripts/verify-public-split.sh"),
"utf8"
);
const privateAcceptance = fs.readFileSync(
path.join(repo, "scripts/acceptance-private.sh"),
"utf8"
);
const requiredReadmePatterns = [
["quickstart heading", /## Quickstart/],
["workspace build", /cargo build --workspace/],
["CLI install", /cargo install --path crates\/disasmer-cli --bin disasmer/],
["node install", /cargo install --path crates\/disasmer-node --bin disasmer-node/],
[
"coordinator install",
/cargo install --path crates\/disasmer-coordinator --bin disasmer-coordinator/,
],
["DAP install", /cargo install --path crates\/disasmer-dap --bin disasmer-debug-dap/],
["VS Code local extension", /code --extensionDevelopmentPath/],
["local coordinator", /disasmer-coordinator --listen/],
["node attach", /disasmer node attach --coordinator/],
["automatic local run", /disasmer run --local --project examples\/launch-build-demo build/],
["demo run", /disasmer run --local --coordinator/],
["entrypoint selection", /disasmer run \[entry\]/],
["implicit hosted mode", /uses the hosted coordinator/],
["local override", /force local coordinator mode/],
["project override", /--project[\s\S]*overrides the project\s+directory/],
["VS Code debug", /Disasmer: Launch\s+Virtual Process/],
["artifact download smoke", /node scripts\/artifact-download-smoke\.js/],
["artifact export smoke", /node scripts\/artifact-export-smoke\.js/],
["acceptance report smoke", /node scripts\/acceptance-report-smoke\.js/],
["CLI-first acceptance gate", /scripts\/acceptance-cli-first\.sh/],
["CLI-first acceptance before e2e", /CLI-first non-e2e gate before any final public-release e2e attempt/],
["public private boundary smoke", /node scripts\/public-private-boundary-smoke\.js/],
["release blocker smoke", /node scripts\/release-blocker-smoke\.js/],
["explicit export", /attached receiver node or user-provided\s+storage integration/],
["cleanup", /Cleanup for the local quickstart/],
["flush docs", /`flush\(\)` publishes metadata/],
["sync docs", /`sync\(\)` is explicit/],
["storage integration is user code", /User-provided storage\/export integrations are ordinary project code or external\s+commands/],
["no managed artifact store feature", /does not provide\s+or manage an explicit artifact-store feature/],
["best-effort retention", /best-effort retained on nodes/],
[
"secure downloads",
/Download links are scoped to the tenant, project, process, artifact, actor, and policy context, expire after a bounded TTL, can be revoked/,
],
["node trust", /Users attach their own nodes for real work/],
["self-hosted trusted teams", /self-hosted local clouds, trusted teams, or VPN deployments/],
["self-hosted coordinator smoke", /node scripts\/self-hosted-coordinator-smoke\.js/],
["wasmtime node smoke", /node scripts\/wasmtime-node-smoke\.js/],
["wasmtime command host import", /versioned `disasmer\.command_run_v1` host capability/],
["Windows sandbox limitation", /Production-grade managed Windows sandboxing is behind an explicit backend stub/],
["hosted community limit", /community tier does not provide arbitrary hosted native commands or hosted containers/],
["browser login", /disasmer login --browser/],
["public-key agents", /disasmer agent enroll --public-key/],
["noninteractive agent CLI", /DISASMER_AGENT_PRIVATE_KEY=<agent-private-key> disasmer run --non-interactive build/],
["agent key lifecycle", /register, list, rotate, and revoke an agent key/],
["capability auto-detect", /auto-detects OS, architecture/],
["capability override", /--cap <name>/],
["non-Git source provider", /Non-Git source providers can implement the public source-provider interface/],
["first-run diagnostics", /## First-Run Diagnostics/],
["missing nodes diagnostic", /Missing nodes/],
["missing environment diagnostic", /Missing environments/],
["quota diagnostic", /Quota limits/],
["unavailable artifact diagnostic", /Unavailable artifacts/],
["auth diagnostic", /Auth failures/],
["debug freeze diagnostic", /Failed debug freezes/],
["source-provider diagnostic", /Source-provider capability gaps/],
["browser and VS Code report metadata", /browser\/VS Code harness metadata/],
["Podman incomplete report", /Linux Podman backend behavior is marked `incomplete`/],
["manual Windows validation workflow", /manual `Windows validation`\s+workflow/],
["intermittent Forgejo Windows runner", /intermittent Windows runner/],
["Windows validation env gate", /DISASMER_WINDOWS_VALIDATION = "forgejo-windows-runner"/],
["Windows validation attach", /runs `disasmer node attach`/],
];
const requiredDryrunPatterns = [
["dry-run runbook status", /source-side release runbook, not public product quickstart/],
["public dry-run hosted coordinator endpoint", /https:\/\/disasmer\.michelpaulissen\.com/],
["public dry-run DNS record", /record is live[\s\S]*no resolver override is required|DNS record is deployed[\s\S]*no resolver override is required/],
["public dry-run real deployment", /real externally reachable service/],
["public dry-run selected users", /shared with selected users/],
["public dry-run Forgejo repo", /git\.michelpaulissen\.com/],
["public dry-run Forgejo Release assets", /Forgejo Release publishes compiled\s+assets/],
["public dry-run filters internal root markdown", /internal root Markdown/],
["public dry-run retains product README", /product-facing `README\.md` remains in the public repository/],
["public dry-run filters Forgejo workflows by default", /\.forgejo\/\*\*` by\s+default/],
["public dry-run Forgejo workflow opt in", /--include-forgejo-workflows/],
["public dry-run selected-user quickstart", /DISASMER_PUBLIC_DRYRUN_GETTING_STARTED-\*\.md/],
["public dry-run selected-user invite", /DISASMER_PUBLIC_DRYRUN_INVITE-\*\.md/],
["public dry-run resolver instructions env", /DISASMER_PUBLIC_DRYRUN_RESOLVER_INSTRUCTIONS=<instructions>/],
["public dry-run fallback hosts entry env", /DISASMER_PUBLIC_DRYRUN_HOSTS_ENTRY="<ip-address> disasmer\.michelpaulissen\.com"/],
["public dry-run deployment IP env", /DISASMER_PUBLIC_RELEASE_DRYRUN_IP=<ip-address>/],
["public dry-run prep script", /node scripts\/prepare-public-release-dryrun\.js/],
["public dry-run publish opt-in", /DISASMER_PUBLISH_PUBLIC_TREE=1/],
["public dry-run public repo remote", /DISASMER_PUBLIC_REPO_REMOTE=ssh:\/\/git\.michelpaulissen\.com/],
["public dry-run Forgejo workflow", /Public release dry run assets/],
["public dry-run manifest", /public-release-manifest\.json/],
["public dry-run release publisher", /node scripts\/publish-public-release-dryrun\.js/],
["public dry-run non-e2e preflight", /node scripts\/public-release-dryrun-preflight\.js/],
["public dry-run Forgejo token", /DISASMER_FORGEJO_TOKEN=<token>/],
["public dry-run publisher infers repo", /publisher infers the Forgejo owner and repository name/],
["public dry-run Forgejo repo owner override", /DISASMER_PUBLIC_REPO_OWNER=<owner>/],
["public dry-run Forgejo repo name override", /DISASMER_PUBLIC_REPO_NAME=<public-repo>/],
["public dry-run service smoke", /public-release-dryrun-service-smoke\.js/],
["public dry-run service address", /DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR=disasmer\.michelpaulissen\.com:443/],
["public dry-run hosted coordinator", /hosted coordinator[\s\S]*disasmer\.michelpaulissen\.com[\s\S]*private\/hosted-policy/],
["public dry-run distinguishes Core", /standalone Core coordinator remains available for local\/self-hosted use/],
["public dry-run validates both coordinators", /dry-run acceptance validates both coordinator deployments/],
["public dry-run validates Core coordinator separately", /standalone Core coordinator is validated separately/],
["public browser login control entry", /POST https:\/\/disasmer\.michelpaulissen\.com\/api\/v1\/control/],
["public browser login hosted callback", /hosted[\s\S]*\/auth\/callback|\/auth\/callback[\s\S]*hosted/],
["public browser login server authority", /hosted service creates the OIDC state, nonce, and PKCE verifier/],
["public browser test driver", /DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND/],
["browser login plan diagnostic", /disasmer login --browser --plan/],
["public dry-run deployment prep", /prepare-public-release-dryrun-deployment\.js/],
["public dry-run systemd unit", /systemd unit[\s\S]*127\.0\.0\.1:9080|loopback[\s\S]*127\.0\.0\.1:9080/],
["public dry-run e2e runner", /public-release-dryrun-e2e\.js/],
["public dry-run e2e gate env", /DISASMER_PUBLIC_RELEASE_DRYRUN_E2E=1/],
["public dry-run e2e service address", /DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR=disasmer\.michelpaulissen\.com:443/],
["public dry-run final verifier", /public-release-dryrun-final-evidence\.js/],
["public dry-run final gate env", /DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL=1/],
["public dry-run e2e evidence", /public-release-dryrun-e2e\.json/],
["public dry-run e2e checks", /downloaded release assets[\s\S]*VS Code debugger behavior[\s\S]*artifact metadata/],
["hosted Client compatibility smoke", /hosted-client-compat-smoke\.js/],
["hosted Client compatibility purpose", /Client CLI browser login[\s\S]*scoped session[\s\S]*node enrollment[\s\S]*cross-tenant denial/],
];
for (const [name, pattern] of requiredReadmePatterns) {
assert.match(readme, pattern, `README missing ${name}`);
}
for (const [name, pattern] of requiredDryrunPatterns) {
assert.match(dryrunDoc, pattern, `public release dry-run runbook missing ${name}`);
}
assert.doesNotMatch(
readme,
/DISASMER_PUBLISH_PUBLIC_TREE|DISASMER_FORGEJO_TOKEN|public-release-manifest\.json|public-release-dryrun-e2e\.json/,
"README must stay product-facing; release-internal dry-run commands belong in public_release_dryrun.md"
);
for (const [file, contents] of userFacingDocs) {
assert.doesNotMatch(
contents,
/community-tier/i,
`${file} should use "community tier" in user-facing prose`
);
}
for (const script of [publicAcceptance, publicSplit]) {
assert(
script.includes("node scripts/docs-smoke.js"),
"public acceptance gates must run docs-smoke.js"
);
assert(
script.includes("node scripts/cli-install-smoke.js"),
"public acceptance gates must run cli-install-smoke.js"
);
assert(
script.includes("node scripts/cli-output-mode-smoke.js"),
"public acceptance gates must run cli-output-mode-smoke.js"
);
assert(
script.includes("node scripts/cli-login-smoke.js"),
"public acceptance gates must run cli-login-smoke.js"
);
assert(
script.includes("node scripts/cli-error-exit-smoke.js"),
"public acceptance gates must run cli-error-exit-smoke.js"
);
assert(
script.includes("node scripts/acceptance-report-smoke.js"),
"public acceptance gates must run acceptance-report-smoke.js"
);
assert(
script.includes("node scripts/acceptance-doc-contract-smoke.js"),
"public acceptance gates must run acceptance-doc-contract-smoke.js"
);
assert(
script.includes("node scripts/acceptance-environment-contract-smoke.js"),
"public acceptance gates must run acceptance-environment-contract-smoke.js"
);
assert(
script.includes("node scripts/acceptance-evidence-contract-smoke.js"),
"public acceptance gates must run acceptance-evidence-contract-smoke.js"
);
assert(
script.includes("node scripts/public-private-boundary-smoke.js"),
"public acceptance gates must run public-private-boundary-smoke.js"
);
assert(
script.includes("node scripts/release-blocker-smoke.js"),
"public acceptance gates must run release-blocker-smoke.js"
);
assert(
script.includes("node scripts/resource-metering-contract-smoke.js"),
"public acceptance gates must run resource-metering-contract-smoke.js"
);
assert(
script.includes("node scripts/hostile-input-contract-smoke.js"),
"public acceptance gates must run hostile-input-contract-smoke.js"
);
assert(
script.includes("node scripts/tenant-isolation-contract-smoke.js"),
"public acceptance gates must run tenant-isolation-contract-smoke.js"
);
assert(
script.includes("node scripts/public-story-contract-smoke.js"),
"public acceptance gates must run public-story-contract-smoke.js"
);
assert(
script.includes("node scripts/public-release-dryrun-contract-smoke.js"),
"public acceptance gates must run public-release-dryrun-contract-smoke.js"
);
assert(
script.includes("node scripts/prepare-public-release-dryrun.js"),
"public acceptance gates must run prepare-public-release-dryrun.js"
);
assert(
script.includes("node scripts/self-hosted-coordinator-smoke.js"),
"public acceptance gates must run self-hosted-coordinator-smoke.js"
);
assert(
script.includes("node scripts/public-local-demo-matrix-smoke.js"),
"public acceptance gates must run public-local-demo-matrix-smoke.js"
);
assert(
script.includes("scripts/release-source-scan.sh"),
"public acceptance gates must run release-source-scan.sh"
);
assert(
script.includes("node scripts/flagship-demo-smoke.js"),
"public acceptance gates must run flagship-demo-smoke.js"
);
assert(
script.includes("node scripts/wasmtime-assignment-smoke.js"),
"public acceptance gates must run the real coordinator-to-Wasm assignment smoke"
);
assert(
script.includes("node scripts/sdk-spawn-runtime-smoke.js"),
"public acceptance gates must run sdk-spawn-runtime-smoke.js"
);
assert(
script.includes("node scripts/node-lifecycle-contract-smoke.js"),
"public acceptance gates must run node-lifecycle-contract-smoke.js"
);
assert(
script.includes("node scripts/artifact-export-smoke.js"),
"public acceptance gates must run artifact-export-smoke.js"
);
assert(
script.includes("node scripts/windows-validation-contract-smoke.js"),
"public acceptance gates must run windows-validation-contract-smoke.js"
);
}
assert(
publicAcceptance.includes("node scripts/podman-backend-smoke.js"),
"public acceptance must run the Linux Podman backend smoke when Podman is available"
);
assert(
publicAcceptance.includes("node scripts/wasmtime-node-smoke.js"),
"public acceptance must run the Wasmtime node smoke"
);
assert(
privateAcceptance.includes("node scripts/resource-metering-contract-smoke.js"),
"private acceptance must run resource-metering-contract-smoke.js"
);
assert(
privateAcceptance.includes("node scripts/hostile-input-contract-smoke.js"),
"private acceptance must run hostile-input-contract-smoke.js"
);
assert(
privateAcceptance.includes("node scripts/tenant-isolation-contract-smoke.js"),
"private acceptance must run tenant-isolation-contract-smoke.js"
);
assert(
privateAcceptance.includes("node scripts/acceptance-doc-contract-smoke.js"),
"private acceptance must run acceptance-doc-contract-smoke.js"
);
assert(
privateAcceptance.includes("node scripts/acceptance-environment-contract-smoke.js"),
"private acceptance must run acceptance-environment-contract-smoke.js"
);
assert(
privateAcceptance.includes("node scripts/acceptance-evidence-contract-smoke.js"),
"private acceptance must run acceptance-evidence-contract-smoke.js"
);
assert(
privateAcceptance.includes("node private/hosted-policy/scripts/hosted-deployment-smoke.js"),
"private acceptance must run hosted-deployment-smoke.js"
);
assert(
privateAcceptance.includes("node private/hosted-policy/scripts/hosted-client-compat-smoke.js"),
"private acceptance must run hosted-client-compat-smoke.js"
);
assert(
privateAcceptance.includes("node scripts/self-hosted-coordinator-smoke.js"),
"private acceptance must run self-hosted-coordinator-smoke.js before final dry-run evidence"
);
assert(
privateAcceptance.includes("node private/hosted-policy/scripts/prepare-public-release-dryrun-deployment.js"),
"private acceptance must prepare public release dry-run deployment bundle"
);
assert(
privateAcceptance.includes("node private/hosted-policy/scripts/public-release-dryrun-service-smoke.js"),
"private acceptance must be able to run public-release-dryrun-service-smoke.js"
);
for (const script of [publicAcceptance, privateAcceptance]) {
assert(
script.includes("node scripts/public-release-dryrun-final-evidence.js"),
"acceptance must be able to run public-release-dryrun-final-evidence.js"
);
assert(
script.includes("DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL"),
"acceptance must gate public-release-dryrun-final-evidence.js"
);
}
assert(
publicAcceptance.includes("node scripts/public-release-dryrun-e2e.js"),
"public acceptance must be able to run public-release-dryrun-e2e.js"
);
assert(
publicAcceptance.includes("DISASMER_PUBLIC_RELEASE_DRYRUN_E2E"),
"public acceptance must gate public-release-dryrun-e2e.js"
);
console.log("Docs smoke passed");

View file

@ -0,0 +1,148 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const extension = require("../vscode-extension/extension");
const repo = path.resolve(__dirname, "..");
const project = path.join(repo, "examples/launch-build-demo");
const source = fs.readFileSync(path.join(project, "src/build.rs"), "utf8");
const forbiddenSourceAssumptions =
/\b(?:std::fs|std::process|git|podman|docker|localhost|127\.0\.0\.1)|\/home\/|\/Users\/|C:\\Users\\/i;
const envs = extension.discoverEnvironmentNames(project);
assert.deepStrictEqual(envs, ["linux", "windows"]);
assert.deepStrictEqual(extension.diagnoseEnvReferences(source, envs), []);
assert.doesNotMatch(
source,
forbiddenSourceAssumptions,
"flagship build source must not bypass Disasmer host capabilities or rely on coordinator-side filesystem, Git, container, or machine-local assumptions"
);
const inspection = JSON.parse(
cp.execFileSync(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
"bundle",
"inspect",
"--project",
project,
"--json"
],
{ cwd: repo, encoding: "utf8" }
)
);
assert.strictEqual(inspection.project, project);
assert.strictEqual(
inspection.source_provider_manifest.coordinator_requires_checkout_access,
false
);
assert.strictEqual(
inspection.source_provider_manifest.transfer_policy.local_source_bytes_remain_node_local,
true
);
assert.strictEqual(
inspection.source_provider_manifest.transfer_policy.coordinator_receives_source_bytes_by_default,
false
);
assert.strictEqual(
inspection.source_provider_manifest.transfer_policy.default_full_repo_tarball,
false
);
assert.deepStrictEqual(
inspection.source_provider_manifest.transfer_policy.allowed_remote_transfer.sort(),
["ExplicitSnapshotChunks", "RequiredContent"]
);
assert.strictEqual(inspection.metadata.embeds_full_container_images, false);
assert(inspection.metadata.environments.some((env) => env.name === "linux"));
assert(inspection.metadata.environments.some((env) => env.name === "windows"));
assert(inspection.metadata.selected_inputs.some((input) => input.path === "src/build.rs"));
const bundleDirectory = path.join(repo, "target/acceptance/flagship-bundle");
const build = JSON.parse(
cp.execFileSync(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
"build",
"--project",
project,
"--output",
bundleDirectory,
"--json",
],
{ cwd: repo, encoding: "utf8" }
)
);
assert.strictEqual(build.status, "built");
assert.strictEqual(build.bundle_artifact.task_descriptor_count, 9);
assert.strictEqual(build.bundle_artifact.entrypoint_count, 3);
assert.deepStrictEqual(build.bundle_artifact.files.sort(), [
"debug-metadata.json",
"entrypoints.json",
"environments.json",
"manifest.json",
"module.wasm",
"source-provider.json",
"task-descriptors.json",
"vfs-seed.json",
]);
const bundleManifest = JSON.parse(
fs.readFileSync(path.join(bundleDirectory, "manifest.json"), "utf8")
);
const bundleEntrypoints = JSON.parse(
fs.readFileSync(path.join(bundleDirectory, "entrypoints.json"), "utf8")
);
assert.deepStrictEqual(
bundleEntrypoints.map((entrypoint) => entrypoint.name).sort(),
["build", "fail", "restart"]
);
const bundleModule = fs.readFileSync(path.join(bundleDirectory, "module.wasm"));
assert.strictEqual(bundleManifest.kind, "disasmer-bundle");
assert.strictEqual(
bundleManifest.bundle_digest,
`sha256:${crypto.createHash("sha256").update(bundleModule).digest("hex")}`
);
assert.strictEqual(bundleManifest.embeds_full_repository, false);
assert.strictEqual(
bundleManifest.coordinator_receives_source_bytes_by_default,
false
);
const taskDescriptors = JSON.parse(
fs.readFileSync(path.join(bundleDirectory, "task-descriptors.json"), "utf8")
);
assert(
taskDescriptors.some(
(task) =>
task.name === "task_add_one" &&
task.argument_schema === "input : i32" &&
task.result_schema === "i32" &&
task.restart_compatibility_hash.startsWith("sha256:") &&
task.probe_symbol === "disasmer.probe.task_add_one"
)
);
cp.execFileSync("cargo", ["test", "-p", "launch-build-demo"], {
cwd: repo,
stdio: "inherit"
});
console.log("Flagship demo smoke passed");

View file

@ -0,0 +1,198 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function maybeRead(segments) {
const fullPath = path.join(repo, ...segments);
if (!fs.existsSync(fullPath)) return null;
return fs.readFileSync(fullPath, "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing hostile-input evidence: ${name}`);
}
function expectGate(script, gateName) {
assert(
script.includes("node scripts/hostile-input-contract-smoke.js"),
`${gateName} must run hostile-input-contract-smoke.js`
);
}
const coreSource = read("crates/disasmer-core/src/source.rs");
const coreCapabilities = read("crates/disasmer-core/src/capability.rs");
const coordinatorService = [
read("crates/disasmer-coordinator/src/service.rs"),
read("crates/disasmer-coordinator/src/service/routing.rs"),
read("crates/disasmer-coordinator/src/service/signed_nodes.rs"),
read("crates/disasmer-coordinator/src/service/logs.rs"),
read("crates/disasmer-coordinator/src/service/tests.rs"),
].join("\n");
const artifactDownloadSmoke = read("scripts/artifact-download-smoke.js");
const operatorPanelSmoke = read("scripts/operator-panel-smoke.js");
const schedulerSmoke = read("scripts/scheduler-placement-smoke.js");
const sourcePreparationSmoke = read("scripts/source-preparation-smoke.js");
const publicAcceptance = read("scripts/acceptance-public.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
for (const [name, pattern] of [
["source manifests validate shape", /pub fn validate_public_mvp\(&self\)[\s\S]*self\.validate_shape\(\)\?/],
["source manifests reject invalid digests", /SourceManifestError::InvalidDigest/],
["source manifests reject invalid custom providers", /SourceManifestError::InvalidProviderId/],
["source manifests reject control characters", /DescriptionControlCharacter/],
["source manifests reject coordinator checkout access", /CoordinatorCheckoutAccess/],
["source manifests reject default source-byte upload", /CoordinatorReceivesSourceBytes/],
]) {
expect(coreSource, name, pattern);
}
for (const [name, pattern] of [
["capability reports validate public shape", /pub fn validate_public_report\(&self\)/],
["capability reports validate architecture labels", /InvalidArchitecture/],
["capability reports validate OS labels", /InvalidOsLabel/],
["capability reports validate source providers", /InvalidSourceProvider/],
["source provider ids reject path traversal", /valid_source_provider_id/],
]) {
expect(coreCapabilities, name, pattern);
}
for (const [name, pattern] of [
["coordinator task log tails are bounded", /MAX_TASK_LOG_TAIL_BYTES: usize = 256 \* 1024/],
["coordinator validates reported stdout tails", /ReportTaskLog[\s\S]*validate_task_log_tail\("stdout_tail", &stdout_tail\)\?/],
["coordinator validates completed task stdout tails", /TaskCompleted[\s\S]*validate_task_log_tail\("stdout_tail", &stdout_tail\)\?/],
["coordinator rejects oversized log tail in unit coverage", /"x"\.repeat\(MAX_TASK_LOG_TAIL_BYTES \+ 1\)/],
]) {
expect(coordinatorService, name, pattern);
}
for (const [name, pattern] of [
["service rejects malformed node capability report", /fn service_rejects_malformed_node_capability_report\(\)/],
["capability report rejection leaves descriptors empty", /assert!\(service\.node_descriptors\.is_empty\(\)\)/],
["node capability report rejects cross-scope writes", /fn service_rejects_node_capability_report_outside_enrollment_scope\(\)/],
["task completion rejects cross-scope writes", /task completion outside node scope|outside/],
]) {
expect(coordinatorService, name, pattern);
}
for (const [name, source, patterns] of [
[
"artifact download smoke",
artifactDownloadSmoke,
[
/const crossTenant = await send/,
/const crossProject = await send/,
/const guessed = await send/,
/const crossActorOpen = await send/,
/token is invalid/,
/tenant mismatch/,
/project mismatch/,
],
],
[
"operator panel smoke",
operatorPanelSmoke,
[
/render_operator_panel/,
/submit_panel_event/,
/assert\(!JSON\.stringify\(panel\)\.includes\("<script"\)\)/,
/assert\(!JSON\.stringify\(panel\)\.toLowerCase\(\)\.includes\("oauth"\)\)/,
/rate limit/i,
/exceeds download limit/,
],
],
[
"scheduler smoke",
schedulerSmoke,
[/const crossTenantReport = await send/, /report_node_capabilities/, /tenant\\\/project scope/],
],
[
"source preparation smoke",
sourcePreparationSmoke,
[/const crossTenantCompletion = await send/, /complete_source_preparation/, /tenant\\\/project scope/i],
],
]) {
for (const pattern of patterns) {
expect(source, name, pattern);
}
}
expectGate(publicAcceptance, "public acceptance");
expectGate(publicSplit, "public split acceptance");
expectGate(privateAcceptance, "private acceptance");
const hostedServiceMain = maybeRead([
"private",
"hosted-policy",
"src",
"bin",
"disasmer-hosted-service.rs",
]);
const hostedValidation = maybeRead([
"private",
"hosted-policy",
"src",
"bin",
"disasmer-hosted-service",
"validation.rs",
]);
const hostedWire = maybeRead([
"private",
"hosted-policy",
"src",
"bin",
"disasmer-hosted-service",
"wire.rs",
]);
const hostedProtocol = maybeRead([
"private",
"hosted-policy",
"src",
"bin",
"disasmer-hosted-service",
"hosted_service_protocol.rs",
]);
const hostedService =
hostedServiceMain && hostedValidation && hostedWire && hostedProtocol
? [hostedServiceMain, hostedValidation, hostedWire, hostedProtocol].join("\n")
: null;
const hostedTests = [
maybeRead(["private", "hosted-policy", "src", "bin", "disasmer-hosted-service", "tests.rs"]),
maybeRead(["private", "hosted-policy", "scripts", "hosted-deployment-smoke.js"]),
maybeRead(["private", "hosted-policy", "scripts", "hosted-client-compat-smoke.js"]),
].filter(Boolean).join("\n");
if (hostedService && hostedTests) {
for (const [name, pattern] of [
["hosted service turns malformed JSON into error responses", /decode_incoming_request[\s\S]*HostedServiceResponse::Error/],
["tenant ids are validated", /fn tenant_id\(value: String\)[\s\S]*validate_identifier\("tenant", &value\)\?/],
["node ids are validated", /fn node_id\(value: String\)[\s\S]*validate_identifier\("node", &value\)\?/],
["process ids are validated", /fn process_id\(value: String\)[\s\S]*validate_identifier\("process", &value\)\?/],
["identifiers reject empty and control/path characters", /fn validate_identifier[\s\S]*trim\(\)\.is_empty\(\)[\s\S]*ch\.is_control\(\) \|\| ch == '\/' \|\| ch == '\\\\'/],
["OIDC text fields are bounded", /fn validate_text[\s\S]*value\.len\(\) > max_bytes[\s\S]*contains unsupported characters/],
["tokens are bounded", /fn validate_token[\s\S]*value\.len\(\) > max_bytes[\s\S]*contains unsupported characters/],
["control request bodies are bounded", /MAX_CONTROL_FRAME_BYTES[\s\S]*control request too large/],
["identity protocol rejects unknown authority fields", /deny_unknown_fields/],
]) {
expect(hostedService, name, pattern);
}
for (const [name, pattern] of [
["old client identity protocol is rejected", /hosted_login_protocol_rejects_client_identity_and_provider_configuration/],
["raw operator action is rejected", /rawOperatorDenied[\s\S]*hosted_operator_request envelope/],
["unsigned client identity is rejected", /const forged = await sendHostedControl[\s\S]*authenticated CLI session/],
["cross-tenant process inspection is rejected", /crossTenantTaskEventsDenied[\s\S]*scope\|denied\|unauthorized/],
]) {
expect(hostedTests, name, pattern);
}
}
console.log("Hostile input contract smoke passed");

300
scripts/node-attach-smoke.js Executable file
View file

@ -0,0 +1,300 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const repo = path.resolve(__dirname, "..");
const identities = new Map();
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function nodeIdentity(node) {
const existing = identities.get(node);
if (existing) return existing;
const { privateKey: privateKeyObject, publicKey } =
crypto.generateKeyPairSync("ed25519");
const privateDer = privateKeyObject.export({ format: "der", type: "pkcs8" });
const publicDer = publicKey.export({
format: "der",
type: "spki",
});
const privateSeed = Buffer.from(privateDer).subarray(-32);
const identity = {
privateKey: `ed25519:${privateSeed.toString("base64")}`,
publicKey: `ed25519:${Buffer.from(publicDer).subarray(-32).toString("base64")}`,
privateKeyObject,
};
identities.set(node, identity);
return identity;
}
function nodeSignatureMessage(
node,
requestKind,
payloadDigest,
nonce,
issuedAtEpochSeconds
) {
const parts = [
"disasmer-node-request-signature:v2",
node,
requestKind,
payloadDigest,
nonce,
String(issuedAtEpochSeconds),
];
return Buffer.concat(
parts.flatMap((part) => [
Buffer.from(`${Buffer.byteLength(part)}:`),
Buffer.from(part),
Buffer.from("\n"),
])
);
}
function signedNodeHeartbeat(node, identity) {
const nonce = `node-attach-heartbeat-${process.pid}-${Date.now()}`;
const issuedAt = Math.floor(Date.now() / 1000);
const payloadDigest = `sha256:${crypto
.createHash("sha256")
.update(JSON.stringify({ node, type: "node_heartbeat" }))
.digest("hex")}`;
const signature = crypto.sign(
null,
nodeSignatureMessage(node, "node_heartbeat", payloadDigest, nonce, issuedAt),
identity.privateKeyObject
);
return {
nonce,
issued_at_epoch_seconds: issuedAt,
signature: `ed25519:${signature.toString("base64")}`,
};
}
function runAttach(addr, grant) {
const identity = nodeIdentity("node-attach");
return new Promise((resolve, reject) => {
const child = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
"node",
"attach",
"--coordinator",
`${addr.host}:${addr.port}`,
"--tenant",
"tenant",
"--project-id",
"project",
"--node",
"node-attach",
"--public-key",
identity.publicKey,
"--enrollment-grant",
grant,
"--cap",
"quic-direct",
"--json",
],
{
cwd: repo,
env: {
...process.env,
DISASMER_NODE_PRIVATE_KEY: identity.privateKey,
},
}
);
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.on("exit", (code) => {
if (code !== 0) {
reject(new Error(`node attach failed with code ${code}\n${stderr}`));
return;
}
try {
resolve(JSON.parse(stdout));
} catch (error) {
reject(
new Error(`node attach output was not JSON: ${stdout}\n${error.stack || error.message}`)
);
}
});
});
}
(async () => {
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback",
],
{ cwd: repo }
);
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const grant = await send(addr, {
type: "create_node_enrollment_grant",
tenant: "tenant",
project: "project",
actor_user: "operator",
ttl_seconds: 900
});
assert.strictEqual(grant.type, "node_enrollment_grant_created");
assert.strictEqual(grant.tenant, "tenant");
assert.strictEqual(grant.project, "project");
assert.match(grant.grant, /^node_grant_[A-Za-z0-9_-]+$/);
assert.strictEqual(grant.scope, "node:attach");
assert(grant.expires_at_epoch_seconds > Math.floor(Date.now() / 1000));
assert(grant.expires_at_epoch_seconds <= Math.floor(Date.now() / 1000) + 900);
const report = await runAttach(addr, grant.grant);
assert.strictEqual(report.plan.node, "node-attach");
assert.strictEqual(report.plan.coordinator, `${addr.host}:${addr.port}`);
assert.strictEqual(report.plan.enrollment.grant, grant.grant);
assert.match(report.plan.enrollment.public_key_fingerprint, /^sha256:[0-9a-f]{64}$/);
assert.strictEqual(
report.plan.enrollment.exchanges_short_lived_grant_for_long_lived_node_identity,
true
);
assert.ok(report.plan.capabilities.arch.length > 0);
assert.ok(report.plan.capabilities.source_providers.includes("filesystem"));
assert.ok(report.plan.capabilities.capabilities.includes("QuicDirect"));
assert.strictEqual(report.plan.detection.auto_detected, true);
assert.strictEqual(report.plan.detection.arch, report.plan.capabilities.arch);
assert.deepStrictEqual(report.plan.detection.manual_capability_overrides, ["quic-direct"]);
assert(
report.plan.detection.recognized_capability_overrides.includes("QuicDirect")
);
assert.strictEqual(
report.plan.detection.os_arch_capabilities_require_manual_flags,
false
);
assert.strictEqual(report.plan.detection.command_backend, "native-command");
assert.strictEqual(report.plan.detection.command_backend_available, true);
assert(
report.plan.detection.source_provider_backends.some(
(provider) => provider.provider === "filesystem" && provider.detected
)
);
assert(
report.grant_disclosures.length > 0,
"node attach should disclose capability grants before reporting capabilities"
);
assert(
report.grant_disclosures.every(
(disclosure) => disclosure.coordinator_policy_limited === true
),
"node attach should mark all capability grants as coordinator-policy-limited"
);
assert(
report.grant_disclosures.some(
(disclosure) => disclosure.grant === "native_command_execution"
),
"node attach should disclose native command execution when detected"
);
assert(
report.grant_disclosures.some(
(disclosure) => disclosure.grant === "source_access"
),
"node attach should disclose source access when detected"
);
assert.strictEqual(report.boundary.cli_contacted_coordinator, true);
assert.strictEqual(report.boundary.used_enrollment_exchange, true);
assert.strictEqual(report.boundary.coordinator_session_requests, 3);
assert.strictEqual(report.coordinator_response.type, "node_enrollment_exchanged");
assert.strictEqual(report.coordinator_response.node, "node-attach");
assert.strictEqual(report.coordinator_response.credential.node, "node-attach");
assert.strictEqual(report.coordinator_response.credential.scope, "node:attach");
assert.strictEqual(report.coordinator_response.credential.credential_kind, "NodeCredential");
assert.match(
report.coordinator_response.credential.capability_policy_digest,
/^sha256:[0-9a-f]{64}$/
);
assert.strictEqual(report.heartbeat_response.type, "node_heartbeat");
assert.strictEqual(report.capability_response.type, "node_capabilities_recorded");
const heartbeat = await send(addr, {
type: "node_heartbeat",
node: "node-attach",
node_signature: signedNodeHeartbeat("node-attach", nodeIdentity("node-attach")),
});
assert.strictEqual(heartbeat.type, "node_heartbeat");
assert.strictEqual(heartbeat.node, "node-attach");
} finally {
coordinator.kill("SIGTERM");
}
console.log("Node attach smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,164 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing node lifecycle evidence: ${name}`);
}
const nodeMain = read("crates/disasmer-node/src/daemon.rs");
const nodeIdentity = read("crates/disasmer-node/src/node_identity.rs");
const cliNode = read("crates/disasmer-cli/src/node.rs");
const nodeTaskReports = read("crates/disasmer-node/src/task_reports.rs");
const nodeDebugAgent = read("crates/disasmer-node/src/debug_agent.rs");
const nodeLib = read("crates/disasmer-node/src/lib.rs");
const sharedWasmtimeRuntime = `${read("crates/disasmer-wasm-runtime/src/lib.rs")}\n${read("crates/disasmer-wasm-runtime/src/task_host_linker.rs")}`;
const nodeRuntimeSurface = `${nodeLib}\n${sharedWasmtimeRuntime}`;
const nodeLifecycleSurface = `${nodeMain}\n${nodeIdentity}\n${nodeTaskReports}\n${nodeDebugAgent}`;
const nodeAssignmentRunner = `${read("crates/disasmer-node/src/assignment_runner.rs")}\n${read("crates/disasmer-node/src/assignment_runner/control_watcher.rs")}\n${read("crates/disasmer-node/src/assignment_runner/process_runner.rs")}\n${read("crates/disasmer-node/src/assignment_runner/validation.rs")}`;
const coordinatorCore = read("crates/disasmer-coordinator/src/lib.rs");
const coordinatorService = `${read("crates/disasmer-coordinator/src/service.rs")}\n${read("crates/disasmer-coordinator/src/service/routing.rs")}`;
const coordinatorServiceTests = read("crates/disasmer-coordinator/src/service/tests.rs");
const coordinatorServiceSurface = `${coordinatorService}\n${coordinatorServiceTests}`;
const wasmtimeAssignmentSmoke = read("scripts/wasmtime-assignment-smoke.js");
const wasmtimeSmoke = read("scripts/wasmtime-node-smoke.js");
const debugCore = read("crates/disasmer-core/src/debug.rs");
const readme = read("README.md");
assert.strictEqual(
(nodeMain.match(/CoordinatorSession::connect/g) || []).length,
1,
"node runtime should open one coordinator session in the local process-boundary runtime"
);
for (const [name, pattern] of [
["enrollment exchange over session", /"type": "exchange_node_enrollment_grant"/],
["persisted node identity is reused locally", /"type": "node_identity_reused"/],
["heartbeat over session", /"type": "node_heartbeat"/],
["node-originated requests use signed envelope", /"type": "signed_node"/],
["capability report over session", /"type": "report_node_capabilities"/],
["task assignment polling over session", /"type": "poll_task_assignment"/],
["process start over session", /"type": "start_process"/],
["reconnect over session", /"type": "reconnect_node"/],
["debug command polling over session", /"type": "poll_debug_command"/],
["log event over session", /"type": "report_task_log"/],
["VFS metadata over session", /"type": "report_vfs_metadata"/],
["task control polling over session", /"type": "poll_task_control"/],
["completion over session", /"type": "task_completed"/],
["cancellation uses same session", /poll_task_cancellation\(session, args, &task, node_private_key\)/],
["request count is reported", /session\.requests\(\)/],
]) {
expect(nodeLifecycleSurface, name, pattern);
}
expect(cliNode, "user-authorized node attach over Client session", /"type": "attach_node"/);
assert.doesNotMatch(
nodeIdentity,
/"type": "attach_node"/,
"a persisted node must authenticate with its signed identity instead of replaying Client attach"
);
for (const [name, pattern] of [
["worker uses enrollment exchange", /workerReady\.node_status, "ready"/],
["worker receives the task instance selected by the SDK runtime", /nodeRun\.task_assignment_response\.task,[\s\S]*sdkRun\.task_spec\.task_instance/],
["worker verifies task ABI", /task_assignment_response\.task_spec\.dispatch\.abi/],
["worker records task completion", /nodeRun\.coordinator_response\.type, "task_recorded"/],
["worker exposes task result", /events\.events\[0\]\.result, \{ SmallJson: 42 \}/],
["Wasm task observes cooperative cancellation", /task_definition: "cooperative_cancellation_probe"[\s\S]*type: "cancel_process"/],
["cooperative cancellation returns under task control", /cancellationNodeRun\.terminal_state, "completed"/],
["running command abort is exercised", /task_definition: "abort_probe"[\s\S]*type: "abort_process"/],
["running command abort reaches terminal state", /abortedNodeRun\.terminal_state, "cancelled"/],
["running native command receives a real Debug Epoch freeze", /waitForNativeSleep[\s\S]*type: "create_debug_epoch"[\s\S]*fully_frozen/],
["native Linux process is observed stopped and resumed", /assert\.match\(procState\(nativeSleepPid\)[\s\S]*stopped[\s\S]*resume_debug_epoch[\s\S]*fully_resumed[\s\S]*assert\.doesNotMatch\(procState\(nativeSleepPid\)/],
["parent and child Wasm tasks are frozen as one process", /task_definition: "debug_parent_probe"[\s\S]*debugChildInstance = "debug_parent_probe-1:child:1"[\s\S]*all-stop across active parent and child Wasm participants[\s\S]*affected_tasks\.length, 2[\s\S]*acknowledgements\.length, 2[\s\S]*\[debugChildInstance, "debug_parent_probe-1"\]/],
["parent and child Wasm tasks both acknowledge resume", /multiParticipantResume[\s\S]*fully_resumed[\s\S]*acknowledgements\.length, 2/],
["abort releases process slot", /afterAbort\.processes, \[\]/],
]) {
expect(wasmtimeAssignmentSmoke, name, pattern);
}
for (const [name, pattern] of [
["cooperative cancellation and abort are distinct", /cancel_requested: false,[\s\S]*abort_requested: true/],
["controlled runner polls abort while command runs", /fn abort_requested[\s\S]*poll_task_control/],
["controlled runner creates a process group", /process\.process_group\(0\)/],
["controlled runner freezes the native process group", /libc::kill\(process_group, libc::SIGSTOP\)/],
["controlled runner resumes the native process group", /libc::kill\(process_group, libc::SIGCONT\)/],
["controlled runner kills the process group", /libc::kill\(process_group, libc::SIGKILL\)/],
["Wasm code can poll cooperative cancellation", /task_control_v1/],
["matched Wasm probes remain at a quiescent boundary", /TaskHostOperation::DebugProbe[\s\S]*enter_quiescent_host_boundary[\s\S]*leave_quiescent_host_boundary/],
["debug snapshots use the live Wasm task handle registry", /debug_handle_snapshot[\s\S]*task_handle_\{handle_id\}[\s\S]*state=active/],
["native command status comes from the controlled runner", /set_command_status[\s\S]*frozen native command pid[\s\S]*native command exited with status/],
]) {
expect(`${coordinatorServiceSurface}\n${nodeLifecycleSurface}\n${sharedWasmtimeRuntime}\n${nodeAssignmentRunner}`, name, pattern);
}
for (const [name, pattern] of [
["coordinator rejects stale process ownership", /fn node_reconnect_rejects_stale_process_epoch_after_restart\(\)/],
["reconnect preserves enrolled node identity", /reconnect_node\(&NodeId::from\("node"\), None\)/],
["stale process epoch is rejected", /CoordinatorError::StaleProcessEpoch/],
]) {
expect(coordinatorCore, name, pattern);
}
for (const [name, pattern] of [
["coordinator delivers cancellation to connected node", /fn service_delivers_cancellation_to_connected_node_and_records_terminal_state\(\)/],
["node polls task control", /CoordinatorRequest::PollTaskControl/],
["cancelled terminal state is recorded", /TaskTerminalState::Cancelled/],
]) {
expect(coordinatorServiceSurface, name, pattern);
}
for (const [name, pattern] of [
["native lifecycle test exists", /fn linux_task_lifecycle_supports_cancel_and_all_stop_freeze_resume\(\)/],
["native freeze succeeds when supported", /lifecycle\.freeze_for_debug_epoch\(\)\.unwrap\(\)/],
["native resume succeeds", /lifecycle\.resume_after_debug_epoch\(\)/],
["native cancel reaches lifecycle", /lifecycle\.cancel\(\)/],
["unsupported freeze errors", /BackendError::DebugFreezeUnsupported/],
["wasmtime runtime exposes freeze resume probe", /pub fn freeze_resume_i32_export_probe/],
["wasmtime runtime captures Wasm frame locals", /debug_i32_export_snapshot[\s\S]*local_values/],
["wasmtime runtime creates Wasm debug participant", /kind: DebugParticipantKind::WasmTask/],
["wasmtime debug participant carries local values", /local_values: snapshot\.local_values\.clone\(\)/],
["wasmtime runtime resumes after freeze", /epoch\.continue_all\(\)/],
]) {
expect(nodeRuntimeSurface, name, pattern);
}
for (const [name, pattern] of [
["wasmtime smoke runs debug freeze resume mode", /--debug-freeze-resume/],
["wasmtime smoke verifies frozen state", /debugReport\.frozen_state, "Frozen"/],
["wasmtime smoke verifies resumed state", /debugReport\.resumed_state, "Running"/],
["wasmtime smoke verifies frame local values", /debugReport\.local_values[\s\S]*wasm_local_0/],
["wasmtime smoke proves node runtime reached wasm task", /node_runtime_reached_wasm_task/],
["wasmtime smoke proves node captured locals", /node_runtime_captured_wasm_locals/],
]) {
expect(wasmtimeSmoke, name, pattern);
}
for (const [name, pattern] of [
["debug model freezes wasm and command participants", /fn breakpoint_creates_all_stop_debug_epoch_for_wasm_and_command_tasks\(\)/],
["debug model rejects unsupported freeze", /fn debug_epoch_reports_freeze_failure_instead_of_claiming_all_stop\(\)/],
["debug model resumes frozen participants", /fn continue_resumes_every_frozen_participant\(\)/],
["debug model includes captured locals", /local_values/],
["wasm participants are modeled", /DebugParticipantKind::WasmTask/],
["controlled native command participants are modeled", /DebugParticipantKind::ControlledNativeCommand/],
]) {
expect(debugCore, name, pattern);
}
for (const [name, pattern] of [
["docs describe long-lived coordinator and worker processes", /real-flagship-harness\.js[\s\S]*separate long-lived processes/],
["docs distinguish cooperative cancellation from forced abort", /cooperative cancellation observed by task code and forced abort of uncooperative Wasm\/native work/],
["docs describe failed freeze diagnostic", /Failed debug freezes/],
]) {
expect(readme, name, pattern);
}
console.log("Node lifecycle contract smoke passed");

177
scripts/node-signing.js Normal file
View file

@ -0,0 +1,177 @@
const crypto = require("crypto");
const identities = new Map();
function nodeIdentity(identityPurpose, node) {
const identityKey = `${identityPurpose}:${node}`;
const existing = identities.get(identityKey);
if (existing) return existing;
const { privateKey: privateKeyObject, publicKey } =
crypto.generateKeyPairSync("ed25519");
const privateDer = privateKeyObject.export({ format: "der", type: "pkcs8" });
const publicDer = publicKey.export({
format: "der",
type: "spki",
});
const privateSeed = Buffer.from(privateDer).subarray(-32);
const identity = {
privateKey: `ed25519:${privateSeed.toString("base64")}`,
publicKey: `ed25519:${Buffer.from(publicDer).subarray(-32).toString("base64")}`,
privateKeyObject,
};
identities.set(identityKey, identity);
return identity;
}
function nodeIdentityFromPrivateKey(privateKey) {
if (typeof privateKey !== "string" || !privateKey.startsWith("ed25519:")) {
throw new Error("node private key must use ed25519:<base64> encoding");
}
const seed = Buffer.from(privateKey.slice("ed25519:".length), "base64");
if (seed.length !== 32) throw new Error("node private key must contain 32 bytes");
const privateKeyObject = crypto.createPrivateKey({
key: Buffer.concat([
Buffer.from("302e020100300506032b657004220420", "hex"),
seed,
]),
format: "der",
type: "pkcs8",
});
const publicKeyObject = crypto.createPublicKey(privateKeyObject);
const publicDer = publicKeyObject.export({ format: "der", type: "spki" });
return {
privateKey,
publicKey: `ed25519:${Buffer.from(publicDer).subarray(-32).toString("base64")}`,
privateKeyObject,
};
}
function canonicalSignedRequest(value, topLevel = true) {
if (Array.isArray(value)) {
return value.map((entry) => canonicalSignedRequest(entry, false));
}
if (value && typeof value === "object") {
return Object.fromEntries(
Object.entries(value)
.filter(
([key, entry]) =>
entry !== null &&
(!topLevel || !["agent_signature", "node_signature"].includes(key))
)
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
.map(([key, entry]) => [key, canonicalSignedRequest(entry, false)])
);
}
return value;
}
function withWireDefaults(request) {
const value = { ...request };
if (value.type === "report_node_capabilities") {
value.dependency_cache_digests ??= [];
} else if (value.type === "launch_task" || value.type === "launch_child_task") {
value.wait_for_node ??= false;
} else if (value.type === "start_process") {
value.restart ??= false;
} else if (value.type === "report_debug_state") {
value.stack_frames ??= [];
value.local_values ??= [];
value.task_args ??= [];
value.handles ??= [];
value.recent_output ??= [];
} else if (value.type === "report_task_log") {
value.stdout_tail ??= "";
value.stderr_tail ??= "";
} else if (value.type === "task_completed") {
value.stdout_tail ??= "";
value.stderr_tail ??= "";
value.stdout_truncated ??= false;
value.stderr_truncated ??= false;
}
return value;
}
function signedRequestPayloadDigest(request) {
return `sha256:${crypto
.createHash("sha256")
.update(JSON.stringify(canonicalSignedRequest(withWireDefaults(request))))
.digest("hex")}`;
}
function nodeSignatureMessage(
node,
requestKind,
payloadDigest,
nonce,
issuedAtEpochSeconds
) {
const parts = [
"disasmer-node-request-signature:v2",
node,
requestKind,
payloadDigest,
nonce,
String(issuedAtEpochSeconds),
];
return Buffer.concat(
parts.flatMap((part) => [
Buffer.from(`${Buffer.byteLength(part)}:`),
Buffer.from(part),
Buffer.from("\n"),
])
);
}
function signedNodeProof(node, identity, requestKind, request, options = {}) {
const nonce =
options.nonce ||
`${requestKind}-${process.pid}-${Date.now()}-${crypto
.randomBytes(8)
.toString("hex")}`;
const issuedAt =
options.issuedAtEpochSeconds ?? Math.floor(Date.now() / 1000);
const signature = crypto.sign(
null,
nodeSignatureMessage(
node,
requestKind,
signedRequestPayloadDigest(request),
nonce,
issuedAt
),
identity.privateKeyObject
);
return {
nonce,
issued_at_epoch_seconds: issuedAt,
signature: `ed25519:${signature.toString("base64")}`,
};
}
function signedNodeHeartbeat(node, identity, options = {}) {
const request = { type: "node_heartbeat", node };
return signedNodeProof(node, identity, "node_heartbeat", request, options);
}
function signedNodeRequest(node, identity, requestKind, request, options = {}) {
return {
type: "signed_node",
node,
node_signature: signedNodeProof(
node,
identity,
requestKind,
request,
options
),
request,
};
}
module.exports = {
nodeIdentity,
nodeIdentityFromPrivateKey,
signedNodeProof,
signedRequestPayloadDigest,
signedNodeHeartbeat,
signedNodeRequest,
};

360
scripts/operator-panel-smoke.js Executable file
View file

@ -0,0 +1,360 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const { nodeIdentity } = require("./node-signing");
const {
ensureRootlessPodman,
repo,
runFlagshipWorker,
send,
startFlagship,
waitForTaskEvent,
waitForJsonLine,
} = require("./real-flagship-harness");
const panelNode = "panel-node";
const panelNodeIdentity = nodeIdentity("operator-panel-smoke", panelNode);
function widget(panel, id) {
const item = panel.widgets[id];
assert(item, `missing panel widget ${id}`);
return item;
}
const delay = (milliseconds) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
async function waitForBreakpointHit(addr, process) {
for (let attempt = 0; attempt < 2400; attempt += 1) {
const status = await send(addr, {
type: "inspect_debug_breakpoints",
tenant: "tenant",
project: "project",
actor_user: "user",
process,
});
assert.strictEqual(status.type, "debug_breakpoints", JSON.stringify(status));
if (status.hit_epoch != null) return status;
await delay(25);
}
throw new Error(`timed out waiting for package breakpoint in ${process}`);
}
async function waitForDebugEpochFrozen(addr, process, epoch) {
for (let attempt = 0; attempt < 2400; attempt += 1) {
const status = await send(addr, {
type: "inspect_debug_epoch",
tenant: "tenant",
project: "project",
actor_user: "user",
process,
epoch,
});
assert.strictEqual(status.type, "debug_epoch_status", JSON.stringify(status));
if (status.failed) {
throw new Error(status.failure_messages.join("; "));
}
if (status.fully_frozen) return status;
await delay(25);
}
throw new Error(`timed out waiting for debug epoch ${epoch} to freeze`);
}
(async () => {
ensureRootlessPodman();
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback"
],
{ cwd: repo }
);
let coordinatorStderr = "";
let worker;
coordinator.stderr.on("data", (chunk) => {
coordinatorStderr += chunk.toString();
});
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const projectCreated = await send(addr, {
type: "create_project",
tenant: "tenant",
actor_user: "user",
project: "project",
name: "Operator panel smoke",
});
assert.strictEqual(projectCreated.type, "project_created");
worker = await runFlagshipWorker(addr, panelNode, panelNodeIdentity);
const workerReady = await worker.ready;
assert.strictEqual(workerReady.node_status, "ready");
const workerCompletion = waitForJsonLine(worker.child);
const flagship = startFlagship(addr);
const configuredBreakpoints = await send(addr, {
type: "set_debug_breakpoints",
tenant: "tenant",
project: "project",
actor_user: "user",
process: flagship.process,
probe_symbols: ["disasmer.probe.package_release"],
});
assert.strictEqual(configuredBreakpoints.type, "debug_breakpoints");
const breakpointHit = await waitForBreakpointHit(addr, flagship.process);
assert.strictEqual(
breakpointHit.hit_probe_symbol,
"disasmer.probe.package_release"
);
const frozenEpoch = await waitForDebugEpochFrozen(
addr,
flagship.process,
breakpointHit.hit_epoch
);
assert(frozenEpoch.acknowledgements.length >= 2);
const compileEvent = await waitForTaskEvent(
addr,
flagship.process,
(event) => event.task_definition === "compile_linux",
"compile_linux before the package breakpoint"
);
const report = await workerCompletion;
assert.strictEqual(report.node_status, "completed");
assert.strictEqual(report.coordinator_response.type, "task_recorded");
const process = flagship.process;
const rendered = await send(addr, {
type: "render_operator_panel",
tenant: "tenant",
project: "project",
process,
actor_user: "user",
max_download_bytes: 1024 * 1024,
stopped: false
});
assert.strictEqual(rendered.type, "operator_panel");
const panel = rendered.panel;
assert.strictEqual(panel.tenant, "tenant");
assert.strictEqual(panel.project, "project");
assert.strictEqual(panel.process, process);
assert.strictEqual(panel.program_ui_events_enabled, true);
assert.deepStrictEqual(widget(panel, "process-status").kind, {
Text: { value: "running" }
});
const taskProgress = widget(panel, "task-progress").kind.Progress;
assert(taskProgress.current >= 2);
assert.strictEqual(taskProgress.current, taskProgress.total);
assert.match(
widget(panel, "task-summary").kind.Text.value,
new RegExp(`compile_linux \\[${compileEvent.task}\\]:Some\\(0\\):panel-node`)
);
assert.match(widget(panel, "recent-logs").kind.Text.value, /stdout=\d+ stderr=\d+/);
const downloadWidget = widget(panel, "download-artifact").kind;
const artifact = downloadWidget.ArtifactDownload.artifact;
assert(
artifact === compileEvent.artifact_path.slice("/vfs/artifacts/".length),
"panel download must point at a real flagship artifact"
);
assert(!JSON.stringify(downloadWidget).includes("url_path"));
assert(!JSON.stringify(downloadWidget).includes("scoped_token_digest"));
assert.deepStrictEqual(widget(panel, "debug-process").kind, {
Button: { action: "debug-process" }
});
assert.deepStrictEqual(widget(panel, "cancel-process").kind, {
Button: { action: "cancel-process" }
});
assert.deepStrictEqual(widget(panel, "restart-selected-task").kind, {
Button: { action: "restart-task" }
});
assert(panel.control_plane_actions.includes("DebugProcess"));
assert(panel.control_plane_actions.includes("CancelProcess"));
assert(
panel.control_plane_actions.some(
(action) =>
action.RestartTask &&
action.RestartTask === compileEvent.task
),
"panel restart must target the real flagship task instance"
);
assert(
panel.control_plane_actions.some(
(action) => action.DownloadArtifact === artifact
)
);
assert(!JSON.stringify(panel).includes("<script"));
assert(!JSON.stringify(panel).toLowerCase().includes("oauth"));
const panelLink = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact: downloadWidget.ArtifactDownload.artifact,
max_bytes: 1024 * 1024,
ttl_seconds: 60
});
assert.strictEqual(panelLink.type, "artifact_download_link");
assert.strictEqual(panelLink.link.artifact, downloadWidget.ArtifactDownload.artifact);
assert.match(panelLink.link.policy_context_digest, /^sha256:[0-9a-f]{64}$/);
assert.deepStrictEqual(panelLink.link.source, { RetainedNode: "panel-node" });
assert(panelLink.link.url_path.endsWith(`/artifacts/tenant/project/${process}/${artifact}`));
const apiTooLarge = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact: downloadWidget.ArtifactDownload.artifact,
max_bytes: 1,
ttl_seconds: 60
});
assert.strictEqual(apiTooLarge.type, "error");
assert.match(apiTooLarge.message, /exceeds download limit/);
const panelTooLarge = await send(addr, {
type: "render_operator_panel",
tenant: "tenant",
project: "project",
process,
actor_user: "user",
max_download_bytes: 1,
stopped: false
});
assert.strictEqual(panelTooLarge.type, "error");
assert.match(panelTooLarge.message, /exceeds download limit/);
const accepted = await send(addr, {
type: "submit_panel_event",
tenant: "tenant",
project: "project",
process,
widget_id: "debug-process",
kind: "ButtonClicked",
max_events: 1
});
assert.strictEqual(accepted.type, "panel_event_accepted");
assert.strictEqual(accepted.used_events, 1);
assert.strictEqual(accepted.max_events, 1);
const rateLimited = await send(addr, {
type: "submit_panel_event",
tenant: "tenant",
project: "project",
process,
widget_id: "debug-process",
kind: "ButtonClicked",
max_events: 1
});
assert.strictEqual(rateLimited.type, "error");
assert.match(rateLimited.message, /rate limit/i);
const stopped = await send(addr, {
type: "render_operator_panel",
tenant: "tenant",
project: "project",
process,
actor_user: "user",
max_download_bytes: 1024 * 1024,
stopped: true
});
assert.strictEqual(stopped.type, "operator_panel");
assert.strictEqual(stopped.panel.program_ui_events_enabled, false);
assert.deepStrictEqual(widget(stopped.panel, "process-status").kind, {
Text: { value: "stopped" }
});
assert.deepStrictEqual(
widget(stopped.panel, "task-progress").kind,
widget(panel, "task-progress").kind
);
assert.deepStrictEqual(
widget(stopped.panel, "task-summary").kind,
widget(panel, "task-summary").kind
);
assert.deepStrictEqual(
widget(stopped.panel, "recent-logs").kind,
widget(panel, "recent-logs").kind
);
assert.deepStrictEqual(
widget(stopped.panel, "download-artifact").kind,
widget(panel, "download-artifact").kind
);
assert(stopped.panel.control_plane_actions.includes("DebugProcess"));
assert(
stopped.panel.control_plane_actions.some(
(action) => action.DownloadArtifact === artifact
)
);
const frozenEvent = await send(addr, {
type: "submit_panel_event",
tenant: "tenant",
project: "project",
process,
widget_id: "debug-process",
kind: "ButtonClicked",
max_events: 10
});
assert.strictEqual(frozenEvent.type, "error");
assert.match(frozenEvent.message, /program UI events are disabled/i);
const crossTenant = await send(addr, {
type: "render_operator_panel",
tenant: "other",
project: "project",
process,
actor_user: "user",
max_download_bytes: 1024 * 1024,
stopped: false
});
assert.strictEqual(crossTenant.type, "error");
assert.match(
crossTenant.message,
/scope|tenant|project|requires an active virtual process/i
);
assert(!crossTenant.message.includes(process));
const resumed = await send(addr, {
type: "resume_debug_epoch",
tenant: "tenant",
project: "project",
actor_user: "user",
process,
epoch: breakpointHit.hit_epoch,
});
assert.strictEqual(resumed.type, "debug_epoch");
const cleanup = await send(addr, {
type: "abort_process",
tenant: "tenant",
project: "project",
actor_user: "user",
process,
});
assert.strictEqual(cleanup.type, "process_aborted");
} catch (error) {
if (coordinatorStderr) {
error.message = `${error.message}\ncoordinator stderr:\n${coordinatorStderr}`;
}
throw error;
} finally {
worker?.child.kill("SIGTERM");
coordinator.kill("SIGTERM");
}
console.log("Operator panel smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

89
scripts/phase3-ledger.js Normal file
View file

@ -0,0 +1,89 @@
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const CRITERION_HEADING =
/^## \*\*(Passed|Partial|Open):\*\* (P3-[A-Z]+-\d{3}):/gm;
function readPhase3Ledger(repo) {
return fs.readFileSync(path.join(repo, "phase_3_acceptance_criteria.md"), "utf8");
}
function criterionStatuses(source) {
return [...source.matchAll(CRITERION_HEADING)].map((match) => ({
status: match[1],
id: match[2],
}));
}
function statusCounts(criteria) {
return Object.fromEntries(
["Passed", "Partial", "Open"].map((status) => [
status,
criteria.filter((criterion) => criterion.status === status).length,
])
);
}
function assertCompleteCriterionSet(criteria) {
assert.strictEqual(criteria.length, 191, "Phase 3 ledger must contain 191 criteria");
assert.strictEqual(
new Set(criteria.map((criterion) => criterion.id)).size,
191,
"Phase 3 criterion ids must be unique"
);
}
function assertPreFinalLedger(source) {
const criteria = criterionStatuses(source);
assertCompleteCriterionSet(criteria);
const counts = statusCounts(criteria);
assert.deepStrictEqual(
counts,
{ Passed: 0, Partial: 181, Open: 10 },
"the public-release E2E requires the independently reset 181 Partial / 10 Open ledger"
);
const expectedOpen = Array.from(
{ length: 10 },
(_, index) => `P3-GATE-${String(index + 1).padStart(3, "0")}`
);
assert.deepStrictEqual(
criteria
.filter((criterion) => criterion.status === "Open")
.map((criterion) => criterion.id),
expectedOpen,
"only the ten final P3-GATE criteria may be Open in the reset ledger"
);
return counts;
}
function assertFinalLedger(source) {
const criteria = criterionStatuses(source);
assertCompleteCriterionSet(criteria);
const counts = statusCounts(criteria);
assert.deepStrictEqual(
counts,
{ Passed: 191, Partial: 0, Open: 0 },
"final release evidence requires all 191 Phase 3 criteria to be Passed"
);
return counts;
}
function assertPreFinalOrFinalLedger(source) {
const criteria = criterionStatuses(source);
assertCompleteCriterionSet(criteria);
const counts = statusCounts(criteria);
if (counts.Open === 10) {
return assertPreFinalLedger(source);
}
return assertFinalLedger(source);
}
module.exports = {
assertFinalLedger,
assertPreFinalLedger,
assertPreFinalOrFinalLedger,
criterionStatuses,
readPhase3Ledger,
statusCounts,
};

86
scripts/podman-backend-smoke.js Executable file
View file

@ -0,0 +1,86 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const path = require("path");
const { configurePodmanTestEnvironment } = require("./podman-test-env");
const repo = path.resolve(__dirname, "..");
const baseImage = "docker.io/library/alpine:3.20";
// Nix's standalone Podman package may not install the distribution-level
// containers/image policy normally found under /etc. Use an isolated test HOME
// without replacing a policy supplied by the host.
configurePodmanTestEnvironment(repo);
function run(command, args, options = {}) {
return cp.execFileSync(command, args, {
cwd: repo,
encoding: "utf8",
stdio: options.stdio || ["ignore", "pipe", "pipe"],
});
}
function incomplete(reason) {
const error = new Error(`Linux Podman backend incomplete: ${reason}`);
error.code = "DISASMER_PODMAN_INCOMPLETE";
throw error;
}
function ensurePodmanBaseImage() {
try {
run("podman", ["--version"]);
} catch (error) {
incomplete(`podman command is unavailable (${error.message})`);
}
let rootless;
try {
rootless = run("podman", ["info", "--format", "{{.Host.Security.Rootless}}"]).trim();
} catch (error) {
incomplete(`podman info did not report rootless status (${error.message})`);
}
if (rootless !== "true") {
incomplete(`podman is not running in rootless mode (reported ${JSON.stringify(rootless)})`);
}
try {
run("podman", ["image", "exists", baseImage]);
} catch (_) {
try {
run("podman", ["pull", baseImage], { stdio: "inherit" });
} catch (error) {
incomplete(`unable to make ${baseImage} available (${error.message})`);
}
}
}
try {
ensurePodmanBaseImage();
const stdout = run("cargo", [
"run",
"-q",
"-p",
"disasmer-node",
"--bin",
"disasmer-podman-smoke"
]);
const report = JSON.parse(stdout.trim().split("\n").at(-1));
assert.strictEqual(report.podman_status, "completed");
assert.strictEqual(report.status_code, 0);
assert.strictEqual(report.stdout, "podman-ok:node-local source\n");
assert.strictEqual(report.large_bytes_uploaded, false);
assert.strictEqual(report.uses_full_repo_tarball, false);
assert.strictEqual(report.coordinator_routed_file_reads, false);
assert.strictEqual(report.staged_artifact.path, "/vfs/artifacts/podman-smoke.txt");
console.log("Podman backend smoke passed");
} catch (error) {
if (error.code === "DISASMER_PODMAN_INCOMPLETE") {
console.error(error.message);
process.exit(2);
}
throw error;
}

View file

@ -0,0 +1,41 @@
const fs = require("fs");
const os = require("os");
const path = require("path");
function configurePodmanTestEnvironment(repo) {
const originalHome = os.homedir();
if (
fs.existsSync(path.join(originalHome, ".config/containers/policy.json")) ||
fs.existsSync("/etc/containers/policy.json")
) {
return;
}
const isolatedHome = path.join(repo, "scripts/containers-home");
const policy = path.join(isolatedHome, ".config/containers/policy.json");
fs.mkdirSync(path.dirname(policy), { recursive: true });
if (!fs.existsSync(policy)) {
fs.writeFileSync(
policy,
`${JSON.stringify(
{ default: [{ type: "insecureAcceptAnything" }] },
null,
2
)}\n`
);
}
process.env.CARGO_HOME ||= path.join(originalHome, ".cargo");
process.env.RUSTUP_HOME ||= path.join(originalHome, ".rustup");
process.env.HOME = isolatedHome;
process.env.XDG_DATA_HOME = path.join(
os.tmpdir(),
`disasmer-containers-data-${process.getuid?.() ?? "user"}`
);
process.env.XDG_CACHE_HOME = path.join(
os.tmpdir(),
`disasmer-containers-cache-${process.getuid?.() ?? "user"}`
);
}
module.exports = { configurePodmanTestEnvironment };

View file

@ -0,0 +1,755 @@
#!/usr/bin/env node
const crypto = require("crypto");
const cp = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const outputRoot = path.resolve(
process.env.DISASMER_PUBLIC_RELEASE_DIR ||
path.join(repo, "target/public-release-dryrun")
);
const publicTree = path.join(outputRoot, "public-tree");
const assetsDir = path.join(outputRoot, "assets");
const stagingDir = path.join(outputRoot, "staging");
const publicBuildTarget = path.join(repo, "target");
const defaultHostedCoordinatorEndpoint = "https://disasmer.michelpaulissen.com";
const forgejoHost = "git.michelpaulissen.com";
const args = new Set(process.argv.slice(2));
const includeForgejoWorkflows =
args.has("--include-forgejo-workflows") ||
/^(1|true|yes)$/i.test(process.env.DISASMER_INCLUDE_FORGEJO_WORKFLOWS || "");
const filteredTopLevel = ["private", "experiments", ".git", "target"];
const filteredDirectoryNames = [".disasmer"];
const archiveIgnoredPathFallbacks = [
"target",
".disasmer",
"vscode-extension/node_modules",
"scripts/containers-home",
];
const publicRepoBranch = process.env.DISASMER_PUBLIC_REPO_BRANCH || "main";
const publicBinaries = [
"disasmer",
"disasmer-coordinator",
"disasmer-node",
"disasmer-debug-dap",
];
function commandOutput(command, args, options = {}) {
try {
const execOptions = {
cwd: repo,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
...options,
};
execOptions.env = commandEnv(command, options.env);
return cp
.execFileSync(command, args, execOptions)
.trim();
} catch (_) {
return null;
}
}
function run(command, args, options = {}) {
const execOptions = {
cwd: repo,
stdio: "inherit",
...options,
};
execOptions.env = commandEnv(command, options.env);
cp.execFileSync(command, args, execOptions);
}
function nonInteractiveGitEnv(extra = {}) {
return {
...process.env,
GIT_TERMINAL_PROMPT: "0",
GIT_ASKPASS: process.env.GIT_ASKPASS || "/bin/false",
SSH_ASKPASS: process.env.SSH_ASKPASS || "/bin/false",
GIT_SSH_COMMAND:
process.env.GIT_SSH_COMMAND ||
"ssh -o BatchMode=yes -o NumberOfPasswordPrompts=0",
...extra,
};
}
function commandEnv(command, env) {
if (command !== "git") {
return env;
}
return nonInteractiveGitEnv(env);
}
function ensureDir(dir) {
fs.mkdirSync(dir, { recursive: true });
}
function filteredOutPatterns() {
return [
"private/**",
"experiments/**",
".git",
"target",
"git-ignored source paths",
"root/*.md except README.md and SECURITY.md",
"**/.disasmer/**",
...(includeForgejoWorkflows ? [] : [".forgejo/**"]),
];
}
function gitIgnoredSourcePaths() {
const output = commandOutput("git", [
"ls-files",
"--others",
"--ignored",
"--exclude-standard",
"--directory",
"-z",
]);
if (output === null) {
return archiveIgnoredPathFallbacks;
}
return [
...new Set([
...archiveIgnoredPathFallbacks,
...output
.split("\0")
.filter(Boolean)
.map((relativePath) =>
relativePath.replaceAll("\\", "/").replace(/\/$/, "")
),
]),
];
}
function isGitIgnored(relativePath, ignoredSourcePaths) {
const normalized = relativePath.replaceAll(path.sep, "/");
return ignoredSourcePaths.some(
(ignored) => normalized === ignored || normalized.startsWith(`${ignored}/`)
);
}
function isFilteredRootMarkdown(relativePath, entry) {
return (
!relativePath.includes(path.sep) &&
(entry.isFile() || entry.isSymbolicLink()) &&
path.extname(entry.name).toLowerCase() === ".md" &&
!["README.md", "SECURITY.md"].includes(entry.name)
);
}
function shouldFilter(entry, relativePath) {
const parts = relativePath.split(path.sep).filter(Boolean);
const topLevel = parts[0];
if (filteredTopLevel.includes(topLevel)) return true;
if (parts.some((part) => filteredDirectoryNames.includes(part))) return true;
if (topLevel === ".forgejo" && !includeForgejoWorkflows) return true;
if (isFilteredRootMarkdown(relativePath, entry)) return true;
return false;
}
function copyFilteredTree(src, dest, ignoredSourcePaths, relative = "") {
ensureDir(dest);
const entries = fs
.readdirSync(src, { withFileTypes: true })
.sort((left, right) => left.name.localeCompare(right.name));
for (const entry of entries) {
const childRelative = relative ? path.join(relative, entry.name) : entry.name;
if (
shouldFilter(entry, childRelative) ||
isGitIgnored(childRelative, ignoredSourcePaths)
) {
continue;
}
const from = path.join(src, entry.name);
const to = path.join(dest, entry.name);
if (entry.isDirectory()) {
copyFilteredTree(from, to, ignoredSourcePaths, childRelative);
} else if (entry.isSymbolicLink()) {
fs.symlinkSync(fs.readlinkSync(from), to);
} else if (entry.isFile()) {
fs.copyFileSync(from, to);
fs.chmodSync(to, fs.statSync(from).mode & 0o777);
}
}
}
function assertFilteredTree(ignoredSourcePaths) {
for (const excluded of ["private", "experiments"]) {
if (fs.existsSync(path.join(publicTree, excluded))) {
throw new Error(`${excluded}/ leaked into the dry-run public tree`);
}
}
for (const file of walkFiles(publicTree)) {
if (file.split(path.sep).includes(".disasmer")) {
throw new Error(`generated .disasmer view state leaked into the dry-run public tree: ${file}`);
}
}
if (!includeForgejoWorkflows && fs.existsSync(path.join(publicTree, ".forgejo"))) {
throw new Error(".forgejo/ leaked into the host-neutral dry-run public tree");
}
if (!fs.existsSync(path.join(publicTree, "README.md"))) {
throw new Error("product README.md is missing from the dry-run public tree");
}
for (const ignored of ignoredSourcePaths) {
if (fs.existsSync(path.join(publicTree, ...ignored.split("/")))) {
throw new Error(`Git-ignored source path leaked into the dry-run public tree: ${ignored}`);
}
}
for (const entry of fs.readdirSync(publicTree, { withFileTypes: true })) {
if (isFilteredRootMarkdown(entry.name, entry)) {
throw new Error(`internal root Markdown file leaked into the dry-run public tree: ${entry.name}`);
}
}
}
function walkFiles(root, relative = "") {
const dir = path.join(root, relative);
const entries = fs
.readdirSync(dir, { withFileTypes: true })
.sort((left, right) => left.name.localeCompare(right.name));
const files = [];
for (const entry of entries) {
const childRelative = relative ? path.join(relative, entry.name) : entry.name;
if (entry.isDirectory()) {
files.push(...walkFiles(root, childRelative));
} else if (entry.isFile()) {
files.push(childRelative);
} else if (entry.isSymbolicLink()) {
files.push(childRelative);
}
}
return files;
}
function hashTree(root) {
const hash = crypto.createHash("sha256");
for (const file of walkFiles(root)) {
const absolute = path.join(root, file);
const stat = fs.lstatSync(absolute);
hash.update(file.replaceAll(path.sep, "/"));
hash.update("\0");
hash.update(String(stat.mode & 0o777));
hash.update("\0");
if (stat.isSymbolicLink()) {
hash.update("symlink");
hash.update("\0");
hash.update(fs.readlinkSync(absolute));
} else {
hash.update(fs.readFileSync(absolute));
}
hash.update("\0");
}
return `sha256:${hash.digest("hex")}`;
}
function sha256File(file) {
return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
}
function tarGz(output, cwd, inputs) {
run("tar", ["-czf", output, "-C", cwd, ...inputs]);
}
function platformName() {
return `${os.platform()}-${os.arch()}`;
}
function binaryName(name) {
return process.platform === "win32" ? `${name}.exe` : name;
}
function buildPublicBinaries() {
run("cargo", ["build", "--workspace", "--bins", "--release", "--jobs", "2"], {
cwd: publicTree,
env: { ...process.env, CARGO_TARGET_DIR: publicBuildTarget },
});
}
function stageBinaryAssets(releaseName) {
const stageRoot = path.join(stagingDir, "binaries");
const binDir = path.join(stageRoot, "bin");
fs.rmSync(stageRoot, { recursive: true, force: true });
ensureDir(binDir);
for (const binary of publicBinaries) {
const fileName = binaryName(binary);
const built = path.join(publicBuildTarget, "release", fileName);
if (!fs.existsSync(built)) {
throw new Error(`expected release binary ${built}`);
}
const staged = path.join(binDir, fileName);
fs.copyFileSync(built, staged);
fs.chmodSync(staged, 0o755);
}
const archive = path.join(
assetsDir,
`disasmer-public-binaries-${releaseName}-${platformName()}.tar.gz`
);
tarGz(archive, stageRoot, ["."]);
return archive;
}
function publicBinaryDigests() {
return Object.fromEntries(
publicBinaries.map((binary) => {
const fileName = binaryName(binary);
const file = path.join(publicBuildTarget, "release", fileName);
if (!fs.existsSync(file)) throw new Error(`missing built release binary ${file}`);
return [fileName, `sha256:${sha256File(file)}`];
})
);
}
function stageEvidenceAsset(
releaseName,
sourceCommit,
publicTreeIdentity,
binaryDigests
) {
const stage = path.join(stagingDir, "evidence");
fs.rmSync(stage, { recursive: true, force: true });
ensureDir(stage);
const evidenceRoot = path.join(repo, "target/acceptance");
const included = [];
for (const name of ["public-environment.json", "wasmtime-assignment.json"]) {
const source = path.join(evidenceRoot, name);
if (!fs.existsSync(source)) continue;
fs.copyFileSync(source, path.join(stage, name));
included.push(name);
}
const binding = {
kind: "disasmer-release-evidence-binding",
source_commit: sourceCommit,
public_tree_identity: publicTreeIdentity,
binary_digests: binaryDigests,
configuration_generation:
process.env.DISASMER_DEPLOYMENT_SYSTEM_GENERATION || null,
included_evidence: included,
};
fs.writeFileSync(
path.join(stage, "EVIDENCE_BINDING.json"),
`${JSON.stringify(binding, null, 2)}\n`
);
const archive = path.join(
assetsDir,
`disasmer-public-evidence-${releaseName}.tar.gz`
);
tarGz(archive, stage, ["."]);
return archive;
}
function stageSourceAsset(releaseName) {
const archive = path.join(assetsDir, `disasmer-public-source-${releaseName}.tar.gz`);
tarGz(archive, publicTree, ["."]);
return archive;
}
function stageExtensionAsset() {
const packageJson = JSON.parse(
fs.readFileSync(path.join(publicTree, "vscode-extension/package.json"), "utf8")
);
const archive = path.join(
assetsDir,
`${packageJson.name}-${packageJson.version}.vsix`
);
run(
"npx",
[
"--yes",
"@vscode/vsce",
"package",
"--allow-missing-repository",
"--skip-license",
"--out",
archive,
],
{ cwd: path.join(publicTree, "vscode-extension") }
);
return archive;
}
function resolverInstructions() {
if (process.env.DISASMER_PUBLIC_DRYRUN_RESOLVER_INSTRUCTIONS) {
return process.env.DISASMER_PUBLIC_DRYRUN_RESOLVER_INSTRUCTIONS.trim();
}
if (process.env.DISASMER_PUBLIC_DRYRUN_HOSTS_ENTRY) {
return [
"Add the controlled hosts entry supplied for this dry run:",
"",
"```",
process.env.DISASMER_PUBLIC_DRYRUN_HOSTS_ENTRY.trim(),
"```",
].join("\n");
}
if (process.env.DISASMER_PUBLIC_RELEASE_DRYRUN_IP) {
return [
"Add this controlled hosts entry for the dry run:",
"",
"```",
`${process.env.DISASMER_PUBLIC_RELEASE_DRYRUN_IP} disasmer.michelpaulissen.com`,
"```",
].join("\n");
}
return [
"`disasmer.michelpaulissen.com` should resolve through public DNS. If it",
"does not resolve yet, wait for DNS propagation or use the fallback hosts",
"entry supplied with the invitation.",
].join("\n");
}
function writeGettingStartedAsset(releaseName, publicTreeIdentity, resolution) {
const file = path.join(assetsDir, `DISASMER_PUBLIC_DRYRUN_GETTING_STARTED-${releaseName}.md`);
fs.writeFileSync(
file,
`# Disasmer Public Dry Run
This dry run is a real Disasmer deployment for selected external users. If
public DNS has not propagated yet, use the fallback resolution instructions
below.
The default hosted coordinator is the deployment at
\`https://disasmer.michelpaulissen.com\`. The word \`public\` in this dry run
refers to the public Forgejo repository, release downloads, selected-user
network access, and public client protocol compatibility. It does not mean the
server is the standalone open-source Core coordinator.
## DNS
${resolution}
## Install
1. Download the binary archive for your platform from the Forgejo Release at
\`git.michelpaulissen.com\`.
2. Verify it against \`SHA256SUMS\`.
3. Extract the archive and put the \`bin/\` directory on your \`PATH\`.
4. Download \`disasmer-vscode-*.vsix\` if you want the debugger and Disasmer
side views, then install it:
\`\`\`bash
code --install-extension disasmer-vscode-*.vsix
\`\`\`
## Connect
Use the default hosted coordinator endpoint:
\`\`\`bash
disasmer login --browser
disasmer bundle inspect --project examples/launch-build-demo
\`\`\`
\`disasmer login --browser\` opens the server-provided Authentik authorization
URL and polls the hosted transaction. The provider callback terminates on the
hosted service; provider codes and tokens do not pass through the CLI.
Enroll a node identity with the grant supplied by the invitation:
\`\`\`bash
disasmer node attach --coordinator https://disasmer.michelpaulissen.com --enrollment-grant <grant> --public-key <public-key>
\`\`\`
That command proves the identity/enrollment path and then exits. To actually run
work for the flagship workflow, leave a worker process running in another
terminal. Use a fresh enrollment grant, or skip the attach command above and use
the worker command directly:
\`\`\`bash
disasmer-node --coordinator https://disasmer.michelpaulissen.com --tenant <tenant> --project-id <project> --node <node-id> --public-key <public-key> --enrollment-grant <grant> --worker --emit-ready
\`\`\`
Then run the flagship workflow from the filtered public repository while that
worker is still running:
\`\`\`bash
disasmer run --project examples/launch-build-demo build
\`\`\`
The dry-run public tree identity is \`${publicTreeIdentity}\`.
The release name is \`${releaseName}\`.
`,
"utf8"
);
return file;
}
function writeInviteAsset(releaseName, publicTreeIdentity, resolution) {
const file = path.join(assetsDir, `DISASMER_PUBLIC_DRYRUN_INVITE-${releaseName}.md`);
const publicRepo =
process.env.DISASMER_PUBLIC_REPO_URL ||
"https://git.michelpaulissen.com/<owner>/<public-repo>";
const releaseUrl =
process.env.DISASMER_FORGEJO_RELEASE_URL ||
"the Forgejo Release attached to the public repository";
fs.writeFileSync(
file,
`# Disasmer Public Dry Run Invite
This invite is for selected external users, such as friends helping test the
MVP release experience. The deployment is real and externally reachable, but it
is intentionally not broadly advertised yet.
The hosted coordinator behind this invite is the deployment at
\`https://disasmer.michelpaulissen.com\`. The public part is the Forgejo
repository, release downloads, network-reachable dry run, and public client
protocol used by the binaries; the hosted server is not the standalone Core
coordinator.
If public DNS has not propagated yet, make sure \`disasmer.michelpaulissen.com\`
resolves to the deployment host before running the CLI.
## Links
- Public repository: ${publicRepo}
- Release downloads: ${releaseUrl}
- Default hosted coordinator endpoint: ${defaultHostedCoordinatorEndpoint}
- Public tree identity: ${publicTreeIdentity}
- Release name: ${releaseName}
## DNS
${resolution}
## First run
1. Download the binary archive for your platform and \`SHA256SUMS\` from the
Forgejo Release.
2. Extract the archive and put \`bin/\` on your \`PATH\`.
3. Optionally install \`disasmer-vscode-*.vsix\` with
\`code --install-extension disasmer-vscode-*.vsix\`.
4. Run \`disasmer login --browser\`; it opens the server-provided Authentik
authorization URL and polls the hosted transaction for a scoped CLI session.
5. Enroll a node identity with the enrollment grant supplied out of band.
6. Start a long-lived worker with a fresh enrollment grant, or use the worker
command directly instead of step 5:
\`disasmer-node --coordinator https://disasmer.michelpaulissen.com --tenant <tenant> --project-id <project> --node <node-id> --public-key <public-key> --enrollment-grant <grant> --worker --emit-ready\`.
7. Run \`disasmer run --project examples/launch-build-demo build\` from the
public repository checkout while the worker process is still running.
`,
"utf8"
);
return file;
}
function writeSha256Sums(assets) {
const sumsPath = path.join(assetsDir, "SHA256SUMS");
const lines = assets
.map((asset) => `${sha256File(asset)} ${path.basename(asset)}`)
.sort()
.join("\n");
fs.writeFileSync(sumsPath, `${lines}\n`);
return sumsPath;
}
function boolEnv(name) {
return /^(1|true|yes)$/i.test(process.env[name] || "");
}
function writePublicTreeProvenance(sourceCommit, releaseName) {
const provenance = {
kind: "disasmer-filtered-public-tree",
source_commit: sourceCommit,
release_name: releaseName,
filtered_out: filteredOutPatterns(),
public_export: {
host_neutral: !includeForgejoWorkflows,
include_forgejo_workflows: includeForgejoWorkflows,
},
forgejo_host: forgejoHost,
default_hosted_coordinator_endpoint: defaultHostedCoordinatorEndpoint,
};
fs.writeFileSync(
path.join(publicTree, "DISASMER_PUBLIC_TREE.json"),
`${JSON.stringify(provenance, null, 2)}\n`
);
}
function publishPublicTree(releaseName, sourceCommit, publicTreeIdentity) {
const remote =
process.env.DISASMER_PUBLIC_REPO_REMOTE ||
process.env.DISASMER_PUBLIC_REPO_URL ||
null;
const enabled = boolEnv("DISASMER_PUBLISH_PUBLIC_TREE");
const result = {
enabled,
remote,
branch: publicRepoBranch,
commit: null,
pushed: false,
};
if (!enabled) {
return result;
}
if (!remote) {
throw new Error(
"DISASMER_PUBLISH_PUBLIC_TREE requires DISASMER_PUBLIC_REPO_REMOTE or DISASMER_PUBLIC_REPO_URL"
);
}
if (!remote.includes(forgejoHost)) {
throw new Error(`public repo remote must point at ${forgejoHost}: ${remote}`);
}
run("git", ["init"], { cwd: publicTree });
run("git", ["checkout", "-B", publicRepoBranch], { cwd: publicTree });
run("git", ["config", "user.name", "Disasmer release dry run"], {
cwd: publicTree,
});
run("git", ["config", "user.email", "release-dryrun@disasmer.invalid"], {
cwd: publicTree,
});
run("git", ["add", "."], { cwd: publicTree });
run(
"git",
[
"commit",
"-m",
`Public dry run ${releaseName}`,
"-m",
`Source commit: ${sourceCommit}`,
"-m",
`Public tree identity: ${publicTreeIdentity}`,
],
{ cwd: publicTree }
);
result.commit = commandOutput("git", ["rev-parse", "HEAD"], { cwd: publicTree });
run("git", ["remote", "add", "public", remote], { cwd: publicTree });
const pushArgs = ["push", "public", `HEAD:${publicRepoBranch}`];
if (boolEnv("DISASMER_PUBLIC_REPO_PUSH_FORCE_WITH_LEASE")) {
run(
"git",
[
"fetch",
"public",
`refs/heads/${publicRepoBranch}:refs/remotes/public/${publicRepoBranch}`,
],
{ cwd: publicTree }
);
pushArgs.splice(1, 0, "--force-with-lease");
}
run("git", pushArgs, { cwd: publicTree });
result.pushed = true;
return result;
}
function main() {
const sourceCommit =
process.env.DISASMER_ACCEPTANCE_COMMIT ||
commandOutput("git", ["rev-parse", "HEAD"]) ||
"unknown";
const shortCommit = sourceCommit === "unknown" ? "unknown" : sourceCommit.slice(0, 12);
const releaseName = process.env.DISASMER_PUBLIC_RELEASE_NAME || `dryrun-${shortCommit}`;
const sourceStatus = commandOutput("git", ["status", "--short"]);
const sourceTreeClean = sourceStatus === null ? null : sourceStatus === "";
fs.rmSync(outputRoot, { recursive: true, force: true });
ensureDir(publicTree);
ensureDir(assetsDir);
ensureDir(stagingDir);
const ignoredSourcePaths = gitIgnoredSourcePaths();
copyFilteredTree(repo, publicTree, ignoredSourcePaths);
assertFilteredTree(ignoredSourcePaths);
writePublicTreeProvenance(sourceCommit, releaseName);
const publicTreeIdentity = hashTree(publicTree);
const sourceArchive = stageSourceAsset(releaseName);
run("node", ["scripts/public-release-dryrun-contract-smoke.js"], {
cwd: publicTree,
});
const publicTreePublish = publishPublicTree(
releaseName,
sourceCommit,
publicTreeIdentity
);
buildPublicBinaries();
const binaryArchive = stageBinaryAssets(releaseName);
const binaryDigests = publicBinaryDigests();
const evidenceArchive = stageEvidenceAsset(
releaseName,
sourceCommit,
publicTreeIdentity,
binaryDigests
);
const extensionArchive = stageExtensionAsset();
const resolution = resolverInstructions();
const gettingStarted = writeGettingStartedAsset(
releaseName,
publicTreeIdentity,
resolution
);
const invite = writeInviteAsset(releaseName, publicTreeIdentity, resolution);
const assets = [
sourceArchive,
binaryArchive,
evidenceArchive,
extensionArchive,
gettingStarted,
invite,
];
const sha256Sums = writeSha256Sums(assets);
const manifest = {
kind: "disasmer-public-release-dryrun",
release_name: releaseName,
source_commit: sourceCommit,
source_tree_clean: sourceTreeClean,
public_tree_identity: publicTreeIdentity,
public_tree: publicTree,
filtered_out: filteredOutPatterns(),
public_export: {
host_neutral: !includeForgejoWorkflows,
include_forgejo_workflows: includeForgejoWorkflows,
},
forgejo_host: forgejoHost,
public_repo_url: process.env.DISASMER_PUBLIC_REPO_URL || publicTreePublish.remote,
public_repo_remote: process.env.DISASMER_PUBLIC_REPO_REMOTE || null,
public_tree_publish: publicTreePublish,
forgejo_release_url: process.env.DISASMER_FORGEJO_RELEASE_URL || null,
default_hosted_coordinator_endpoint: defaultHostedCoordinatorEndpoint,
dns_publication_state:
process.env.DISASMER_DNS_PUBLICATION_STATE || "published",
resolver_override:
process.env.DISASMER_RESOLVER_OVERRIDE || "none-required-public-dns",
platform: platformName(),
binary_digests: binaryDigests,
configuration_generation:
process.env.DISASMER_DEPLOYMENT_SYSTEM_GENERATION || null,
tool_versions: {
node: process.version,
rustc: commandOutput("rustc", ["--version"]) || null,
cargo: commandOutput("cargo", ["--version"]) || null,
tar: commandOutput("tar", ["--version"]) || null,
},
commands: [
"node scripts/public-release-dryrun-contract-smoke.js",
...(publicTreePublish.enabled
? [`git push public HEAD:${publicRepoBranch}`]
: []),
"cargo build --workspace --bins --release --jobs 2",
],
assets: [...assets, sha256Sums].map((asset) => ({
file: asset,
name: path.basename(asset),
sha256: sha256File(asset),
})),
notes: [
"Upload the assets to the Forgejo Release for the filtered public repository.",
"The real service deployment and full e2e dry run remain separate acceptance evidence.",
],
};
const manifestPath = path.join(outputRoot, "public-release-manifest.json");
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
console.log(JSON.stringify({ manifest: manifestPath, assets: assetsDir }, null, 2));
}
main();

View file

@ -0,0 +1,77 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const infraRepo = path.resolve(repo, "..", "michelpaulissen.com");
function read(relativePath, base = repo) {
return fs.readFileSync(path.join(base, relativePath), "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing public browser login evidence: ${name}`);
}
const cliSource = [
read("crates/disasmer-cli/src/main.rs"),
read("crates/disasmer-cli/src/dispatch.rs"),
read("crates/disasmer-cli/src/auth.rs"),
].join("\n");
const cliSmoke = read("scripts/cli-browser-login-flow-smoke.js");
const publicAcceptance = read("scripts/acceptance-public.sh");
const phase2 = read("acceptance_criteria_phase2.md");
const base = read("acceptance_criteria.md");
for (const [name, source] of [
["base acceptance", base],
["phase 2 acceptance", phase2],
]) {
expect(source, `${name} released binary browser criterion`, /Public released binaries[\s\S]*(?:human |server-owned )browser\/account flow/);
}
expect(cliSource, "diagnostic plan flag", /plan: bool/);
expect(cliSource, "interactive browser branch", /else if !args\.plan[\s\S]*execute_interactive_browser_login/);
expect(cliSource, "browser command override", /DISASMER_BROWSER_OPEN_COMMAND/);
expect(cliSource, "server-owned login start", /"type": "begin_oidc_browser_login"[\s\S]*requested_project/);
expect(cliSource, "opaque login polling", /"type": "poll_oidc_browser_login"[\s\S]*transaction_id[\s\S]*polling_secret/);
expect(cliSource, "server-owned state nonce and PKCE", /server_owns_state: true[\s\S]*server_owns_nonce: true[\s\S]*pkce_required: true/);
expect(cliSource, "CLI receives no provider code or claims", /cli_receives_provider_authorization_code: false[\s\S]*cli_submits_identity_claims: false/);
assert.doesNotMatch(cliSource, /TcpListener::bind|authorization_code.*issuer_url.*client_id/s);
expect(cliSmoke, "smoke uses fake browser opener", /DISASMER_BROWSER_OPEN_COMMAND/);
expect(cliSmoke, "smoke verifies server-owned browser transaction", /server-owned browser transaction/);
expect(cliSmoke, "smoke rejects client OIDC authority", /assert\.deepStrictEqual\(request,[\s\S]*begin_oidc_browser_login[\s\S]*requested_project/);
expect(cliSmoke, "smoke verifies coordinator completion", /scoped_cli_session_received/);
expect(publicAcceptance, "public acceptance runs browser flow smoke", /node scripts\/cli-browser-login-flow-smoke\.js/);
if (fs.existsSync(infraRepo)) {
const stack = read("modules/stack.nix", infraRepo);
const hypervisor = read("hosts/hypervisor/default.nix", infraRepo);
const oauth = read("modules/oauth-bootstrap.nix", infraRepo);
const site = read("disasmer-site/index.html", infraRepo);
expect(stack, "Disasmer public host", /publicHost = "disasmer\.michelpaulissen\.com"/);
expect(stack, "Disasmer loopback API port", /apiPort = 9080/);
expect(hypervisor, "nginx Disasmer vhost", /\$\{stack\.hosts\.disasmer\.publicHost\}/);
expect(hypervisor, "nginx Disasmer site root", /root = \.\.\/\.\.\/disasmer-site/);
expect(hypervisor, "nginx control API proxy", /locations\."= \/api\/v1\/control"[\s\S]*proxyPass/);
expect(hypervisor, "nginx hosted callback proxy", /locations\."= \/auth\/callback"[\s\S]*proxyPass/);
assert.doesNotMatch(hypervisor, /locations\."= \/auth\/browser\/start"/);
expect(hypervisor, "hosted service uses configured API port", /stack\.hosts\.disasmer\.apiPort/);
expect(oauth, "Disasmer Authentik provider", /name: disasmer-provider/);
expect(oauth, "Disasmer public OIDC client", /client_type: public/);
expect(oauth, "Disasmer client id", /client_id: \${disasmerClientId}/);
expect(oauth, "Disasmer hosted callback", /https:\/\/disasmer\.michelpaulissen\.com\/auth\/callback/);
expect(oauth, "Disasmer Authentik application", /slug: disasmer/);
expect(site, "site describes CLI login", /disasmer login --browser/);
expect(site, "site describes hosted callback authority", /hosted service processes the callback/);
expect(site, "site explains attached-node execution", /placed on a node you attach and explicitly authorize/);
expect(site, "site labels pre-release status", /pre-release deployment under active verification/);
assert.doesNotMatch(site, /local callback|provider codes and tokens are returned to the CLI/i);
} else {
console.warn("Skipping VPS config checks because ../michelpaulissen.com is not present");
}
console.log("Public browser login contract smoke passed");

View file

@ -0,0 +1,69 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing public local demo evidence: ${name}`);
}
const publicAcceptance = read("scripts/acceptance-public.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const cliInstall = read("scripts/cli-install-smoke.js");
const flagship = read("scripts/flagship-demo-smoke.js");
const cliLocalRun = read("scripts/cli-local-run-smoke.js");
const nodeAttach = read("scripts/node-attach-smoke.js");
const vscodeExtension = read("scripts/vscode-extension-smoke.js");
const vscodeF5 = read("scripts/vscode-f5-smoke.js");
const artifactDownload = read("scripts/artifact-download-smoke.js");
const artifactExport = read("scripts/artifact-export-smoke.js");
for (const script of [publicAcceptance, publicSplit]) {
for (const smoke of [
"scripts/cli-install-smoke.js",
"scripts/flagship-demo-smoke.js",
"scripts/cli-local-run-smoke.js",
"scripts/node-attach-smoke.js",
"scripts/vscode-extension-smoke.js",
"scripts/vscode-f5-smoke.js",
"scripts/artifact-download-smoke.js",
"scripts/artifact-export-smoke.js",
]) {
assert(script.includes(`node ${smoke}`), `public demo gate must run ${smoke}`);
}
}
expect(cliInstall, "CLI install from project path", /cargo[\s\S]*install[\s\S]*crates\/disasmer-cli/);
expect(cliInstall, "CLI install smoke targets flagship project", /const project = path\.join\(repo, "examples\/launch-build-demo"\)/);
expect(cliInstall, "installed CLI inspects flagship project", /installedBin[\s\S]*\["bundle", "inspect", "--project", project, "--json"\]/);
expect(flagship, "flagship project source is Rust workflow", /examples\/launch-build-demo[\s\S]*src\/build\.rs/);
expect(flagship, "flagship source avoids local machine assumptions", /forbiddenSourceAssumptions/);
expect(flagship, "flagship cargo test runs", /cargo[\s\S]*test[\s\S]*launch-build-demo/);
expect(cliLocalRun, "local run starts node process", /cli_process_started_node_process[\s\S]*true/);
expect(cliLocalRun, "local run records real task events", /events\.events\.length >= 4[\s\S]*prepare_source[\s\S]*compile_linux[\s\S]*package_release/);
expect(cliLocalRun, "local run records artifact metadata", /events\.events\.some\(\(event\) => event\.artifact_path\)/);
expect(nodeAttach, "Linux node attach creates enrollment grant", /create_node_enrollment_grant/);
expect(nodeAttach, "Linux node attach uses enrollment exchange", /used_enrollment_exchange[\s\S]*true/);
expect(nodeAttach, "attached Linux node proves signed enrollment", /used_enrollment_exchange[\s\S]*signedNodeHeartbeat/);
expect(vscodeExtension, "extension contributes debugger", /contributes\.debuggers[\s\S]*type === "disasmer"/);
expect(vscodeF5, "F5 uses local-services backend", /runtimeBackend[\s\S]*local-services/);
expect(vscodeF5, "F5 exposes virtual thread", /thread\.name\.includes\("build virtual process"\)[\s\S]*virtual thread/);
expect(vscodeF5, "F5 does not fabricate a terminal event at the entry probe", /coordinator_task_events[\s\S]*value === 0[\s\S]*must not fabricate a terminal task event/);
expect(artifactDownload, "artifact download creates scoped link", /create_artifact_download_link/);
expect(artifactDownload, "artifact download opens stream", /open_artifact_download_stream/);
expect(artifactExport, "artifact export targets receiver node", /export_artifact_to_node[\s\S]*node-export-receiver/);
expect(artifactExport, "artifact export rejects coordinator bulk relay", /coordinator_bulk_relay_allowed[\s\S]*false/);
console.log("Public local demo matrix smoke passed");

View file

@ -0,0 +1,185 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const os = require("os");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function walk(relativePath, files = []) {
const fullPath = path.join(repo, relativePath);
if (!fs.existsSync(fullPath)) return files;
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
const base = path.basename(relativePath);
if (["target", "node_modules", ".git", "containers-home"].includes(base)) {
return files;
}
for (const entry of fs.readdirSync(fullPath)) {
walk(path.join(relativePath, entry), files);
}
return files;
}
files.push(relativePath);
return files;
}
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function copyPublicTree(sourceRoot, destinationRoot, relativePath = ".") {
const skippedDirectories = new Set([
".git",
"target",
"node_modules",
"containers-home",
"private",
"experiments",
]);
const parts = relativePath.split(path.sep).filter(Boolean);
if (parts.some((part) => skippedDirectories.has(part))) {
return;
}
const source = path.join(sourceRoot, relativePath);
const destination = path.join(destinationRoot, relativePath);
const stat = fs.statSync(source);
if (stat.isDirectory()) {
fs.mkdirSync(destination, { recursive: true });
for (const entry of fs.readdirSync(source)) {
copyPublicTree(sourceRoot, destinationRoot, path.join(relativePath, entry));
}
return;
}
fs.mkdirSync(path.dirname(destination), { recursive: true });
fs.copyFileSync(source, destination);
}
function assertPublicSplitTreeIsCoherent() {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-public-split-"));
try {
copyPublicTree(repo, tmp);
for (const forbidden of ["private", "experiments"]) {
assert(
!fs.existsSync(path.join(tmp, forbidden)),
`${forbidden} must be absent from the public split tree`
);
}
const workspaceToml = fs.readFileSync(path.join(tmp, "Cargo.toml"), "utf8");
const membersBlock = workspaceToml.match(/members\s*=\s*\[([\s\S]*?)\]/);
assert(membersBlock, "public workspace must define members");
const members = [...membersBlock[1].matchAll(/"([^"]+)"/g)].map(
(match) => match[1]
);
assert(members.length > 0, "public workspace must list members");
for (const member of members) {
assert(
!member.startsWith("private/") && !member.startsWith("experiments/"),
`public workspace member must not point at filtered source: ${member}`
);
assert(
fs.existsSync(path.join(tmp, member, "Cargo.toml")),
`public workspace member is missing after split: ${member}`
);
}
for (const required of [
"scripts/acceptance-public.sh",
"scripts/verify-public-split.sh",
"scripts/public-private-boundary-smoke.js",
"scripts/public-local-demo-matrix-smoke.js",
"vscode-extension/package.json",
"examples/launch-build-demo/Cargo.toml",
]) {
assert(
fs.existsSync(path.join(tmp, required)),
`public split tree is missing ${required}`
);
}
} finally {
fs.rmSync(tmp, { recursive: true, force: true });
}
}
function publicSourceFiles() {
return [
...walk("crates"),
...walk("examples"),
...walk("scripts"),
...walk("vscode-extension"),
"Cargo.toml",
].filter((file) => {
if (file === "scripts/acceptance-private.sh") return false;
if (file === "scripts/acceptance-evidence-contract-smoke.js") return false;
if (file === "scripts/acceptance-environment-contract-smoke.js") return false;
if (file === "scripts/docs-smoke.js") return false;
if (file === "scripts/public-private-boundary-smoke.js") return false;
if (file === "scripts/release-blocker-smoke.js") return false;
return /\.(rs|toml|js|json|sh)$/.test(file);
});
}
const forbiddenPublicPatterns = [
/\bdisasmer[_-]hosted[_-]policy\b/,
/private\/hosted-policy/,
/path\s*=\s*["'][^"']*private\//,
/include!\s*\([^)]*private\//,
/mod\s+private_hosted/,
];
for (const file of publicSourceFiles()) {
const content = read(file);
for (const pattern of forbiddenPublicPatterns) {
assert(
!pattern.test(content),
`public source ${file} must not reference private hosted code via ${pattern}`
);
}
}
const workspace = read("Cargo.toml");
assert(
!/members\s*=\s*\[[\s\S]*private\//.test(workspace),
"public workspace members must not include private hosted crates"
);
assertPublicSplitTreeIsCoherent();
const privateHostedRoot = path.join(repo, "private", "hosted-policy");
if (fs.existsSync(privateHostedRoot)) {
const privateCargo = read("private/hosted-policy/Cargo.toml");
assert.match(privateCargo, /name\s*=\s*"disasmer-hosted-policy"/);
assert.match(privateCargo, /disasmer-core\s*=\s*\{/);
assert.match(privateCargo, /disasmer-coordinator\s*=\s*\{/);
const privateLib = read("private/hosted-policy/src/lib.rs");
for (const required of [
"AuthentikOidcConfig",
"CommunityTierPolicy",
"AdminControls",
"preflight_zero_capability_hosted_wasm",
"impl CapabilityPolicy for CommunityTierPolicy",
"AuthContext",
]) {
assert(
privateLib.includes(required),
`private hosted policy is missing ${required}`
);
}
const privateFiles = walk("private").filter((file) => !file.includes("/target/"));
const privateNodeRuntimeFiles = privateFiles.filter((file) =>
/(^|\/)(disasmer-node|node-runtime)(\/|$)/.test(file)
);
assert.deepStrictEqual(
privateNodeRuntimeFiles,
[],
"hosted mode must not carry a forked private node runtime"
);
}
console.log("Public/private boundary smoke passed");

View file

@ -0,0 +1,321 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const serviceEndpoint = "https://disasmer.michelpaulissen.com";
const serviceHost = "disasmer.michelpaulissen.com";
const forgejoHost = "git.michelpaulissen.com";
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function maybeRead(relativePath) {
const file = path.join(repo, relativePath);
return fs.existsSync(file) ? fs.readFileSync(file, "utf8") : null;
}
function expect(source, name, pattern) {
assert(source !== null && source !== undefined, `missing source for ${name}`);
assert.match(source, pattern, `missing public release dry-run evidence: ${name}`);
}
const phase2 = maybeRead("acceptance_criteria_phase2.md");
const readme = maybeRead("README.md");
const cliSource = [
read("crates/disasmer-cli/src/main.rs"),
read("crates/disasmer-cli/src/config.rs"),
read("crates/disasmer-cli/src/run.rs"),
read("crates/disasmer-cli/src/client.rs"),
read("crates/disasmer-cli/src/tests.rs"),
].join("\n");
const controlSource = read("crates/disasmer-control/src/lib.rs");
const cliLoginSmoke = read("scripts/cli-login-smoke.js");
const vscodePackage = JSON.parse(read("vscode-extension/package.json"));
const vscodeExtension = read("vscode-extension/extension.js");
const vscodeSmoke = read("scripts/vscode-extension-smoke.js");
const prepScript = read("scripts/prepare-public-release-dryrun.js");
const publishScript = read("scripts/publish-public-release-dryrun.js");
const preflightScript = read("scripts/public-release-dryrun-preflight.js");
const e2eScript = read("scripts/public-release-dryrun-e2e.js");
const finalEvidenceScript = read("scripts/public-release-dryrun-final-evidence.js");
const workflow = maybeRead(".forgejo/workflows/public-release-dryrun.yml");
const publicAcceptance = read("scripts/acceptance-public.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
const publicSplit = read("scripts/verify-public-split.sh");
if (readme) {
expect(readme, "README", new RegExp(serviceHost.replaceAll(".", "\\.")));
}
if (phase2) {
const name = "phase 2 criteria";
expect(phase2, name, new RegExp(serviceHost.replaceAll(".", "\\.")));
expect(phase2, `${name} DNS publication state`, /DNS record|public DNS|dns[-_]publication/i);
expect(phase2, `${name} resolver fallback`, /no resolver override|required resolver override|hosts entry|controlled resolution|fallback/i);
expect(phase2, `${name} Forgejo host`, new RegExp(forgejoHost.replaceAll(".", "\\.")));
expect(phase2, `${name} Forgejo Release`, /Forgejo Release/);
expect(phase2, `${name} compiled assets`, /compiled\s+(release\s+)?assets|compiled release assets/);
expect(phase2, `${name} filtered tree`, /private\/\*\*[\s\S]*experiments\/\*\*/);
expect(phase2, `${name} root Markdown export filter`, /root `\*\.md`|root Markdown/);
expect(phase2, `${name} host-neutral workflow filter`, /\.forgejo[\s\S]*--include-forgejo-workflows/);
expect(phase2, `${name} GitHub release out of scope`, /GitHub[\s\S]*outside this dry run|public GitHub-release[\s\S]*out of scope/);
}
expect(cliSource, "CLI default hosted coordinator constant", new RegExp(`DEFAULT_HOSTED_COORDINATOR_ENDPOINT: &str =[\\s\\S]*"${serviceEndpoint.replaceAll(".", "\\.")}"`));
expect(cliSource, "login uses default hosted coordinator", /default_value_t = default_hosted_coordinator_endpoint\(\)/);
expect(cliSource, "hosted run records coordinator endpoint", /hosted_coordinator_endpoint[\s\S]*Some\(default_hosted_coordinator_endpoint\(\)\)/);
expect(controlSource, "hosted URL uses the shared HTTP control transport", /ControlTransport::Https[\s\S]*agent[\s\S]*\.post\(url\)/);
expect(controlSource, "hosted control transport uses the canonical API path", /CONTROL_API_PATH: &str = "\/api\/v1\/control"/);
expect(controlSource, "plain HTTP is restricted to loopback", /endpoint\.starts_with\("http:\/\/"\) && !endpoint_is_loopback\(endpoint\)/);
expect(cliSource, "default hosted coordinator resolves to the HTTPS control API", /hosted_coordinator_remains_a_real_https_control_endpoint[\s\S]*https:\/\/disasmer\.michelpaulissen\.com\/api\/v1\/control/);
assert.doesNotMatch(cliSource, /coord\.disasmer\.invalid/);
expect(cliLoginSmoke, "CLI login smoke covers default hosted coordinator", new RegExp(`defaultHostedCoordinatorEndpoint = "${serviceEndpoint.replaceAll(".", "\\.")}"`));
assert.strictEqual(
vscodePackage.contributes.debuggers[0].configurationAttributes.launch.properties.coordinatorEndpoint.default,
undefined
);
expect(vscodeSmoke, "VS Code smoke covers session-inferred coordinator endpoint", /coordinatorEndpoint\.default, undefined/);
for (const binary of [
"disasmer",
"disasmer-coordinator",
"disasmer-node",
"disasmer-debug-dap",
]) {
expect(prepScript, `release prep includes ${binary}`, new RegExp(`"${binary}"`));
}
for (const [name, pattern] of [
["release prep filters private and experiments", /filteredTopLevel = \["private", "experiments", "\.git", "target"\]/],
["release prep enumerates Git-ignored source paths", /function gitIgnoredSourcePaths\(\)[\s\S]*"ls-files"[\s\S]*"--ignored"[\s\S]*"--exclude-standard"[\s\S]*"--directory"/],
["release prep has archive-safe ignored-path fallbacks without Git metadata", /archiveIgnoredPathFallbacks = \[[\s\S]*"target"[\s\S]*"\.disasmer"[\s\S]*"vscode-extension\/node_modules"[\s\S]*"scripts\/containers-home"[\s\S]*if \(output === null\) \{[\s\S]*return archiveIgnoredPathFallbacks/],
["release prep filters Git-ignored source paths", /isGitIgnored\(childRelative, ignoredSourcePaths\)/],
["release prep verifies Git-ignored paths are absent", /Git-ignored source path leaked into the dry-run public tree/],
["release prep filters generated view state", /filteredDirectoryNames = \["\.disasmer"\]/],
["release prep filters internal root Markdown", /isFilteredRootMarkdown[\s\S]*path\.extname\(entry\.name\)\.toLowerCase\(\) === "\.md"[\s\S]*README\.md[\s\S]*SECURITY\.md/],
["release prep retains product README", /product README\.md is missing from the dry-run public tree/],
["release prep filters .forgejo by default", /topLevel === "\.forgejo" && !includeForgejoWorkflows/],
["release prep has Forgejo workflow opt-in argument", /--include-forgejo-workflows/],
["release prep builds public release bins", /cargo"[\s\S]*"build"[\s\S]*"--workspace"[\s\S]*"--bins"[\s\S]*"--release"/],
["release prep writes binary archive", /disasmer-public-binaries-\$\{releaseName\}-\$\{platformName\(\)\}\.tar\.gz/],
["release prep writes source archive", /disasmer-public-source-\$\{releaseName\}\.tar\.gz/],
["release prep writes extension VSIX", /\$\{packageJson\.name\}-\$\{packageJson\.version\}\.vsix[\s\S]*@vscode\/vsce[\s\S]*package/],
["release prep packages extension non-interactively", /@vscode\/vsce[\s\S]*package[\s\S]*--skip-license/],
["release prep writes selected-user guide", /DISASMER_PUBLIC_DRYRUN_GETTING_STARTED-\$\{releaseName\}\.md/],
["release prep writes selected-user invite", /DISASMER_PUBLIC_DRYRUN_INVITE-\$\{releaseName\}\.md/],
["release prep accepts resolver instructions", /DISASMER_PUBLIC_DRYRUN_RESOLVER_INSTRUCTIONS/],
["release prep accepts hosts entry", /DISASMER_PUBLIC_DRYRUN_HOSTS_ENTRY/],
["release prep accepts deployment IP", /DISASMER_PUBLIC_RELEASE_DRYRUN_IP/],
["selected-user guide documents DNS or fallback", /public DNS[\s\S]*(fallback|hosts entry)|DNS record[\s\S]*controlled resolution/],
["selected-user guide names hosted coordinator", /default hosted coordinator is the deployment/],
["selected-user guide rejects standalone Core coordinator", /standalone open-source Core coordinator/],
["selected-user invite documents friends dry run", /friends helping test[\s\S]*not broadly advertised/],
["selected-user invite distinguishes Core", /hosted server is not the standalone Core\s+coordinator/],
["selected-user guide documents default login", /disasmer login --browser/],
["selected-user guide documents VSIX install", /code --install-extension disasmer-vscode-\*\.vsix/],
["selected-user guide documents node attach", /disasmer node attach --coordinator https:\/\/disasmer\.michelpaulissen\.com/],
["release prep packages generated evidence", /stageEvidenceAsset[\s\S]*EVIDENCE_BINDING\.json[\s\S]*disasmer-public-evidence-/],
["release prep binds binary digests", /binary_digests: binaryDigests/],
["release prep writes checksums", /SHA256SUMS/],
["release prep writes manifest", /public-release-manifest\.json/],
["release prep writes public tree provenance", /DISASMER_PUBLIC_TREE\.json/],
["release prep records public tree identity", /public_tree_identity: publicTreeIdentity/],
["release prep records DNS state", /dns_publication_state:/],
["release prep records resolver override", /resolver_override:/],
["release prep records Forgejo URLs", /public_repo_url:[\s\S]*public_repo_remote:[\s\S]*forgejo_release_url:/],
["release prep requires publish opt-in", /DISASMER_PUBLISH_PUBLIC_TREE/],
["release prep requires Forgejo remote", /remote\.includes\(forgejoHost\)/],
["release prep can push filtered tree", /git"[\s\S]*"push"[\s\S]*"public"[\s\S]*`HEAD:\$\{publicRepoBranch\}`/],
["release prep records publish result", /public_tree_publish: publicTreePublish/],
["release prep publishes tree before building target", /const publicTreePublish = publishPublicTree[\s\S]*buildPublicBinaries\(\)/],
]) {
expect(prepScript, name, pattern);
}
for (const [name, pattern] of [
["release publisher requires Forgejo token", /DISASMER_FORGEJO_TOKEN/],
["release publisher infers Forgejo repo identity", /function resolveRepoIdentity\(manifest\)[\s\S]*parseForgejoRepoIdentity/],
["release publisher uses manifest public repo URL", /manifest\.public_repo_url[\s\S]*manifest\.public_repo_remote/],
["release publisher uses token auth", /Authorization: `token \$\{token\}`/],
["release publisher lists releases", /\/repos\/\$\{encodeURIComponent\(owner\)\}\/\$\{encodeURIComponent\(repoName\)\}\/releases\?limit=100/],
["release publisher creates release", /POST[\s\S]*\/repos\/\$\{encodeURIComponent\(owner\)\}\/\$\{encodeURIComponent\(repoName\)\}\/releases/],
["release publisher reloads release details", /function loadRelease\(releaseId\)[\s\S]*\/releases\/\$\{releaseId\}/],
["release publisher uploads assets", /releases\/\$\{release\.id\}\/assets\?name=\$\{encodeURIComponent\(asset\.name\)\}/],
["release publisher uses attachment multipart field", /multipartFile\("attachment", asset\.file\)/],
["release publisher skips already attached assets", /existingAssetByName\(release, asset\.name\)/],
["release publisher rejects stale release manifests", /manifest\.source_commit[\s\S]*expectedSourceCommit\(\)/],
["release publisher checks manifest kind", /manifest\.kind !== "disasmer-public-release-dryrun"/],
["release publisher requires public tree push", /public tree must be pushed before publishing the Forgejo Release/],
["release publisher accepts external public tree push", /function publicTreeAlreadyPushed\(manifest\)[\s\S]*DISASMER_PUBLIC_TREE_ALREADY_PUSHED/],
["release publisher targets external public tree commit", /function publicTreeCommit\(manifest\)[\s\S]*DISASMER_PUBLIC_TREE_COMMIT/],
["release publisher writes evidence report", /public-release-dryrun-forgejo-release\.json/],
["release publisher records reused assets", /reused_assets:/],
]) {
expect(publishScript, name, pattern);
}
for (const [name, pattern] of [
["preflight rejects stale release manifests", /manifest\.source_commit[\s\S]*currentSourceCommit/],
["preflight disables interactive remote prompts", /function nonInteractiveEnv[\s\S]*GIT_TERMINAL_PROMPT[\s\S]*GIT_ASKPASS[\s\S]*SSH_ASKPASS[\s\S]*GIT_SSH_COMMAND[\s\S]*BatchMode=yes[\s\S]*NumberOfPasswordPrompts=0[\s\S]*git", \["ls-remote"[\s\S]*timeout/],
["preflight accepts external public tree push", /function publicTreeAlreadyPushed\(manifest\)[\s\S]*DISASMER_PUBLIC_TREE_ALREADY_PUSHED/],
["preflight verifies public branch commit", /remoteMain[\s\S]*publicTreeCommit/],
["preflight verifies local asset checksums", /parseSha256Sums[\s\S]*checksum mismatch/],
["preflight records public tree push source", /public_tree_push_source/],
["preflight records pending external gates", /external_gates:[\s\S]*forgejo_release_publication[\s\S]*public_release_e2e/],
["preflight writes evidence report", /public-release-dryrun-preflight\.json/],
]) {
expect(preflightScript, name, pattern);
}
for (const [name, pattern] of [
["e2e runner requires explicit opt-in", /DISASMER_PUBLIC_RELEASE_DRYRUN_E2E=1/],
["e2e runner rejects stale release manifests", /manifest\.source_commit[\s\S]*expectedSourceCommit\(\)/],
["e2e runner disables interactive git prompts", /function nonInteractiveGitEnv[\s\S]*GIT_TERMINAL_PROMPT[\s\S]*GIT_ASKPASS[\s\S]*SSH_ASKPASS[\s\S]*GIT_SSH_COMMAND[\s\S]*BatchMode=yes[\s\S]*NumberOfPasswordPrompts=0[\s\S]*function commandEnv/],
["e2e runner accepts external public tree push", /function publicTreeAlreadyPushed\(manifest\)[\s\S]*DISASMER_PUBLIC_TREE_ALREADY_PUSHED/],
["e2e runner downloads Forgejo Release assets", /downloadReleaseAssets/],
["e2e runner verifies SHA256SUMS", /verifyChecksums/],
["e2e runner clones public repo", /"git", \["clone", "--depth", "1"/],
["e2e runner rejects private tree leaks", /private[\s\S]*experiments[\s\S]*target/],
["e2e runner rejects internal root Markdown leaks", /internal root Markdown file leaked into public repo/],
["e2e runner requires product README", /public checkout must include product README\.md/],
["e2e runner rejects .forgejo leaks by default", /\.forgejo\/ leaked into public repo/],
["e2e runner rejects generated view state", /generated \.disasmer view state leaked into public repo/],
["e2e runner checks public tree identity", /hashTree\(checkout\)[\s\S]*manifest\.public_tree_identity/],
["e2e runner extracts public binaries", /tar"[\s\S]*"-xzf"/],
["e2e runner loads public coordinator binary", /executable\(installDir, "disasmer-coordinator"\)/],
["e2e runner checks default hosted coordinator", /defaultLoginPlan\.coordinator[\s\S]*serviceEndpoint/],
["e2e runner requires an external browser driver", /DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND/],
["e2e runner uses the CLI browser opener boundary", /DISASMER_BROWSER_OPEN_COMMAND: browserOpenCommand/],
["e2e runner derives scope from the hosted session", /const tenant = loginSession\.tenant[\s\S]*const project = loginSession\.project[\s\S]*const user = loginSession\.user/],
["e2e runner uses public CLI node attach", /"node"[\s\S]*"attach"[\s\S]*serviceEndpoint/],
["e2e runner starts public worker runtime", /workerArgs[\s\S]*"--worker"[\s\S]*cp\.spawn\(disasmerNode/],
["e2e runner launches the released product through CLI", /"run"[\s\S]*"build"[\s\S]*runReport\.status[\s\S]*main_launched/],
["standalone Core proof launches a real Wasm TaskSpec", /type: "launch_task"[\s\S]*task_spec:[\s\S]*kind: "coordinator_node_wasm"[\s\S]*bundle_digest: manifest\.bundle_digest/],
["e2e runner verifies assignment polling", /worker_assignment_poll_verified/],
["e2e runner validates standalone Core coordinator", /validateStandaloneCoreCoordinator/],
["e2e runner uses canonical standalone Core wire envelopes", /function sendCore\(addr, message\)[\s\S]*coordinatorWireRequest\(message, "public-e2e-core"\)/],
["e2e runner records public coordinator validation", /core_coordinator_validated/],
["e2e runner validates released live DAP", /validateReleasedLiveDap/],
["e2e runner verifies attach-mode Debug Epoch transition", /validateReleasedLiveDap[\s\S]*resumed through coordinator[\s\S]*requested freeze/],
["e2e runner verifies attached coordinator task completion", /validateReleasedLiveDap[\s\S]*variable\.name === "state" && variable\.value === "Completed"[\s\S]*coordinator task event from node/],
["e2e runner attaches live DAP to Client-authorized process", /attached_to_existing_client_process/],
["e2e runner verifies task events", /type: "list_task_events"/],
["e2e runner verifies download link", /type: "create_artifact_download_link"/],
["e2e runner verifies VS Code debugger", /scripts\/vscode-f5-smoke\.js/],
["e2e runner writes e2e report", /public-release-dryrun-e2e\.json/],
]) {
expect(e2eScript, name, pattern);
}
for (const [name, pattern] of [
["final evidence reads manifest", /public-release-manifest\.json/],
["final evidence rejects stale release manifests", /manifest\.source_commit[\s\S]*expectedSourceCommit\(\)/],
["final evidence verifies filtered export", /function assertFilteredOut\(manifest\)/],
["final evidence reads Forgejo Release report", /public-release-dryrun-forgejo-release\.json/],
["final evidence reads deployment manifest", /deployment-manifest\.json/],
["final evidence reads service smoke report", /public-release-dryrun-service\.json/],
["final evidence reads hosted Client compatibility report", /hosted-client-compat\.json/],
["final evidence reads Core coordinator compatibility report", /core-coordinator-compat\.json/],
["final evidence requires public e2e report", /public-release-dryrun-e2e\.json/],
["final evidence verifies Forgejo host", /forgejoHost = "git\.michelpaulissen\.com"/],
["final evidence verifies default hosted coordinator", /serviceEndpoint = "https:\/\/disasmer\.michelpaulissen\.com"/],
["final evidence accepts external public tree push", /function publicTreeAlreadyPushed\(manifest\)[\s\S]*DISASMER_PUBLIC_TREE_ALREADY_PUSHED/],
["final evidence records resolved public repo", /resolvedPublicRepoRemote[\s\S]*public_repository_url: resolvedPublicRepoRemote/],
["final evidence requires private hosted coordinator", /coordinator_implementation[\s\S]*"hosted-policy-coordinator"/],
["final evidence requires service private coordinator marker", /service\.coordinator_implementation[\s\S]*"hosted-policy-coordinator"/],
["final evidence requires current service smoke source", /service\.source_commit[\s\S]*manifest\.source_commit/],
["final evidence requires current service smoke release", /service\.release_name[\s\S]*manifest\.release_name/],
["final evidence requires current Client compatibility source", /compat\.source_commit[\s\S]*manifest\.source_commit/],
["final evidence requires current Client compatibility release", /compat\.release_name[\s\S]*manifest\.release_name/],
["final evidence requires current public coordinator source", /coreCoordinator\.source_commit[\s\S]*manifest\.source_commit/],
["final evidence requires current public coordinator release", /coreCoordinator\.release_name[\s\S]*manifest\.release_name/],
["final evidence requires server-generated service enrollment", /"server_generated_enrollment_grant"/],
["final evidence requires service probe cleanup", /"process_abort"/],
["final evidence requires process main launch", /e2e\.launch_task_response[\s\S]*"main_launched"/],
["final evidence requires assignment polling", /worker_assignment_poll_verified/],
["final evidence requires public coordinator validation", /core_coordinator_validated/],
["final evidence requires standalone Core coordinator", /standalone-core-coordinator/],
["final evidence requires released live DAP", /released_live_dap_verified/],
["final evidence requires pushed public tree", /publicTreeAlreadyPushed\(manifest\)/],
["final evidence requires release assets", /downloaded_release_assets/],
["final evidence requires VS Code debugger", /vscode_debugger_verified/],
["final evidence writes final report", /public-release-dryrun-final\.json/],
]) {
expect(finalEvidenceScript, name, pattern);
}
if (workflow) {
for (const [name, pattern] of [
["manual Forgejo workflow", /workflow_dispatch:/],
["Linux Forgejo asset job", /linux-assets:[\s\S]*runs-on: docker/],
["Windows Forgejo asset job", /windows-assets:[\s\S]*runs-on: windows/],
["Windows runner caveat", /intermittently online/],
["workflow runs release prep", /node scripts\/prepare-public-release-dryrun\.js/],
["workflow uploads assets", /actions\/upload-artifact@v4[\s\S]*target\/public-release-dryrun\/assets\/\*/],
]) {
expect(workflow, name, pattern);
}
}
expect(
prepScript,
"public tree prep disables interactive git prompts",
/function nonInteractiveGitEnv[\s\S]*GIT_TERMINAL_PROMPT[\s\S]*GIT_ASKPASS[\s\S]*SSH_ASKPASS[\s\S]*GIT_SSH_COMMAND[\s\S]*BatchMode=yes[\s\S]*NumberOfPasswordPrompts=0[\s\S]*function commandEnv/
);
for (const [scriptName, script] of [
["public acceptance", publicAcceptance],
["public split", publicSplit],
]) {
assert(
script.includes("node scripts/public-release-dryrun-contract-smoke.js"),
`${scriptName} must run public-release-dryrun-contract-smoke.js`
);
assert(
script.includes("node scripts/prepare-public-release-dryrun.js"),
`${scriptName} must run prepare-public-release-dryrun.js`
);
assert(
script.includes("node scripts/publish-public-release-dryrun.js"),
`${scriptName} must be able to publish the Forgejo Release`
);
assert(
script.includes("DISASMER_FORGEJO_TOKEN"),
`${scriptName} must gate Forgejo Release publishing on a token`
);
assert(
script.includes('if [[ -n "${DISASMER_FORGEJO_TOKEN:-}" ]]'),
`${scriptName} must not require owner/repo env when the manifest can infer the Forgejo repository`
);
}
for (const [scriptName, script] of [
["public acceptance", publicAcceptance],
["private acceptance", privateAcceptance],
]) {
if (scriptName === "public acceptance") {
assert(
script.includes("node scripts/public-release-dryrun-e2e.js"),
"public acceptance must be able to run public-release-dryrun-e2e.js"
);
assert(
script.includes("DISASMER_PUBLIC_RELEASE_DRYRUN_E2E"),
"public acceptance must gate public-release-dryrun-e2e.js"
);
}
assert(
script.includes("node scripts/public-release-dryrun-final-evidence.js"),
`${scriptName} must be able to run public-release-dryrun-final-evidence.js`
);
assert(
script.includes("DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL"),
`${scriptName} must gate final public release dry-run evidence`
);
}
console.log("Public release dry-run contract smoke passed");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,515 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const {
assertFinalLedger,
readPhase3Ledger,
} = require("./phase3-ledger");
const repo = path.resolve(__dirname, "..");
const releaseRoot = path.resolve(
process.env.DISASMER_PUBLIC_RELEASE_DIR ||
path.join(repo, "target/public-release-dryrun")
);
const acceptanceRoot = path.join(repo, "target/acceptance");
const serviceEndpoint = "https://disasmer.michelpaulissen.com";
const serviceHost = "disasmer.michelpaulissen.com";
const serviceAddr = `${serviceHost}:443`;
const forgejoHost = "git.michelpaulissen.com";
const inputs = {
manifest: process.env.DISASMER_PUBLIC_RELEASE_MANIFEST ||
path.join(releaseRoot, "public-release-manifest.json"),
forgejoRelease: process.env.DISASMER_PUBLIC_RELEASE_FORGEJO_REPORT ||
path.join(acceptanceRoot, "public-release-dryrun-forgejo-release.json"),
deployment: process.env.DISASMER_PUBLIC_RELEASE_DEPLOYMENT_MANIFEST ||
path.join(releaseRoot, "deployment/stage/deployment-manifest.json"),
service: process.env.DISASMER_PUBLIC_RELEASE_SERVICE_REPORT ||
path.join(acceptanceRoot, "public-release-dryrun-service.json"),
hostedClientCompat: process.env.DISASMER_HOSTED_CLIENT_COMPAT_REPORT ||
path.join(acceptanceRoot, "hosted-client-compat.json"),
coreCoordinatorCompat: process.env.DISASMER_CORE_COORDINATOR_COMPAT_REPORT ||
path.join(acceptanceRoot, "core-coordinator-compat.json"),
e2e: process.env.DISASMER_PUBLIC_RELEASE_E2E_REPORT ||
path.join(acceptanceRoot, "public-release-dryrun-e2e.json"),
};
assertFinalLedger(readPhase3Ledger(repo));
function readJson(name, file) {
assert(fs.existsSync(file), `missing ${name} evidence: ${file}`);
return JSON.parse(fs.readFileSync(file, "utf8"));
}
function assertIncludes(value, expected, message) {
assert(
typeof value === "string" && value.includes(expected),
`${message}: expected ${JSON.stringify(value)} to include ${expected}`
);
}
function assetNames(manifest) {
assert(Array.isArray(manifest.assets), "manifest assets must be an array");
return new Set(manifest.assets.map((asset) => asset.name));
}
function uploadedAssetNames(report) {
return new Set(
[...(report.uploaded_assets || []), ...(report.reused_assets || [])].map(
(asset) => asset.name
)
);
}
function assertEvidenceBooleans(report, fields) {
for (const field of fields) {
assert.strictEqual(report[field], true, `e2e report must set ${field}=true`);
}
}
function compactToolVersions(...reports) {
const versions = {};
for (const [name, report] of reports) {
if (report && report.tool_versions) {
versions[name] = report.tool_versions;
}
}
return versions;
}
function assertDnsState(value, name) {
assert(
["not-published", "published"].includes(value),
`${name} has unexpected DNS publication state: ${value}`
);
}
function assertFilteredOut(manifest) {
assert(Array.isArray(manifest.filtered_out), "manifest filtered_out must be an array");
for (const expected of [
"private/**",
"experiments/**",
".git",
"target",
"root/*.md except README.md and SECURITY.md",
"**/.disasmer/**",
]) {
assert(
manifest.filtered_out.includes(expected),
`manifest filtered_out must include ${expected}`
);
}
const includeForgejoWorkflows =
manifest.public_export && manifest.public_export.include_forgejo_workflows;
if (!includeForgejoWorkflows) {
assert(
manifest.filtered_out.includes(".forgejo/**"),
"manifest filtered_out must include .forgejo/** for the host-neutral export"
);
}
}
function publicTreeAlreadyPushed(manifest) {
return (
(manifest.public_tree_publish && manifest.public_tree_publish.pushed === true) ||
process.env.DISASMER_PUBLIC_TREE_ALREADY_PUSHED === "1"
);
}
function publicRepoRemote(manifest) {
return (
manifest.public_repo_url ||
manifest.public_repo_remote ||
process.env.DISASMER_PUBLIC_REPO_REMOTE ||
process.env.DISASMER_PUBLIC_REPO_URL ||
""
);
}
function commandOutput(command, args) {
try {
return require("child_process")
.execFileSync(command, args, {
cwd: repo,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
})
.trim();
} catch (_) {
return null;
}
}
function expectedSourceCommit() {
return (
process.env.DISASMER_ACCEPTANCE_COMMIT ||
commandOutput("git", ["rev-parse", "HEAD"]) ||
"unknown"
);
}
const manifest = readJson("public release manifest", inputs.manifest);
assert.strictEqual(manifest.kind, "disasmer-public-release-dryrun");
assert.strictEqual(
manifest.source_tree_clean,
true,
"final release evidence cannot be produced from a dirty source tree"
);
for (const binary of [
"disasmer",
"disasmer-coordinator",
"disasmer-node",
"disasmer-debug-dap",
]) {
const platformName = process.platform === "win32" ? `${binary}.exe` : binary;
assert.match(
manifest.binary_digests && manifest.binary_digests[platformName],
/^sha256:[a-f0-9]{64}$/,
`manifest omitted release binary digest for ${platformName}`
);
}
assert.strictEqual(
manifest.source_commit,
expectedSourceCommit(),
"final public release evidence must be generated from the current acceptance commit"
);
assert.strictEqual(manifest.default_hosted_coordinator_endpoint, serviceEndpoint);
assert.strictEqual(manifest.forgejo_host, forgejoHost);
assertDnsState(manifest.dns_publication_state, "manifest");
assert(manifest.resolver_override, "manifest must record resolver override");
assertFilteredOut(manifest);
assert.strictEqual(
publicTreeAlreadyPushed(manifest),
true,
"filtered public tree must be pushed to Forgejo"
);
const resolvedPublicRepoRemote = publicRepoRemote(manifest);
assertIncludes(
resolvedPublicRepoRemote,
forgejoHost,
"manifest public repository must point at Forgejo"
);
const manifestAssets = assetNames(manifest);
for (const pattern of [
/^disasmer-public-source-/,
/^disasmer-public-binaries-/,
/^disasmer-public-evidence-/,
/^disasmer-vscode-/,
/^DISASMER_PUBLIC_DRYRUN_GETTING_STARTED-/,
/^DISASMER_PUBLIC_DRYRUN_INVITE-/,
/^SHA256SUMS$/,
]) {
assert(
[...manifestAssets].some((name) => pattern.test(name)),
`manifest is missing asset matching ${pattern}`
);
}
const forgejoRelease = readJson("Forgejo Release report", inputs.forgejoRelease);
assert.strictEqual(
forgejoRelease.kind,
"disasmer-public-release-dryrun-forgejo-release"
);
assertIncludes(forgejoRelease.forgejo_url, forgejoHost, "Forgejo Release host");
assert.strictEqual(forgejoRelease.release_name, manifest.release_name);
assert.strictEqual(
forgejoRelease.default_hosted_coordinator_endpoint,
manifest.default_hosted_coordinator_endpoint
);
assert.strictEqual(
forgejoRelease.public_tree_identity,
manifest.public_tree_identity
);
assert.strictEqual(forgejoRelease.source_commit, manifest.source_commit);
const releaseAssets = uploadedAssetNames(forgejoRelease);
for (const asset of manifestAssets) {
assert(releaseAssets.has(asset), `Forgejo Release is missing asset ${asset}`);
}
const deployment = readJson("deployment manifest", inputs.deployment);
assert.strictEqual(deployment.kind, "disasmer-public-release-dryrun-deployment");
assert.strictEqual(deployment.default_hosted_coordinator_endpoint, serviceEndpoint);
assert.strictEqual(deployment.coordinator_implementation, "hosted-policy-coordinator");
assert.match(
deployment.public_release_meaning || "",
/public repository[\s\S]*public release assets[\s\S]*public client protocol/
);
assert.strictEqual(deployment.service_host, serviceHost);
assert.strictEqual(deployment.service_addr, serviceAddr);
assertDnsState(deployment.dns_publication_state, "deployment");
assert(deployment.resolver_override, "deployment manifest must record resolver override");
assert(deployment.deployed_service_commit, "deployment must record deployed service commit");
const service = readJson("live service smoke report", inputs.service);
assert.strictEqual(service.kind, "disasmer-public-release-dryrun-service");
assert.strictEqual(service.source_commit, manifest.source_commit);
assert.strictEqual(service.release_name, manifest.release_name);
assert.strictEqual(service.endpoint, serviceEndpoint);
assert.strictEqual(service.service_addr, serviceAddr);
assert.strictEqual(service.coordinator_implementation, "hosted-policy-coordinator");
assertDnsState(service.dns_publication_state, "service smoke");
assert(service.resolver_override, "service smoke must record resolver override");
assert.strictEqual(
service.public_tree_identity || manifest.public_tree_identity,
manifest.public_tree_identity
);
assert.strictEqual(
service.deployed_service_commit || deployment.deployed_service_commit,
deployment.deployed_service_commit
);
assert(service.deployment_config_commit, "service smoke must record deployment config commit");
assert(
service.deployment_system_generation,
"service smoke must record the activated NixOS system generation"
);
assert(service.service_unit, "service smoke must record the active service unit fragment");
for (const key of [
"ping",
"login",
"projects",
"forged_unsigned_project",
"session_scope",
"server_generated_enrollment_grant",
"node_credential",
"signed_node_heartbeat",
"signed_node_capabilities",
"scoped_node_listing",
"process_start",
"debug_attach",
"process_abort",
]) {
assert(service.evidence && service.evidence[key], `service smoke missing ${key}`);
}
assert.strictEqual(service.evidence.forged_unsigned_project, "error");
assert.strictEqual(service.evidence.session_scope, "derived_from_server_identity");
if (service.acceptance_result) {
assert.strictEqual(service.acceptance_result, "passed");
}
const compat = readJson("hosted Client compatibility report", inputs.hostedClientCompat);
assert.strictEqual(compat.kind, "disasmer-hosted-client-compatibility");
assert.strictEqual(compat.source_commit, manifest.source_commit);
assert.strictEqual(compat.release_name, manifest.release_name);
assert.strictEqual(
compat.public_cli_attach.coordinator_response,
"node_enrollment_exchanged"
);
assert.strictEqual(compat.public_cli_attach.heartbeat_response, "node_heartbeat");
assert.strictEqual(compat.server_owned_browser_login.response, "oidc_browser_session");
assert(compat.server_owned_browser_login.coordinator_requests >= 2);
assert.strictEqual(
compat.server_owned_browser_login.provider_tokens_exposed_to_cli,
false
);
assert.strictEqual(compat.server_owned_browser_login.session_scope_derived, true);
assert.strictEqual(compat.authority_denials.forged_unsigned_project, "error");
assert.strictEqual(compat.authority_denials.cross_tenant_task_events, "error");
assert.strictEqual(compat.session_lifecycle.logout_revoked, true);
assert.strictEqual(compat.session_lifecycle.revoked_reuse, "error");
assert.strictEqual(compat.session_lifecycle.expired_reuse, "error");
const coreCoordinator = readJson(
"Core coordinator compatibility report",
inputs.coreCoordinatorCompat
);
assert.strictEqual(coreCoordinator.kind, "disasmer-core-coordinator-compatibility");
assert.strictEqual(coreCoordinator.source_commit, manifest.source_commit);
assert.strictEqual(coreCoordinator.release_name, manifest.release_name);
assert.strictEqual(
coreCoordinator.coordinator_implementation,
"standalone-core-coordinator"
);
assert.strictEqual(coreCoordinator.client_authority, "strict");
assert.strictEqual(coreCoordinator.authenticated_session, true);
assert.strictEqual(coreCoordinator.forged_body_authority_denied, "error");
assert.strictEqual(coreCoordinator.wrong_session_denied, "error");
assert.strictEqual(coreCoordinator.self_hosted_cli.connected, "connected");
assert.strictEqual(coreCoordinator.self_hosted_cli.secret_read_from_stdin, true);
assert.strictEqual(coreCoordinator.self_hosted_cli.secret_exposed_in_report, false);
assert.strictEqual(coreCoordinator.self_hosted_cli.authenticated_status, "auth_status");
assert.strictEqual(
coreCoordinator.self_hosted_admin.nonce_bound_proof_succeeded,
"admin_status"
);
assert.strictEqual(coreCoordinator.self_hosted_admin.replay_denied, "error");
if (process.platform !== "win32") {
assert.strictEqual(coreCoordinator.self_hosted_cli.session_file_mode, "600");
}
assert.strictEqual(coreCoordinator.task_placement, "task_placement");
assert.strictEqual(coreCoordinator.task_completion, "task_recorded");
assert(coreCoordinator.task_events >= 1, "Core coordinator compat must record task events");
assert.strictEqual(coreCoordinator.artifact_export_plan, "artifact_export_plan");
const e2e = readJson("public repository e2e report", inputs.e2e);
assert.strictEqual(e2e.kind, "disasmer-public-release-dryrun-e2e");
assert.strictEqual(e2e.default_hosted_coordinator_endpoint, serviceEndpoint);
assert.strictEqual(e2e.service_addr, serviceAddr);
assert.strictEqual(e2e.launch_task_verified, true);
assert.strictEqual(e2e.worker_assignment_poll_verified, true);
assert.strictEqual(e2e.worker_assignment_poll_protocol, "poll_task_assignment");
assert.strictEqual(e2e.launch_task_response, "main_launched");
assert.strictEqual(e2e.worker_assignment_process, e2e.process);
assert.strictEqual(e2e.core_coordinator_validated, true);
assert.strictEqual(
e2e.core_coordinator_implementation,
"standalone-core-coordinator"
);
assert.strictEqual(e2e.core_coordinator_client_authority, "strict");
assert.strictEqual(e2e.core_coordinator_authenticated_session, true);
assert.strictEqual(e2e.core_coordinator_forged_body_authority_denied, "error");
assert.strictEqual(e2e.core_coordinator_wrong_session_denied, "error");
assert.strictEqual(e2e.core_coordinator_launch_task_response, "task_launched");
assert.strictEqual(e2e.core_coordinator_assignment_response, "task_assignment");
assert(e2e.core_coordinator_task_events >= 1, "e2e must record public coordinator task events");
assert.strictEqual(e2e.released_live_dap_verified, true);
assert.strictEqual(
e2e.released_live_dap_coordinator_implementation,
"hosted-policy-coordinator"
);
assert.strictEqual(e2e.released_live_dap_attached_to_client_process, true);
assert.strictEqual(e2e.released_live_dap_authenticated_with_cli_session, true);
assert(e2e.released_live_dap_task_events >= 1, "e2e must record released live-DAP task events");
assert(
e2e.evidence &&
e2e.evidence.released_live_dap &&
e2e.evidence.released_live_dap.attached_to_existing_client_process === true,
"e2e must prove released DAP attaches to the existing Client-authorized process"
);
assert(
e2e.evidence &&
e2e.evidence.released_live_dap &&
e2e.evidence.released_live_dap.variables_verified === true,
"e2e must prove released live-DAP variables are inspectable"
);
if (e2e.dns_publication_state) {
assertDnsState(e2e.dns_publication_state, "public repository e2e");
}
if (e2e.acceptance_result) {
assert.strictEqual(e2e.acceptance_result, "passed");
}
assertIncludes(e2e.public_repository_url, forgejoHost, "e2e public repo URL");
assert.strictEqual(e2e.release_name, manifest.release_name);
assert.strictEqual(e2e.public_tree_identity, manifest.public_tree_identity);
assert.strictEqual(e2e.source_commit, manifest.source_commit);
assertEvidenceBooleans(e2e, [
"downloaded_release_assets",
"verified_checksums",
"clean_public_checkout",
"public_repo_build_or_install",
"default_operator_selected",
"browser_or_cli_login",
"attached_user_node",
"core_coordinator_validated",
"released_live_dap_verified",
"ran_flagship_workflow",
"vscode_debugger_verified",
"logs_verified",
"artifact_metadata_verified",
"artifact_download_or_export_verified",
]);
assert(Array.isArray(e2e.commands) && e2e.commands.length > 0);
assert(Array.isArray(e2e.tool_versions) || typeof e2e.tool_versions === "object");
const finalReport = {
kind: "disasmer-public-release-dryrun-final-evidence",
release_name: manifest.release_name,
source_commit: manifest.source_commit,
public_tree_identity: manifest.public_tree_identity,
deployed_service_commit: deployment.deployed_service_commit,
default_hosted_coordinator_endpoint: serviceEndpoint,
service_addr: serviceAddr,
dns_publication_state: {
manifest: manifest.dns_publication_state,
deployment: deployment.dns_publication_state,
service: service.dns_publication_state,
public_repository_e2e: e2e.dns_publication_state || null,
},
resolver_override: {
manifest: manifest.resolver_override,
deployment: deployment.resolver_override,
service: service.resolver_override,
public_repository_e2e: e2e.resolver_override || null,
},
deployment_config: {
repo: service.deployment_config_repo || null,
commit: service.deployment_config_commit || null,
system_generation: service.deployment_system_generation || null,
service_unit: service.service_unit || null,
},
coordinator_validation: {
private_hosted_default_operator: {
coordinator_implementation: service.coordinator_implementation,
service_addr: service.service_addr,
launch_task: service.evidence.launch_task,
assignment_poll: service.evidence.assignment_poll,
released_live_dap: e2e.evidence.released_live_dap,
},
standalone_core_coordinator: {
coordinator_implementation: coreCoordinator.coordinator_implementation,
client_authority: coreCoordinator.client_authority,
authenticated_session: coreCoordinator.authenticated_session,
forged_body_authority_denied:
coreCoordinator.forged_body_authority_denied,
wrong_session_denied: coreCoordinator.wrong_session_denied,
self_hosted_cli: coreCoordinator.self_hosted_cli,
task_placement: coreCoordinator.task_placement,
task_events: coreCoordinator.task_events,
release_binary_e2e: {
client_authority: e2e.core_coordinator_client_authority,
authenticated_session: e2e.core_coordinator_authenticated_session,
forged_body_authority_denied:
e2e.core_coordinator_forged_body_authority_denied,
wrong_session_denied: e2e.core_coordinator_wrong_session_denied,
launch_task: e2e.core_coordinator_launch_task_response,
assignment_poll: e2e.core_coordinator_assignment_response,
task_events: e2e.core_coordinator_task_events,
},
},
},
forgejo_host: forgejoHost,
public_repository_url: resolvedPublicRepoRemote,
forgejo_release: {
owner: forgejoRelease.owner,
repo: forgejoRelease.repo,
release_id: forgejoRelease.release_id,
asset_count: releaseAssets.size,
},
tool_versions: compactToolVersions(
["manifest", manifest],
["service_smoke", service],
["public_repository_e2e", e2e]
),
acceptance_results: {
public_release_preparation: {
commands: manifest.commands,
result: "passed",
},
deployment_bundle: {
commands: deployment.commands,
result: "passed",
},
live_service_smoke: {
command: service.acceptance_command || null,
result: service.acceptance_result || "passed",
evidence: service.evidence,
},
core_coordinator_compatibility: {
result: "passed",
evidence: coreCoordinator,
},
public_repository_e2e: {
commands: e2e.commands,
result: "passed",
evidence: e2e.evidence,
},
},
evidence_files: inputs,
};
const output = path.join(acceptanceRoot, "public-release-dryrun-final.json");
fs.mkdirSync(path.dirname(output), { recursive: true });
fs.writeFileSync(output, `${JSON.stringify(finalReport, null, 2)}\n`);
console.log(`Public release dry-run final evidence passed: ${output}`);

View file

@ -0,0 +1,292 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const releaseRoot = path.resolve(
process.env.DISASMER_PUBLIC_RELEASE_DIR ||
path.join(repo, "target/public-release-dryrun")
);
const acceptanceRoot = path.join(repo, "target/acceptance");
const manifestPath =
process.env.DISASMER_PUBLIC_RELEASE_MANIFEST ||
path.join(releaseRoot, "public-release-manifest.json");
const reportPath =
process.env.DISASMER_PUBLIC_RELEASE_PREFLIGHT_REPORT ||
path.join(acceptanceRoot, "public-release-dryrun-preflight.json");
function commandOutput(command, args, options = {}) {
try {
return cp
.execFileSync(command, args, {
cwd: repo,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
...options,
})
.trim();
} catch (_) {
return null;
}
}
function nonInteractiveEnv(extra = {}) {
return {
...process.env,
GIT_TERMINAL_PROMPT: "0",
GIT_ASKPASS: process.env.GIT_ASKPASS || "/bin/false",
SSH_ASKPASS: process.env.SSH_ASKPASS || "/bin/false",
GIT_SSH_COMMAND:
process.env.GIT_SSH_COMMAND ||
"ssh -o BatchMode=yes -o NumberOfPasswordPrompts=0",
...extra,
};
}
function expectedSourceCommit() {
return (
process.env.DISASMER_ACCEPTANCE_COMMIT ||
commandOutput("git", ["rev-parse", "HEAD"]) ||
"unknown"
);
}
function readJson(file) {
return JSON.parse(fs.readFileSync(file, "utf8"));
}
function sha256File(file) {
return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
}
function parseSha256Sums(file) {
const sums = new Map();
for (const line of fs.readFileSync(file, "utf8").split(/\r?\n/)) {
if (!line.trim()) continue;
const match = /^([0-9a-f]{64})\s+(.+)$/.exec(line.trim());
assert(match, `malformed SHA256SUMS line: ${line}`);
sums.set(path.basename(match[2]), match[1]);
}
return sums;
}
function remoteHead(remote) {
const output = commandOutput("git", ["ls-remote", remote, "HEAD", "refs/heads/main"], {
env: nonInteractiveEnv(),
timeout: Number(process.env.DISASMER_PUBLIC_REPO_REMOTE_TIMEOUT_MS || 30000),
});
if (!output) return null;
const lines = output.split(/\r?\n/).filter(Boolean);
const head = lines.find((line) => line.endsWith("\tHEAD")) || lines[0];
return head && head.split(/\s+/)[0];
}
function publicTreeAlreadyPushed(manifest) {
return (
(manifest.public_tree_publish && manifest.public_tree_publish.pushed === true) ||
process.env.DISASMER_PUBLIC_TREE_ALREADY_PUSHED === "1"
);
}
function publicTreePushSource(manifest) {
return manifest.public_tree_publish && manifest.public_tree_publish.pushed === true
? "manifest"
: "external-env";
}
function publicRepoRemoteForManifest(manifest) {
return (
manifest.public_repo_url ||
manifest.public_repo_remote ||
process.env.DISASMER_PUBLIC_REPO_REMOTE ||
process.env.DISASMER_PUBLIC_REPO_URL ||
null
);
}
function publicTreeCommitForManifest(manifest) {
return (
(manifest.public_tree_publish && manifest.public_tree_publish.commit) ||
process.env.DISASMER_PUBLIC_TREE_COMMIT ||
process.env.DISASMER_PUBLIC_RELEASE_TARGET ||
null
);
}
function envState(name) {
return process.env[name] ? "set" : "unset";
}
function staleEvidence(file, currentSourceCommit) {
if (!fs.existsSync(file)) {
return { file, status: "missing", source_commit: null, release_name: null };
}
const evidence = readJson(file);
if (!evidence.source_commit) {
return {
file,
status: "unversioned",
source_commit: null,
release_name: evidence.release_name || null,
};
}
return {
file,
status: evidence.source_commit === currentSourceCommit ? "current" : "stale",
source_commit: evidence.source_commit,
release_name: evidence.release_name || null,
};
}
assert(fs.existsSync(manifestPath), `missing public release manifest: ${manifestPath}`);
const manifest = readJson(manifestPath);
const currentSourceCommit = expectedSourceCommit();
const currentTreeStatus = commandOutput("git", ["status", "--short"]) || "";
assert.strictEqual(
currentTreeStatus,
"",
"public release preflight requires a clean source tree"
);
assert.strictEqual(manifest.kind, "disasmer-public-release-dryrun");
assert.strictEqual(
manifest.source_commit,
currentSourceCommit,
"public release manifest must be regenerated for the current acceptance commit"
);
assert.strictEqual(manifest.source_tree_clean, true, "public release prep must start clean");
assert.strictEqual(
publicTreeAlreadyPushed(manifest),
true,
"filtered public tree must be pushed to Forgejo before release publication"
);
const publicRepoRemote = publicRepoRemoteForManifest(manifest);
assert(publicRepoRemote, "manifest must record public repository URL or remote");
const publicTreeCommit = publicTreeCommitForManifest(manifest);
const remoteMain = remoteHead(publicRepoRemote);
assert(remoteMain, "Forgejo public repository main branch must be readable");
if (publicTreeCommit) {
assert.strictEqual(
remoteMain,
publicTreeCommit,
"Forgejo public repository main branch must match the prepared public tree commit"
);
}
assert(Array.isArray(manifest.assets) && manifest.assets.length > 0, "manifest assets missing");
const checksumAsset = manifest.assets.find((asset) => asset.name === "SHA256SUMS");
assert(checksumAsset, "manifest must include SHA256SUMS");
assert(fs.existsSync(checksumAsset.file), `missing checksum asset: ${checksumAsset.file}`);
const checksums = parseSha256Sums(checksumAsset.file);
const assets = manifest.assets.map((asset) => {
assert(fs.existsSync(asset.file), `missing release asset: ${asset.file}`);
const actual = sha256File(asset.file);
const expected = checksums.get(asset.name);
if (asset.name !== "SHA256SUMS") {
assert.strictEqual(actual, expected, `checksum mismatch for ${asset.name}`);
}
return {
name: asset.name,
file: asset.file,
bytes: fs.statSync(asset.file).size,
sha256: actual,
};
});
const evidence = [
staleEvidence(
path.join(acceptanceRoot, "public-release-dryrun-forgejo-release.json"),
currentSourceCommit
),
staleEvidence(
path.join(acceptanceRoot, "public-release-dryrun-service.json"),
currentSourceCommit
),
staleEvidence(
path.join(acceptanceRoot, "hosted-client-compat.json"),
currentSourceCommit
),
staleEvidence(
path.join(acceptanceRoot, "core-coordinator-compat.json"),
currentSourceCommit
),
staleEvidence(
path.join(acceptanceRoot, "public-release-dryrun-e2e.json"),
currentSourceCommit
),
staleEvidence(
path.join(acceptanceRoot, "public-release-dryrun-final.json"),
currentSourceCommit
),
];
const report = {
kind: "disasmer-public-release-dryrun-preflight",
source_commit: currentSourceCommit,
release_name: manifest.release_name,
public_tree_commit: publicTreeCommit || remoteMain,
public_tree_push_source: publicTreePushSource(manifest),
public_repo_url: publicRepoRemote,
public_repo_remote_head: remoteMain,
source_tree_clean: currentTreeStatus === "",
local_assets_ready: true,
assets,
evidence,
external_gates: {
forgejo_release_publication: {
status: envState("DISASMER_FORGEJO_TOKEN") === "set" ? "ready" : "pending",
env: {
DISASMER_FORGEJO_TOKEN: envState("DISASMER_FORGEJO_TOKEN"),
},
},
live_service_smoke: {
status:
envState("DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR") === "set" &&
envState("DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND") === "set"
? "ready"
: "pending",
env: {
DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR: envState(
"DISASMER_PUBLIC_RELEASE_DRYRUN_SERVICE_ADDR"
),
DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND: envState(
"DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND"
),
},
},
public_release_e2e: {
status:
envState("DISASMER_PUBLIC_RELEASE_DRYRUN_E2E") === "set" &&
process.env.DISASMER_PUBLIC_RELEASE_DRYRUN_E2E === "1" &&
envState("DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND") === "set"
? "ready"
: "pending",
env: {
DISASMER_PUBLIC_RELEASE_DRYRUN_E2E:
process.env.DISASMER_PUBLIC_RELEASE_DRYRUN_E2E || "unset",
DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND: envState(
"DISASMER_PUBLIC_RELEASE_DRYRUN_BROWSER_OPEN_COMMAND"
),
},
},
final_evidence: {
status:
envState("DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL") === "set" &&
process.env.DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL === "1"
? "ready"
: "pending",
env: {
DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL:
process.env.DISASMER_PUBLIC_RELEASE_DRYRUN_FINAL || "unset",
},
},
},
};
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
fs.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`);
console.log(JSON.stringify({ report: reportPath, release_name: report.release_name }, null, 2));

View file

@ -0,0 +1,101 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing public-story evidence: ${name}`);
}
const readme = read("README.md");
const publicAcceptance = read("scripts/acceptance-public.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const cliLocalRunSmoke = read("scripts/cli-local-run-smoke.js");
const dapSmoke = read("scripts/dap-smoke.js");
const wasmtimeAssignmentSmoke = read("scripts/wasmtime-assignment-smoke.js");
const debuggerEvidence = `${dapSmoke}\n${wasmtimeAssignmentSmoke}`;
const flagshipDemoSmoke = read("scripts/flagship-demo-smoke.js");
const artifactDownloadSmoke = read("scripts/artifact-download-smoke.js");
const artifactExportSmoke = read("scripts/artifact-export-smoke.js");
for (const [scriptName, script] of [
["public acceptance", publicAcceptance],
["public split", publicSplit],
]) {
assert(
script.includes("node scripts/public-story-contract-smoke.js"),
`${scriptName} must run public-story-contract-smoke.js`
);
}
for (const [name, pattern] of [
[
"README states public story",
/one virtual process, many virtual threads\/tasks, ordinary debugger controls, attached user nodes, and explicit artifact handling/,
],
[
"README states local-first bytes policy",
/local source checkouts and large outputs stay node-local unless user code or policy explicitly moves bytes/,
],
[
"README states normal debugger controls",
/ordinary debugger\s+controls for breakpoints, continue, pause, and restart/,
],
]) {
expect(readme, name, pattern);
}
for (const [name, pattern] of [
["CLI local run starts a node process", /cli_process_started_node_process/],
["CLI local run checks node is separate from CLI", /assert\.notStrictEqual\(report\.boundary\.spawned_node_process_id, cliPid\)/],
["CLI local run checks node is separate from coordinator", /assert\.notStrictEqual\(report\.boundary\.spawned_node_process_id, coordinator\.pid\)/],
["CLI local run records the real virtual task tree", /events\.events\.length >= 4[\s\S]*prepare_source[\s\S]*compile_linux[\s\S]*package_release/],
["CLI local run records real artifact metadata", /events\.events\.some\(\(event\) => event\.artifact_path\)/],
["CLI local-only run starts coordinator", /cli_process_started_coordinator_process[\s\S]*true/],
["CLI local-only run hides coordinator address requirement", /\["run"[\s\S]*"--local"[\s\S]*"--project"[\s\S]*project/],
]) {
expect(cliLocalRunSmoke, name, pattern);
}
for (const [name, pattern] of [
["DAP smoke uses local-services runtime", /runtimeBackend: "local-services"/],
["DAP smoke exposes dynamic entry and child virtual threads", /mainThread[\s\S]*build virtual process[\s\S]*childThread[\s\S]*notStrictEqual\(childThread\.id, failThread\.id\)/],
["DAP smoke binds the real entrypoint breakpoint", /stack\[0\]\.line, buildMainLine[\s\S]*stack\[0\]\.name, \/build_main::wasm\//],
["DAP smoke binds the real child task breakpoint", /childStack\[0\]\.line, taskTrapLine[\s\S]*childStack\[0\]\.name, \/task_trap::wasm\//],
["DAP smoke all-stops on breakpoint", /assert\.strictEqual\(stopped\.body\.allThreadsStopped, true\)/],
["runtime smoke proves acknowledged pause all-stop", /fully_frozen[\s\S]*resume_debug_epoch[\s\S]*fully_resumed/],
["DAP smoke refuses active-task restart without a clean boundary", /restartFailure[\s\S]*checkpoint boundary\|still active/],
["DAP smoke supports rebuilt terminal main restart", /restartFrame[\s\S]*Restarted main from the rebuilt bundle/],
["DAP smoke avoids native child debugger claims", /doesNotMatch\(stack\[0\]\.name, \/podman\|cmd\\\.exe\|powershell\|pid\|native child\/i\)/],
["DAP smoke crosses coordinator-node boundary without fabricating terminal state", /runtime_backend[\s\S]*LocalServices[\s\S]*coordinator_task_events[\s\S]*0/],
]) {
expect(debuggerEvidence, name, pattern);
}
for (const [name, pattern] of [
["flagship source does not need coordinator checkout", /coordinator_requires_checkout_access[\s\S]*false/],
["flagship source bytes remain node-local", /local_source_bytes_remain_node_local[\s\S]*true/],
["flagship avoids default source upload", /coordinator_receives_source_bytes_by_default[\s\S]*false/],
["flagship avoids default repo tarball", /default_full_repo_tarball[\s\S]*false/],
]) {
expect(flagshipDemoSmoke, name, pattern);
}
for (const [name, source, pattern] of [
["artifact download creates scoped link", artifactDownloadSmoke, /create_artifact_download_link/],
["artifact download records retained-node source", artifactDownloadSmoke, /assert\.deepStrictEqual\(link\.link\.source, \{ RetainedNode: "node-download" \}\)/],
["artifact download opens scoped stream", artifactDownloadSmoke, /open_artifact_download_stream/],
["artifact export targets attached receiver node", artifactExportSmoke, /export_artifact_to_node[\s\S]*node-export-receiver/],
["artifact export disables coordinator bulk relay", artifactExportSmoke, /coordinator_bulk_relay_allowed[\s\S]*false/],
]) {
expect(source, name, pattern);
}
console.log("Public story contract smoke passed");

View file

@ -0,0 +1,349 @@
#!/usr/bin/env node
const fs = require("fs");
const https = require("https");
const path = require("path");
const cp = require("child_process");
const repo = path.resolve(__dirname, "..");
const releaseRoot = path.resolve(
process.env.DISASMER_PUBLIC_RELEASE_DIR ||
path.join(repo, "target/public-release-dryrun")
);
const manifestPath = path.join(releaseRoot, "public-release-manifest.json");
const reportPath = path.join(
repo,
"target/acceptance/public-release-dryrun-forgejo-release.json"
);
const forgejoUrl = (
process.env.DISASMER_FORGEJO_URL || "https://git.michelpaulissen.com"
).replace(/\/+$/, "");
const token = process.env.DISASMER_FORGEJO_TOKEN;
let owner = process.env.DISASMER_PUBLIC_REPO_OWNER;
let repoName = process.env.DISASMER_PUBLIC_REPO_NAME;
function requireEnv(name, value) {
if (!value) {
throw new Error(`${name} is required`);
}
}
function commandOutput(command, args) {
try {
return cp
.execFileSync(command, args, {
cwd: repo,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
})
.trim();
} catch (_) {
return null;
}
}
function expectedSourceCommit() {
return (
process.env.DISASMER_ACCEPTANCE_COMMIT ||
commandOutput("git", ["rev-parse", "HEAD"]) ||
"unknown"
);
}
function parseForgejoRepoIdentity(remote) {
if (!remote) {
return null;
}
let pathname = remote;
try {
pathname = new URL(remote).pathname;
} catch (_) {
const scpLike = /^[^@/]+@[^:]+:(.+)$/.exec(remote);
if (scpLike) {
pathname = scpLike[1];
}
}
const parts = pathname
.replace(/^\/+/, "")
.replace(/\.git$/, "")
.split("/")
.filter(Boolean);
if (parts.length < 2) {
return null;
}
return {
owner: parts[parts.length - 2],
repoName: parts[parts.length - 1],
};
}
function resolveRepoIdentity(manifest) {
if (owner && repoName) {
return;
}
const inferred = parseForgejoRepoIdentity(
manifest.public_repo_url ||
manifest.public_repo_remote ||
process.env.DISASMER_PUBLIC_REPO_REMOTE
);
owner = owner || (inferred && inferred.owner);
repoName = repoName || (inferred && inferred.repoName);
if (!owner || !repoName) {
throw new Error(
"DISASMER_PUBLIC_REPO_OWNER and DISASMER_PUBLIC_REPO_NAME are required when the manifest does not contain a parseable Forgejo repository URL"
);
}
}
function publicTreeAlreadyPushed(manifest) {
return (
(manifest.public_tree_publish && manifest.public_tree_publish.pushed === true) ||
process.env.DISASMER_PUBLIC_TREE_ALREADY_PUSHED === "1"
);
}
function publicTreeCommit(manifest) {
return (
(manifest.public_tree_publish && manifest.public_tree_publish.commit) ||
process.env.DISASMER_PUBLIC_TREE_COMMIT ||
process.env.DISASMER_PUBLIC_RELEASE_TARGET ||
null
);
}
function apiPath(pathname) {
return `/api/v1${pathname}`;
}
function request(method, pathname, { body, headers = {} } = {}) {
const url = new URL(apiPath(pathname), forgejoUrl);
const payload =
body === undefined
? null
: Buffer.isBuffer(body)
? body
: Buffer.from(JSON.stringify(body));
const requestHeaders = {
Accept: "application/json",
Authorization: `token ${token}`,
...headers,
};
if (payload) {
requestHeaders["Content-Length"] = payload.length;
if (!requestHeaders["Content-Type"]) {
requestHeaders["Content-Type"] = "application/json";
}
}
return new Promise((resolve, reject) => {
const req = https.request(
url,
{
method,
headers: requestHeaders,
},
(res) => {
const chunks = [];
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => {
const text = Buffer.concat(chunks).toString("utf8");
let parsed = null;
if (text.trim()) {
try {
parsed = JSON.parse(text);
} catch (_) {
parsed = text;
}
}
if (res.statusCode < 200 || res.statusCode >= 300) {
reject(
new Error(
`${method} ${url.pathname} failed with ${res.statusCode}: ${text}`
)
);
return;
}
resolve({ status: res.statusCode, body: parsed });
});
}
);
req.on("error", reject);
if (payload) req.write(payload);
req.end();
});
}
function multipartFile(fieldName, file) {
const boundary = `disasmer-${Date.now()}-${Math.random().toString(16).slice(2)}`;
const name = path.basename(file);
const header = Buffer.from(
`--${boundary}\r\n` +
`Content-Disposition: form-data; name="${fieldName}"; filename="${name}"\r\n` +
"Content-Type: application/octet-stream\r\n\r\n"
);
const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
return {
body: Buffer.concat([header, fs.readFileSync(file), footer]),
contentType: `multipart/form-data; boundary=${boundary}`,
};
}
async function existingRelease(tagName) {
const releases = await request(
"GET",
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repoName)}/releases?limit=100`
);
return (releases.body || []).find((release) => release.tag_name === tagName) || null;
}
async function createOrReuseRelease(manifest) {
const tagName = manifest.release_name;
const found = await existingRelease(tagName);
if (found) {
return { release: found, created: false };
}
const targetCommitish =
publicTreeCommit(manifest) ||
"main";
const body = [
"Disasmer public release dry run.",
"",
`Default hosted coordinator endpoint: ${manifest.default_hosted_coordinator_endpoint}`,
`DNS publication state: ${manifest.dns_publication_state}`,
`Resolver override: ${manifest.resolver_override}`,
`Public tree identity: ${manifest.public_tree_identity}`,
`Source commit: ${manifest.source_commit}`,
].join("\n");
const created = await request(
"POST",
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repoName)}/releases`,
{
body: {
tag_name: tagName,
target_commitish: targetCommitish,
name: tagName,
body,
draft: false,
prerelease: true,
},
}
);
return { release: created.body, created: true };
}
async function loadRelease(releaseId) {
const response = await request(
"GET",
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repoName)}/releases/${releaseId}`
);
return response.body;
}
async function uploadAsset(release, asset) {
const { body, contentType } = multipartFile("attachment", asset.file);
const response = await request(
"POST",
`/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repoName)}/releases/${release.id}/assets?name=${encodeURIComponent(asset.name)}`,
{
body,
headers: {
"Content-Type": contentType,
},
}
);
return response.body;
}
function existingAssetByName(release, name) {
return Array.isArray(release.assets)
? release.assets.find((asset) => asset.name === name) || null
: null;
}
async function main() {
requireEnv("DISASMER_FORGEJO_TOKEN", token);
if (!fs.existsSync(manifestPath)) {
throw new Error(`missing public release manifest: ${manifestPath}`);
}
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
resolveRepoIdentity(manifest);
if (manifest.kind !== "disasmer-public-release-dryrun") {
throw new Error(`unexpected public release manifest kind: ${manifest.kind}`);
}
if (manifest.source_commit !== expectedSourceCommit()) {
throw new Error(
"public release manifest is stale; regenerate it for the current acceptance commit before publishing the Forgejo Release"
);
}
if (
!publicTreeAlreadyPushed(manifest)
) {
throw new Error(
"public tree must be pushed before publishing the Forgejo Release; run prepare-public-release-dryrun.js with DISASMER_PUBLISH_PUBLIC_TREE=1"
);
}
if (!Array.isArray(manifest.assets) || manifest.assets.length === 0) {
throw new Error("public release manifest has no assets");
}
const { release: releaseResult, created } = await createOrReuseRelease(manifest);
const release = await loadRelease(releaseResult.id);
const uploaded = [];
const reused = [];
for (const asset of manifest.assets) {
if (!fs.existsSync(asset.file)) {
throw new Error(`missing release asset: ${asset.file}`);
}
const existing = existingAssetByName(release, asset.name);
if (existing) {
reused.push(existing);
continue;
}
uploaded.push(await uploadAsset(release, asset));
}
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
const report = {
kind: "disasmer-public-release-dryrun-forgejo-release",
forgejo_url: forgejoUrl,
owner,
repo: repoName,
release_id: release.id,
release_name: release.name || manifest.release_name,
tag_name: release.tag_name || manifest.release_name,
release_created: created,
default_hosted_coordinator_endpoint: manifest.default_hosted_coordinator_endpoint,
public_tree_identity: manifest.public_tree_identity,
public_tree_commit: publicTreeCommit(manifest),
source_commit: manifest.source_commit,
uploaded_assets: uploaded.map((asset) => ({
id: asset.id,
name: asset.name,
size: asset.size,
browser_download_url: asset.browser_download_url,
})),
reused_assets: reused.map((asset) => ({
id: asset.id,
name: asset.name,
size: asset.size,
browser_download_url: asset.browser_download_url,
})),
};
fs.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`);
console.log(
JSON.stringify(
{ report: reportPath, uploaded: uploaded.length, reused: reused.length },
null,
2
)
);
}
main().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

154
scripts/quic-smoke.js Executable file
View file

@ -0,0 +1,154 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const repo = path.resolve(__dirname, "..");
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function rendezvousRequest(overrides = {}) {
return {
type: "request_rendezvous",
scope: {
tenant: "tenant",
project: "project",
process: "vp-quic",
object: { Artifact: "quic-artifact" },
authorization_subject: "node-a-to-node-b",
},
source: {
node: "node-a",
advertised_addr: "node-a.mesh.invalid:4433",
public_key_fingerprint: "sha256:node-a-public-key",
},
destination: {
node: "node-b",
advertised_addr: "node-b.mesh.invalid:4433",
public_key_fingerprint: "sha256:node-b-public-key",
},
direct_connectivity: true,
failure_reason: "",
...overrides,
};
}
(async () => {
const output = cp.execFileSync(
"cargo",
["run", "-q", "-p", "disasmer-node", "--bin", "disasmer-quic-smoke"],
{ cwd: repo, encoding: "utf8" }
);
const report = JSON.parse(output.trim().split("\n").at(-1));
assert.strictEqual(report.kind, "disasmer_quic_smoke");
assert.strictEqual(report.transport, "NativeQuic");
assert.strictEqual(report.rust_native_quic, true);
assert.strictEqual(report.authenticated_direct_connection, true);
assert.strictEqual(report.coordinator_assisted_rendezvous, true);
assert.strictEqual(report.coordinator_bulk_relay_allowed, false);
assert.strictEqual(report.source_node, "node-a");
assert.strictEqual(report.destination_node, "node-b");
assert.strictEqual(report.scope.tenant, "tenant");
assert.strictEqual(report.scope.project, "project");
assert.strictEqual(report.scope.process, "vp-quic");
assert.deepStrictEqual(report.scope.object, { Artifact: "quic-artifact" });
assert.ok(report.authorization_digest.startsWith("sha256:"));
assert.ok(report.request_bytes > 0);
assert.strictEqual(report.server_received_request_bytes, report.request_bytes);
assert.ok(report.payload_bytes > 0);
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback",
],
{ cwd: repo }
);
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
const plan = await send(addr, rendezvousRequest());
assert.strictEqual(plan.type, "rendezvous_plan");
assert.strictEqual(plan.charged_rendezvous_attempts, 1);
assert.strictEqual(plan.plan.transport, "NativeQuic");
assert.strictEqual(plan.plan.scope.tenant, "tenant");
assert.strictEqual(plan.plan.scope.project, "project");
assert.strictEqual(plan.plan.source.node, "node-a");
assert.strictEqual(plan.plan.destination.node, "node-b");
assert.strictEqual(plan.plan.coordinator_assisted_rendezvous, true);
assert.strictEqual(plan.plan.coordinator_bulk_relay_allowed, false);
assert.ok(plan.plan.authorization_digest.startsWith("sha256:"));
const failed = await send(
addr,
rendezvousRequest({
direct_connectivity: false,
failure_reason: "nat traversal failed",
})
);
assert.strictEqual(failed.type, "error");
assert.match(failed.message, /nat traversal failed/);
assert.match(failed.message, /coordinator bulk relay is disabled/);
} finally {
coordinator.kill("SIGTERM");
}
console.log("QUIC smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,230 @@
const assert = require("assert");
const cp = require("child_process");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const { configurePodmanTestEnvironment } = require("./podman-test-env");
const repo = path.resolve(__dirname, "..");
const project = path.join(repo, "examples/launch-build-demo");
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.stderr?.on("data", (chunk) => {
stderr += chunk.toString();
if (stderr.length > 4096) stderr = stderr.slice(-4096);
});
child.once("exit", (code) => {
const detail = stderr.trim();
reject(new Error(
`process exited before JSON line with code ${code}${detail ? `: ${detail}` : ""}`
));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function configureContainerPolicyHome() {
configurePodmanTestEnvironment(repo);
}
function commandWithPodman(program, args) {
if (cp.spawnSync("podman", ["--version"], { stdio: "ignore" }).status === 0) {
return { program, args };
}
if (cp.spawnSync("nix", ["--version"], { stdio: "ignore" }).status === 0) {
return {
program: "nix",
args: ["shell", "nixpkgs#podman", "--command", program, ...args],
};
}
throw new Error(
"real flagship smoke requires rootless Podman (or Nix to provide it)"
);
}
function ensureRootlessPodman() {
configureContainerPolicyHome();
const invocation = commandWithPodman("podman", [
"info",
"--format",
"{{.Host.Security.Rootless}}",
]);
const rootless = cp.execFileSync(invocation.program, invocation.args, {
cwd: repo,
env: process.env,
encoding: "utf8",
}).trim();
assert.strictEqual(rootless, "true", "flagship worker must use rootless Podman");
}
async function runFlagshipWorker(addr, node, identity) {
const enrollment = await send(addr, {
type: "create_node_enrollment_grant",
tenant: "tenant",
project: "project",
actor_user: "user",
ttl_seconds: 60,
});
assert.strictEqual(enrollment.type, "node_enrollment_grant_created");
const cargoArgs = [
"run", "-q", "-p", "disasmer-node", "--bin", "disasmer-node", "--",
"--coordinator", `${addr.host}:${addr.port}`,
"--tenant", "tenant",
"--project-id", "project",
"--node", node,
"--enrollment-grant", enrollment.grant,
"--worker",
"--emit-ready",
"--project-root", project,
"--assignment-poll-ms", "25",
];
const invocation = commandWithPodman("cargo", cargoArgs);
const child = cp.spawn(invocation.program, invocation.args, {
cwd: repo,
env: {
...process.env,
DISASMER_NODE_PRIVATE_KEY: identity.privateKey,
},
});
return { child, ready: waitForJsonLine(child) };
}
const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
async function waitForTaskEvent(addr, process, predicate, description) {
for (let attempt = 0; attempt < 2400; attempt += 1) {
const response = await send(addr, {
type: "list_task_events",
tenant: "tenant",
project: "project",
actor_user: "user",
process,
});
assert.strictEqual(response.type, "task_events", JSON.stringify(response));
const event = response.events.find(predicate);
if (event) return event;
await delay(25);
}
throw new Error(`timed out waiting for real Wasm task ${description}`);
}
function startFlagship(addr) {
const report = JSON.parse(
cp.execFileSync(
"cargo",
[
"run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--",
"run", "build",
"--coordinator", `disasmer+tcp://${addr.host}:${addr.port}`,
"--project", project,
"--json",
],
{ cwd: repo, env: process.env, encoding: "utf8" }
)
);
assert.strictEqual(report.command, "run");
assert.strictEqual(report.status, "main_launched", JSON.stringify(report));
assert.strictEqual(report.entry, "build");
assert.strictEqual(report.task_launch.type, "main_launched");
assert.strictEqual(report.task_launch.task_instance, report.task_instance);
assert.strictEqual(report.task_launch.task_definition, report.task_definition);
assert.strictEqual(report.worker_placement_requested, true);
assert.match(report.bundle_digest, /^sha256:[0-9a-f]{64}$/);
assert.match(report.entry_export, /^disasmer_entry_v1_/);
const virtualProcess = report.process;
return { report, process: virtualProcess };
}
async function launchFlagship(addr) {
const { report, process: virtualProcess } = startFlagship(addr);
const compileEvent = await waitForTaskEvent(
addr,
virtualProcess,
(event) => event.task_definition === "compile_linux",
"compile_linux"
);
const packageEvent = await waitForTaskEvent(
addr,
virtualProcess,
(event) => event.task_definition === "package_release",
"package_release"
);
const buildEvent = await waitForTaskEvent(
addr,
virtualProcess,
(event) => event.task === report.task_instance && event.executor === "coordinator_main",
"coordinator build main"
);
for (const event of [compileEvent, packageEvent, buildEvent]) {
assert.strictEqual(event.terminal_state, "completed", JSON.stringify(event));
}
return {
report,
process: virtualProcess,
compileEvent,
packageEvent,
buildEvent,
};
}
function flagshipNodeCapabilities() {
return {
os: "Linux",
arch: process.arch,
capabilities: [
"Command",
"Containers",
"RootlessPodman",
"SourceFilesystem",
"VfsArtifacts",
],
environment_backends: ["Container"],
source_providers: ["filesystem"],
};
}
module.exports = {
ensureRootlessPodman,
flagshipNodeCapabilities,
launchFlagship,
project,
repo,
runFlagshipWorker,
send,
startFlagship,
waitForTaskEvent,
waitForJsonLine,
};

189
scripts/release-blocker-smoke.js Executable file
View file

@ -0,0 +1,189 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function maybeRead(relativePath) {
const fullPath = path.join(repo, relativePath);
if (!fs.existsSync(fullPath)) return null;
return fs.readFileSync(fullPath, "utf8");
}
function section(source, heading) {
const marker = `## ${heading}`;
const start = source.indexOf(marker);
assert(start >= 0, `missing section ${marker}`);
const next = source.indexOf("\n## ", start + marker.length);
return source.slice(start, next >= 0 ? next : source.length);
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing release-blocker evidence: ${name}`);
}
const hiddenDemoBlockerPattern = new RegExp(
[
"flagship demo requires",
["undocumented", "manual state"].join(" "),
["hard-coded", "local paths"].join(" "),
["demo-only", "credentials"].join(" "),
["hidden", "setup"].join(" "),
].join("[\\s\\S]*")
);
const hiddenDemoScanPattern = new RegExp(
`demo_setup_pattern='${[
["undocumented", "manual state"].join(" "),
["hidden", "setup"].join(" "),
["demo-only", "credentials?"].join(" "),
["hard-coded", "local paths?"].join(" "),
]
.map((term) => term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
.join("\\\\|")}'`
);
const phase2 = read("acceptance_criteria_phase2.md");
const base = read("acceptance_criteria.md");
const publicAcceptance = read("scripts/acceptance-public.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const artifactDownloadSmoke = read("scripts/artifact-download-smoke.js");
const operatorPanelSmoke = read("scripts/operator-panel-smoke.js");
const schedulerSmoke = read("scripts/scheduler-placement-smoke.js");
const sourcePreparationSmoke = read("scripts/source-preparation-smoke.js");
const hostedClientCompatSmoke = maybeRead("private/hosted-policy/scripts/hosted-client-compat-smoke.js");
const releaseSourceScan = read("scripts/release-source-scan.sh");
const flagshipDemoSmoke = read("scripts/flagship-demo-smoke.js");
const releaseBlockers = section(phase2, "20. Release blockers");
expect(
releaseBlockers,
"cross-tenant access is listed as a release blocker",
/Cross-tenant access succeeds for projects, nodes, processes, logs, artifacts, downloads, debug state, panels, capabilities, source manifests, credentials, or metadata/
);
expect(
releaseBlockers,
"manual-state flagship blocker is listed",
hiddenDemoBlockerPattern
);
expect(
section(base, "21. Authorization and tenant isolation"),
"base criteria require tenant isolation failures to block release",
/Tenant isolation failures are treated as release blockers/
);
for (const [scriptName, script] of [
["public acceptance", publicAcceptance],
["public split", publicSplit],
]) {
for (const smoke of [
"scripts/artifact-download-smoke.js",
"scripts/operator-panel-smoke.js",
"scripts/source-preparation-smoke.js",
"scripts/scheduler-placement-smoke.js",
"scripts/flagship-demo-smoke.js",
]) {
assert(
script.includes(`node ${smoke}`),
`${scriptName} must run ${smoke} as part of tenant-isolation release blocking`
);
}
assert(
script.includes("scripts/release-source-scan.sh"),
`${scriptName} must run release-source-scan.sh as part of release blocking`
);
}
assert(
privateAcceptance.includes("node private/hosted-policy/scripts/hosted-client-compat-smoke.js"),
"private acceptance must run hosted Client cross-tenant checks"
);
assert(
privateAcceptance.includes("node private/hosted-policy/scripts/hosted-deployment-smoke.js"),
"private acceptance must run hosted deployment checks"
);
const boundaryEvidence = [
[
"artifact download",
artifactDownloadSmoke,
[/const crossTenant = await send/, /const crossTenantOpen = await send/, /tenant mismatch/],
],
[
"operator panel",
operatorPanelSmoke,
[/const crossTenant = await send/, /render_operator_panel/, /scope\|tenant\|project/],
],
[
"source preparation",
sourcePreparationSmoke,
[/const crossTenantCompletion = await send/, /complete_source_preparation/, /tenant\\\/project scope/i],
],
[
"scheduler/node capability",
schedulerSmoke,
[/const crossTenantReport = await send/, /report_node_capabilities/, /tenant\\\/project scope/],
],
];
if (hostedClientCompatSmoke) {
boundaryEvidence.push([
"hosted Client compatibility",
hostedClientCompatSmoke,
[
/const forged = await sendHostedControl/,
/const crossTenantTaskEventsDenied = await sendHostedControl/,
/scope\|denied\|unauthorized/,
],
]);
}
for (const [name, source, patterns] of boundaryEvidence) {
for (const pattern of patterns) {
expect(source, name, pattern);
}
}
for (const [name, pattern] of [
["release source scan rejects manual demo state", hiddenDemoScanPattern],
["release source scan rejects hidden local paths", /hidden_local_pattern='file:\/\/\|\/home\/\[.*\]_.-\]\+\/\|\/Users\/\[.*\]_.-\]\+\/\|C:\\\\Users\\\\\|https\?:\/\/\(localhost\|127\\\.0\\\.0\\\.1\)/],
]) {
expect(releaseSourceScan, name, pattern);
}
for (const [name, pattern] of [
["public split excludes private modules", /--exclude='\.\/private'/],
["public split excludes experiments", /--exclude='\.\/experiments'/],
["public split tests copied workspace", /cargo test --workspace --manifest-path "\$tmp_dir\/Cargo\.toml"/],
["public split builds copied workspace bins", /cargo build --workspace --bins --manifest-path "\$tmp_dir\/Cargo\.toml"/],
["public split installs CLI from copied tree", /\(cd "\$tmp_dir" && node scripts\/cli-install-smoke\.js\)/],
["public split installs VS Code extension from copied tree", /\(cd "\$tmp_dir" && node scripts\/vscode-extension-smoke\.js\)/],
["public split attaches node from copied tree", /\(cd "\$tmp_dir" && node scripts\/node-attach-smoke\.js\)/],
["public split runs real Wasm assignments from copied tree", /\(cd "\$tmp_dir" && node scripts\/wasmtime-assignment-smoke\.js\)/],
["public split runs CLI local workflow from copied tree", /\(cd "\$tmp_dir" && node scripts\/cli-local-run-smoke\.js\)/],
["public split runs artifact download from copied tree", /\(cd "\$tmp_dir" && node scripts\/artifact-download-smoke\.js\)/],
["public split runs artifact export from copied tree", /\(cd "\$tmp_dir" && node scripts\/artifact-export-smoke\.js\)/],
["public split runs DAP smoke from copied tree", /\(cd "\$tmp_dir" && node scripts\/dap-smoke\.js\)/],
["public split runs flagship demo smoke from copied tree", /\(cd "\$tmp_dir" && node scripts\/flagship-demo-smoke\.js\)/],
]) {
expect(publicSplit, name, pattern);
}
for (const [name, pattern] of [
["flagship demo rejects local machine assumptions", /forbiddenSourceAssumptions/],
["flagship demo rejects coordinator checkout access", /coordinator_requires_checkout_access[\s\S]*false/],
["flagship demo asserts local source bytes stay node-local", /local_source_bytes_remain_node_local[\s\S]*true/],
["flagship demo asserts coordinator receives no source bytes by default", /coordinator_receives_source_bytes_by_default[\s\S]*false/],
["flagship demo asserts no default full repo tarball", /default_full_repo_tarball[\s\S]*false/],
]) {
expect(flagshipDemoSmoke, name, pattern);
}
console.log("Release blocker smoke passed");

71
scripts/release-source-scan.sh Executable file
View file

@ -0,0 +1,71 @@
#!/usr/bin/env bash
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo"
release_paths=(
Cargo.toml
Cargo.lock
README.md
crates
examples
private
scripts
vscode-extension
)
existing_release_paths=()
for path in "${release_paths[@]}"; do
if [[ -e "$path" ]]; then
existing_release_paths+=("$path")
fi
done
prose_scan_paths=(
README.md
crates
examples
private
scripts
vscode-extension
)
existing_prose_scan_paths=()
for path in "${prose_scan_paths[@]}"; do
if [[ -e "$path" ]]; then
existing_prose_scan_paths+=("$path")
fi
done
scan_globs=(
--glob '!**/target/**'
--glob '!**/node_modules/**'
--glob '!scripts/release-source-scan.sh'
)
placeholder_pattern='debugger-gate|experiments/debugger-gate|DISASMER-DEMO|device-code-placeholder|artifact://demo|vp-local-demo'
if rg -n "${scan_globs[@]}" "$placeholder_pattern" "${existing_release_paths[@]}"; then
echo "release source scan failed: stale experiment/demo placeholder reference found" >&2
exit 1
fi
demo_setup_pattern='undocumented manual state|hidden setup|demo-only credentials?|hard-coded local paths?'
if rg -n "${scan_globs[@]}" "$demo_setup_pattern" "${existing_prose_scan_paths[@]}"; then
echo "release source scan failed: demo requires hidden setup or demo-only state" >&2
exit 1
fi
hidden_local_pattern='file://|/home/[[:alnum:]_.-]+/|/Users/[[:alnum:]_.-]+/|C:\\Users\\|https?://(localhost|127\.0\.0\.1)[^[:space:]]*/artifacts/'
if rg -n "${scan_globs[@]}" "$hidden_local_pattern" "${existing_release_paths[@]}"; then
echo "release source scan failed: hidden local path or local artifact URL found" >&2
exit 1
fi
public_wording_pattern='reddit|hacker news|lobsters|launch forum|traffic source|free tier'
if rg -n "${scan_globs[@]}" "$public_wording_pattern" "${existing_prose_scan_paths[@]}"; then
echo "release source scan failed: public-facing launch-forum/free-tier wording found" >&2
exit 1
fi
echo "Release source scan passed"

View file

@ -0,0 +1,214 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function maybeRead(segments) {
const fullPath = path.join(repo, ...segments);
if (!fs.existsSync(fullPath)) return null;
return fs.readFileSync(fullPath, "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing resource metering evidence: ${name}`);
}
function expectGate(script, gateName) {
assert(
script.includes("node scripts/resource-metering-contract-smoke.js"),
`${gateName} must run resource-metering-contract-smoke.js`
);
}
const coreLimits = read("crates/disasmer-core/src/limits.rs");
// Phase 3 keeps the protocol dispatch in service.rs and the metered operation
// implementations in focused service modules. Read the complete relevant
// boundary so this contract follows the refactor instead of one mega-file.
const coordinatorService = [
read("crates/disasmer-coordinator/src/service.rs"),
read("crates/disasmer-coordinator/src/service/routing.rs"),
read("crates/disasmer-coordinator/src/service/processes.rs"),
read("crates/disasmer-coordinator/src/service/process_launch.rs"),
read("crates/disasmer-coordinator/src/service/artifacts.rs"),
].join("\n");
const coordinatorQuota = read("crates/disasmer-coordinator/src/service/quota.rs");
const coordinatorLogs = read("crates/disasmer-coordinator/src/service/logs.rs");
const coordinatorDebug = read("crates/disasmer-coordinator/src/service/debug.rs");
const coordinatorTests = read("crates/disasmer-coordinator/src/service/tests.rs");
const artifactDownloadSmoke = read("scripts/artifact-download-smoke.js");
const operatorPanelSmoke = read("scripts/operator-panel-smoke.js");
const quicSmoke = read("scripts/quic-smoke.js");
const publicAcceptance = read("scripts/acceptance-public.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
for (const [name, pattern] of [
["API call limit kind", /\bApiCall,/],
["spawn limit kind", /\bSpawn,/],
["log bytes limit kind", /\bLogBytes,/],
["metadata bytes limit kind", /\bMetadataBytes,/],
["debug read bytes limit kind", /\bDebugReadBytes,/],
["UI event limit kind", /\bUiEvent,/],
["rendezvous attempt limit kind", /\bRendezvousAttempt,/],
["artifact download bytes limit kind", /\bArtifactDownloadBytes,/],
["hosted fuel limit kind", /\bHostedFuel,/],
[
"preflight can check without consuming",
/pub fn can_charge\([\s\S]*used\.saturating_add\(amount\) > limit/,
],
[
"charge goes through preflight",
/pub fn charge\([\s\S]*self\.can_charge\(limits, kind, amount\)\?/,
],
]) {
expect(coreLimits, name, pattern);
}
for (const [name, pattern] of [
[
"rendezvous charges before transport planning",
/handle_request_rendezvous[\s\S]*charge_rendezvous_attempt\([\s\S]*&scope\.tenant[\s\S]*&scope\.project[\s\S]*now_epoch_seconds[\s\S]*plan_authenticated_direct_bulk_transfer/,
],
[
"artifact link creation preflights downloadable bytes before link creation",
/handle_create_artifact_download_link[\s\S]*downloadable_size[\s\S]*can_charge_download\([\s\S]*&context\.tenant[\s\S]*&context\.project[\s\S]*downloadable_size[\s\S]*create_download_link/,
],
[
"artifact delivery charges scoped bytes before advancing its offset",
/handle_open_artifact_download_stream[\s\S]*stream_download_chunk\([\s\S]*charge_download\([\s\S]*&context\.tenant[\s\S]*&context\.project[\s\S]*streamed_bytes[\s\S]*delivered_offset = end/,
],
]) {
expect(coordinatorService, name, pattern);
}
for (const [name, pattern] of [
[
"quota keys include tenant/project resource kind and window",
/struct ProjectQuotaScope[\s\S]*tenant: TenantId[\s\S]*project: ProjectId[\s\S]*struct MeterKey[\s\S]*kind: LimitKind[\s\S]*window: u64/,
],
[
"quota module discards expired windows for an accessed scope and kind",
/fn meter_mut[\s\S]*self\.meters\.retain[\s\S]*existing\.scope != key\.scope[\s\S]*existing\.kind != kind[\s\S]*existing\.window == key\.window/,
],
[
"quota module charges rendezvous attempts through the scoped window meter",
/fn charge_rendezvous_attempt[\s\S]*self\.charge\([\s\S]*tenant[\s\S]*project[\s\S]*LimitKind::RendezvousAttempt/,
],
[
"quota module charges authenticated API calls through the scoped window meter",
/fn charge_api_call[\s\S]*self\.charge\(tenant, project, LimitKind::ApiCall, 1, now_epoch_seconds\)/,
],
[
"quota module preflights and charges log bytes through the scoped window meter",
/fn can_charge_log_bytes[\s\S]*LimitKind::LogBytes[\s\S]*fn charge_log_bytes[\s\S]*LimitKind::LogBytes/,
],
[
"quota module preflights artifact download bytes through the scoped meter",
/fn can_charge_download[\s\S]*self\.can_charge\([\s\S]*tenant[\s\S]*project[\s\S]*LimitKind::ArtifactDownloadBytes/,
],
[
"quota status reports current scoped window usage",
/fn project_status[\s\S]*for kind in LimitKind::ALL[\s\S]*self\.used\(tenant, project, kind, now_epoch_seconds\)/,
],
]) {
expect(coordinatorQuota, name, pattern);
}
for (const [source, name, pattern] of [
[
coordinatorService,
"authenticated API calls are charged after session authorization and before dispatch",
/authenticate_cli_session[\s\S]*authorize_authenticated_user_operation[\s\S]*charge_api_call[\s\S]*match request/,
],
[
coordinatorLogs,
"signed node log ingestion preflights and charges bytes before accepting the report",
/handle_report_task_log[\s\S]*authorize_node_for_process_or_termination[\s\S]*can_charge_log_bytes[\s\S]*charge_log_bytes[\s\S]*TaskLogRecorded/,
],
[
coordinatorDebug,
"debug reads charge the scoped debug-read budget before audit state is recorded",
/record_debug_audit_event[\s\S]*charge_debug_read[\s\S]*DebugAuditEvent/,
],
[
coordinatorTests,
"tests prove API-call and log-byte quota enforcement and project isolation",
/authenticated_api_calls_are_metered_per_tenant_and_project_before_dispatch[\s\S]*project-a[\s\S]*project-b[\s\S]*signed_node_log_ingestion_checks_scoped_quota_before_accepting_bytes[\s\S]*LogBytes/,
],
]) {
expect(source, name, pattern);
}
for (const [name, source, patterns] of [
[
"rendezvous smoke",
quicSmoke,
[/charged_rendezvous_attempts, 1/, /coordinator bulk relay is disabled/],
],
[
"artifact download smoke",
artifactDownloadSmoke,
[
/downloaded\.response\.charged_download_bytes,[\s\S]*packageEvent\.artifact_size_bytes/,
/retaining_node_reverse_stream/,
/revoked/,
],
],
[
"operator panel smoke",
operatorPanelSmoke,
[
/type: "submit_panel_event"/,
/max_events: 1/,
/used_events, 1/,
/rate limit/i,
/max_download_bytes: 1/,
/exceeds download limit/,
],
],
]) {
for (const pattern of patterns) {
expect(source, name, pattern);
}
}
expectGate(publicAcceptance, "public acceptance");
expectGate(publicSplit, "public split acceptance");
expectGate(privateAcceptance, "private acceptance");
const privateHostedLibSource = maybeRead(["private", "hosted-policy", "src", "lib.rs"]);
const privateHostedTests = maybeRead(["private", "hosted-policy", "src", "tests.rs"]);
const privateHostedLib = privateHostedLibSource
? [privateHostedLibSource, privateHostedTests].filter(Boolean).join("\n")
: null;
if (privateHostedLib) {
for (const [name, pattern] of [
[
"private hosted configuration owns exact limits and quota windows",
/community_tier_resource_limits[\s\S]*LimitKind::ApiCall[\s\S]*LimitKind::HostedFuel[\s\S]*community_tier_quota_configuration[\s\S]*CoordinatorQuotaConfiguration::new/,
],
[
"hosted zero-capability Wasm budget preflight is atomic across every resource kind",
/preflight_zero_capability_hosted_wasm\([\s\S]*let mut trial_meter = meter\.clone\(\)[\s\S]*LimitKind::HostedFuel[\s\S]*LimitKind::HostedMemoryBytes[\s\S]*LimitKind::HostedWallClockMs[\s\S]*LimitKind::HostedStateBytes[\s\S]*LimitKind::LogBytes[\s\S]*LimitKind::MetadataBytes[\s\S]*LimitKind::UiEvent[\s\S]*LimitKind::ApiCall[\s\S]*\*meter = trial_meter/,
],
[
"hosted tests cover each zero-capability Wasm budget",
/hosted_zero_capability_wasm_preflight_rejects_each_budget_over_limit\([\s\S]*LimitKind::HostedFuel[\s\S]*LimitKind::LogBytes[\s\S]*LimitKind::MetadataBytes[\s\S]*LimitKind::UiEvent[\s\S]*LimitKind::ApiCall/,
],
[
"hosted tests prove tenant/project quota isolation",
/hosted_resource_usage_is_isolated_by_tenant_and_project\([\s\S]*project-a[\s\S]*project-b[\s\S]*HostedFuel/,
],
]) {
expect(privateHostedLib, name, pattern);
}
}
console.log("Resource metering contract smoke passed");

View file

@ -0,0 +1,407 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const { nodeIdentity, signedNodeRequest } = require("./node-signing");
const repo = path.resolve(__dirname, "..");
const digest = (value) =>
`sha256:${crypto.createHash("sha256").update(value).digest("hex")}`;
const environmentDigest = digest("scheduler-linux-container");
const dependencyDigest = digest("scheduler-toolchain-dependencies");
const sourceDigest = digest("scheduler-source-tree");
function buildFlagshipBundle() {
const output = cp.execFileSync(
"cargo",
[
"run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--",
"build", "--project", "examples/launch-build-demo", "--json",
],
{ cwd: repo, encoding: "utf8" }
);
const report = JSON.parse(output);
const directory = path.resolve(repo, report.bundle_artifact.directory);
const manifest = JSON.parse(fs.readFileSync(path.join(directory, "manifest.json"), "utf8"));
const entrypoints = JSON.parse(
fs.readFileSync(path.join(directory, manifest.entrypoints), "utf8")
);
const entrypoint = entrypoints.find((candidate) => candidate.name === "build");
assert(entrypoint, "flagship bundle omitted build entrypoint");
const taskDescriptors = JSON.parse(
fs.readFileSync(path.join(directory, manifest.task_descriptors), "utf8")
);
const prepareSource = taskDescriptors.find(
(candidate) => candidate.name === "prepare_source"
);
assert(prepareSource, "flagship bundle omitted prepare_source task");
return {
digest: manifest.bundle_digest,
taskExport: prepareSource.export,
wasmModuleBase64: fs.readFileSync(path.join(directory, "module.wasm")).toString("base64"),
};
}
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function linuxCapabilities() {
return {
os: "Linux",
arch: "x86_64",
capabilities: [
"Command",
"Containers",
"RootlessPodman",
"SourceFilesystem",
"VfsArtifacts"
],
environment_backends: ["Container"],
source_providers: ["filesystem"]
};
}
function gitCapabilities() {
const capabilities = linuxCapabilities();
capabilities.capabilities = [...capabilities.capabilities, "SourceGit"].sort();
capabilities.source_providers = [...capabilities.source_providers, "git"].sort();
return capabilities;
}
async function attachNode(addr, node) {
const identity = nodeIdentity("scheduler-placement-smoke", node);
const attached = await send(addr, {
type: "attach_node",
tenant: "tenant",
project: "project",
node,
public_key: identity.publicKey
});
assert.strictEqual(attached.type, "node_attached");
assert.strictEqual(attached.node, node);
return identity;
}
async function reportNode(addr, node, identity, locality) {
const recorded = await send(addr, signedNodeRequest(node, identity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node,
capabilities: locality.capabilities || linuxCapabilities(),
cached_environment_digests: locality.cached_environment_digests,
dependency_cache_digests: locality.dependency_cache_digests,
source_snapshots: locality.source_snapshots,
artifact_locations: locality.artifact_locations,
direct_connectivity: locality.direct_connectivity !== false,
online: true
}));
assert.strictEqual(
recorded.type,
"node_capabilities_recorded",
JSON.stringify(recorded)
);
assert.strictEqual(recorded.node, node);
return recorded;
}
(async () => {
const bundle = buildFlagshipBundle();
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback"
],
{ cwd: repo }
);
let coordinatorStderr = "";
coordinator.stderr.on("data", (chunk) => {
coordinatorStderr += chunk.toString();
});
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const coldNode = await attachNode(addr, "cold-node");
const warmNode = await attachNode(addr, "warm-node");
const cold = await reportNode(addr, "cold-node", coldNode, {
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: false
});
assert.strictEqual(cold.node_descriptors, 1);
const warm = await reportNode(addr, "warm-node", warmNode, {
cached_environment_digests: [environmentDigest],
dependency_cache_digests: [dependencyDigest],
source_snapshots: [sourceDigest],
artifact_locations: ["toolchain-cache"]
});
assert.strictEqual(warm.node_descriptors, 2);
const reportedNodes = new Set([cold.node, warm.node]);
assert.strictEqual(reportedNodes.size, 2);
assert(reportedNodes.has("cold-node"));
assert(reportedNodes.has("warm-node"));
const inspected = await send(addr, {
type: "list_node_descriptors",
tenant: "tenant",
project: "project",
actor_user: "operator"
});
assert.strictEqual(inspected.type, "node_descriptors");
assert.strictEqual(inspected.actor, "operator");
assert.strictEqual(inspected.descriptors.length, 2);
const warmDescriptor = inspected.descriptors.find(
(descriptor) => descriptor.id === "warm-node"
);
assert(warmDescriptor, "warm node descriptor must be visible to inspector state");
assert(warmDescriptor.capabilities.capabilities.includes("Command"));
assert(warmDescriptor.capabilities.capabilities.includes("RootlessPodman"));
assert(warmDescriptor.cached_environments.includes(environmentDigest));
assert(warmDescriptor.dependency_caches.includes(dependencyDigest));
assert(warmDescriptor.source_snapshots.includes(sourceDigest));
assert(warmDescriptor.artifact_locations.includes("toolchain-cache"));
const crossScopeInspection = await send(addr, {
type: "list_node_descriptors",
tenant: "other-tenant",
project: "project",
actor_user: "operator"
});
assert.strictEqual(crossScopeInspection.type, "node_descriptors");
assert.strictEqual(crossScopeInspection.descriptors.length, 0);
const crossTenantReport = await send(addr, signedNodeRequest("warm-node", warmNode, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "other-tenant",
project: "project",
node: "warm-node",
capabilities: linuxCapabilities(),
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: true,
online: true
}));
assert.strictEqual(crossTenantReport.type, "error");
assert.match(crossTenantReport.message, /tenant\/project scope/);
const placement = await send(addr, {
type: "schedule_task",
tenant: "tenant",
project: "project",
environment: {
os: "Linux",
arch: null,
capabilities: ["Containers", "RootlessPodman"]
},
environment_digest: environmentDigest,
required_capabilities: ["Command"],
dependency_cache: dependencyDigest,
source_snapshot: sourceDigest,
required_artifacts: ["toolchain-cache"],
prefer_node: null
});
assert.strictEqual(placement.type, "task_placement");
assert.strictEqual(placement.placement.node, "warm-node");
assert.ok(placement.placement.score > 0);
assert.ok(placement.placement.reasons.includes("warm environment cache"));
assert.ok(placement.placement.reasons.includes("warm dependency cache"));
assert.ok(placement.placement.reasons.includes("source snapshot already local"));
assert.ok(
placement.placement.reasons.includes("1 required artifact(s) already local")
);
const impossible = await send(addr, {
type: "schedule_task",
tenant: "tenant",
project: "project",
environment: null,
environment_digest: null,
required_capabilities: ["WindowsCommandDev"],
dependency_cache: null,
source_snapshot: null,
required_artifacts: [],
prefer_node: null
});
assert.strictEqual(impossible.type, "error");
assert.match(impossible.message, /WindowsCommandDev/);
const started = await send(addr, {
type: "start_process",
tenant: "tenant",
project: "project",
actor_user: "operator",
process: "vp-wait-for-git"
});
assert.strictEqual(started.type, "process_started");
const queued = await send(addr, {
type: "launch_task",
tenant: "tenant",
project: "project",
actor_user: "operator",
task_spec: {
tenant: "tenant",
project: "project",
process: "vp-wait-for-git",
task_definition: "prepare_source",
task_instance: "prepare_source-1",
dispatch: {
kind: "coordinator_node_wasm",
export: bundle.taskExport,
abi: "task_v1",
},
environment_id: null,
environment: null,
environment_digest: null,
required_capabilities: ["SourceFilesystem", "SourceGit"],
dependency_cache: null,
source_snapshot: null,
required_artifacts: [],
args: [],
vfs_epoch: started.epoch,
bundle_digest: bundle.digest,
},
wait_for_node: true,
artifact_path: "/vfs/artifacts/git-status.txt",
wasm_module_base64: bundle.wasmModuleBase64,
});
assert.strictEqual(queued.type, "task_queued");
assert.strictEqual(queued.process, "vp-wait-for-git");
assert.strictEqual(queued.task, "prepare_source-1");
assert.match(queued.reason, /SourceGit/);
assert.strictEqual(queued.queued_tasks, 1);
const gitNode = await attachNode(addr, "git-node");
const gitRecorded = await reportNode(addr, "git-node", gitNode, {
capabilities: gitCapabilities(),
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: false
});
assert.strictEqual(gitRecorded.type, "node_capabilities_recorded");
const pendingAssignment = await send(addr, signedNodeRequest("git-node", gitNode, "poll_task_assignment", {
type: "poll_task_assignment",
tenant: "tenant",
project: "project",
node: "git-node"
}));
assert.strictEqual(pendingAssignment.type, "task_assignment");
assert(pendingAssignment.assignment, "late capable node should receive queued assignment");
assert.strictEqual(pendingAssignment.assignment.process, "vp-wait-for-git");
assert.strictEqual(pendingAssignment.assignment.task, "prepare_source-1");
assert.strictEqual(pendingAssignment.assignment.node, "git-node");
assert.strictEqual(
pendingAssignment.assignment.task_spec.dispatch.export,
bundle.taskExport
);
const emptyAssignment = await send(addr, signedNodeRequest("git-node", gitNode, "poll_task_assignment", {
type: "poll_task_assignment",
tenant: "tenant",
project: "project",
node: "git-node"
}));
assert.strictEqual(emptyAssignment.type, "task_assignment");
assert.strictEqual(emptyAssignment.assignment, null);
await reportNode(addr, "warm-node", warmNode, {
cached_environment_digests: [],
dependency_cache_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: false
});
const disconnectedTransfer = await send(addr, {
type: "schedule_task",
tenant: "tenant",
project: "project",
environment: null,
environment_digest: null,
required_capabilities: ["Command"],
dependency_cache: null,
source_snapshot: sourceDigest,
required_artifacts: ["toolchain-cache"],
prefer_node: null
});
assert.strictEqual(disconnectedTransfer.type, "error");
assert.match(disconnectedTransfer.message, /source snapshot unavailable/);
assert.match(disconnectedTransfer.message, /required artifact\(s\) unavailable/);
assert.match(disconnectedTransfer.message, /direct connectivity unavailable/);
} catch (error) {
if (coordinatorStderr) {
error.message = `${error.message}\ncoordinator stderr:\n${coordinatorStderr}`;
}
throw error;
} finally {
coordinator.kill("SIGTERM");
}
console.log("Scheduler placement smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,49 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const sdk = fs.readFileSync(path.join(repo, "crates/disasmer-sdk/src/lib.rs"), "utf8");
const productRuntime = fs.readFileSync(
path.join(repo, "crates/disasmer-sdk/src/sdk_runtime.rs"),
"utf8"
);
assert.match(sdk, /pub struct RuntimeSpawnEvent/);
assert.match(sdk, /pub debugger_visible: bool/);
assert.match(sdk, /fn register_runtime_thread/);
assert.match(sdk, /register_runtime_thread\(id, self\.name, self\.env\)/);
assert.match(sdk, /pub fn debugger_visible\(&self\) -> bool/);
assert.match(sdk, /ProductRuntimeConfig::from_env\(\)/);
assert.match(sdk, /start_remote_task\(config, task_id/);
assert.match(sdk, /start_guest_host_task/);
assert.match(sdk, /join_remote_task\(remote\)/);
assert.match(productRuntime, /let spec = TaskSpec \{/);
assert.match(productRuntime, /CoordinatorNodeWasm/);
assert.match(productRuntime, /task_start_v1/);
assert.match(productRuntime, /task_join_v1/);
assert.match(productRuntime, /command_run_v1/);
assert.match(productRuntime, /"task_spec": spec/);
assert.match(productRuntime, /remote_completion_observed/);
assert.match(productRuntime, /TaskJoinState::Pending/);
assert.doesNotMatch(
productRuntime,
/entry\s*\(/,
"product runtime must not invoke the submitted local Rust closure"
);
cp.execFileSync(
"cargo",
[
"test",
"-p",
"disasmer-sdk",
"spawn_task_start_registers_debugger_visible_runtime_thread",
],
{ cwd: repo, stdio: "inherit" }
);
console.log("SDK spawn runtime smoke passed");

View file

@ -0,0 +1,723 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const repo = path.resolve(__dirname, "..");
const teamArtifactDigest = `sha256:${"a".repeat(64)}`;
const teamEnvironmentDigest = `sha256:${crypto
.createHash("sha256")
.update("env-team-linux")
.digest("hex")}`;
const teamDependencyCacheDigest = `sha256:${crypto
.createHash("sha256")
.update("cargo-cache")
.digest("hex")}`;
const teamSourceDigest = `sha256:${crypto
.createHash("sha256")
.update("source-team")
.digest("hex")}`;
const coordinatorTaskModule = Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]);
const coordinatorTaskBundleDigest = `sha256:${crypto
.createHash("sha256")
.update(coordinatorTaskModule)
.digest("hex")}`;
const adminToken = "self-hosted-smoke-admin-token";
const clientSessionSecret = "self-hosted-smoke-client-session-secret";
const releaseManifestPath =
process.env.DISASMER_PUBLIC_RELEASE_MANIFEST ||
path.join(repo, "target/public-release-dryrun/public-release-manifest.json");
function sha256(value) {
return `sha256:${crypto.createHash("sha256").update(value).digest("hex")}`;
}
function digestFromParts(parts) {
const hash = crypto.createHash("sha256");
for (const value of parts) {
const bytes = Buffer.from(String(value));
const length = Buffer.alloc(8);
length.writeBigUInt64BE(BigInt(bytes.length));
hash.update(length);
hash.update(bytes);
}
return `sha256:${hash.digest("hex")}`;
}
function adminRequest(token, operation, tenant, actorUser, targetTenant, nonce) {
const issuedAtEpochSeconds = Math.floor(Date.now() / 1000);
return {
type: operation,
tenant,
actor_user: actorUser,
...(operation === "suspend_tenant" ? { target_tenant: targetTenant } : {}),
admin_proof: digestFromParts([
"disasmer-admin-request-proof:v1",
sha256(token),
operation,
tenant,
actorUser,
targetTenant,
nonce,
issuedAtEpochSeconds,
]),
admin_nonce: nonce,
issued_at_epoch_seconds: issuedAtEpochSeconds,
};
}
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function authenticated(request, sessionSecret = clientSessionSecret) {
return {
type: "authenticated",
session_secret: sessionSecret,
request,
};
}
function linuxNodeCapabilities() {
return {
os: "Linux",
arch: "x86_64",
capabilities: ["Command", "RootlessPodman", "VfsArtifacts", "QuicDirect"],
environment_backends: ["Container"],
source_providers: ["filesystem", "git"]
};
}
function nodeIdentity(node) {
void node;
const { privateKey: privateKeyObject, publicKey } =
crypto.generateKeyPairSync("ed25519");
const publicDer = publicKey.export({
format: "der",
type: "spki",
});
return {
publicKey: `ed25519:${Buffer.from(publicDer).subarray(-32).toString("base64")}`,
privateKeyObject,
};
}
function signedRequestPayloadDigest(request) {
const canonicalize = (value, topLevel = true) => {
if (Array.isArray(value)) return value.map((entry) => canonicalize(entry, false));
if (value && typeof value === "object") {
return Object.fromEntries(
Object.entries(value)
.filter(
([key, entry]) =>
entry !== null &&
(!topLevel || !["agent_signature", "node_signature"].includes(key))
)
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
.map(([key, entry]) => [key, canonicalize(entry, false)])
);
}
return value;
};
return `sha256:${crypto
.createHash("sha256")
.update(JSON.stringify(canonicalize(request)))
.digest("hex")}`;
}
function nodeSignatureMessage(
node,
requestKind,
payloadDigest,
nonce,
issuedAtEpochSeconds
) {
const parts = [
"disasmer-node-request-signature:v2",
node,
requestKind,
payloadDigest,
nonce,
String(issuedAtEpochSeconds),
];
return Buffer.concat(
parts.flatMap((part) => [
Buffer.from(`${Buffer.byteLength(part)}:`),
Buffer.from(part),
Buffer.from("\n"),
])
);
}
function signedNodeHeartbeat(node, identity) {
const request = { type: "node_heartbeat", node };
const nonce = `self-hosted-heartbeat-${process.pid}-${Date.now()}`;
const issuedAt = Math.floor(Date.now() / 1000);
const signature = crypto.sign(
null,
nodeSignatureMessage(
node,
"node_heartbeat",
signedRequestPayloadDigest(request),
nonce,
issuedAt
),
identity.privateKeyObject
);
return {
nonce,
issued_at_epoch_seconds: issuedAt,
signature: `ed25519:${signature.toString("base64")}`,
};
}
function signedNodeRequest(node, identity, requestKind, request) {
return {
type: "signed_node",
node,
node_signature: signedNodeHeartbeatForKind(node, identity, requestKind, request),
request,
};
}
function signedNodeHeartbeatForKind(node, identity, requestKind, request) {
const nonce = `${requestKind}-${process.pid}-${Date.now()}`;
const issuedAt = Math.floor(Date.now() / 1000);
const signature = crypto.sign(
null,
nodeSignatureMessage(
node,
requestKind,
signedRequestPayloadDigest(request),
nonce,
issuedAt
),
identity.privateKeyObject
);
return {
nonce,
issued_at_epoch_seconds: issuedAt,
signature: `ed25519:${signature.toString("base64")}`,
};
}
function commandOutput(command, args) {
try {
return cp
.execFileSync(command, args, {
cwd: repo,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
})
.trim();
} catch (_) {
return null;
}
}
function runJson(command, args, options = {}) {
return JSON.parse(
cp.execFileSync(command, args, {
cwd: options.cwd || repo,
encoding: "utf8",
input: options.input,
})
);
}
function expectedSourceCommit() {
return (
process.env.DISASMER_ACCEPTANCE_COMMIT ||
commandOutput("git", ["rev-parse", "HEAD"])
);
}
function readReleaseManifest() {
if (!fs.existsSync(releaseManifestPath)) return null;
const manifest = JSON.parse(fs.readFileSync(releaseManifestPath, "utf8"));
assert.strictEqual(manifest.kind, "disasmer-public-release-dryrun");
const expectedCommit = expectedSourceCommit();
if (expectedCommit) {
assert.strictEqual(
manifest.source_commit,
expectedCommit,
"self-hosted coordinator smoke must use the manifest for the current acceptance commit"
);
}
return manifest;
}
function releaseIdentity() {
const manifest = readReleaseManifest();
return {
sourceCommit: manifest ? manifest.source_commit : expectedSourceCommit(),
releaseName:
(manifest && manifest.release_name) ||
process.env.DISASMER_PUBLIC_RELEASE_NAME ||
null,
};
}
async function attachTrustedNode(addr, node, capabilities = linuxNodeCapabilities()) {
const identity = nodeIdentity(node);
const grant = await send(addr, authenticated({
type: "create_node_enrollment_grant",
ttl_seconds: 900,
}));
assert.strictEqual(grant.type, "node_enrollment_grant_created");
const attached = await send(addr, {
type: "exchange_node_enrollment_grant",
tenant: "team",
project: "self-hosted",
node,
public_key: identity.publicKey,
enrollment_grant: grant.grant,
});
assert.strictEqual(attached.type, "node_enrollment_exchanged");
const heartbeat = await send(addr, {
type: "node_heartbeat",
node,
node_signature: signedNodeHeartbeat(node, identity)
});
assert.strictEqual(heartbeat.type, "node_heartbeat");
const reported = await send(addr, signedNodeRequest(node, identity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "team",
project: "self-hosted",
node,
capabilities,
cached_environment_digests: [teamEnvironmentDigest],
dependency_cache_digests: [teamDependencyCacheDigest],
source_snapshots: [teamSourceDigest],
artifact_locations: [],
direct_connectivity: true,
online: true
}));
assert.strictEqual(reported.type, "node_capabilities_recorded");
return identity;
}
(async () => {
const release = releaseIdentity();
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0"
],
{
cwd: repo,
env: {
...process.env,
DISASMER_ADMIN_TOKEN: adminToken,
DISASMER_SELF_HOSTED_SESSION_SECRET: clientSessionSecret,
DISASMER_SELF_HOSTED_TENANT: "team",
DISASMER_SELF_HOSTED_PROJECT: "self-hosted",
DISASMER_SELF_HOSTED_USER: "developer",
},
}
);
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual(ready.client_authority, "strict");
assert.strictEqual(ready.self_hosted_session_bootstrapped, true);
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const forgedBodyAuthority = await send(addr, {
type: "start_process",
tenant: "victim-tenant",
project: "victim-project",
actor_user: "forged-user",
process: "vp-forged",
});
assert.strictEqual(forgedBodyAuthority.type, "error");
assert.match(forgedBodyAuthority.message, /body.*identity.*not authority/i);
const wrongSession = await send(
addr,
authenticated({ type: "auth_status" }, "wrong-session-secret")
);
assert.strictEqual(wrongSession.type, "error");
assert.match(wrongSession.message, /session.*not recognized|not recognized.*session/i);
const authStatus = await send(addr, authenticated({ type: "auth_status" }));
assert.strictEqual(authStatus.type, "auth_status");
assert.strictEqual(authStatus.tenant, "team");
assert.strictEqual(authStatus.project, "self-hosted");
assert.strictEqual(authStatus.actor, "developer");
const missingAdminCredential = await send(
addr,
adminRequest("", "admin_status", "team", "forged-admin", "team", "admin-empty")
);
assert.strictEqual(missingAdminCredential.type, "error");
assert.match(missingAdminCredential.message, /admin.*proof.*invalid/i);
const wrongAdminCredential = await send(
addr,
adminRequest(
"wrong-token",
"admin_status",
"team",
"forged-admin",
"team",
"admin-wrong"
)
);
assert.strictEqual(wrongAdminCredential.type, "error");
assert.match(wrongAdminCredential.message, /admin.*proof.*invalid/i);
const replayableAdminRequest = adminRequest(
adminToken,
"admin_status",
"team",
"self-hosted-admin",
"team",
"admin-replay"
);
const directAdminStatus = await send(addr, replayableAdminRequest);
assert.strictEqual(directAdminStatus.type, "admin_status");
const replayedAdminStatus = await send(addr, replayableAdminRequest);
assert.strictEqual(replayedAdminStatus.type, "error");
assert.match(replayedAdminStatus.message, /nonce was already used/i);
const cargoTargetDir = path.resolve(
process.env.CARGO_TARGET_DIR || path.join(repo, "target")
);
const cliBin = path.join(
cargoTargetDir,
"debug",
process.platform === "win32" ? "disasmer.exe" : "disasmer"
);
const selfHostedCliProject = path.join(
repo,
"target/acceptance/self-hosted-cli-project"
);
fs.rmSync(selfHostedCliProject, { recursive: true, force: true });
fs.mkdirSync(selfHostedCliProject, { recursive: true });
const cliConnect = runJson(
cliBin,
[
"auth",
"connect-self-hosted",
"--coordinator",
ready.listen,
"--tenant",
"team",
"--project-id",
"self-hosted",
"--user",
"developer",
"--session-secret-stdin",
"--json",
],
{ cwd: selfHostedCliProject, input: `${clientSessionSecret}\n` }
);
assert.strictEqual(cliConnect.status, "connected");
assert.strictEqual(cliConnect.session_secret_read_from_stdin, true);
assert.strictEqual(cliConnect.session_secret_exposed_in_report, false);
assert.strictEqual(cliConnect.coordinator_response.type, "auth_status");
const sessionPath = path.join(
selfHostedCliProject,
".disasmer/session.json"
);
const storedSession = JSON.parse(fs.readFileSync(sessionPath, "utf8"));
assert.strictEqual(storedSession.kind, "self_hosted");
assert.strictEqual(storedSession.session_secret, clientSessionSecret);
assert.strictEqual(storedSession.provider_tokens_exposed_to_cli, false);
assert.strictEqual(storedSession.provider_tokens_sent_to_nodes, false);
if (process.platform !== "win32") {
assert.strictEqual(fs.statSync(sessionPath).mode & 0o777, 0o600);
}
const cliAuthStatus = runJson(
cliBin,
["auth", "status", "--json"],
{ cwd: selfHostedCliProject }
);
assert.strictEqual(cliAuthStatus.active_coordinator, ready.listen);
assert.strictEqual(
cliAuthStatus.coordinator_account_status.used_cli_session_credential,
true
);
assert.strictEqual(
cliAuthStatus.coordinator_account_status.coordinator_response_type,
"auth_status"
);
const cliAdminStatus = runJson(cliBin, [
"admin",
"status",
"--coordinator",
ready.listen,
"--tenant",
"team",
"--user",
"self-hosted-admin",
"--admin-token",
adminToken,
"--json",
]);
assert.strictEqual(cliAdminStatus.response.type, "admin_status");
assert.strictEqual(cliAdminStatus.suspended, false);
const cliAdminSuspend = runJson(cliBin, [
"admin",
"suspend-tenant",
"--coordinator",
ready.listen,
"--tenant",
"team",
"--user",
"self-hosted-admin",
"--target-tenant",
"admin-probe-tenant",
"--admin-token",
adminToken,
"--yes",
"--json",
]);
assert.strictEqual(cliAdminSuspend.response.type, "tenant_suspended");
assert.strictEqual(cliAdminSuspend.suspended, true);
const cliAdminProbeStatus = runJson(cliBin, [
"admin",
"status",
"--coordinator",
ready.listen,
"--tenant",
"admin-probe-tenant",
"--user",
"self-hosted-admin",
"--admin-token",
adminToken,
"--json",
]);
assert.strictEqual(cliAdminProbeStatus.suspended, true);
const teamLinuxA = await attachTrustedNode(addr, "team-linux-a");
const teamLinuxBCapabilities = linuxNodeCapabilities();
teamLinuxBCapabilities.capabilities = teamLinuxBCapabilities.capabilities.filter(
(capability) => capability !== "VfsArtifacts"
);
await attachTrustedNode(addr, "team-linux-b", teamLinuxBCapabilities);
const placement = await send(addr, authenticated({
type: "schedule_task",
environment: {
os: "Linux",
arch: "x86_64",
capabilities: ["Command", "QuicDirect"]
},
environment_digest: teamEnvironmentDigest,
required_capabilities: ["VfsArtifacts"],
source_snapshot: teamSourceDigest,
required_artifacts: [],
prefer_node: "team-linux-a"
}));
assert.strictEqual(placement.type, "task_placement");
assert.strictEqual(placement.placement.node, "team-linux-a");
assert(placement.placement.reasons.includes("preferred node"));
assert(placement.placement.reasons.includes("warm environment cache"));
assert(placement.placement.reasons.includes("source snapshot already local"));
const started = await send(addr, authenticated({
type: "start_process",
process: "vp-team-build",
restart: false,
}));
assert.strictEqual(started.type, "process_started");
const reconnected = await send(addr, signedNodeRequest("team-linux-a", teamLinuxA, "reconnect_node", {
type: "reconnect_node",
node: "team-linux-a",
process: "vp-team-build",
epoch: started.epoch
}));
assert.strictEqual(reconnected.type, "node_reconnected");
const launched = await send(addr, authenticated({
type: "launch_task",
task_spec: {
tenant: "team",
project: "self-hosted",
process: "vp-team-build",
task_definition: "compile-linux",
task_instance: "compile-linux",
dispatch: {
kind: "coordinator_node_wasm",
export: "compile_linux",
abi: "task_v1",
},
environment_id: null,
environment: null,
environment_digest: null,
required_capabilities: ["VfsArtifacts"],
dependency_cache: null,
source_snapshot: null,
required_artifacts: [],
args: [],
vfs_epoch: started.epoch,
bundle_digest: coordinatorTaskBundleDigest,
},
wait_for_node: false,
artifact_path: "/vfs/artifacts/team-output.txt",
wasm_module_base64: coordinatorTaskModule.toString("base64"),
}));
assert.strictEqual(launched.type, "task_launched", JSON.stringify(launched));
assert.strictEqual(launched.placement.node, "team-linux-a");
const completed = await send(addr, signedNodeRequest("team-linux-a", teamLinuxA, "task_completed", {
type: "task_completed",
tenant: "team",
project: "self-hosted",
process: "vp-team-build",
node: "team-linux-a",
task: "compile-linux",
status_code: 0,
stdout_bytes: 18,
stderr_bytes: 0,
stdout_tail: "",
stderr_tail: "",
stdout_truncated: false,
stderr_truncated: false,
artifact_path: "/vfs/artifacts/team-output.txt",
artifact_digest: teamArtifactDigest,
artifact_size_bytes: 18
}));
assert.strictEqual(completed.type, "task_recorded", JSON.stringify(completed));
const events = await send(addr, authenticated({
type: "list_task_events",
process: "vp-team-build",
}));
assert.strictEqual(events.type, "task_events");
assert.strictEqual(events.events.length, 1);
assert.strictEqual(events.events[0].node, "team-linux-a");
assert.strictEqual(events.events[0].artifact_path, "/vfs/artifacts/team-output.txt");
const link = await send(addr, authenticated({
type: "create_artifact_download_link",
artifact: "team-output.txt",
max_bytes: 1024 * 1024,
ttl_seconds: 60
}));
assert.strictEqual(link.type, "artifact_download_link");
assert.deepStrictEqual(link.link.source, { RetainedNode: "team-linux-a" });
const exportPlan = await send(addr, authenticated({
type: "export_artifact_to_node",
artifact: "team-output.txt",
receiver_node: "team-linux-b",
direct_connectivity: true,
failure_reason: ""
}));
assert.strictEqual(exportPlan.type, "artifact_export_plan");
assert.strictEqual(exportPlan.source_node, "team-linux-a");
assert.strictEqual(exportPlan.receiver_node, "team-linux-b");
assert.strictEqual(exportPlan.plan.transport, "NativeQuic");
assert.strictEqual(exportPlan.plan.coordinator_assisted_rendezvous, true);
assert.strictEqual(exportPlan.plan.coordinator_bulk_relay_allowed, false);
const reportPath = path.join(repo, "target/acceptance/core-coordinator-compat.json");
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
fs.writeFileSync(
reportPath,
`${JSON.stringify(
{
kind: "disasmer-core-coordinator-compatibility",
source_commit: release.sourceCommit,
release_name: release.releaseName,
coordinator_implementation: "standalone-core-coordinator",
coordinator_addr: ready.listen,
client_authority: ready.client_authority,
authenticated_session: authStatus.authenticated,
forged_body_authority_denied: forgedBodyAuthority.type,
wrong_session_denied: wrongSession.type,
ping: "pong",
nodes: ["team-linux-a", "team-linux-b"],
task_placement: placement.type,
process_started: started.type,
task_completion: completed.type,
task_events: events.events.length,
artifact_download_link: link.type,
artifact_export_plan: exportPlan.type,
self_hosted_admin: {
missing_credential_denied: missingAdminCredential.type,
wrong_credential_denied: wrongAdminCredential.type,
nonce_bound_proof_succeeded: directAdminStatus.type,
replay_denied: replayedAdminStatus.type,
cli_status: cliAdminStatus.response.type,
cli_suspend: cliAdminSuspend.response.type,
suspended_state_observed: cliAdminProbeStatus.suspended,
},
self_hosted_cli: {
connected: cliConnect.status,
secret_read_from_stdin: cliConnect.session_secret_read_from_stdin,
secret_exposed_in_report: cliConnect.session_secret_exposed_in_report,
session_file_mode:
process.platform === "win32"
? "windows-best-effort"
: (fs.statSync(sessionPath).mode & 0o777).toString(8),
authenticated_status:
cliAuthStatus.coordinator_account_status.coordinator_response_type,
},
},
null,
2
)}\n`
);
} finally {
coordinator.kill("SIGTERM");
}
console.log("Self-hosted coordinator smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,218 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const { nodeIdentity, signedNodeRequest } = require("./node-signing");
const repo = path.resolve(__dirname, "..");
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function sourceCapableNode(sourceProviders = ["git"]) {
return {
os: "Linux",
arch: "x86_64",
capabilities: ["Command", "SourceFilesystem", "SourceGit"],
environment_backends: [],
source_providers: sourceProviders
};
}
(async () => {
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback"
],
{ cwd: repo }
);
let coordinatorStderr = "";
coordinator.stderr.on("data", (chunk) => {
coordinatorStderr += chunk.toString();
});
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const pending = await send(addr, {
type: "request_source_preparation",
tenant: "tenant",
project: "project",
provider: "Git"
});
assert.strictEqual(pending.type, "source_preparation");
assert.strictEqual(pending.status.preparation.tenant, "tenant");
assert.strictEqual(pending.status.preparation.project, "project");
assert.strictEqual(pending.status.preparation.provider, "Git");
assert.strictEqual(
pending.status.preparation.coordinator_requires_checkout_access,
false
);
assert.deepStrictEqual(pending.status.preparation.required_capabilities, [
"SourceGit"
]);
assert.match(pending.status.disposition.Pending.reason, /waiting|node/i);
const nodeIdentities = new Map();
for (const node of ["source-cold", "source-ready"]) {
const identity = nodeIdentity("source-preparation-smoke", node);
nodeIdentities.set(node, identity);
const attached = await send(addr, {
type: "attach_node",
tenant: "tenant",
project: "project",
node,
public_key: identity.publicKey
});
assert.strictEqual(attached.type, "node_attached");
}
const cold = await send(addr, signedNodeRequest("source-cold", nodeIdentities.get("source-cold"), "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: "source-cold",
capabilities: sourceCapableNode(),
cached_environment_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: true,
online: true
}));
assert.strictEqual(cold.type, "node_capabilities_recorded");
const readyReport = await send(addr, signedNodeRequest("source-ready", nodeIdentities.get("source-ready"), "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: "source-ready",
capabilities: sourceCapableNode(),
cached_environment_digests: [],
source_snapshots: [],
artifact_locations: [],
direct_connectivity: true,
online: true
}));
assert.strictEqual(readyReport.type, "node_capabilities_recorded");
const assigned = await send(addr, {
type: "request_source_preparation",
tenant: "tenant",
project: "project",
provider: "Git"
});
assert.strictEqual(assigned.type, "source_preparation");
assert(["source-cold", "source-ready"].includes(assigned.status.disposition.Assigned.node));
assert.strictEqual(
assigned.status.preparation.coordinator_requires_checkout_access,
false
);
const crossTenantCompletion = await send(addr, signedNodeRequest("source-ready", nodeIdentities.get("source-ready"), "complete_source_preparation", {
type: "complete_source_preparation",
tenant: "other",
project: "project",
node: "source-ready",
provider: "Git",
source_snapshot: "sha256:source-prepared"
}));
assert.strictEqual(crossTenantCompletion.type, "error");
assert.match(crossTenantCompletion.message, /tenant\/project scope/i);
const completed = await send(addr, signedNodeRequest("source-ready", nodeIdentities.get("source-ready"), "complete_source_preparation", {
type: "complete_source_preparation",
tenant: "tenant",
project: "project",
node: "source-ready",
provider: "Git",
source_snapshot: "sha256:source-prepared"
}));
assert.strictEqual(completed.type, "source_preparation_completed");
assert.strictEqual(completed.node, "source-ready");
assert.strictEqual(completed.provider, "Git");
assert.strictEqual(completed.source_snapshot, "sha256:source-prepared");
const placement = await send(addr, {
type: "schedule_task",
tenant: "tenant",
project: "project",
environment: null,
environment_digest: null,
required_capabilities: ["SourceGit"],
source_snapshot: "sha256:source-prepared",
required_artifacts: [],
prefer_node: null
});
assert.strictEqual(placement.type, "task_placement");
assert.strictEqual(placement.placement.node, "source-ready");
assert(
placement.placement.reasons.includes("source snapshot already local"),
"completed source preparation must update node source locality"
);
} catch (error) {
if (coordinatorStderr) {
error.message = `${error.message}\ncoordinator stderr:\n${coordinatorStderr}`;
}
throw error;
} finally {
coordinator.kill("SIGTERM");
}
console.log("Source preparation smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,197 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function maybeRead(segments) {
const fullPath = path.join(repo, ...segments);
if (!fs.existsSync(fullPath)) return null;
return fs.readFileSync(fullPath, "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing tenant-isolation evidence: ${name}`);
}
function expectGate(script, gateName) {
assert(
script.includes("node scripts/tenant-isolation-contract-smoke.js"),
`${gateName} must run tenant-isolation-contract-smoke.js`
);
}
const auth = read("crates/disasmer-core/src/auth.rs");
const artifact = read("crates/disasmer-core/src/artifact.rs");
const operatorPanel = read("crates/disasmer-core/src/operator_panel.rs");
const source = read("crates/disasmer-core/src/source.rs");
const coordinatorService = [
read("crates/disasmer-coordinator/src/service.rs"),
read("crates/disasmer-coordinator/src/service/routing.rs"),
read("crates/disasmer-coordinator/src/service/nodes.rs"),
read("crates/disasmer-coordinator/src/service/keys.rs"),
read("crates/disasmer-coordinator/src/service/artifacts.rs"),
read("crates/disasmer-coordinator/src/service/processes.rs"),
read("crates/disasmer-coordinator/src/service/process_launch.rs"),
read("crates/disasmer-coordinator/src/service/tests.rs"),
].join("\n");
const artifactDownloadSmoke = read("scripts/artifact-download-smoke.js");
const operatorPanelSmoke = read("scripts/operator-panel-smoke.js");
const schedulerSmoke = read("scripts/scheduler-placement-smoke.js");
const sourcePreparationSmoke = read("scripts/source-preparation-smoke.js");
const releaseBlockerSmoke = read("scripts/release-blocker-smoke.js");
const publicAcceptance = read("scripts/acceptance-public.sh");
const publicSplit = read("scripts/verify-public-split.sh");
const privateAcceptance = read("scripts/acceptance-private.sh");
for (const [name, pattern] of [
["auth contexts carry tenant and project", /pub struct AuthContext[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId/],
["enrollment grants carry tenant and project", /pub struct EnrollmentGrant[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId/],
["node credentials carry tenant and project", /pub struct NodeCredential[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId/],
["same tenant/project denies tenant mismatch", /pub fn same_tenant_project[\s\S]*tenant mismatch/],
["same tenant/project denies project mismatch", /pub fn same_tenant_project[\s\S]*project mismatch/],
["auth unit denies cross-tenant access", /fn tenant_project_scope_denies_cross_tenant_access\(\)/],
]) {
expect(auth, name, pattern);
}
for (const [name, pattern] of [
["artifact metadata carries tenant and project", /pub struct ArtifactMetadata[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId/],
["download links carry tenant project process and actor", /pub struct DownloadLink[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId[\s\S]*pub process: ProcessId[\s\S]*pub actor: Actor/],
["downloads authorize against scoped metadata", /let authz = same_tenant_project\(context, &scope\)/],
["artifact test denies cross-tenant download", /fn cross_tenant_download_is_denied_even_with_known_artifact_id\(\)/],
["artifact test denies cross-project download", /fn cross_project_download_is_denied_even_with_known_artifact_id\(\)/],
]) {
expect(artifact, name, pattern);
}
for (const [name, pattern] of [
["panel state carries tenant project and process", /pub struct PanelState[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId[\s\S]*pub process: ProcessId/],
["panel events carry tenant project and process", /pub struct PanelEvent[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId[\s\S]*pub process: ProcessId/],
["panel events reject scope mismatch", /PanelError::ScopeMismatch/],
["panel scope validation compares tenant project process", /self\.tenant != event\.tenant[\s\S]*self\.project != event\.project[\s\S]*self\.process != event\.process/],
]) {
expect(operatorPanel, name, pattern);
}
expect(
source,
"source preparation carries tenant and project",
/pub struct SourcePreparation[\s\S]*pub tenant: TenantId[\s\S]*pub project: ProjectId/
);
for (const [name, pattern] of [
["project creation rejects foreign tenant reuse", /project id is outside the signed-in tenant scope/],
["project selection rejects foreign tenant", /project is outside the signed-in tenant scope/],
["project listing uses tenant-scoped context", /CoordinatorRequest::ListProjects[\s\S]*list_projects\(&context\)/],
["node capability reports check enrollment tenant scope", /node capability report is outside the enrolled tenant\/project scope/],
["operator panel stop state is tenant/project/process keyed", /type PanelStopKey = \(TenantId, ProjectId, ProcessId\)/],
["download service tests tenant mismatch", /cross_tenant\.to_string\(\)\.contains\("tenant mismatch"\)/],
["download service tests project mismatch", /cross_project\.to_string\(\)\.contains\("project mismatch"\)/],
["node capability test rejects cross-scope report", /fn service_rejects_node_capability_report_outside_enrollment_scope\(\)/],
["source preparation test rejects cross-scope completion", /fn service_rejects_source_preparation_completion_outside_node_scope\(\)/],
]) {
expect(coordinatorService, name, pattern);
}
for (const [name, sourceText, patterns] of [
[
"artifact download smoke",
artifactDownloadSmoke,
[
/const crossTenant = await send/,
/const crossProject = await send/,
/const crossTenantOpen = await send/,
/const crossProjectOpen = await send/,
/tenant mismatch/,
/project mismatch/,
/token is invalid/,
],
],
[
"operator panel smoke",
operatorPanelSmoke,
[/const crossTenant = await send/, /render_operator_panel/, /scope\|tenant\|project/],
],
[
"scheduler and capability smoke",
schedulerSmoke,
[
/const crossScopeInspection = await send/,
/assert\.strictEqual\(crossScopeInspection\.descriptors\.length, 0\)/,
/const crossTenantReport = await send/,
/tenant\\\/project scope/,
],
],
[
"source preparation smoke",
sourcePreparationSmoke,
[/const crossTenantCompletion = await send/, /complete_source_preparation/, /tenant\\\/project scope/i],
],
]) {
for (const pattern of patterns) {
expect(sourceText, name, pattern);
}
}
expect(releaseBlockerSmoke, "release blockers list tenant-isolation failure", /cross-tenant access is listed as a release blocker/);
expectGate(publicAcceptance, "public acceptance");
expectGate(publicSplit, "public split acceptance");
expectGate(privateAcceptance, "private acceptance");
const hostedLibRoot = maybeRead(["private", "hosted-policy", "src", "lib.rs"]);
const hostedServiceSource = maybeRead([
"private",
"hosted-policy",
"src",
"bin",
"disasmer-hosted-service.rs",
]);
const hostedLib = hostedLibRoot;
const hostedSmoke = maybeRead([
"private",
"hosted-policy",
"scripts",
"hosted-client-compat-smoke.js",
]);
if (hostedLib && hostedServiceSource && hostedSmoke) {
for (const [name, pattern] of [
["hosted private layer is a compact identity broker", /pub struct HostedIdentityBroker[\s\S]*cli_session_ttl_seconds/],
["hosted private layer has no parallel coordinator", /Runtime, persistence, nodes, processes,[\s\S]*remain owned by public CoordinatorService/],
["hosted service delegates Client state to Core", /core_coordinator: CoordinatorService/],
["hosted login creates project through Core", /issue_cli_session[\s\S]*AuthenticatedCoordinatorRequest::CreateProject/],
]) {
expect(`${hostedLib}\n${hostedServiceSource}`, name, pattern);
}
for (const forbidden of [
"HostedCommunityControlPlane",
"HostedObservabilitySnapshot",
"agent_public_keys: BTreeMap",
"node_statuses: BTreeMap",
"process_statuses: BTreeMap",
"debug_sessions: BTreeMap",
]) {
assert(
!hostedLib.includes(forbidden),
`private hosted policy must not reimplement Core state: ${forbidden}`
);
}
for (const [name, pattern] of [
["client-supplied identity is denied", /const forged = await sendHostedControl[\s\S]*authenticated CLI session/],
["second OIDC subject receives a different tenant", /assert\.notStrictEqual\(victimLogin\.session\.tenant, session\.tenant\)/],
["cross-tenant process events are denied", /const crossTenantTaskEventsDenied = await sendHostedControl[\s\S]*vp-victim[\s\S]*scope\|denied\|unauthorized/],
]) {
expect(hostedSmoke, name, pattern);
}
}
console.log("Tenant isolation contract smoke passed");

View file

@ -0,0 +1,120 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(file) {
return fs.readFileSync(path.join(repo, file), "utf8");
}
function extractBalancedBlock(source, marker) {
const start = source.indexOf(marker);
assert(start >= 0, `missing marker ${marker}`);
const open = source.indexOf("{", start);
assert(open >= 0, `missing opening brace for ${marker}`);
let depth = 0;
for (let index = open; index < source.length; index += 1) {
const char = source[index];
if (char === "{") depth += 1;
if (char === "}") {
depth -= 1;
if (depth === 0) return source.slice(start, index + 1);
}
}
throw new Error(`missing closing brace for ${marker}`);
}
function extractEnumVariant(source, variant) {
const marker = ` ${variant} {`;
return extractBalancedBlock(source, marker);
}
const forbiddenUserSessionCredentials =
/\b(BrowserSession|CliDeviceSession|BrowserLoginFlow|CliLoginFlow|authorization_url|verification_url|device_code|access_token|refresh_token|provider_token|provider_tokens|session_token|user_token|oauth_token)\b/i;
function assertNoUserSessionCredential(surface, text) {
assert.doesNotMatch(
text,
forbiddenUserSessionCredentials,
`${surface} must not carry user OAuth/browser/session credentials`
);
}
const coordinatorService = `${read("crates/disasmer-coordinator/src/service/protocol.rs")}\n${read("crates/disasmer-coordinator/src/service/protocol/responses.rs")}`;
for (const variant of [
"AdminStatus",
"SuspendTenant",
"AttachNode",
"RegisterAgentPublicKey",
"ListAgentPublicKeys",
"RotateAgentPublicKey",
"RevokeAgentPublicKey",
"NodeHeartbeat",
"ReportNodeCapabilities",
"RevokeNodeCredential",
"RequestRendezvous",
"RequestSourcePreparation",
"CompleteSourcePreparation",
"StartProcess",
"ReconnectNode",
"CancelTask",
"CancelProcess",
"PollTaskControl",
"RestartTask",
"DebugAttach",
"TaskCompleted",
]) {
assertNoUserSessionCredential(
`CoordinatorRequest::${variant}`,
extractEnumVariant(coordinatorService, variant)
);
}
const nodeRuntime = [
read("crates/disasmer-node/src/lib.rs"),
read("crates/disasmer-node/src/command_runner.rs"),
].join("\n");
for (const marker of [
"pub struct LinuxCommandRunPlan",
"pub struct LinuxCommandTaskOutput",
"pub struct CapturedCommandLogs",
"pub struct VirtualThreadCommand",
"pub struct CommandOutput",
]) {
assertNoUserSessionCredential(marker, extractBalancedBlock(nodeRuntime, marker));
}
const coreExecution = read("crates/disasmer-core/src/execution.rs");
assertNoUserSessionCredential(
"CommandInvocation",
extractBalancedBlock(coreExecution, "pub struct CommandInvocation")
);
const dapAdapter = read("crates/disasmer-dap/src/variables.rs");
assertNoUserSessionCredential(
"DAP variables response",
extractBalancedBlock(dapAdapter, "fn variables_response")
);
const panel = read("crates/disasmer-core/src/operator_panel.rs");
assertNoUserSessionCredential(
"PanelEvent",
extractBalancedBlock(panel, "pub struct PanelEvent")
);
const auth = read("crates/disasmer-core/src/auth.rs");
assert.match(
auth,
/task_credentials_do_not_contain_user_session/,
"core auth must keep the task credential user-session guard"
);
assert.match(
auth,
/CredentialKind::BrowserSession \| CredentialKind::CliDeviceSession/,
"task credential guard must reject browser and CLI sessions"
);
console.log("User session token boundary smoke passed");

75
scripts/verify-public-split.sh Executable file
View file

@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source_commit="$(git -C "$repo_root" rev-parse HEAD)"
export DISASMER_ACCEPTANCE_COMMIT="$source_commit"
tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' EXIT
tar \
--exclude='./.git' \
--exclude='./target' \
--exclude='./private' \
--exclude='./experiments' \
--exclude='./.disasmer' \
--exclude='./vscode-extension/node_modules' \
--exclude='./scripts/containers-home' \
-C "$repo_root" \
-cf - . | tar -C "$tmp_dir" -xf -
if find "$tmp_dir" -path "$tmp_dir/private" -print -quit | grep -q .; then
echo "private directory leaked into public split" >&2
exit 1
fi
if find "$tmp_dir" -path "$tmp_dir/experiments" -print -quit | grep -q .; then
echo "experiments directory leaked into public split" >&2
exit 1
fi
cargo test --workspace --manifest-path "$tmp_dir/Cargo.toml"
cargo build --workspace --bins --manifest-path "$tmp_dir/Cargo.toml"
(cd "$tmp_dir" && node scripts/acceptance-report-smoke.js)
(cd "$tmp_dir" && node scripts/acceptance-doc-contract-smoke.js)
(cd "$tmp_dir" && node scripts/acceptance-environment-contract-smoke.js)
(cd "$tmp_dir" && node scripts/acceptance-evidence-contract-smoke.js)
(cd "$tmp_dir" && node scripts/code-size-guard.js)
(cd "$tmp_dir" && node scripts/public-private-boundary-smoke.js)
(cd "$tmp_dir" && node scripts/release-blocker-smoke.js)
(cd "$tmp_dir" && node scripts/resource-metering-contract-smoke.js)
(cd "$tmp_dir" && node scripts/hostile-input-contract-smoke.js)
(cd "$tmp_dir" && node scripts/tenant-isolation-contract-smoke.js)
(cd "$tmp_dir" && node scripts/public-story-contract-smoke.js)
(cd "$tmp_dir" && node scripts/public-release-dryrun-contract-smoke.js)
(cd "$tmp_dir" && node scripts/self-hosted-coordinator-smoke.js)
(cd "$tmp_dir" && node scripts/public-local-demo-matrix-smoke.js)
(cd "$tmp_dir" && scripts/release-source-scan.sh)
(cd "$tmp_dir" && node scripts/prepare-public-release-dryrun.js)
if [[ -n "${DISASMER_FORGEJO_TOKEN:-}" ]]; then
(cd "$tmp_dir" && node scripts/publish-public-release-dryrun.js)
fi
(cd "$tmp_dir" && node scripts/docs-smoke.js)
(cd "$tmp_dir" && node scripts/cli-output-mode-smoke.js)
(cd "$tmp_dir" && node scripts/cli-login-smoke.js)
(cd "$tmp_dir" && node scripts/cli-error-exit-smoke.js)
(cd "$tmp_dir" && node scripts/cli-browser-login-flow-smoke.js)
(cd "$tmp_dir" && node scripts/cli-install-smoke.js)
(cd "$tmp_dir" && node scripts/user-session-token-boundary-smoke.js)
(cd "$tmp_dir" && node scripts/sdk-spawn-runtime-smoke.js)
(cd "$tmp_dir" && node scripts/node-lifecycle-contract-smoke.js)
(cd "$tmp_dir" && node scripts/vscode-extension-smoke.js)
(cd "$tmp_dir" && node scripts/vscode-f5-smoke.js)
(cd "$tmp_dir" && node scripts/node-attach-smoke.js)
(cd "$tmp_dir" && node scripts/wasmtime-assignment-smoke.js)
(cd "$tmp_dir" && node scripts/cli-local-run-smoke.js)
(cd "$tmp_dir" && node scripts/artifact-download-smoke.js)
(cd "$tmp_dir" && node scripts/artifact-export-smoke.js)
(cd "$tmp_dir" && node scripts/operator-panel-smoke.js)
(cd "$tmp_dir" && node scripts/source-preparation-smoke.js)
(cd "$tmp_dir" && node scripts/scheduler-placement-smoke.js)
(cd "$tmp_dir" && node scripts/windows-best-effort-smoke.js)
(cd "$tmp_dir" && node scripts/windows-validation-contract-smoke.js)
(cd "$tmp_dir" && node scripts/quic-smoke.js)
(cd "$tmp_dir" && node scripts/dap-smoke.js)
(cd "$tmp_dir" && node scripts/flagship-demo-smoke.js)

232
scripts/vscode-extension-smoke.js Executable file
View file

@ -0,0 +1,232 @@
#!/usr/bin/env node
const fs = require("fs");
const os = require("os");
const path = require("path");
const assert = require("assert");
const extension = require("../vscode-extension/extension");
const packageJson = require("../vscode-extension/package.json");
const extensionSource = fs.readFileSync(
path.join(__dirname, "../vscode-extension/extension.js"),
"utf8"
);
const readme = fs.readFileSync(path.join(__dirname, "../README.md"), "utf8");
const repo = path.resolve(__dirname, "..");
assert.strictEqual(packageJson.main, "./extension.js");
assert(fs.existsSync(path.join(__dirname, "../vscode-extension", packageJson.main)));
assert.deepStrictEqual(packageJson.dependencies || {}, {});
assert.match(readme, /code --extensionDevelopmentPath "\$\(pwd\)\/vscode-extension"/);
const root = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-vscode-"));
fs.mkdirSync(path.join(root, "envs/linux"), { recursive: true });
fs.writeFileSync(path.join(root, "envs/linux/Containerfile"), "FROM alpine\n");
fs.mkdirSync(path.join(root, ".disasmer"), { recursive: true });
fs.writeFileSync(
extension.disasmerViewStatePath(root),
JSON.stringify({
nodes: [{ id: "node-linux", status: "online", capabilities: "Command RootlessPodman" }],
processes: [{ id: "vp-build", status: "running", entry: "build" }],
logs: [{ task: "compile-linux", message: "stdout=12 stderr=0", bytes: 12 }],
artifacts: [{ path: "/vfs/artifacts/app.tar.zst", status: "retained", size: 12 }],
inspector: [{ label: "debug", value: "attached" }]
})
);
const envs = extension.discoverEnvironmentNames(root);
assert.deepStrictEqual(envs, ["linux"]);
const diagnostics = extension.diagnoseEnvReferences(
'let _ = env!("linux"); let _ = env!("windows");',
envs
);
assert.strictEqual(diagnostics.length, 1);
assert.strictEqual(diagnostics[0].name, "windows");
assert.match(diagnostics[0].message, /envs\/windows\/Containerfile/);
const inspectCommand = extension.bundleInspectCommand(root, "/repo");
assert.strictEqual(inspectCommand.command, "cargo");
assert.deepStrictEqual(inspectCommand.args.slice(0, 8), [
"run",
"-q",
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
"bundle"
]);
assert(inspectCommand.args.includes("inspect"));
assert(inspectCommand.args.includes("--project"));
assert(inspectCommand.args.includes(root));
assert(inspectCommand.args.includes("--json"));
const refreshed = extension.refreshBundleBeforeLaunch(root, "/repo", (command, args, options) => {
assert.strictEqual(command, "cargo");
assert(args.includes("bundle"));
assert.strictEqual(options.cwd, "/repo");
return {
status: 0,
stdout: JSON.stringify({ metadata: { identity: "sha256:abc" } }),
stderr: ""
};
});
assert.strictEqual(refreshed.metadata.identity, "sha256:abc");
const launch = extension.resolveDisasmerDebugConfiguration(
{ uri: { fsPath: root } },
{}
);
assert.deepStrictEqual(launch, {
name: "Disasmer: Launch Virtual Process",
type: "disasmer",
request: "launch",
entry: "build",
project: root,
runtimeBackend: "local-services"
});
assert.strictEqual(
extension.disasmerProcessId("/workspace/app", "build"),
"vp-e4bd6ef50539"
);
assert.strictEqual(
extension.existingProcessRelationship(
{ process: "vp-e4bd6ef50539", state: "running" },
"vp-e4bd6ef50539"
),
"same_launch_target"
);
assert.strictEqual(
extension.existingProcessRelationship(
{ process: "vp-other", state: "running" },
"vp-e4bd6ef50539"
),
"different_launch_target"
);
const liveProcesses = extension.loadLiveProcesses(root, "/repo", (_command, args) => {
assert.deepStrictEqual(args.slice(-3), ["process", "list", "--json"]);
return {
status: 0,
stdout: JSON.stringify({
coordinator: "https://disasmer.michelpaulissen.com",
tenant: "tenant-live",
project: "project-live",
user: "user-live",
processes: [{ process: "vp-live", state: "cancelling" }]
}),
stderr: ""
};
});
assert.deepStrictEqual(liveProcesses.processes, [
{ process: "vp-live", state: "cancelling" }
]);
assert.strictEqual(liveProcesses.project, "project-live");
const adapter = extension.debugAdapterExecutableSpec(root, repo);
assert.strictEqual(adapter.command, "cargo");
assert.deepStrictEqual(adapter.args, [
"run",
"-q",
"-p",
"disasmer-dap",
"--bin",
"disasmer-debug-dap"
]);
assert.deepStrictEqual(adapter.options, { cwd: repo });
const releasedAdapterPath = path.join(root, process.platform === "win32" ? "disasmer-debug-dap.exe" : "disasmer-debug-dap");
fs.writeFileSync(releasedAdapterPath, "");
const releasedAdapter = extension.debugAdapterExecutableSpec(root, repo);
assert.strictEqual(releasedAdapter.command, releasedAdapterPath);
assert.deepStrictEqual(releasedAdapter.args, []);
assert.deepStrictEqual(releasedAdapter.options, { cwd: root });
assert.throws(
() =>
extension.refreshBundleBeforeLaunch(root, "/repo", () => ({
status: 1,
stdout: "",
stderr: "missing environment linux"
})),
/missing environment linux/
);
assert(
packageJson.contributes.viewsContainers.activitybar.some(
(container) => container.id === "disasmer" && container.title === "Disasmer"
),
"package.json must contribute a Disasmer activity-bar container"
);
assert(
fs.existsSync(path.join(__dirname, "../vscode-extension/resources/disasmer.svg")),
"Disasmer activity-bar icon must exist"
);
const packageViewIds = packageJson.contributes.views.disasmer.map((view) => view.id).sort();
const descriptorViewIds = extension.disasmerViewDescriptors().map((view) => view.id).sort();
assert.deepStrictEqual(descriptorViewIds, [
"disasmer.artifacts",
"disasmer.inspector",
"disasmer.logs",
"disasmer.nodes",
"disasmer.processes"
]);
assert.deepStrictEqual(packageViewIds, descriptorViewIds);
for (const viewId of descriptorViewIds) {
const items = extension.disasmerViewItems(
extension.loadDisasmerViewState(root),
viewId
);
assert(
items.length > 0 && !items[0].label.startsWith("No "),
`${viewId} should render state-backed items`
);
}
assert.deepStrictEqual(
extension.disasmerViewItems(extension.loadDisasmerViewState(root), "disasmer.nodes")[0],
{
label: "node-linux",
description: "online Command RootlessPodman"
}
);
assert(
packageJson.contributes.debuggers.some((debuggerContribution) => debuggerContribution.type === "disasmer"),
"package.json must contribute the disasmer debugger type"
);
for (const viewId of descriptorViewIds) {
assert(
packageJson.activationEvents.includes(`onView:${viewId}`),
`${viewId} should activate the extension when opened`
);
}
const launchProperties =
packageJson.contributes.debuggers[0].configurationAttributes.launch.properties;
assert.strictEqual(launchProperties.runtimeBackend.default, "local-services");
assert(launchProperties.runtimeBackend.enum.includes("live-services"));
assert.strictEqual(launchProperties.coordinatorEndpoint.default, undefined);
assert.strictEqual(launchProperties.tenant, undefined);
assert.strictEqual(launchProperties.projectId, undefined);
assert.strictEqual(launchProperties.actorUser, undefined);
assert(
packageJson.contributes.debuggers[0].configurationAttributes.attach,
"package.json must contribute an attach configuration"
);
for (const command of [
"disasmer.refreshProcesses",
"disasmer.process.attach",
"disasmer.process.cancel",
"disasmer.process.abort"
]) {
assert(
packageJson.contributes.commands.some((entry) => entry.command === command),
`${command} must be contributed`
);
}
assert.match(extensionSource, /registerDebugAdapterDescriptorFactory\("disasmer"/);
assert.match(extensionSource, /disasmer-debug-dap/);
assert.match(extensionSource, /\.disasmer\/views\.json/);
fs.rmSync(root, { recursive: true, force: true });
console.log("VS Code extension smoke passed");

310
scripts/vscode-f5-smoke.js Executable file
View file

@ -0,0 +1,310 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const path = require("path");
const extension = require("../vscode-extension/extension");
class DapClient {
constructor(spec) {
this.child = cp.spawn(spec.command, spec.args, {
cwd: spec.options && spec.options.cwd,
env: spec.options && spec.options.env,
detached: process.platform !== "win32"
});
this.seq = 1;
this.buffer = Buffer.alloc(0);
this.messages = [];
this.waiters = [];
this.stderr = "";
this.child.stdout.on("data", (chunk) => {
this.buffer = Buffer.concat([this.buffer, chunk]);
this.parse();
});
this.child.stderr.on("data", (chunk) => {
this.stderr += chunk.toString();
});
this.child.on("exit", () => this.flushWaiters());
}
send(command, args = {}) {
const seq = this.seq++;
const message = { seq, type: "request", command, arguments: args };
const payload = Buffer.from(JSON.stringify(message));
this.child.stdin.write(`Content-Length: ${payload.length}\r\n\r\n`);
this.child.stdin.write(payload);
return seq;
}
async response(seq, command) {
const message = await this.waitFor(
(item) =>
item.type === "response" &&
item.request_seq === seq &&
item.command === command
);
if (!message.success) {
throw new Error(
`DAP ${command} failed: ${message.message || JSON.stringify(message)}\n${this.stderr}`
);
}
return message;
}
terminate() {
if (this.child.exitCode !== null) return;
if (process.platform === "win32") {
this.child.kill("SIGKILL");
return;
}
try {
process.kill(-this.child.pid, "SIGKILL");
} catch (_) {
this.child.kill("SIGKILL");
}
}
waitFor(predicate, timeoutMs = 240000) {
const existing = this.messages.find(predicate);
if (existing) return Promise.resolve(existing);
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
this.terminate();
reject(new Error(`timed out waiting for DAP message\n${this.stderr}`));
}, timeoutMs);
this.waiters.push({ predicate, resolve, timer });
});
}
parse() {
while (true) {
const headerEnd = this.buffer.indexOf("\r\n\r\n");
if (headerEnd < 0) return;
const header = this.buffer.slice(0, headerEnd).toString();
const match = header.match(/Content-Length: (\d+)/i);
if (!match) throw new Error(`bad DAP header: ${header}`);
const length = Number(match[1]);
const start = headerEnd + 4;
const end = start + length;
if (this.buffer.length < end) return;
const payload = this.buffer.slice(start, end).toString();
this.buffer = this.buffer.slice(end);
this.messages.push(JSON.parse(payload));
this.flushWaiters();
}
}
flushWaiters() {
for (const waiter of [...this.waiters]) {
const message = this.messages.find(waiter.predicate);
if (!message) continue;
clearTimeout(waiter.timer);
this.waiters.splice(this.waiters.indexOf(waiter), 1);
waiter.resolve(message);
}
}
async close() {
if (this.child.exitCode !== null) return;
const seq = this.send("disconnect");
await this.response(seq, "disconnect");
this.child.stdin.end();
}
}
(async () => {
const repo = path.resolve(__dirname, "..");
const project = path.join(repo, "examples/launch-build-demo");
const buildSourceLines = fs
.readFileSync(path.join(project, "src/build.rs"), "utf8")
.split(/\r?\n/);
const sourceLine = (needle) => {
const index = buildSourceLines.findIndex((line) => line.includes(needle));
assert(index >= 0, `flagship source must contain ${needle}`);
return index + 1;
};
const buildMainLine = sourceLine("pub async fn build_main()");
const launchConfig = extension.resolveDisasmerDebugConfiguration(
{ uri: { fsPath: project } },
{}
);
assert.strictEqual(launchConfig.type, "disasmer");
assert.strictEqual(launchConfig.request, "launch");
assert.strictEqual(launchConfig.entry, "build");
assert.strictEqual(launchConfig.project, project);
assert.strictEqual(launchConfig.runtimeBackend, "local-services");
const inspection = extension.refreshBundleBeforeLaunch(project, repo);
assert.match(inspection.metadata.identity, /^sha256:/);
// Keep the timed attach focused on the runtime boundary. A completely fresh
// public checkout may otherwise spend most of that window compiling the
// coordinator or node after the adapter has already started waiting.
cp.execFileSync(
"cargo",
[
"build",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"-p",
"disasmer-node",
"--bin",
"disasmer-node",
],
{ cwd: repo, stdio: "inherit" }
);
const executableSuffix = process.platform === "win32" ? ".exe" : "";
const adapterSpec = extension.debugAdapterExecutableSpec(repo);
adapterSpec.options = {
...(adapterSpec.options || {}),
env: {
...process.env,
DISASMER_COORDINATOR_BIN: path.join(
repo,
"target",
"debug",
`disasmer-coordinator${executableSuffix}`
),
DISASMER_NODE_BIN: path.join(
repo,
"target",
"debug",
`disasmer-node${executableSuffix}`
),
},
};
const client = new DapClient(adapterSpec);
try {
const initialize = client.send("initialize", {
adapterID: "disasmer",
linesStartAt1: true,
columnsStartAt1: true
});
await client.response(initialize, "initialize");
const launch = client.send("launch", launchConfig);
await client.response(launch, "launch");
await client.waitFor(
(message) => message.type === "event" && message.event === "initialized"
);
const breakpoints = client.send("setBreakpoints", {
source: { path: path.join(project, "src/build.rs") },
breakpoints: [{ line: buildMainLine }]
});
const breakpointResponse = await client.response(breakpoints, "setBreakpoints");
assert.strictEqual(breakpointResponse.body.breakpoints[0].verified, true);
const configurationDone = client.send("configurationDone");
await client.response(configurationDone, "configurationDone");
const stopped = await client.waitFor(
(message) => message.type === "event" && message.event === "stopped"
);
assert.strictEqual(stopped.body.allThreadsStopped, true);
assert.strictEqual(stopped.body.reason, "breakpoint");
const threadsRequest = client.send("threads");
const threads = (await client.response(threadsRequest, "threads")).body.threads;
const mainThread = threads.find((thread) => thread.name.includes("build virtual process"));
assert(mainThread, "F5 launch must expose the real entrypoint as a virtual thread");
const stackRequest = client.send("stackTrace", {
threadId: mainThread.id,
startFrame: 0,
levels: 1
});
const stack = (await client.response(stackRequest, "stackTrace")).body.stackFrames;
assert.strictEqual(stack[0].line, buildMainLine);
assert.strictEqual(stack[0].source.path, path.join(project, "src/build.rs"));
assert.strictEqual(stack[0].source.sourceReference || 0, 0);
const sourceRequest = client.send("source", { source: stack[0].source });
const source = (await client.response(sourceRequest, "source")).body;
assert.match(source.content, /compile_linux/);
const scopesRequest = client.send("scopes", { frameId: stack[0].id });
const scopes = (await client.response(scopesRequest, "scopes")).body.scopes;
const localsScope = scopes.find((scope) => scope.name === "Source Locals");
const argsScope = scopes.find((scope) => scope.name === "Task Args and Handles");
const runtimeScope = scopes.find((scope) => scope.name === "Disasmer Runtime");
const outputScope = scopes.find((scope) => scope.name === "Recent Output");
assert(localsScope, "F5 launch must expose source locals scope");
assert(argsScope, "F5 launch must expose task args and handles");
assert(runtimeScope, "F5 launch must expose Disasmer runtime state");
assert(outputScope, "F5 launch must expose recent output state");
const localsRequest = client.send("variables", {
variablesReference: localsScope.variablesReference
});
const locals = (await client.response(localsRequest, "variables")).body.variables;
assert(
locals.some(
(variable) =>
variable.name === "unavailable-local-diagnostic" &&
String(variable.value).includes("cannot be inspected")
),
"source locals scope must report unavailable real Rust locals explicitly"
);
const runtimeRequest = client.send("variables", {
variablesReference: runtimeScope.variablesReference
});
const runtime = (await client.response(runtimeRequest, "variables")).body.variables;
assert(
runtime.some(
(variable) => variable.name === "runtime_backend" && variable.value === "LocalServices"
),
"extension-resolved F5 launch must use the real local-services backend"
);
assert(
runtime.some(
(variable) => variable.name === "coordinator_task_events" && variable.value === 0
),
"a task frozen at its entry probe must not fabricate a terminal task event"
);
assert(
runtime.some(
(variable) =>
variable.name === "command_status" &&
String(variable.value).includes(
"frozen through local services at executing Wasm probe"
)
)
);
assert(
runtime.some(
(variable) => variable.name === "state" && variable.value === "Frozen"
),
"F5 must expose the node-acknowledged frozen participant state"
);
assert(runtime.some((variable) => variable.name === "command_spec"));
assert(runtime.some((variable) => variable.name === "stdout_tail"));
assert(runtime.some((variable) => variable.name === "stderr_tail"));
const outputRequest = client.send("variables", {
variablesReference: outputScope.variablesReference
});
const output = (await client.response(outputRequest, "variables")).body.variables;
assert(output.some((variable) => variable.name === "stdout_tail"));
assert(output.some((variable) => variable.name === "stderr_tail"));
await client.close();
} catch (error) {
client.terminate();
throw error;
}
console.log("VS Code F5 smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,172 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const wasmTarget = path.join(
repo,
"target",
"wasm32-unknown-unknown",
"release",
"launch_build_demo.wasm"
);
cp.execFileSync(
"cargo",
[
"build",
"--release",
"-p",
"launch-build-demo",
"--target",
"wasm32-unknown-unknown",
],
{
cwd: repo,
stdio: "inherit",
env: {
...process.env,
CARGO_PROFILE_RELEASE_OPT_LEVEL: "z",
CARGO_PROFILE_RELEASE_LTO: "thin",
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: "1",
},
}
);
assert(fs.existsSync(wasmTarget), `missing compiled Wasm module at ${wasmTarget}`);
const output = cp.execFileSync(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-node",
"--bin",
"disasmer-wasmtime-smoke",
"--",
wasmTarget,
"task_add_one",
"41",
"42",
],
{ cwd: repo, encoding: "utf8" }
);
const report = JSON.parse(output);
assert.strictEqual(report.type, "wasmtime_task_smoke");
assert.strictEqual(report.export, "task_add_one");
assert.strictEqual(report.arg, 41);
assert.strictEqual(report.result, 42);
const debugOutput = cp.execFileSync(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-node",
"--bin",
"disasmer-wasmtime-smoke",
"--",
"--debug-freeze-resume",
wasmTarget,
"task_add_one",
"41",
"42",
],
{ cwd: repo, encoding: "utf8" }
);
const debugReport = JSON.parse(debugOutput);
assert.strictEqual(debugReport.type, "wasmtime_debug_freeze_resume_smoke");
assert.strictEqual(debugReport.export, "task_add_one");
assert.strictEqual(debugReport.task, "task_add_one");
assert.strictEqual(debugReport.frozen_state, "Frozen");
assert.strictEqual(debugReport.resumed_state, "Running");
assert(debugReport.stack_frames.some((frame) => String(frame).includes("task_add_one")));
assert(
debugReport.local_values.some(
([name, value]) => name === "wasm_local_0" && String(value).includes("41")
),
"Wasmtime debug snapshot must expose the real i32 argument as a frame local"
);
assert.strictEqual(debugReport.node_runtime_captured_wasm_locals, true);
assert.strictEqual(debugReport.result, 42);
assert.strictEqual(debugReport.node_runtime_reached_wasm_task, true);
const hostCommandOutput = cp.execFileSync(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-node",
"--bin",
"disasmer-wasmtime-smoke",
"--",
"--host-command",
wasmTarget,
"compile_linux",
],
{ cwd: repo, encoding: "utf8" }
);
const hostCommandReport = JSON.parse(hostCommandOutput);
assert.strictEqual(hostCommandReport.type, "wasmtime_host_command_smoke");
assert.strictEqual(hostCommandReport.task, "compile_linux");
assert.match(hostCommandReport.export, /^disasmer_task_v1_[0-9a-f]{64}$/);
assert.strictEqual(hostCommandReport.program, "cc");
assert.deepStrictEqual(hostCommandReport.args, [
"-Os",
"-static",
"-s",
"fixture/hello-disasmer.c",
"-o",
"/disasmer/output/hello-disasmer",
]);
assert.strictEqual(hostCommandReport.working_directory, "/workspace");
assert.deepStrictEqual(hostCommandReport.environment_variables, {
SOURCE_DATE_EPOCH: "0",
});
assert.strictEqual(hostCommandReport.timeout_ms, 180000);
assert.strictEqual(hostCommandReport.network, "disabled");
assert.strictEqual(hostCommandReport.status_code, 0);
assert.strictEqual(hostCommandReport.stdout, "");
assert.strictEqual(hostCommandReport.artifact_name, "hello-disasmer");
assert.strictEqual(hostCommandReport.artifact_size_bytes, "hello-disasmer".length);
assert.match(hostCommandReport.artifact_digest, /^sha256:[0-9a-f]{64}$/);
assert.strictEqual(hostCommandReport.node_host_import, "disasmer.command_run_v1");
assert.strictEqual(hostCommandReport.artifact_host_import, "disasmer.vfs_operation_v1");
assert.strictEqual(hostCommandReport.flagship_linux_build_task, true);
assert.strictEqual(hostCommandReport.node_executed_host_command, true);
assert.strictEqual(hostCommandReport.hosted_control_plane_ran_command, false);
const artifactOutput = cp.execFileSync(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-node",
"--bin",
"disasmer-wasmtime-smoke",
"--",
"--task-artifact",
wasmTarget,
"package_release",
],
{ cwd: repo, encoding: "utf8" }
);
const artifactReport = JSON.parse(artifactOutput);
assert.strictEqual(artifactReport.type, "wasmtime_task_artifact_smoke");
assert.strictEqual(artifactReport.task, "package_release");
assert.strictEqual(artifactReport.artifact_name, "release.tar");
assert.strictEqual(artifactReport.artifact_size_bytes, "release.tar".length);
assert.match(artifactReport.artifact_digest, /^sha256:[0-9a-f]{64}$/);
assert.strictEqual(artifactReport.host_import, "disasmer.vfs_operation_v1");
assert.strictEqual(artifactReport.host_issued_handle_returned, true);
assert.ok(artifactReport.artifact.id.endsWith(artifactReport.artifact_digest.slice("sha256:".length)));
console.log("Wasmtime node smoke passed");

View file

@ -0,0 +1,105 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const inventoryPath = path.join(repo, "website_mvp_inventory.md");
if (!fs.existsSync(inventoryPath)) {
if (fs.existsSync(path.join(repo, "DISASMER_PUBLIC_TREE.json"))) {
console.log(
"Website inventory contract smoke skipped: website_mvp_inventory.md is filtered from this public tree"
);
process.exit(0);
}
throw new Error("website_mvp_inventory.md is missing");
}
const source = fs.readFileSync(inventoryPath, "utf8");
function expect(name, pattern) {
assert.match(source, pattern, `missing website inventory evidence: ${name}`);
}
function criterionLines() {
return source
.split(/\r?\n/)
.filter((line) => /^- \[[ x]\] \*\*/.test(line));
}
expect("header", /^# Disasmer MVP Website Acceptance Criteria/m);
expect(
"acceptance-style status",
/\*\*Status:\*\* (?:private )?hosted website addendum to `acceptance_criteria\.md`, `acceptance_criteria_phase2\.md`, and `cli_acceptance_criteria\.md`/
);
expect(
"hosted signup exception",
/except hosted Authentik account creation/
);
expect(
"no duplicate work note",
/does not automatically mean new product code, a new feature, or even actual implementation work is required/
);
expect(
"prove existing behavior before implementation",
/prefer proving, documenting, or tightening that existing behavior over duplicating capability or overengineering a parallel website mechanism/
);
expect(
"barebones no CSS",
/barebones functional HTML with no CSS/
);
expect(
"future hosted business scope",
/Billing is not part of the MVP[\s\S]*Paid checkout, paid-plan management, upgrade flows, hosted support tooling, a full hosted admin console, broad moderation workflows/
);
expect(
"billing is not MVP website work",
/Do not build billing\/upgrade flows into the minimal website for this MVP/
);
expect(
"billing-only surfaces are postponed",
/If a website route, API, database field, control, or acceptance item exists only for billing, paid plans, hosted business operations, broad admin\/moderation, team management, provider setup, secret management, durable account\/business-process management, or any similarly future hosted-business concern, postpone it instead of building it for this MVP\./
);
expect(
"billing plan flags are placeholders",
/Design-document references to billing, paid plans, or plan flags are future metadata placeholders; they do not require MVP website routes, database fields, UI controls, CLI commands, coordinator routes, or service logic/
);
assert.doesNotMatch(source, /community-tier/, "use `community tier`, not `community-tier`");
const lines = criterionLines();
assert(lines.length > 0, "website inventory must contain status-prefixed checklist items");
for (const line of lines) {
assert.match(
line,
/^- \[[ x]\] \*\*(Passed|Partial|Open|Postponed)(?: \([^)]+\))?:\*\*/,
`website inventory item lacks an explicit status prefix: ${line}`
);
}
for (const [name, pattern] of [
["CLI login command", /`disasmer login \[--browser\] \[--coordinator <url>\]`/],
["CLI auth status command", /`disasmer auth status`/],
["CLI key command", /`disasmer key add --public-key <pubkey>`/],
["CLI project init command", /`disasmer project init`/],
["CLI node enroll command", /`disasmer node enroll --coordinator <url> --ttl-seconds <seconds>`/],
["CLI process status command", /`disasmer process status`/],
["CLI task list command", /`disasmer task list`/],
["CLI DAP command", /`disasmer dap`/],
["CLI quota command", /`disasmer quota status`/],
["CLI admin status command", /`disasmer admin status`/],
]) {
expect(name, pattern);
}
for (const [name, pattern] of [
["website default project is open", /- \[ \] \*\*Open:\*\* land in their default project\./],
["website node attach is open", /- \[ \] \*\*Open:\*\* copy a node attach command\./],
["website process view is open", /- \[ \] \*\*Open:\*\* see the single current virtual process\./],
["website logs are open", /- \[ \] \*\*Open:\*\* see recent bounded logs\./],
["website artifact download is open", /- \[ \] \*\*Open:\*\* securely download an available best-effort retained artifact\./],
["website keys are partial through CLI", /- \[ \] \*\*Partial:\*\* manage\/revoke public keys or know the CLI command to do so\./],
]) {
expect(name, pattern);
}
console.log("Website inventory contract smoke passed");

View file

@ -0,0 +1,302 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const { nodeIdentity, signedNodeRequest } = require("./node-signing");
const repo = path.resolve(__dirname, "..");
const digest = (value) =>
`sha256:${crypto.createHash("sha256").update(value).digest("hex")}`;
const environmentDigest = digest("windows-command-dev-environment");
const sourceDigest = digest("windows-best-effort-source");
const windowsArtifactBytes = Buffer.from("windows-output-data");
const windowsArtifactDigest = digest(windowsArtifactBytes);
const emptyWasm = Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]);
const emptyWasmDigest = digest(emptyWasm);
const nodeDaemon = fs.readFileSync(path.join(repo, "crates/disasmer-node/src/daemon.rs"), "utf8");
const taskReports = fs.readFileSync(
path.join(repo, "crates/disasmer-node/src/task_reports.rs"),
"utf8"
);
const nodeLib = fs.readFileSync(path.join(repo, "crates/disasmer-node/src/lib.rs"), "utf8");
const windowsDev = fs.readFileSync(
path.join(repo, "crates/disasmer-node/src/windows_dev.rs"),
"utf8"
);
const executionCore = fs.readFileSync(
path.join(repo, "crates/disasmer-core/src/execution.rs"),
"utf8"
);
const dapSource = [
fs.readFileSync(path.join(repo, "crates/disasmer-dap/src/demo_backend.rs"), "utf8"),
fs.readFileSync(path.join(repo, "crates/disasmer-dap/src/tests.rs"), "utf8"),
].join("\n");
const windowsNode = "windows-node";
const windowsIdentity = nodeIdentity("windows-best-effort-smoke", windowsNode);
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function windowsCapabilities() {
return {
os: "Windows",
arch: "x86_64",
capabilities: ["Command", "VfsArtifacts", "WindowsCommandDev"],
environment_backends: ["WindowsCommandDev"],
source_providers: ["filesystem"]
};
}
function assertWindowsBackendBoundary() {
assert.match(nodeDaemon, /CoordinatorSession::connect\(&args\.coordinator\)/);
assert.match(nodeDaemon, /record_completed_task\(/);
assert.match(taskReports, /"type": "task_completed"/);
assert.doesNotMatch(nodeDaemon, /WindowsCommandDev|windows-command-dev|cfg\(windows\)/);
assert.match(nodeLib, /impl CommandBackend for LinuxRootlessPodmanBackend/);
assert.match(nodeLib, /mod windows_dev/);
assert.match(nodeLib, /pub use windows_dev::\{WindowsCommandDevBackend, WindowsSandboxStubBackend\}/);
assert.match(windowsDev, /impl CommandBackend for WindowsCommandDevBackend/);
assert.match(windowsDev, /impl CommandBackend for WindowsSandboxStubBackend/);
assert.doesNotMatch(windowsDev, /LinuxRootlessPodmanBackend/);
assert.match(executionCore, /\bLinuxRootlessPodman\b/);
assert.match(executionCore, /\bWindowsCommandDev\b/);
assert.match(executionCore, /\bStubbedWindowsSandbox\b/);
assert.match(dapSource, /thread\(WINDOWS_THREAD, "compile-windows", "compile windows"/);
assert.match(dapSource, /fn launch_threads_include_windows_task_in_same_virtual_process\(\)/);
assert.match(dapSource, /fn windows_thread_runtime_variables_share_virtual_process\(\)/);
}
(async () => {
assertWindowsBackendBoundary();
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback"
],
{ cwd: repo }
);
let coordinatorStderr = "";
coordinator.stderr.on("data", (chunk) => {
coordinatorStderr += chunk.toString();
});
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const attached = await send(addr, {
type: "attach_node",
tenant: "tenant",
project: "project",
node: windowsNode,
public_key: windowsIdentity.publicKey
});
assert.strictEqual(attached.type, "node_attached");
assert.strictEqual(attached.node, windowsNode);
const recorded = await send(addr, signedNodeRequest(windowsNode, windowsIdentity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: windowsNode,
capabilities: windowsCapabilities(),
cached_environment_digests: [environmentDigest],
dependency_cache_digests: [],
source_snapshots: [sourceDigest],
artifact_locations: [],
direct_connectivity: true,
online: true
}));
assert.strictEqual(recorded.type, "node_capabilities_recorded");
assert.strictEqual(recorded.node, windowsNode);
const placement = await send(addr, {
type: "schedule_task",
tenant: "tenant",
project: "project",
environment: {
os: "Windows",
arch: null,
capabilities: ["WindowsCommandDev"]
},
environment_digest: environmentDigest,
required_capabilities: ["Command"],
dependency_cache: null,
source_snapshot: sourceDigest,
required_artifacts: [],
prefer_node: null
});
assert.strictEqual(placement.type, "task_placement");
assert.strictEqual(placement.placement.node, windowsNode);
assert.ok(placement.placement.reasons.includes("warm environment cache"));
assert.ok(placement.placement.reasons.includes("source snapshot already local"));
const started = await send(addr, {
type: "start_process",
tenant: "tenant",
project: "project",
process: "vp-windows"
});
assert.strictEqual(started.type, "process_started");
assert.strictEqual(started.process, "vp-windows");
const reconnected = await send(addr, signedNodeRequest(windowsNode, windowsIdentity, "reconnect_node", {
type: "reconnect_node",
node: windowsNode,
process: "vp-windows",
epoch: started.epoch
}));
assert.strictEqual(reconnected.type, "node_reconnected");
const launched = await send(addr, {
type: "launch_task",
tenant: "tenant",
project: "project",
actor_user: "operator",
task_spec: {
tenant: "tenant",
project: "project",
process: "vp-windows",
task_definition: "windows-command-dev",
task_instance: "windows-command-dev",
dispatch: {
kind: "coordinator_node_wasm",
export: "windows_command_dev",
abi: "task_v1",
},
environment_id: "windows",
environment: {
os: "Windows",
arch: null,
capabilities: ["WindowsCommandDev"],
},
environment_digest: environmentDigest,
required_capabilities: ["Command", "WindowsCommandDev"],
dependency_cache: null,
source_snapshot: sourceDigest,
required_artifacts: [],
args: [],
vfs_epoch: started.epoch,
bundle_digest: emptyWasmDigest,
},
wait_for_node: false,
artifact_path: "/vfs/artifacts/windows-output.txt",
wasm_module_base64: emptyWasm.toString("base64"),
});
assert.strictEqual(launched.type, "task_launched", JSON.stringify(launched));
assert.strictEqual(launched.placement.node, windowsNode);
const recordedTask = await send(addr, signedNodeRequest(windowsNode, windowsIdentity, "task_completed", {
type: "task_completed",
tenant: "tenant",
project: "project",
process: "vp-windows",
node: windowsNode,
task: "windows-command-dev",
status_code: 0,
stdout_bytes: 18,
stderr_bytes: 0,
stdout_tail: "",
stderr_tail: "",
stdout_truncated: false,
stderr_truncated: false,
artifact_path: "/vfs/artifacts/windows-output.txt",
artifact_digest: windowsArtifactDigest,
artifact_size_bytes: windowsArtifactBytes.length
}));
assert.strictEqual(recordedTask.type, "task_recorded");
assert.strictEqual(recordedTask.task, "windows-command-dev");
const events = await send(addr, {
type: "list_task_events",
tenant: "tenant",
project: "project",
actor_user: "user",
process: "vp-windows"
});
assert.strictEqual(events.type, "task_events");
assert.strictEqual(events.events.length, 1);
assert.strictEqual(events.events[0].node, "windows-node");
assert.strictEqual(events.events[0].artifact_path, "/vfs/artifacts/windows-output.txt");
const link = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact: "windows-output.txt",
max_bytes: 1024
});
assert.strictEqual(link.type, "artifact_download_link");
assert.strictEqual(link.link.process, "vp-windows");
assert.deepStrictEqual(link.link.source, { RetainedNode: "windows-node" });
} catch (error) {
if (coordinatorStderr) {
error.message = `${error.message}\ncoordinator stderr:\n${coordinatorStderr}`;
}
throw error;
} finally {
coordinator.kill("SIGTERM");
}
console.log("Windows best-effort smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

479
scripts/windows-runner-smoke.js Executable file
View file

@ -0,0 +1,479 @@
#!/usr/bin/env node
const assert = require("assert");
const cp = require("child_process");
const crypto = require("crypto");
const fs = require("fs");
const net = require("net");
const path = require("path");
const { coordinatorWireRequest } = require("./coordinator-wire");
const { nodeIdentity, signedNodeRequest } = require("./node-signing");
const repo = path.resolve(__dirname, "..");
const forgejoWindowsNode = "forgejo-windows-node";
const forgejoWindowsIdentity = nodeIdentity("windows-runner-smoke", forgejoWindowsNode);
const windowsEnvironmentDigest = `sha256:${crypto
.createHash("sha256")
.update("disasmer/windows-command-dev/v1")
.digest("hex")}`;
const sourceSnapshot = `sha256:${crypto
.createHash("sha256")
.update("disasmer/windows-runner/source/v1")
.digest("hex")}`;
class DapClient {
constructor() {
this.child = cp.spawn(
"cargo",
["run", "-q", "-p", "disasmer-dap", "--bin", "disasmer-debug-dap"],
{ cwd: repo }
);
this.seq = 1;
this.buffer = Buffer.alloc(0);
this.messages = [];
this.waiters = [];
this.stderr = "";
this.child.stdout.on("data", (chunk) => {
this.buffer = Buffer.concat([this.buffer, chunk]);
this.parse();
});
this.child.stderr.on("data", (chunk) => {
this.stderr += chunk.toString();
});
this.child.on("exit", () => this.flushWaiters());
}
send(command, args = {}) {
const seq = this.seq++;
const message = { seq, type: "request", command, arguments: args };
const payload = Buffer.from(JSON.stringify(coordinatorWireRequest(message)));
this.child.stdin.write(`Content-Length: ${payload.length}\r\n\r\n`);
this.child.stdin.write(payload);
return seq;
}
async response(seq, command) {
const message = await this.waitFor(
(item) =>
item.type === "response" &&
item.request_seq === seq &&
item.command === command
);
if (!message.success) {
throw new Error(`DAP ${command} failed: ${message.message || JSON.stringify(coordinatorWireRequest(message))}`);
}
return message;
}
waitFor(predicate, timeoutMs = 120000) {
const existing = this.messages.find(predicate);
if (existing) return Promise.resolve(existing);
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
this.child.kill("SIGKILL");
reject(new Error(`timed out waiting for DAP message\n${this.stderr}`));
}, timeoutMs);
this.waiters.push({ predicate, resolve, timer });
});
}
parse() {
while (true) {
const headerEnd = this.buffer.indexOf("\r\n\r\n");
if (headerEnd < 0) return;
const header = this.buffer.slice(0, headerEnd).toString();
const match = header.match(/Content-Length: (\d+)/i);
if (!match) throw new Error(`bad DAP header: ${header}`);
const length = Number(match[1]);
const start = headerEnd + 4;
const end = start + length;
if (this.buffer.length < end) return;
const payload = this.buffer.slice(start, end).toString();
this.buffer = this.buffer.slice(end);
this.messages.push(JSON.parse(payload));
this.flushWaiters();
}
}
flushWaiters() {
for (const waiter of [...this.waiters]) {
const message = this.messages.find(waiter.predicate);
if (!message) continue;
clearTimeout(waiter.timer);
this.waiters.splice(this.waiters.indexOf(waiter), 1);
waiter.resolve(message);
}
}
async close() {
if (this.child.exitCode !== null) return;
const seq = this.send("disconnect");
await this.response(seq, "disconnect");
this.child.stdin.end();
}
}
function waitForJsonLine(child) {
return new Promise((resolve, reject) => {
let buffer = "";
child.stdout.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
try {
resolve(JSON.parse(buffer.slice(0, newline).trim()));
} catch (error) {
reject(error);
}
});
child.once("exit", (code) => {
reject(new Error(`process exited before JSON line with code ${code}`));
});
});
}
function send(addr, message) {
return new Promise((resolve, reject) => {
const socket = net.connect(addr.port, addr.host, () => {
socket.write(`${JSON.stringify(coordinatorWireRequest(message))}\n`);
});
let buffer = "";
socket.on("data", (chunk) => {
buffer += chunk.toString();
const newline = buffer.indexOf("\n");
if (newline < 0) return;
socket.end();
try {
resolve(JSON.parse(buffer.slice(0, newline)));
} catch (error) {
reject(error);
}
});
socket.on("error", reject);
});
}
function runWindowsAttach(addr, grant) {
return new Promise((resolve, reject) => {
const child = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-cli",
"--bin",
"disasmer",
"--",
"node",
"attach",
"--coordinator",
`${addr.host}:${addr.port}`,
"--tenant",
"tenant",
"--project-id",
"project",
"--node",
forgejoWindowsNode,
"--public-key",
forgejoWindowsIdentity.publicKey,
"--enrollment-grant",
grant,
"--cap",
"windows-command-dev",
"--json"
],
{
cwd: repo,
env: {
...process.env,
DISASMER_NODE_PRIVATE_KEY: forgejoWindowsIdentity.privateKey,
},
}
);
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.on("exit", (code) => {
if (code !== 0) {
reject(new Error(`Windows node attach failed with code ${code}\n${stderr}`));
return;
}
try {
resolve(JSON.parse(stdout));
} catch (error) {
reject(
new Error(`Windows node attach output was not JSON: ${stdout}\n${error.stack || error.message}`)
);
}
});
});
}
function runWindowsNode(addr, grant) {
return new Promise((resolve, reject) => {
const child = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-node",
"--bin",
"disasmer-node",
"--",
"--coordinator",
`${addr.host}:${addr.port}`,
"--tenant",
"tenant",
"--project-id",
"project",
"--node",
forgejoWindowsNode,
"--public-key",
forgejoWindowsIdentity.publicKey,
"--enrollment-grant",
grant,
"--process",
"vp-forgejo-windows",
"--task",
"windows-command-dev",
"--command",
"cmd",
"--arg",
"/C",
"--arg",
"echo disasmer-windows-runner",
"--artifact",
"/vfs/artifacts/windows-runner-output.txt"
],
{
cwd: repo,
env: {
...process.env,
DISASMER_NODE_PRIVATE_KEY: forgejoWindowsIdentity.privateKey,
},
}
);
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.on("exit", (code) => {
if (code !== 0) {
reject(new Error(`Windows node smoke failed with code ${code}\n${stderr}`));
return;
}
try {
resolve(JSON.parse(stdout.trim().split(/\r?\n/).at(-1)));
} catch (error) {
reject(new Error(`node output was not JSON: ${stdout}\n${error.stack || error.message}`));
}
});
});
}
async function assertDebuggerShowsWindowsThread() {
const client = new DapClient();
try {
const initialize = client.send("initialize", {
adapterID: "disasmer",
linesStartAt1: true,
columnsStartAt1: true
});
await client.response(initialize, "initialize");
const launch = client.send("launch", {
entry: "build",
project: path.join(repo, "examples/launch-build-demo"),
runtimeBackend: "simulated"
});
await client.response(launch, "launch");
await client.waitFor(
(message) => message.type === "event" && message.event === "initialized"
);
const configurationDone = client.send("configurationDone");
await client.response(configurationDone, "configurationDone");
const threadsRequest = client.send("threads");
const threads = (await client.response(threadsRequest, "threads")).body.threads;
assert(
threads.some((thread) => thread.name.includes("compile windows")),
"debugger must represent the Windows task as a virtual thread"
);
await client.close();
} catch (error) {
client.child.kill("SIGKILL");
throw error;
}
}
(async () => {
if (process.platform !== "win32") {
throw new Error(
`Windows runner validation requires win32; current platform is ${process.platform}`
);
}
const coordinator = cp.spawn(
"cargo",
[
"run",
"-q",
"-p",
"disasmer-coordinator",
"--bin",
"disasmer-coordinator",
"--",
"--listen",
"127.0.0.1:0",
"--allow-local-trusted-loopback"
],
{ cwd: repo }
);
let coordinatorStderr = "";
coordinator.stderr.on("data", (chunk) => {
coordinatorStderr += chunk.toString();
});
try {
const ready = await waitForJsonLine(coordinator);
const [host, portText] = ready.listen.split(":");
const addr = { host, port: Number(portText) };
assert.strictEqual((await send(addr, { type: "ping" })).type, "pong");
const attachGrant = await send(addr, {
type: "create_node_enrollment_grant",
tenant: "tenant",
project: "project",
actor_user: "operator",
ttl_seconds: 900
});
assert.strictEqual(attachGrant.type, "node_enrollment_grant_created");
assert.strictEqual(attachGrant.scope, "node:attach");
const attach = await runWindowsAttach(addr, attachGrant.grant);
assert.strictEqual(attach.plan.node, forgejoWindowsNode);
assert.strictEqual(attach.boundary.cli_contacted_coordinator, true);
assert.strictEqual(attach.boundary.used_enrollment_exchange, true);
assert.strictEqual(attach.coordinator_response.type, "node_enrollment_exchanged");
assert.strictEqual(attach.coordinator_response.credential.scope, "node:attach");
assert(attach.plan.capabilities.capabilities.includes("WindowsCommandDev"));
const runtimeGrant = await send(addr, {
type: "create_node_enrollment_grant",
tenant: "tenant",
project: "project",
actor_user: "operator",
ttl_seconds: 900
});
assert.strictEqual(runtimeGrant.type, "node_enrollment_grant_created");
const report = await runWindowsNode(addr, runtimeGrant.grant);
assert.strictEqual(report.node_status, "completed");
assert.strictEqual(report.virtual_thread, "windows-command-dev");
assert.strictEqual(report.status_code, 0);
assert.strictEqual(report.large_bytes_uploaded, false);
assert.strictEqual(
report.staged_artifact.path,
"/vfs/artifacts/windows-runner-output.txt"
);
assert.strictEqual(report.registration_response.type, "node_enrollment_exchanged");
assert.strictEqual(report.registration_response.credential.scope, "node:attach");
assert.strictEqual(report.coordinator_response.type, "task_recorded");
const recorded = await send(addr, signedNodeRequest(forgejoWindowsNode, forgejoWindowsIdentity, "report_node_capabilities", {
type: "report_node_capabilities",
tenant: "tenant",
project: "project",
node: forgejoWindowsNode,
capabilities: {
os: "Windows",
arch: "x86_64",
capabilities: ["Command", "WindowsCommandDev", "VfsArtifacts"],
environment_backends: ["WindowsCommandDev"],
source_providers: ["filesystem"]
},
cached_environment_digests: [windowsEnvironmentDigest],
source_snapshots: [sourceSnapshot],
artifact_locations: ["windows-runner-output.txt"],
direct_connectivity: true,
online: true
}));
assert.strictEqual(recorded.type, "node_capabilities_recorded");
const placement = await send(addr, {
type: "schedule_task",
tenant: "tenant",
project: "project",
environment: {
os: "Windows",
arch: null,
capabilities: ["WindowsCommandDev"]
},
environment_digest: windowsEnvironmentDigest,
required_capabilities: ["Command"],
source_snapshot: sourceSnapshot,
required_artifacts: ["windows-runner-output.txt"],
prefer_node: null
});
assert.strictEqual(placement.type, "task_placement");
assert.strictEqual(placement.placement.node, "forgejo-windows-node");
const link = await send(addr, {
type: "create_artifact_download_link",
tenant: "tenant",
project: "project",
actor_user: "user",
artifact: "windows-runner-output.txt",
max_bytes: 1024
});
assert.strictEqual(link.type, "artifact_download_link");
assert.deepStrictEqual(link.link.source, {
RetainedNode: "forgejo-windows-node"
});
} catch (error) {
if (coordinatorStderr) {
error.message = `${error.message}\ncoordinator stderr:\n${coordinatorStderr}`;
}
throw error;
} finally {
coordinator.kill("SIGTERM");
}
await assertDebuggerShowsWindowsThread();
const outDir = path.join(repo, "target", "acceptance");
fs.mkdirSync(outDir, { recursive: true });
fs.writeFileSync(
path.join(outDir, "windows-runner.json"),
`${JSON.stringify(
{
kind: "disasmer_windows_runner_validation",
platform: process.platform,
runner: process.env.FORGEJO_RUNNER_NAME || process.env.RUNNER_NAME || null,
validated: true
},
null,
2
)}\n`
);
console.log("Windows runner smoke passed");
})().catch((error) => {
console.error(error.stack || error.message);
process.exit(1);
});

View file

@ -0,0 +1,59 @@
#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
function read(relativePath) {
return fs.readFileSync(path.join(repo, relativePath), "utf8");
}
function expect(source, name, pattern) {
assert.match(source, pattern, `missing Windows validation evidence: ${name}`);
}
const workflow = read(".forgejo/workflows/windows-validation.yml");
const runnerSmoke = read("scripts/windows-runner-smoke.js");
const readme = read("README.md");
const publicAcceptance = read("scripts/acceptance-public.sh");
const publicSplit = read("scripts/verify-public-split.sh");
expect(workflow, "manual workflow dispatch", /workflow_dispatch/);
expect(workflow, "intermittent Forgejo Windows runner note", /intermittently online/);
expect(workflow, "Windows runner label", /runs-on:\s*windows/);
expect(workflow, "Windows validation acceptance report env", /DISASMER_WINDOWS_VALIDATION:\s*forgejo-windows-runner/);
expect(workflow, "acceptance report step", /node scripts\/acceptance-report\.js windows/);
expect(workflow, "Windows runtime unit coverage", /cargo test -p disasmer-node windows_backend_is_labeled_user_attached_dev_execution/);
expect(workflow, "Windows runner smoke step", /node scripts\/windows-runner-smoke\.js/);
expect(runnerSmoke, "real Windows platform guard", /process\.platform !== "win32"/);
expect(runnerSmoke, "CLI node attach function", /function runWindowsAttach/);
expect(runnerSmoke, "CLI node attach command", /"node"[\s\S]*"attach"[\s\S]*"windows-command-dev"/);
expect(runnerSmoke, "server-generated enrollment grant creation", /create_node_enrollment_grant[\s\S]*attachGrant\.grant/);
expect(runnerSmoke, "CLI enrollment exchange asserted", /used_enrollment_exchange[\s\S]*true/);
expect(runnerSmoke, "server-generated runtime enrollment grant", /const runtimeGrant[\s\S]*create_node_enrollment_grant[\s\S]*runtimeGrant\.grant/);
expect(runnerSmoke, "runtime uses enrollment grant", /"--enrollment-grant"[\s\S]*grant/);
expect(runnerSmoke, "Windows command task runs", /"windows-command-dev"[\s\S]*"cmd"[\s\S]*"echo disasmer-windows-runner"/);
expect(runnerSmoke, "artifact metadata is asserted", /windows-runner-output\.txt[\s\S]*artifact_download_link/);
expect(runnerSmoke, "Windows placement is asserted", /schedule_task[\s\S]*WindowsCommandDev[\s\S]*forgejo-windows-node/);
expect(runnerSmoke, "debugger shows Windows virtual thread", /compile windows/);
expect(runnerSmoke, "validation result artifact", /disasmer_windows_runner_validation/);
expect(readme, "docs mention manual Windows workflow", /manual `Windows validation`\s+workflow/);
expect(readme, "docs mention intermittent runner", /intermittent Windows runner/);
expect(readme, "docs mention CLI attach in Windows validation", /runs `disasmer node attach`/);
expect(readme, "docs keep Windows unvalidated when report is not-run", /windows_validation: "not-run"[\s\S]*best-effort and unvalidated/);
for (const [scriptName, script] of [
["public acceptance", publicAcceptance],
["public split", publicSplit],
]) {
assert(
script.includes("node scripts/windows-validation-contract-smoke.js"),
`${scriptName} must run windows-validation-contract-smoke.js`
);
}
console.log("Windows validation contract smoke passed");