Skip to content

test(deploy): real-build integration + gated live e2e for the Cloudflare backend - #284

Merged
Brooooooklyn merged 16 commits into
mainfrom
test/cloudflare-deploy-e2e
Jul 23, 2026
Merged

Brooooooklyn merged 16 commits into
mainfrom
test/cloudflare-deploy-e2e

Conversation

@Brooooooklyn

@Brooooooklyn Brooooooklyn commented Jul 22, 2026 •

Copy link
Copy Markdown
Member

Real-build integration + gated live e2e for void deploy --backend cloudflare

Follow-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 shape verifyGeneratedDeployConfig reconstructs, 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.ts

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 the guard's expected with the same exported builders runCloudflareDeploy uses (computeDesiredCloudflareResources + the snapshot* fns + reconstructExpectedContainers), and asserts:

real emitted dist/ssr/wrangler.json → verifyGeneratedDeployConfig → { ok: true }     ← the FP-safety LOCK
reconstructed container set == emitted sandbox container (byte-identical)
6 on-disk tampers → { ok: false }:  inject container · swap D1 id · add EXTRA_DB · add cron · add services · add routes

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 in beforeAll, 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 in describe.skipIf(...) so it is inert in CI and skips cleanly with no credentials; the live run is a manual operator step:

VOID_E2E_CF_TOKEN=<token> VOID_E2E_CF_ACCOUNT_ID=<id> vp test run packages/void/test/e2e

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 from spawnSync. Instead the test plays the provisioner's role — pre-creates the id-bearing D1 + KV with wrangler … create, writes their real ids (+ migrations_dir + account_id) into the app's root config exactly as --provision would, then runs the CI-safe void deploy --backend cloudflare. That exercises the real pipeline end to end:

ownership gate → pre-create D1+KV → vite build → tamper-guard →
remote D1 migration → wrangler deploy → GET /api/hello 200 → teardown (0 leaks)

Harness hardening:

  • Fail-closed ownership gate — refuses to run if the fixed-name worker/D1/KV already exist; every lookup it can't positively confirm as free is treated as a collision (worker via CF API 200/404 with a bounded retry against transient blips; D1/KV via list).
  • Existence-aware teardown — deletes each resource only if it is still present, fails loud on a present-but-undeletable resource, and fails closed on an ambiguous lookup, so a real leak is never silently swallowed.
  • Transport pinning — 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 deploy uploads 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.sql with no drizzle meta/, which trips the deploy's schema-drift gate. This adds the coherent meta (journal + snapshot) under the existing 001 tag so the app deploys cleanly, keeping 001_create_users.sql byte-identical (immutable history — renaming it would re-run CREATE TABLE against an already-migrated D1 and wedge existing dev databases).

Other non-test changes (both minimal)

  • export parseRootWranglerConfig in cli/deploy.ts — so the test parses the pre-build root config with the same JSONC parser the orchestrator uses.
  • vite.config.ts — wire packages/void/test/e2e/** into the integration test project so the gated suite is discovered and skipped in CI, not silently missing.

Testing

  • Part A: vp test run packages/void/test/integration/cloudflare-deploy-build.test.ts → 11 passed (real build).
  • Part B (no creds): vp test run packages/void/test/e2e → 2 skipped — verified inert.
  • Part B (live account): vp test run packages/void/test/e2e with 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 --check clean.

🤖 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 build integration lock on playground/kitchen-sink and a gated live-account e2e that runs void deploy --backend cloudflare against playground/spa, then tears down uniquely named workers/D1/KV.

The integration test rebuilds the same expected payload as runCloudflareDeploy, asserts the real emitted wrangler.json passes verifyGeneratedDeployConfig, and rejects minimal on-disk tampers (injected bindings, swapped D1 id, extra cron/routes/services). parseRootWranglerConfig is 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 separate live-e2e job on direct main pushes only, using the cloudflare-e2e environment secrets, credential preflight, and VOID_E2E_RUN_ID; the main test job stays uncredentialed and the suite self-skips there. vite.config.ts forwards the e2e env vars and includes test/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.

…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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
Comment thread packages/void/test/integration/cloudflare-deploy-build.test.ts Outdated
… 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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
…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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
…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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
…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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts
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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/integration/cloudflare-deploy-build.test.ts
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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread .github/workflows/ci.yml Outdated
Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
Comment thread packages/void/test/e2e/README.md Outdated
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

Comment thread packages/void/test/e2e/README.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/README.md Outdated
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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
@Brooooooklyn
Brooooooklyn force-pushed the test/cloudflare-deploy-e2e branch from 0980807 to f159f96 Compare July 22, 2026 14:13
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@Brooooooklyn

Copy link
Copy Markdown
Member Author

Addressed the review feedback in 21aa086:

CI credential boundary. The live Cloudflare deploy e2e now runs in a dedicated live-e2e job bound to a new cloudflare-e2e GitHub Environment whose deployment branch policy allows main only. The account token is an environment secret reachable only from that ref-gated job (if: github.event_name == 'push' && github.ref == 'refs/heads/main'); the main test job carries no creds and the live suite self-skips there. Because the environment ref-check is enforced server-side, a pull_request run — even one that edits this workflow — cannot reach the token (an expression-level event_name == 'push' gate alone would be bypassable that way, since a same-repo PR runs its own copy of the workflow and still receives secrets). The two secrets were migrated from repo-level to the environment.

wrangler JSON parsing. wrangler() now returns stdout separately from the combined stdout+stderr (kept for error text); every --json list parse reads stdout alone, so a status-0 stderr notice can no longer break the ownership gate or teardown.

Empty run id. uniqueRunSuffix treats an empty VOID_E2E_RUN_ID (forwarded as '' by the vitest test.env) as absent (||, not ??), falling back to a unique timestamp+random suffix; CI's run id is unaffected.

URL extraction. Multi-label-safe regex plus an assertion that the deployed host's worker label equals the run's name — catching a clobbered wrangler.jsonc overlay.

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
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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
@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@Brooooooklyn

Copy link
Copy Markdown
Member Author

Expanded the live Cloudflare deploy e2e (01b3b58) beyond the static 200 check to exercise the deploy's real integrations against the deployed worker:

  • D1 round-trip — POST /api/users then GET, proving remote migrations applied and the DB binding resolves (the /api/hello check passes even if d1 migrations apply --remote silently failed).
  • KV round-trip — PUT/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 cron via the CF API (retried against transient API blips; fails loud if genuinely unregistered).
  • Re-deploy idempotency — a second void deploy --backend cloudflare succeeds and the worker still serves (drift-check + already-applied remote migration + in-place update).

Verified passing 6/6 against a real account with zero leaked resources.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts
…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
@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts
Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts
…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
@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
…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
@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
Comment thread packages/void/test/e2e/cloudflare-deploy-live.test.ts Outdated
… 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
@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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)

@Brooooooklyn
Brooooooklyn merged commit fc01007 into main Jul 23, 2026
9 of 11 checks passed
@Brooooooklyn
Brooooooklyn deleted the test/cloudflare-deploy-e2e branch July 23, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant