Skip to content

release: to prod#1509

Merged
joelorzet merged 13 commits into
prodfrom
staging
Jun 10, 2026
Merged

release: to prod#1509
joelorzet merged 13 commits into
prodfrom
staging

Conversation

@joelorzet

Copy link
Copy Markdown

No description provided.

OleksandrUA and others added 13 commits June 10, 2026 15:08
The scheduled load test runs tests/k6/execution-load-test.js, which has
its own self-contained h() header builder rather than importing from
tests/k6/helpers/http.js. The prior bypass-header wiring only landed in
the helpers module, so all VUs in execution mode still got signup 400 +
65 follow-on wf-create 401s after KEEP-574 (load-test captcha bypass)
merged.

Mirror the same pattern: read LOAD_TEST_CAPTCHA_BYPASS_TOKEN from __ENV,
attach X-Load-Test-Captcha-Bypass to h() when set. The header is only
sent when the GH Actions secret is populated (staging), so prod is
unchanged.

The HTTP ramp mode already works because tests/k6/load-test.js routes
through scenarios/user-journey.js -> helpers/auth.js -> helpers/http.js.
…bypass

fix(tests/k6): send captcha bypass header from execution-load-test
K6 now signs in as one of 50 pre-seeded users (k6-loadtest-vu1..50)
instead of dynamically signing up + verifying email each run. Removes
the captcha-bypass wrapper and bypass-header wiring landed in #1502 and
#1503; they no longer have a code path that exercises them.

Server-side:
- proxy.ts: skip the mandatory-MFA gate when X-Load-Test-Mfa-Bypass
  matches LOAD_TEST_BYPASS_TOKEN (timing-safe). No env var in prod -> no
  bypass surface.
- app/api/admin/test/cleanup/route.staging.ts: add a workflow-only
  cleanup pass for the seeded users (user/org/membership rows
  preserved); tighten the destructive pattern from k6-% to k6-vu% so it
  no longer matches seeded users.
- scripts/seed-load-test-users.ts: idempotent seeder, run once against
  staging via kubectl exec.

Reverted from #1502 / #1503:
- lib/auth.ts captcha-plugin wrapper
- tests/k6/helpers/http.js + execution-load-test.js bypass header
- tests/unit/signup-defenses.test.ts bypass tests

Env var name changed from LOAD_TEST_CAPTCHA_BYPASS_TOKEN to
LOAD_TEST_BYPASS_TOKEN since it only powers the MFA bypass now. The
SSM path stays at load-test-captcha-bypass-token so we don't have to
re-issue the secret.

KEEP-574
Verified locally that twoFactorEnabled=true on the user row causes
better-auth's twoFactor plugin to intercept signin with a 2FA challenge
cookie instead of issuing a session. K6 has no way to complete TOTP, so
no usable session is created.

With twoFactorEnabled=false, signin issues a real session, and the
proxy.ts MFA bypass header (X-Load-Test-Mfa-Bypass) handles the
mfa_enrollment_required gate on subsequent requests.

Verified locally end-to-end against pnpm dev + the seeded users:
- signin: 200 with real session token
- /api/workflows/create with bypass header: 200
- /api/workflows/create without bypass header: 403 mfa_enrollment_required
- /api/workflows/create with wrong bypass: 403 mfa_enrollment_required
- /api/admin/test/cleanup: removes workflows for seeded users, preserves
  user/org/membership rows
refactor(load-test): switch k6 to pre-seeded users
Without a subscription row, getOrgPlan() defaults the seeded org to
"free", and enforceWorkflowFeatures returns 402 upgrade_required on
every /api/workflows/create attempt that uses an HTTP Request action
(which the k6 test does). Inserting a plan=pro row in the same
transaction matches what staging needs and avoids manual SQL on every
re-seed.

Verified locally and against staging:
- seed -> all 4 row types + subscription
- staging k6 dispatch with pro subs: 1625 workflows created, 1781
  manual triggers ok, http_req_failed=7.25%, end-to-end green
Web3 write steps always execute in isolated K8s Job runner pods, which
only receive the variables listed in RUNNER_SYSTEM_ENV_VARS. The
sponsorship path needs three vars that were never forwarded:

- NEXT_PUBLIC_GAS_SPONSORSHIP_ENABLED: isGasSponsorshipEnabled() read it
  as undefined in the runner, so the sponsorship guard was always false
  and every write fell back to direct EOA signing.
- TURNKEY_ORGANIZATION_ID: getTurnkeyClientForOrg() throws when it is
  unset, so enabling the flag alone would still fail in the runner.
- NEXT_PUBLIC_BILLING_ENABLED: without it the runner treats billing as
  off, so the per-org gas-credit cap is not enforced on scheduled runs.

Add the three vars to the runner forward list and set them on the
executor deployment (staging enabled, prod mirrors the app: disabled).
fix(scripts/seed): give seeded orgs a pro subscription
… check

getTurnkeyClientForOrg() throws when TURNKEY_ORGANIZATION_ID is unset, so
a runner pod missing it silently falls back to direct signing. Add it to
assertTurnkeyEnvForActiveWallets so a missing org id fails fast at executor
boot (warns in ephemeral PR envs) instead of degrading at runtime.
…p-flag

fix(executor): forward gas sponsorship envs to workflow runner pods
Staging is validated (sponsorship works, gas-credit cap guardrail enforced).
Flip NEXT_PUBLIC_GAS_SPONSORSHIP_ENABLED to true on both the prod app and
prod executor so scheduled web3 writes are sponsored in prod too. Staging
already true on both.
…prod

chore(deploy): enable gas sponsorship in prod
@joelorzet joelorzet requested review from a team, OleksandrUA, eskp and suisuss and removed request for a team June 10, 2026 18:25
@joelorzet joelorzet merged commit 687e82e into prod Jun 10, 2026
25 checks passed
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.

2 participants