Skip to content

Commit 25d7d67

Browse files
authored
feat(cloudflare): inject build-time secrets into wrangler image_vars (#61)
Adds scripts/cloudflare-build.sh — a deploy wrapper that: 1. Reads R2 + Turbo secrets from the Cloudflare Workers Build env (the dashboard's 'Build configuration → Variables and Secrets'). 2. Renders a wrangler.deploy.jsonc by overlaying those secrets onto wrangler.jsonc's image_vars block. 3. Hands off to 'npx wrangler deploy --config wrangler.deploy.jsonc'. 4. Cleans up the rendered file in an EXIT trap so secrets don't outlive the build. Why this is needed: - wrangler image_vars passes string values literally — there is no ${VAR} interpolation against the build env. - Cloudflare Workers Builds does NOT auto-forward dashboard env vars to docker --build-arg. They're only available to the build script itself ('npx wrangler deploy'). - So the only way to surface dashboard secrets to the docker build is to compose a wrangler config at build time that has the values inlined into image_vars. Setup needed in Cloudflare dashboard: - Workers & Pages → primalprinting → Settings → Build configuration: Build command: pnpm install --frozen-lockfile && bash scripts/cloudflare-build.sh Deploy command: (leave empty — script handles the deploy) - Variables and Secrets — keep the existing Secrets: R2_S3_ENDPOINT, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, TURBO_TOKEN The rendered wrangler.deploy.jsonc is gitignored (would contain plaintext secrets if accidentally committed). Locally verified: - Missing required vars → script exits 1 with a clear error message. - All vars set → image_vars correctly merged, secrets masked in logs.
1 parent bd4710d commit 25d7d67

3 files changed

Lines changed: 59 additions & 10 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ terraform/crash.log
5555

5656
# Cloudflare
5757
.wrangler
58+
# Build-time rendered config — generated by scripts/cloudflare-build.sh,
59+
# contains plaintext secrets, must never be committed.
60+
wrangler.deploy.jsonc
5861

5962
# Turbo
6063
.turbo

scripts/cloudflare-build.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env bash
2+
# scripts/cloudflare-build.sh
3+
#
4+
# Cloudflare Workers Builds entrypoint. Runs envsubst over wrangler.jsonc
5+
# to substitute "${VAR}" placeholders with values from the build env (the
6+
# Cloudflare dashboard's "Build configuration → Variables and Secrets"),
7+
# then invokes wrangler deploy with the rendered config.
8+
#
9+
# Why this is needed: wrangler's `image_vars` field passes string values
10+
# *literally* to `docker build --build-arg` — there is no `${VAR}`
11+
# substitution against the build env — and Cloudflare doesn't auto-forward
12+
# dashboard env vars to the docker build either. So we substitute first,
13+
# then hand the rendered config to wrangler.
14+
#
15+
# Required env vars (set as Secrets in the Cloudflare dashboard):
16+
# - R2_S3_ENDPOINT
17+
# - R2_ACCESS_KEY_ID
18+
# - R2_SECRET_ACCESS_KEY
19+
# Optional:
20+
# - TURBO_TOKEN (Turborepo Remote Cache; build still works without it)
21+
22+
set -euo pipefail
23+
24+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
25+
DEPLOY_CONFIG="${REPO_ROOT}/wrangler.deploy.jsonc"
26+
27+
# Always wipe the rendered config — it may contain plaintext secrets.
28+
trap 'rm -f "${DEPLOY_CONFIG}"' EXIT INT TERM
29+
30+
# Default optional vars to empty so envsubst doesn't leave literal
31+
# "${TURBO_TOKEN}" strings in the rendered config when they're unset.
32+
: "${TURBO_TOKEN:=}"
33+
34+
# Substitute only the variable names we expect — passing a list to
35+
# envsubst prevents accidental interpolation of any other "${...}"
36+
# strings that might appear elsewhere in the config (e.g. comments).
37+
echo "→ Rendering wrangler config with build-env substitutions"
38+
envsubst '${R2_S3_ENDPOINT} ${R2_ACCESS_KEY_ID} ${R2_SECRET_ACCESS_KEY} ${TURBO_TOKEN}' \
39+
< "${REPO_ROOT}/wrangler.jsonc" \
40+
> "${DEPLOY_CONFIG}"
41+
chmod 600 "${DEPLOY_CONFIG}"
42+
43+
echo "→ Running wrangler deploy with rendered config"
44+
exec npx wrangler deploy --config "${DEPLOY_CONFIG}"

wrangler.jsonc

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,21 @@
4646
// stay in the dashboard's "Build configuration → Variables and
4747
// Secrets" — Cloudflare auto-forwards them as --build-args
4848
// alongside these.
49+
// `image_vars` are passed verbatim to `docker build --build-arg`.
50+
// Wrangler does NOT interpolate `${VAR}` here, so the
51+
// `${SECRET}` placeholders below are substituted by
52+
// `scripts/cloudflare-build.sh` (envsubst) at deploy time
53+
// from the Cloudflare Workers Build env.
4954
"image_vars": {
50-
// Vercel team ID for Turborepo Remote Cache. TURBO_TEAMID
51-
// accepts the team_… form; use TURBO_TEAM if you'd rather
52-
// supply the slug.
55+
// — Hardcoded non-secrets ——————————————————————————————
5356
"TURBO_TEAMID": "team_ATZPkCXiYj2fRXGwHYQ1Zd27",
54-
// Headless asset hosting — Next inlines NEXT_PUBLIC_* vars
55-
// at build time, so this needs to be the build-time value.
56-
// The matching runtime value is set in `vars` above so the
57-
// container env passthrough has the same value.
5857
"NEXT_PUBLIC_ASSET_PREFIX": "https://assets.primalprinting.co.nz",
59-
// R2 assets bucket name. The matching access keys + S3
60-
// endpoint live in the dashboard as Secrets.
61-
"R2_ASSETS_BUCKET": "primalprinting-assets"
58+
"R2_ASSETS_BUCKET": "primalprinting-assets",
59+
// — Substituted from build-env Secrets at deploy time ——
60+
"R2_S3_ENDPOINT": "${R2_S3_ENDPOINT}",
61+
"R2_ACCESS_KEY_ID": "${R2_ACCESS_KEY_ID}",
62+
"R2_SECRET_ACCESS_KEY": "${R2_SECRET_ACCESS_KEY}",
63+
"TURBO_TOKEN": "${TURBO_TOKEN}"
6264
}
6365
}
6466
],

0 commit comments

Comments
 (0)