返回 CodeWhale
check-cloudflare-deploy-env.mjs
根目录 / web / scripts / check-cloudflare-deploy-env.mjs
1 #!/usr/bin/env node
2 /**
3 * check-cloudflare-deploy-env.mjs - fail fast when the GitHub deploy job is
4 * missing Cloudflare credentials.
5 *
6 * The actual deploy still belongs to Wrangler/OpenNext. This script only makes
7 * the common GitHub Actions failure mode obvious before the expensive build
8 * starts.
9 */
10
11 const required = [
12 {
13 name: "CLOUDFLARE_ACCOUNT_ID",
14 source: "repository variable",
15 expected: "Settings > Secrets and variables > Actions > Variables",
16 validate(value) {
17 return /^[a-f0-9]{32}$/i.test(value);
18 },
19 detail: "expected the 32-character Cloudflare account id",
20 },
21 {
22 name: "CLOUDFLARE_API_TOKEN",
23 source: "repository secret",
24 expected: "Settings > Secrets and variables > Actions > Secrets",
25 validate(value) {
26 return value.length >= 20;
27 },
28 detail: "expected a non-empty Cloudflare API token",
29 },
30 ];
31
32 const placeholderPattern = /^(changeme|replace(_with)?|todo|example|dummy|null|undefined)$/i;
33 const failures = [];
34 const preflight = process.argv.includes("--preflight");
35
36 function printReceipt(credentialState) {
37 console.log(
38 `[check-cloudflare-deploy-env] receipt ${JSON.stringify({
39 event: process.env.GITHUB_EVENT_NAME || null,
40 ref: process.env.GITHUB_REF || null,
41 sourceRevision:
42 process.env.CODEWHALE_SOURCE_REVISION || process.env.GITHUB_SHA || null,
43 credentialState,
44 deploymentStarted: false,
45 })}`,
46 );
47 }
48
49 for (const item of required) {
50 const value = (process.env[item.name] ?? "").trim();
51 if (!value) {
52 failures.push({
53 item,
54 reason: `${item.name} is not set`,
55 kind: "missing",
56 });
57 continue;
58 }
59
60 if (placeholderPattern.test(value)) {
61 failures.push({
62 item,
63 reason: `${item.name} is a placeholder`,
64 kind: "invalid",
65 });
66 continue;
67 }
68
69 if (!item.validate(value)) {
70 failures.push({
71 item,
72 reason: `${item.name} is set but does not look valid`,
73 kind: "invalid",
74 });
75 }
76 }
77
78 if (failures.length > 0) {
79 if (preflight) {
80 const invalid = failures.filter((failure) => failure.kind === "invalid");
81 if (invalid.length > 0) {
82 console.error(
83 "[check-cloudflare-deploy-env] FAIL - malformed credential placeholders are not a valid preflight.",
84 );
85 for (const failure of invalid) console.error(`- ${failure.reason}`);
86 printReceipt("invalid");
87 process.exit(1);
88 }
89 console.log(
90 "[check-cloudflare-deploy-env] PREFLIGHT - deploy credentials are intentionally unavailable in this environment.",
91 );
92 console.log(
93 `[check-cloudflare-deploy-env] ${failures.length} credential input(s) must be supplied by the protected manual deploy job.`,
94 );
95 console.log("[check-cloudflare-deploy-env] Wrangler deploy was not started.");
96 printReceipt("withheld");
97 process.exit(0);
98 }
99
100 console.error("[check-cloudflare-deploy-env] FAIL - Cloudflare deploy configuration is incomplete.");
101 for (const failure of failures) {
102 const { item, reason } = failure;
103 console.error("");
104 console.error(`- ${reason}`);
105 console.error(` Configure ${item.name} as a GitHub ${item.source}.`);
106 console.error(` Location: ${item.expected}.`);
107 console.error(` Hint: ${item.detail}.`);
108 }
109 console.error("");
110 console.error("Wrangler deploy was not started.");
111 printReceipt(failures.some((failure) => failure.kind === "invalid") ? "invalid" : "missing");
112 process.exit(1);
113 }
114
115 if (process.env.GITHUB_ACTIONS === "true") {
116 const event = process.env.GITHUB_EVENT_NAME;
117 const ref = process.env.GITHUB_REF;
118 const revision = process.env.GITHUB_SHA;
119 if (
120 event !== "workflow_dispatch" ||
121 ref !== "refs/heads/main" ||
122 !revision ||
123 !/^[0-9a-f]{40}$/i.test(revision)
124 ) {
125 console.error(
126 "[check-cloudflare-deploy-env] FAIL - GitHub deployment requires workflow_dispatch on refs/heads/main at an exact SHA.",
127 );
128 printReceipt("present");
129 process.exit(1);
130 }
131 }
132
133 console.log("[check-cloudflare-deploy-env] OK - Cloudflare deploy environment is present.");
134 printReceipt("present");
135
135 lines Plain Text