Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,33 @@ jobs:
cache: pnpm
- run: pnpm install --frozen-lockfile

# The committed wrangler.jsonc carries placeholders for every
# account-specific value; the real file is the operator overlay, stored
# base64-encoded (one line, so log masking covers all of it) and written
# over the placeholders here — the same single-file overwrite
# actions/deploy-dispatcher-action performs. A missing secret fails the
# job rather than deploying placeholders.
- name: Apply operator overlay
shell: bash
run: |
set -euo pipefail
if [ -z "${WRANGLER_OVERLAY_B64:-}" ]; then
echo "::error title=overlay missing::Set the WRANGLER_OVERLAY_B64 secret to the base64 of this deploy's wrangler.jsonc." >&2
exit 1
fi
printf '%s' "$WRANGLER_OVERLAY_B64" | base64 -d > wrangler.jsonc
env:
WRANGLER_OVERLAY_B64: ${{ secrets.WRANGLER_OVERLAY_B64 }}

# Schema before code — the same rule the substrate job states, which the
# dispatcher's own database was never held to. Its five migrations were
# applied by hand in a single run on 2026-07-11 and nothing here has ever
# applied one since, so a PR that adds a migration ships code querying a
# column production does not have. Already-applied migrations are a no-op,
# which is what makes this safe to add after the fact.
# which is what makes this safe to add after the fact. Addressed by binding,
# so the overlay's database name never needs restating here.
- name: Apply D1 migrations
run: pnpm exec wrangler d1 migrations apply flare-dispatch --remote
run: pnpm exec wrangler d1 migrations apply RUNS_METADATA --remote
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
Expand Down
45 changes: 27 additions & 18 deletions wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
// Non-destructive: distinct name + fresh D1/R2/KV so it never collides with
// any prior deployment in the same account. Dashboard SPA assets are omitted
// (the SSR fallback in dashboard.ts serves the routes).
//
// Account-specific values below are placeholders marked `operator overlay`.
// A deploying org replaces this whole file with its own copy carrying the
// real ones (actions/deploy-dispatcher-action). Locally, keep that copy as
// the gitignored wrangler.overlay.local.jsonc and pass it with
// `pnpm exec wrangler deploy -c wrangler.overlay.local.jsonc`.
"$schema": "node_modules/wrangler/config-schema.json",
"name": "flare-dispatch",
"main": "apps/dispatcher/src/index.ts",
Expand Down Expand Up @@ -45,12 +51,11 @@
//
// Add the expression here when that decision is made; the runs need no change.

// Custom domain (requires the fractalbox.dev zone in this account). The
// GitHub App install flow substitutes the request origin into the manifest,
// so hitting the install page on this host wires the App's webhook/callback
// URLs to it. The bare flare-dispatch.fractalbox.dev serves the documentation
// site (apps/docs/wrangler.jsonc).
"routes": [{ "pattern": "flare-dispatch-app.fractalbox.dev", "custom_domain": true }],
// Custom domain (requires its zone in the deploying account). The GitHub App
// install flow substitutes the request origin into the manifest, so hitting
// the install page on this host wires the App's webhook/callback URLs to it.
// Hostname: operator overlay.
"routes": [{ "pattern": "dispatcher.example.com", "custom_domain": true }],

// Workers AI — backs the modelGateway capability the pr-review engine calls.
// The binding IS the auth (account-billed), so no model API key is needed.
Expand All @@ -61,14 +66,15 @@
"browser": { "binding": "BROWSER" },

"vars": {
"CLOUDFLARE_ACCOUNT_ID": "c91d52c288c452ab734ede1518b00e11",
// Operator overlay.
"CLOUDFLARE_ACCOUNT_ID": "00000000000000000000000000000000",
// AI Gateway the modelGateway routes through — REQUIRED for prefixed model
// ids (`anthropic/*`, `deepseek/*`, `openai/*`, `bedrock/*`), which ride the
// gateway universal endpoint / Bedrock forwarder. `openai/*` additionally
// needs unified billing enabled on this gateway (or a stored OpenAI key —
// mutually exclusive). If the gateway has Authenticated Gateway turned on,
// also set the AI_GATEWAY_AUTH_TOKEN secret.
"AI_GATEWAY_ID": "fractalbox-engineering-gateway",
// also set the AI_GATEWAY_AUTH_TOKEN secret. Operator overlay.
"AI_GATEWAY_ID": "your-ai-gateway",
"ADMISSION_CAP": "16",
// Opt the human-facing viewer surfaces (incl. the GitHub App install flow)
// out of the Cloudflare Access gate for the initial dogfood. Configure
Expand All @@ -80,11 +86,13 @@
// Cloudflare Access team domain (issuer) — shared by the viewer + deploy
// gates. The deploy console verifies the Access JWT against this + the AUD
// below, and fetches identity from <issuer>/cdn-cgi/access/get-identity.
"ACCESS_TEAM_DOMAIN": "fractalbox.cloudflareaccess.com",
// Operator overlay.
"ACCESS_TEAM_DOMAIN": "your-team.cloudflareaccess.com",
// Deploy console (/deploy) Access application AUD. Distinct from the viewer
// ACCESS_AUD. The app's policy allows the GitHub `fractalboxdev/devs` team;
// per-env authorization is CONFIG_KV `deploy.env-authz`. See deploy-access.ts.
"DEPLOY_ACCESS_AUD": "44c3a07df1b0a4e454b28da9f55e7dbf3e279d1d09274667467a4d41ba79cafe",
// ACCESS_AUD. The app's policy allows the org's GitHub team; per-env
// authorization is CONFIG_KV `deploy.env-authz`. See deploy-access.ts.
// Operator overlay.
"DEPLOY_ACCESS_AUD": "your-deploy-access-aud",
// Execution backend. "on" routes every facade-capable run through the
// SUBSTRATE binding below; anything else keeps the container path in this
// config. Flipping it is the cutover — see apps/substrate/specs/adoption-runbook.md.
Expand Down Expand Up @@ -207,25 +215,26 @@
{ "tag": "v4", "new_sqlite_classes": ["RunSandboxRelease"] },
],

"r2_buckets": [{ "binding": "RUNS_STORAGE", "bucket_name": "flare-dispatch" }],
// Bucket name, database name and id, and namespace ids: operator overlay.
"r2_buckets": [{ "binding": "RUNS_STORAGE", "bucket_name": "your-runs-bucket" }],

"d1_databases": [
{
"binding": "RUNS_METADATA",
"database_name": "flare-dispatch",
"database_id": "3a365bf1-fae3-4a29-bef7-5b020f8cb283",
"database_name": "your-runs-database",
"database_id": "00000000-0000-0000-0000-000000000000",
"migrations_dir": "infra/migrations",
},
],

"kv_namespaces": [
{
"binding": "CONFIG_KV",
"id": "dff3e9657cf34c94955c31a333084f1c",
"id": "00000000000000000000000000000001",
},
{
"binding": "IDEMPOTENCY_KV",
"id": "3002db8dac904fc794cf2686fb5dfe57",
"id": "00000000000000000000000000000002",
},
],
}
Loading