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
167 lines
5.4 KiB
JavaScript
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 };
|