Files
elizaos--eliza/packages/scripts/cloud/verify-environment-routing-cli.mjs
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

167 lines
5.4 KiB
JavaScript

#!/usr/bin/env node
/**
* CLI for the cross-environment routing verifier.
*
* Probes each live custom domain's `/api/health` and asserts the environment
* that answered matches the environment the domain is supposed to serve -
* catching "staging is pointing at prod CF" (a staging subdomain that fell into
* the prod `*.elizacloud.ai/*` Worker wildcard, or a Pages deployment reattached
* to the wrong environment). See `verify-environment-routing.mjs` for the why.
*
* Usage:
* node packages/scripts/cloud/verify-environment-routing-cli.mjs \
* [--environment staging|production|all] (default: all)
* [--require-beacon] treat a build-without-beacon as a failure
* [--allow-unreachable] downgrade an unreachable origin to a warning
* [--json] emit the machine-readable report to stdout
*
* Exit code: 0 when every probed domain routed correctly; 1 on any failure
* (a genuine cross-wire always fails; unreachable/beacon-missing per the flags).
* A GitHub step summary is appended when $GITHUB_STEP_SUMMARY is set.
*/
import fs from "node:fs";
import {
classifyProbe,
decideRoutingVerdict,
ENVIRONMENT_ROUTING,
fetchServedEnvironment,
} from "./verify-environment-routing.mjs";
function parseArgs(argv) {
const out = {
environment: "all",
requireBeacon: false,
requireReachable: true,
json: false,
};
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === "--require-beacon") out.requireBeacon = true;
else if (arg === "--allow-unreachable") out.requireReachable = false;
else if (arg === "--json") out.json = true;
else if (arg === "--environment") out.environment = argv[++i];
else if (arg.startsWith("--environment=")) {
out.environment = arg.slice("--environment=".length);
}
}
return out;
}
const STATUS_LABEL = {
ok: "ok",
misrouted: "fail",
unexpected_env: "warn",
beacon_missing: "no-beacon",
unreachable: "unreachable",
};
function stdout(line = "") {
process.stdout.write(`${line}\n`);
}
function stderr(line = "") {
process.stderr.write(`${line}\n`);
}
function selectMatrix(environment) {
if (environment === "all" || !environment) return ENVIRONMENT_ROUTING;
const target = environment === "prod" ? "production" : environment;
return ENVIRONMENT_ROUTING.filter((e) => e.environment === target);
}
function writeStepSummary(verdict) {
// biome-ignore lint/suspicious/noUndeclaredEnvVars: GitHub Actions provides this path.
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
if (!summaryPath) return;
const lines = [
"### Cross-environment routing verification",
"",
`**${verdict.ok ? "PASS" : "FAIL"}** - ${verdict.summary}`,
"",
"| Domain | Expected | Answered | Status |",
"| --- | --- | --- | --- |",
...verdict.probes.map(
(p) =>
`| \`${p.domain}\` | ${p.expected} | ${p.observed ?? "-"} | ${STATUS_LABEL[p.status] ?? ""} ${p.status} |`,
),
"",
];
if (!verdict.ok) {
lines.push(
"> A **misrouted** domain means a staging host is being served by the",
"> production environment (or vice-versa). Reconcile the Cloudflare Worker",
"> routes (`packages/cloud/api/wrangler.toml` `[env.staging].routes`) and the",
"> Pages custom-domain to deployment mapping, then re-run this check.",
"",
);
}
try {
fs.appendFileSync(summaryPath, `${lines.join("\n")}\n`);
} catch {
// error-policy:J7 diagnostics-must-not-kill-the-loop - the step summary is
// auxiliary CI output; the process exit code still carries the verdict.
// A summary-write failure must never change the verdict.
}
}
async function main() {
const args = parseArgs(process.argv.slice(2));
const matrix = selectMatrix(args.environment);
if (matrix.length === 0) {
stderr(
`verify-environment-routing: no domains match --environment=${args.environment}`,
);
process.exit(2);
}
const probes = await Promise.all(
matrix.map(async ({ domain, environment }) => {
const { observed, reachable, detail } =
await fetchServedEnvironment(domain);
return classifyProbe({
domain,
expected: environment,
observed,
reachable,
detail,
});
}),
);
const verdict = decideRoutingVerdict({
probes,
requireBeacon: args.requireBeacon,
requireReachable: args.requireReachable,
});
if (args.json) {
stdout(JSON.stringify(verdict, null, 2));
} else {
for (const p of verdict.probes) {
const failed = verdict.failures.includes(p);
const write = failed ? stderr : stdout;
write(`[${STATUS_LABEL[p.status] ?? "status"}] ${p.message}`);
}
stdout("");
stdout(`${verdict.ok ? "PASS" : "FAIL"}: ${verdict.summary}`);
}
writeStepSummary(verdict);
process.exit(verdict.ok ? 0 : 1);
}
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch((err) => {
// error-policy:J1 boundary translation - an unexpected verifier crash must
// leave CI red instead of being mistaken for healthy routing.
// An unexpected crash in the verifier itself must NOT be read as "routing
// is fine": exit non-zero so a broken monitor is visible, not silently green.
stderr("verify-environment-routing: unexpected error");
stderr(err instanceof Error ? (err.stack ?? err.message) : String(err));
process.exit(1);
});
}
export { parseArgs, selectMatrix };