| 1 | #!/usr/bin/env bash |
| 2 | # Generate the Worker's own secrets once (never rotated automatically): |
| 3 | # MASTER_KEY root key for encrypting Actions secrets (rotated by hand, with |
| 4 | # MASTER_KEY_PREV, which this script never touches; see |
| 5 | # apps/diffinery/docs/self-hosting/configuration.md, "Rotating MASTER_KEY") |
| 6 | # OIDC_PRIVATE_KEY ES256 key that signs workflow OIDC id tokens |
| 7 | # and, when missing, sets TURNSTILE_SECRET from the Turnstile widget whose site key was deployed |
| 8 | # (scripts/turnstile.sh, through bootstrap and render-config). |
| 9 | # Values are created on the runner (or read from Cloudflare's API) and sent straight to Cloudflare; |
| 10 | # they are never printed. |
| 11 | set -euo pipefail |
| 12 | ROOT="$(cd "$(dirname "$0")/.." && pwd)" |
| 13 | APP="$ROOT/apps/diffinery" |
| 14 | WRANGLER=(pnpm --dir "$APP" exec wrangler) |
| 15 | |
| 16 | # Fail closed: if listing fails we must not mistake "unknown" for "missing" and |
| 17 | # overwrite MASTER_KEY, which would make every stored Actions secret unreadable. |
| 18 | LIST="$("${WRANGLER[@]}" secret list -c wrangler.deploy.jsonc --format json)" |
| 19 | EXISTING="$(jq -er '.[].name' <<<"$LIST" || true)" |
| 20 | jq -e 'type == "array"' >/dev/null <<<"$LIST" || { echo "unexpected output from wrangler secret list" >&2; exit 1; } |
| 21 | |
| 22 | if ! grep -qx MASTER_KEY <<<"$EXISTING"; then |
| 23 | openssl rand -base64 32 | tr -d '\n' | "${WRANGLER[@]}" secret put MASTER_KEY -c wrangler.deploy.jsonc >/dev/null |
| 24 | echo "set MASTER_KEY" |
| 25 | fi |
| 26 | if ! grep -qx OIDC_PRIVATE_KEY <<<"$EXISTING"; then |
| 27 | node --input-type=module -e ' |
| 28 | const { subtle } = globalThis.crypto; |
| 29 | const k = await subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]); |
| 30 | const jwk = await subtle.exportKey("jwk", k.privateKey); |
| 31 | jwk.kid = "diffinery-" + new Date().toISOString().slice(0, 10); |
| 32 | process.stdout.write(JSON.stringify(jwk)); |
| 33 | ' | "${WRANGLER[@]}" secret put OIDC_PRIVATE_KEY -c wrangler.deploy.jsonc >/dev/null |
| 34 | echo "set OIDC_PRIVATE_KEY" |
| 35 | fi |
| 36 | # Without the Turnstile permission this warns (scripts/turnstile.sh names it) and the deploy goes on: |
| 37 | # people who aren't signed in can't send security reports until it's set. |
| 38 | SITE_KEY="$(tail -n +2 "$APP/wrangler.deploy.jsonc" | jq -r '.vars.TURNSTILE_SITE_KEY // empty')" |
| 39 | if [[ -n "$SITE_KEY" ]] && ! grep -qx TURNSTILE_SECRET <<<"$EXISTING"; then |
| 40 | if "$ROOT/scripts/turnstile.sh" secret "$SITE_KEY" -c wrangler.deploy.jsonc; then |
| 41 | echo "set TURNSTILE_SECRET" |
| 42 | else |
| 43 | echo "::warning::TURNSTILE_SECRET is not set, so only people who are signed in can send security reports. The next deploy tries again." >&2 |
| 44 | fi |
| 45 | fi |