#!/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 publicOperatorCompatSmoke = maybeRead("private/hosted-policy/scripts/public-operator-compat-smoke.js"); const hostedService = maybeRead("private/hosted-policy/src/bin/disasmer-hosted-service.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/local-services-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 community smoke", "node private/hosted-policy/scripts/hosted-community-smoke.js"); expectIncludes(privateAcceptance, "private gate runs public operator compatibility smoke", "node private/hosted-policy/scripts/public-operator-compat-smoke.js"); expectIncludes(privateAcceptance, "private gate runs standalone public 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 OIDC test issuer", /DISASMER_PUBLIC_RELEASE_DRYRUN_OIDC_ISSUER_URL/], ["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 performs OIDC login", /type: "oidc_browser_login"/], ["service smoke creates project", /type: "create_project"/], ["service smoke enrolls node", /type: "create_node_enrollment_token"[\s\S]*exchange_node_enrollment_token/], ["service smoke starts user node process", /type: "start_user_node_process"/], ["service smoke records task", /type: "record_user_node_task_completion"/], ["service smoke reads debug state", /type: "debug_process"/], ["service smoke reads artifact metadata", /type: "artifact_metadata"/], ["service smoke creates download link", /type: "create_artifact_download_link"/], ["service smoke records observability", /type: "observability_snapshot"/], ["service smoke records private hosted coordinator", /operator_implementation:[\s\S]*"private-hosted-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, /operator_implementation:[\s\S]*"private-hosted-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 binds public TCP 9443", publicDryrunSystemd, /--listen 0\.0\.0\.0:9443/], ["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, / disasmer\.michelpaulissen\.com/], ]) { expect(source, name, pattern); } } if (publicOperatorCompatSmoke && hostedService) { for (const [name, pattern] of [ ["hosted service embeds private coordinator runtime", /private_coordinator: CoordinatorService/], ["hosted service parses public client protocol requests", /serde_json::from_str::/], ["hosted service delegates public requests", /handle_public_request/], ["hosted service marks public protocol sessions", /ConnectionProtocol::Public/], ["hosted service seeds public projects from hosted auth", /seed_public_project/], ["hosted service seeds public enrollment grants", /seed_public_node_enrollment_grant/], ]) { expect(hostedService, 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 hosted enrollment grant", /type: "create_node_enrollment_token"/], ["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 node runtime", /"disasmer-node"/], ["compat smoke launches through coordinator assignment", /type: "launch_task"/], ["compat smoke verifies assignment polling", /poll_task_assignment/], ["compat smoke verifies public node metadata", /vfs_metadata_recorded/], ["compat smoke writes evidence report", /public-operator-compat\.json/], ]) { expect(publicOperatorCompatSmoke, name, pattern); } } for (const [name, pattern] of [ ["e2e runner requires explicit opt-in", /DISASMER_PUBLIC_RELEASE_DRYRUN_E2E/], ["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 operator", /defaultLoginPlan\.coordinator[\s\S]*serviceEndpoint/], ["e2e runner completes browser login", /--complete-browser-code/], ["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 through coordinator assignment", /type: "launch_task"/], ["e2e runner verifies public assignment polling", /worker_assignment_poll_protocol/], ["e2e runner validates standalone public coordinator", /validateStandalonePublicCoordinator/], ["e2e runner records standalone public coordinator", /public_coordinator_operator_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 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 public operator compatibility evidence", /public-operator-compat\.json/], ["final verifier requires public coordinator compatibility evidence", /public-coordinator-compat\.json/], ["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");