Repository navigation
test(deploy): real-build integration + gated live e2e for the Cloudflare backend - #284
Conversation
…are backend The existing unit tests drive `runCloudflareDeploy` end to end but stub the `vite build`, wrangler, and Cloudflare, asserting against hand-written emitted configs. Nothing verified the guard's core premise — that a REAL `@cloudflare/vite-plugin` + wrangler build emits exactly the shape `verifyGeneratedDeployConfig` reconstructs, adding nothing that would false-positive a legitimate deploy. Add two layers of coverage. Part A — `test/integration/cloudflare-deploy-build.test.ts` (CI-runnable, no Cloudflare account). Runs a real `vite build` of the kitchen-sink playground (D1 + KV + R2 + AI + sandbox/containers + cron + queue) with an overlaid root `wrangler.jsonc` carrying real-shaped ids, reconstructs `expected` with the same exported builders `runCloudflareDeploy` uses, and asserts the real emitted `dist/ssr/wrangler.json` passes the real guard unmodified (the FP-safety lock — a future plugin/wrangler field addition breaks this instead of blocking a real deploy). Negative cases start from the same real emission, apply one minimal tamper (injected container, swapped D1 id, injected EXTRA_DB / cron / services / routes), and assert rejection. Part B — `test/e2e/cloudflare-deploy-live.test.ts` (gated). A real `void deploy --backend cloudflare --provision` of the spa playground, verified against a live 200 and torn down, wrapped in `describe.skipIf(!VOID_E2E_CF_TOKEN)` so it is inert without credentials. The `test/e2e/**` glob is wired into the void integration test project so it is collected and skipped cleanly in CI rather than left undiscovered; the live run is a manual operator step with their own token. `parseRootWranglerConfig` is exported so the integration test reconstructs the pre-build root config the same way the orchestrator does. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_dd1fef3d-fc5b-4130-9cd3-68538bb9a873) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: da003ba449
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… and cover ISR_CACHE in the FP-lock Three test-quality fixes to the new Cloudflare-backend coverage. Live e2e teardown — match the KV namespace by EXACT title before deleting. Matching the derived title as an `endsWith` suffix could select and delete an unrelated namespace that merely shares the suffix; the provisioner creates and matches the namespace by its exact title, so the teardown does too. Live e2e teardown — surface cleanup failures. Each delete was best-effort with its exit status discarded, so a transient API error or missing delete permission left a worker or database behind while the run still reported green. Collect the nonzero exits and re-throw after all cleanup + config restore, so a leak fails loud with the resources to remove manually. Real-build integration — cover ISR_CACHE in the FP-lock. kitchen-sink enables ISR (pages/revalidate.server.ts), so computeDesiredCloudflareResources adds a second KV binding, ISR_CACHE, beyond the app's own KV. The overlay pinned a real id only for KV, so the guard's clean-pass never exercised the two-KV shape a provisioned ISR deploy builds. Pin a distinct real-shaped ISR_CACHE id; the real build now emits both namespaces and the FP-lock covers them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f5af01f8-d697-4e74-a220-45d1b3c0c501) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8fcfa2c724
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…404 does not flake The live-e2e worker poll returned on any status below 500, so a freshly-deployed route that transiently 404s during edge propagation was taken as the final answer and the "serves a live 200" assertion flaked. Retry on ANY non-200 (the test's actual intent is a live 200), returning the last response on exhaustion so the assertion still reports the real final status, and throwing only when every attempt was a network error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_04c04464-a6da-4a0c-b1de-8d8ce61292fe) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40b91d1a32
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ix the wrangler bin path The live-e2e teardown deleted the fixed-name worker, D1 database, and KV namespace whenever credentials were set — regardless of whether this run created them. Since `--provision` adopts an exact-name D1/KV (it would migrate pre-existing data) and teardown then deletes by that name, a name collision with a real resource could destroy data the test does not own. Add a pre-deploy ownership gate: before provisioning, check the account for a worker / D1 / KV already using the throwaway names and refuse to run on any collision (fail closed if a name cannot be confirmed free). Only after proving exclusive ownership is `ownershipVerified` set, and teardown deletes solely when it is — so a gate failure never deletes the colliding resource, and a partial deploy's own resources are still cleaned up. Also fix `WRANGLER_BIN`, which pointed at a nonexistent repo-root `node_modules/.bin/wrangler`; the real bin is under the package root. The gated suite never ran in CI, so this latent break was invisible until now. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_deb077a0-54c6-4dc0-bef3-293b36e08f81) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8449728942
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…2e gate The pre-run ownership gate proved the fixed-name worker/D1/KV are free before letting teardown delete by those names. The worker (`deployments list`) and D1 (`d1 info`) checks treated any nonzero exit as "free", but a genuinely-absent resource ALSO exits nonzero — so a transient API error or a missing read scope was indistinguishable from a confirmed not-found and could still arm teardown. Resolve the worker against the CF API (unambiguous 200/404; anything else is unknown → collision) and the D1 database against `d1 list --json` (a successful list that omits the name proves free; a list failure or non-JSON body is a collision). KV already listed-and-failed-closed; all three are now symmetric. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_63c1ccf4-d728-4544-aa1e-5379b5c6a2c9) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d90fce6e41
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The gated live e2e drove `void deploy --backend cloudflare --provision`, but `--provision` fails closed in non-interactive shells by design (a spawned CLI has no TTY, and CI cannot commit back the ids a create would mint) — so from `spawnSync` the suite could never reach a real deploy. Restructure it to play the provisioner's role directly: pre-create the id-bearing D1 + KV with `wrangler … create`, write their real ids (plus migrations_dir + account_id) into the app's root config, then run the CI-safe `void deploy --backend cloudflare` (no --provision). This exercises the real build → tamper-guard → remote-migrations → `wrangler deploy` path end to end and asserts a live 200. Also: - Teardown is async + existence-aware: a resource confirmed absent (the deploy never created it) is skipped, present-and-undeletable fails loud, and a lookup that cannot confirm removal fails closed — so a real leak is never silently swallowed. - `workerExistence()` retries a few times: a definitive 200/404 returns immediately, only a persistently non-definitive lookup yields 'unknown' (still fail-closed), so a lone transient API blip no longer refuses a run. - `cloudEnv()` scrubs wrangler transport-redirect overrides (CLOUDFLARE_API_BASE_URL / CF_API_BASE_URL / WRANGLER_API_ENVIRONMENT / CLOUDFLARE_COMPLIANCE_REGION) so the spawned wrangler calls and the direct existence fetch resolve the same public api base. - Document the operator prerequisites (token scopes + a registered workers.dev subdomain) in the e2e README. playground/spa carried a hand-written db/migrations/001_create_users.sql with no drizzle meta, which trips the deploy's schema-drift gate. Add the coherent meta (journal + snapshot) under the existing 001 tag so the app deploys cleanly, keeping 001_create_users.sql byte-identical (immutable history — a renamed migration would re-run CREATE TABLE against an already-migrated D1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3f95ebf5-5f01-4df9-a535-5560d2530ed1) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 71d740ba98
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The real-build integration guard test reconstructed `expected` (desired set + identity snapshots + container set) AFTER running the build, but `runCloudflareDeploy` snapshots the root config BEFORE the build — that pre-build snapshot is the entire basis of the tamper guard. If build-time code rewrote the root wrangler config, the test would read the modified inputs and bless them, so the FP-safety lock could pass an artifact production would reject. Move the reconstruction ahead of the build spawn so the test's snapshot timing matches the orchestrator's; the suite still passes 11/11. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_5a87ca78-1072-4484-bda9-2405a56c5f79) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1cb7b09472
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The live e2e ran wrangler through Node's native `spawnSync` against pnpm's extensionless `.bin/wrangler` POSIX shim, which Windows cannot execute (the runnable shim there is `wrangler.cmd`) — so every ownership / create / teardown command would fail with a spawn error before reaching Cloudflare. Switch to `cross-spawn` (which resolves the `.cmd` shim on Windows), matching the pattern the sibling integration tests already use. Drop-in on POSIX; the live suite still passes 2/2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3c67f29c-2356-4457-9db1-9604d7ed2947) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_200031be-279f-4c73-becf-1e24b5e8f40f) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 700fedf31d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_d15cba91-d5fb-44cd-a949-68ae558a4dc1) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f3616428-507e-4064-bf2b-a6a466cf3847) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_2b86dffb-0cdb-4183-8d9c-efa071b6b88e) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 085511bf66
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f9c517d0-1daf-4f2b-afa6-9391ed523267) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_4b27d0a2-a51b-4e8f-8fcf-1c3e42e9fa51) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_46013a01-8dd2-409d-bcb4-c01ef5004c12) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c0b0aaead4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_dc3df194-d6be-417a-8ca4-1d4df1d5d418) |
Wire VOID_E2E_CF_TOKEN / VOID_E2E_CF_ACCOUNT_ID (GitHub repo secrets) into the CI
test job so the gated live deploy e2e runs on every push/PR instead of only ever
skipping; fork PRs get empty secrets and skip, and win32 skips the live path. Each
run deploys under a UNIQUE per-run worker/D1/KV name (VOID_E2E_RUN_ID = run-id +
attempt) and tears it down, so overlapping runs never collide and every run gets a
fresh environment.
Getting the credentials to the test required threading them past three env filters:
- vitest collects the test file before the runner injects the step env, so the
enable gate + credentials + unique name are read at EXECUTION time (functions +
ctx.skip), never at module top-level.
- vp run passes only a task's declared env vars to it, so test:all declares the
three vars in untrackedEnv (untracked = not folded into the cache fingerprint).
- vitest filters the worker env too, mirrored via test.env on the core-markdown
project.
The live-worker 200 check polls ~2 min because a brand-new *.workers.dev hostname
needs its route to propagate (slower from a CI runner), and reports the URL plus
whether the workers.dev route is enabled on a persistent non-200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
0980807 to
f159f96
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_805ee65e-4247-4698-b7a2-bf403254655d) |
…arden wrangler parsing Move the live Cloudflare deploy e2e into a dedicated `live-e2e` CI job bound to the `cloudflare-e2e` GitHub Environment (deployment branch policy: main only), running only on a direct push to main. The account token is an environment secret reachable only from that ref-gated job, so a pull_request run — even one that edits the workflow — cannot read it; the main `test` job carries no creds and the live suite self-skips there. - Parse wrangler `--json` list output from stdout alone (the helper still exposes the combined stdout+stderr for error text), so a status-0 stderr notice can no longer break the ownership gate or teardown via JSON.parse. - Treat an empty VOID_E2E_RUN_ID as absent (`||`, not `??`) so a local run falls back to a unique timestamp+random suffix instead of collapsing every run onto `-local`; CI's run id is unaffected. - Match the deployed workers.dev host with a multi-label-safe regex and assert its worker label equals this run's name, catching a clobbered wrangler.jsonc overlay. - Document the environment-gated CI flow, unique per-run naming, and the local single-run constraint in the e2e README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_438bd27d-ec9d-4cfd-8abb-b28c4eeb015e) |
|
Addressed the review feedback in 21aa086: CI credential boundary. The live Cloudflare deploy e2e now runs in a dedicated wrangler JSON parsing. Empty run id. URL extraction. Multi-label-safe regex plus an assertion that the deployed host's worker label equals the run's name — catching a clobbered Docs. README rewritten for the environment-gated flow, unique per-run naming, and the local single-run constraint. The temporary env-probe / diagnostic tests referenced in a couple of threads were already removed. |
…absent The dedicated live-e2e job self-skipped when a secret was empty (unset, deleted, or a not-yet-rotated token), so it exited 0 and `done` stayed green — silently removing the live-deploy gate. Add a preflight step that fails the job when either credential is empty (the `test` job's uncredentialed run still self-skips), and scope the job to the canonical repo so forks don't run it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a716ed57-678e-43fe-9e8a-ddd47f548446) |
…ve e2e Extend the live Cloudflare deploy e2e beyond "serves a 200" to exercise the deploy's actual integrations against the deployed worker: - D1 round-trip: POST /api/users then GET, proving remote migrations applied and the DB binding resolves (the static /api/hello check passes even if `d1 migrations apply --remote` silently failed). - KV round-trip: PUT then GET a new /api/kv/:key route, proving the KV binding resolves the real namespace. The route 404s on an absent key so the poll absorbs KV read-after-write propagation. - Cron registration: assert the deployed worker's schedules include the app's cron via the CF API, with a retry so a transient API blip can't red a healthy deploy. - Re-deploy idempotency: a second `void deploy --backend cloudflare` succeeds and the worker still serves, covering the drift-check + already-applied remote migration + in-place worker update. Generalize fetchWithRetry to forward a request init (for the KV PUT); add a small cfWorkerApi helper for the schedules read. Add the /api/kv/:key route and document it in the spa README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e44229ea-be55-4aa1-9158-b74696129244) |
|
Expanded the live Cloudflare deploy e2e (01b3b58) beyond the static 200 check to exercise the deploy's real integrations against the deployed worker:
Verified passing 6/6 against a real account with zero leaked resources. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 01b3b58921
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tronger idempotency - Bound both deploy subprocesses with a spawn.sync timeout below the enclosing test timeout: a hung CLI/wrangler would otherwise block the worker's event loop (so vitest's own timer cannot fire) and keep afterAll from running, leaking the worker/D1/KV. A timeout now yields a null status that fails loud and lets teardown reclaim the resources. - Widen the KV read poll to 80s (past KV's ~60s eventual-consistency / negative-cache window) so a first-read miss that raced the write's central visibility converges instead of false-failing CI. - Add a per-request AbortSignal timeout to the polling fetches and the schedules read, so one stalled socket aborts and the retry loop continues rather than eating the whole budget. - Strengthen the idempotency case: read the URL from the second deploy's own output (no fallback to the first deploy), assert the host's worker label equals WORKER_NAME, and re-check a D1-backed route so a redeploy that uploaded nothing or dropped a binding fails instead of passing on a stale /api/hello. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_4c1bc13c-042c-426a-bd59-f6424daa8951) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dee7f6e96a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…n the live e2e Two remaining unbounded calls could freeze teardown and leak resources: - The wrangler() helper used spawn.sync with no timeout, so a stalled wrangler/CF call during setup or teardown would block the worker's event loop (keeping vitest's hook timer from firing) and strand already-created resources. Bound it with a finite timeout; a timeout yields a non-zero status that every caller already treats as a failed call (fail-closed gate / recorded teardown failure) and surfaces the error in the output. - workerExistence() and workersDevEnabled() fetched the CF API with no abort deadline, so an accepted-but-unanswered request could hang the ownership gate or teardown existence check. Add the same per-request AbortSignal deadline the other API helpers already use. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_85bf85d0-96a9-43bb-88af-f15f5307d775) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4319634086
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…s signal fetchWithRetry only bounded each request (AbortSignal.timeout), not the loop: a worker that accepts connections but never answers could keep the 40-attempt loop running ~15 minutes while the enclosing test times out at 200s, and vitest cannot cancel the still-running promise — so requests and timers leaked into later tests and teardown. Thread the test's ctx.signal (which vitest aborts at the test timeout) into fetchWithRetry: break the loop when it fires, combine it with the per-request deadline via AbortSignal.any, and make the inter-attempt delay abortable. The loop now stops with its test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e54f30b2-1b88-4c2b-80c5-5cd18de0b156) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c90652bfc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… deadline Two loop/aggregate operations in the live Cloudflare e2e were bounded only per-call, so a stalled Cloudflare service could overrun the enclosing test or hook while spawn.sync blocked vitest's timer. - Cron poll: thread the test signal through cfWorkerApi (AbortSignal.any with the per-request timeout) and wait with abortableDelay, breaking on ctx.signal.aborted — so 8x20s of polling can't outlive the 60s test, matching fetchWithRetry. - Wrangler calls: each hook now stamps a wranglerDeadline (setup 90s, teardown 200s) and wrangler() shrinks each call's timeout to the time remaining, skipping as a failed call once spent — so the 5-6 sequential spawn.sync calls can't collectively overrun the hook (setup 90s+480s deploy < 600s beforeAll; teardown 200s+~64s probe < 300s afterAll). An exhausted budget records the un-deleted resource as a loud failure instead of hanging. Verified: typecheck clean; live e2e 6/6 pass, account left clean (0 workers, 0 D1, 0 KV). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_80282dbb-389b-4644-b81e-bdd9a9748b79) |
Real-build integration + gated live e2e for
void deploy --backend cloudflareFollow-up to #273. That PR shipped the direct-to-Cloudflare deploy and its emitted-config tamper guard with 616 unit tests — but those stub the
vite build, wrangler, and Cloudflare via DI seams and assert against hand-written emitted-config fixtures. Nothing verified the guard's core premise: that a real@cloudflare/vite-plugin+ wrangler build emits exactly the shapeverifyGeneratedDeployConfigreconstructs, adding nothing that would false-positive a legitimate deploy. This PR closes that gap — and adds a live e2e that has been run end to end against a real account.Part A — real-build integration test (CI-runnable, no Cloudflare account)
packages/void/test/integration/cloudflare-deploy-build.test.tsRuns a real
vite buildof the kitchen-sink playground (D1 + KV + R2 + AI + sandbox/containers + cron + queue) with an overlaid rootwrangler.jsonccarrying real-shaped ids, reconstructs the guard'sexpectedwith the same exported buildersrunCloudflareDeployuses (computeDesiredCloudflareResources+ thesnapshot*fns +reconstructExpectedContainers), and asserts:Why it matters: if a future
@cloudflare/vite-plugin/ wrangler upgrade adds a field to the emitted config, this test fails in CI — instead of the drift shipping as a production false-positive that blocks a real deploy. 11 tests, ~5.5s (one build inbeforeAll, reused across cases).Part B — gated live-account e2e (real deploy, verified end to end)
packages/void/test/e2e/cloudflare-deploy-live.test.ts(+test/e2e/README.md)Deploys the spa playground (D1 + KV + cron) to a real account, asserts a live
200, then tears everything down. Wrapped indescribe.skipIf(...)so it is inert in CI and skips cleanly with no credentials; the live run is a manual operator step:It does not drive
--provision: that path fails closed in non-interactive shells by design (a spawned CLI has no TTY, and CI can't commit back the ids a create would mint), so it can't run fromspawnSync. Instead the test plays the provisioner's role — pre-creates the id-bearing D1 + KV withwrangler … create, writes their real ids (+migrations_dir+account_id) into the app's root config exactly as--provisionwould, then runs the CI-safevoid deploy --backend cloudflare. That exercises the real pipeline end to end:Harness hardening:
cloudEnv()scrubs wrangler API-base overrides so the spawned wrangler calls and the direct existence fetch always resolve the same public api base.Operator prerequisites (documented in the README): a token with Workers Scripts / D1 / KV Edit, and an account with a workers.dev subdomain already registered (else
wrangler deployuploads the worker but can't publish a public URL for the assertion).playground/spa migration coherence
The spa app carried a hand-written
db/migrations/001_create_users.sqlwith no drizzlemeta/, which trips the deploy's schema-drift gate. This adds the coherent meta (journal + snapshot) under the existing001tag so the app deploys cleanly, keeping001_create_users.sqlbyte-identical (immutable history — renaming it would re-runCREATE TABLEagainst an already-migrated D1 and wedge existing dev databases).Other non-test changes (both minimal)
export parseRootWranglerConfigincli/deploy.ts— so the test parses the pre-build root config with the same JSONC parser the orchestrator uses.vite.config.ts— wirepackages/void/test/e2e/**into the integration test project so the gated suite is discovered and skipped in CI, not silently missing.Testing
vp test run packages/void/test/integration/cloudflare-deploy-build.test.ts→ 11 passed (real build).vp test run packages/void/test/e2e→ 2 skipped — verified inert.vp test run packages/void/test/e2ewith both env vars → 2 passed against a real account — build → guard → remote migration → deploy → live 200 → clean teardown with zero leaked resources (verified worker/D1/KV absent afterward).vp run check+vp lint+vp fmt --checkclean.🤖 Generated with Claude Code
https://claude.ai/code/session_019wnwcxjavdb2xys8XGZora
Note
Medium Risk
Introduces a main-branch job that uses Cloudflare API tokens against a real account, though isolation (environment branch policy, no creds on PR/fork test jobs) is deliberate; production deploy logic only gains a test export.
Overview
Extends Cloudflare deploy coverage beyond stubbed unit tests with a real
vite buildintegration lock onplayground/kitchen-sinkand a gated live-account e2e that runsvoid deploy --backend cloudflareagainstplayground/spa, then tears down uniquely named workers/D1/KV.The integration test rebuilds the same
expectedpayload asrunCloudflareDeploy, asserts the real emittedwrangler.jsonpassesverifyGeneratedDeployConfig, and rejects minimal on-disk tampers (injected bindings, swapped D1 id, extra cron/routes/services).parseRootWranglerConfigis exported so tests parse root JSONC like production.The live suite pre-creates D1/KV (non-interactive substitute for
--provision), deploys, checks HTTP 200 plus D1/KV/cron and idempotent re-deploy, with fail-closed ownership and teardown. CI adds a separatelive-e2ejob on directmainpushes only, using thecloudflare-e2eenvironment secrets, credential preflight, andVOID_E2E_RUN_ID; the maintestjob stays uncredentialed and the suite self-skips there.vite.config.tsforwards the e2e env vars and includestest/e2e/**in the test project.playground/spa gains a KV API route, Drizzle migration meta so deploy drift checks pass, and README notes.
Reviewed by Cursor Bugbot for commit f17334d. Bugbot is set up for automated code reviews on this repo. Configure here.