clusterflux-public/scripts/docs-smoke.js
2026-07-03 23:12:37 +02:00

347 lines
16 KiB
JavaScript

#!/usr/bin/env node
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const repo = path.resolve(__dirname, "..");
const readme = fs.readFileSync(path.join(repo, "README.md"), "utf8");
const userFacingDocs = [
"README.md",
"MVP.md",
"acceptance_criteria.md",
"acceptance_criteria_phase2.md",
"cli_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", /node `disasmer\.cmd_run` host import/],
["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_PUBLIC_KEY=<agent-public-key> disasmer run 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`/],
["public dry-run operator endpoint", /https:\/\/disasmer\.michelpaulissen\.com:9443/],
["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 root markdown", /root `\*\.md` files/],
["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:9443/],
["public dry-run private hosted coordinator", /default operator at `disasmer\.michelpaulissen\.com:9443` is the private hosted\s+coordinator from `private\/hosted-policy`/],
["public dry-run not standalone public coordinator", /does not mean deploying the standalone\s+open-source\/public coordinator as the hosted operator/],
["public dry-run validates both coordinators", /dry-run acceptance validates both coordinator implementations/],
["public dry-run validates public coordinator separately", /standalone public\/open-source\s+coordinator is validated separately/],
["public browser login site", /disasmer\.michelpaulissen\.com\/auth\/browser\/start/],
["public browser login local callback", /local callback/],
["public dry-run barebones HTML no CSS", /barebones HTML with\s+no CSS/],
["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 that\s+binds `0\.0\.0\.0:9443`/],
["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:9443/],
["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/],
["public operator compatibility smoke", /public-operator-compat-smoke\.js/],
["public operator compatibility purpose", /public CLI and public\s+node runtime can attach, launch work through coordinator task assignment, and\s+publish debug\/log\/artifact metadata/],
];
for (const [name, pattern] of requiredReadmePatterns) {
assert.match(readme, pattern, `README missing ${name}`);
}
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/cancellation-smoke.js"),
"public acceptance gates must run cancellation-smoke.js"
);
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/public-operator-compat-smoke.js"),
"private acceptance must run public-operator-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");