Skip to content

release: to prod#1396

Merged
joelorzet merged 24 commits into
prodfrom
staging
May 28, 2026
Merged

release: to prod#1396
joelorzet merged 24 commits into
prodfrom
staging

Conversation

@joelorzet

Copy link
Copy Markdown

No description provided.

joelorzet added 14 commits May 6, 2026 10:10
…ng code

Para signing was retired in PR #983; this follow-up removes the now-dead
surface area so Turnkey is the only wallet path.

- Drop @getpara/ethers-v6-integration and @getpara/server-sdk from
  package.json + pnpm-lock; delete lib/para/, lib/encryption.ts (Para
  MPC user-share helpers), and Para spec docs.
- Replace the Para-backed viem LocalAccount used by sponsored-client.ts
  with a Turnkey-backed adapter (lib/web3/turnkey-viem-account.ts) that
  signs through the Turnkey API client. Move org-scoped wallet helpers
  out of lib/para/ to lib/web3/wallet-helpers.ts and drop the deprecated
  user-id-keyed lookups.
- Delete Para-only API routes (refresh-share, share) and strip the
  provider="turnkey" filter from export-key/verify since provider is
  going away.
- Drop the Para columns (provider, para_wallet_id, user_share) and
  rename para_wallets -> organization_wallets via migration 0069.
  Update Drizzle schema, relations, and the prometheus / db-metrics
  collectors to drop the Para gauge and provider split.
- Remove Para test infrastructure: delete the eip7702-spike integration
  test, the Para portal cleanup logic in the Playwright e2e helpers,
  and the seed-test-wallet / fund-test-wallet scripts. Update
  transaction-flow + write-contract-workflow tests to skip on missing
  Turnkey env (instead of missing PARA_*).
- Strip PARA_* env vars from staging / prod / pr-environment helm
  values, the e2e GitHub workflow, and the setup-e2e-db action.
Renumbers KEEP-230 migration from 0069 to 0071 to land after staging's
0069_add_feedback_table and 0070_workflow_executions_billable. Restores
the Turnkey-rewritten seed-test-wallet script that staging maintains for
E2E (retargeted onto organization_wallets and stripped of the dropped
provider column) along with its db:seed-test-wallet npm script. Cleans
up remaining para_wallets references in agentic-wallet-workflow-binding
test mock, playwright cleanup util, and schema-extensions header.
Renumbers KEEP-230 migration from 0071 to 0072 to land after the new
0071_keep_470_workflow_tx_hash_array migration on staging.
Renumbers KEEP-230 migration from 0072 to 0077 to land after staging's
0072-0076 (workflows seeded_at, executions error classification, soft
delete, db indexes, wallet integration name backfill).

Fixes stale @/lib/para/wallet-helpers imports in
plugins/web3/steps/sign-typed-data-core.ts and two test mocks that were
added on staging after this branch deleted that path; retargets them to
@/lib/web3/wallet-helpers.

Keeps both halves of the package.json scripts conflict so staging's
db:seed-workflows + db:seed-all coexist with the restored
db:seed-test-wallet entry that db:seed-all depends on. Restores staging's
SYSTEM_ACTIONS/TEMPLATE_SYNTAX/TRIGGERS imports in
app/api/mcp/schemas/route.ts.
Renumbers KEEP-230 migration from 0077 to 0079 to land after staging's
0077_keep_575_schedule_interval and 0078_error_type_label_rename.
Renumbers KEEP-230 migration from 0079 to 0082 to land after staging's
0079 safe_wallet_integration, 0080 safe_role direct rules, and 0081
address_book unique address.

Fixes stale @/lib/para/wallet-helpers imports in three new Safe-related
files added on staging (lib/safe/deployment.ts, roles-orchestrator.ts,
signer-resolver.ts) and three test mocks; retargets them all to
@/lib/web3/wallet-helpers.

Restores db:seed-test-wallet npm script that staging's db:seed-all
depends on, and keeps staging's test:protocol path move into
tests/e2e/vitest/protocol-coverage.
Removes .claude/scheduled_tasks.lock and deploy/local/observability/
from the index. Both are local developer state, not PR content.
Para has been fully removed; the comment claiming the Safe owner could
be a Turnkey or Para row was leftover from the dual-provider era.
paraWallets schema mock and the provider field on the wallet fixture
are no longer read by anything; the schema export is gone and the
column is dropped by migration 0082.
Postgres auto-rewires the FK target on RENAME TABLE but keeps the
constraint name. Renaming the constraint here avoids a future
drizzle-kit generate emitting a one-line rename migration of its own.
Idempotent via pg_constraint lookup so reruns are safe.
Also drop WALLET_ENCRYPTION_KEY everywhere it was forwarded: the only
consumer was the deleted lib/encryption.ts (Para MPC user-share helpers),
so the executor config field, the k8s-job env propagation, the
GitHub Actions composite (start-app/wallet_encryption_key input,
e2e-tests-ephemeral.yml forwarding) and the helm values for staging /
prod / pr-environment / executor / local-dev are all dead config now.

Resolve conflicts:
- app/api/user/wallet/export-key/request/route.ts -> accept staging's
  deletion (the endpoint was retired with the dual-factor MFA flow).
- app/api/user/wallet/export-key/verify/route.ts -> keep staging's
  TOTP-only verify flow; the email-OTP code that this branch was
  cleaning up is now gone entirely.
- app/api/user/wallet/withdraw/route.ts -> take staging's new
  requireOwnerWithMfa + helper imports, but point them at the new
  lib/web3/wallet-helpers path instead of the deleted lib/para path.
- keeperhub-executor/startup-checks.ts -> keep staging's ephemeral-env
  downgrade + query timeout, but drop the provider="turnkey" filter
  since the provider column is being removed by migration 0092.
- drizzle/meta/_journal.json -> renumber the Para decom migration from
  0082 to 0092 to land after all of staging's interleaved migrations,
  and rename drizzle/0082_keep_230_decom_para.sql accordingly.
- pnpm-lock.yaml -> take staging's lockfile and regenerate so the
  @getpara/* entries stay out and staging's additions are picked up.

Drop specs/integration-based-wallet-creation.md (entirely Para-flow
documentation, replaced by the Turnkey path) and update tests/README.md
to point at the Turnkey provisioning env vars instead of the Para
user-share / WALLET_ENCRYPTION_KEY pair.
Hard-grep sweep across the repo after the staging merge for any
Para-flavoured strings the previous commits missed.

- Spec docs: delete the historical Para handover / migration docs
  (organizations_migration_handover, wallet-migration-todo,
  organization-wallet-execution) that documented the Para-era flow
  end-to-end; rewrite the surviving organization / wallet-overlay specs
  and the logging-and-metrics example to use Turnkey naming and
  /lib/web3/wallet-helpers paths.
- Executor helm charts (prod + staging + pr-environment): drop the
  PARA_API_KEY parameterStore entry and the PARA_ENVIRONMENT kv entry
  alongside the WALLET_ENCRYPTION_KEY removal.
- Local dev: strip the PARA_API_KEY / PARA_ENVIRONMENT /
  NEXT_PUBLIC_PARA_* kv stanzas from values-keeperhub.template.yaml
  and the matching sed substitutions + help text from deploy.sh.
- PR seed verifier: query organization_wallets instead of para_wallets.
- Tests: drop the paraWallets mock from safe-roles-orchestrator and the
  stray "ParaWallet" comment in lib/auth.ts permissions config.
…aming

The org-scoped wallet model documented here is still load-bearing
architecture; only the signer backend changed Para -> Turnkey. The
previous sweep deleted the file along with the genuinely obsolete
handover / migration docs, which removed useful design context. Bring
it back and rename the Para references inline:

- initializeParaSigner -> initializeWalletSigner
- Para signer -> Turnkey signer
- ParaWallet / Para wallet -> Wallet
- para_wallets -> organization_wallets
- keeperhub/lib/para/wallet-helpers.ts -> lib/web3/wallet-helpers.ts
chore: KEEP-230 remove Para SDK and supporting code
@joelorzet joelorzet requested review from a team, OleksandrUA, eskp and suisuss and removed request for a team May 28, 2026 19:29
joelorzet added 9 commits May 28, 2026 17:23
…agers

Replaces the email OTP <input> in DualFactorSteps with a contenteditable
div so 1Password, Bitwarden, LastPass and Dashlane have no element to
autofill. Data-* opt-outs were not enough: 1Password's TOTP-fill
heuristic kept landing the authenticator code in the email slot because
the only visible field on step 1 was a 6-digit numeric input.
Password manager content scripts only target input/textarea/select, so a
div with role="textbox" and inputMode="numeric" is fundamentally outside
their reach while preserving the mobile numeric keyboard and visual
parity with the existing Input component.
The contenteditable div was using flex justify-center, which centers
child boxes but not the caret of an empty editable region — so the
cursor sat at the far left. Switch to block + text-center and use
text-indent to absorb tracking's trailing letter-space so the
placeholder and typed digits also appear visually centered.
Enter in the contenteditable was inserting a newline. Suppress the
default and trigger the Continue action when the 6-digit email code is
ready, matching how a real <input type=text> in a form behaves.
Adds sanitizeNextPath which whitelists the value before it is fed back
into the browser as a redirect. Rejects /monitoring (Sentry tunnel),
/api/*, /_next/*, protocol-relative URLs, parent-traversal segments,
and percent-encoded variants of any of those, falling back to "/" so
the worst case is the home page rather than a dead-end internal route
that 404s with the URL pinned in the address bar.

Applied at every read site: the verify-mfa, verify-ip, and enroll-mfa
pages, the OAuth callback intercept that builds the verify-mfa redirect,
the OAuth-MFA and verify-IP finalize routes, and the client-side guard
handler that captures window.location before bouncing to step-up.

Also two local-dev helper scripts under scripts/miscellaneous: reset-mfa
wipes a user's TOTP enrollment so they can re-enroll, and peek-email-otp
decrypts the live email OTP from the verifications table using
BETTER_AUTH_SECRET. Both refuse to run unless DATABASE_URL points at a
localhost host.
These were committed by mistake. Both are local-debug utilities only,
not appropriate for the repo. The OTP-peek script in particular
documents the BETTER_AUTH_SECRET decrypt path against the verifications
table, which we should not ship even with a localhost guard. Keep them
out of tree; recreate locally as needed.
Extracts the contenteditable email-OTP slot from DualFactorSteps into a
shared EmailOtpField component and applies it to the credentials-signin
dialog's signin-email-otp view. The previous <Input autoComplete=
"one-time-code" /> there was the actual bypass: 1Password's TOTP
heuristic filled the 6-digit slot with the authenticator code and the
surrounding <form> auto-submitted, advancing the wizard past step 1
without the user typing anything. Replacing the element with a div
contentEditable puts the field outside the autofill domain so this
cannot happen.

Also fixes the SignInStepIndicator so the done step no longer paints in
green: only the current step renders with the green bubble, matching
DualFactorSteps. Done and pending labels are plain foreground (no muted
gray) per design ask.

Includes temporary [signin-flow] console.info breadcrumbs on the
strict-signin start, the signin-email-otp submit, and the totp submit
so the bypass can be reproduced and confirmed fixed end to end. Will be
stripped before merge.
Swaps the email-OTP <Input autoComplete=one-time-code> for the
contenteditable EmailOtpField on the two remaining surfaces that pair
an email code with a TOTP code in the same flow:

  - DualFactorInput (the always-mounted email + TOTP variant used by
    settings/account-settings and overlays/api-keys-overlay).
  - Forgot-password Reset Code in the auth dialog. The sibling
    Authenticator code input on that same view is left as-is because
    1Password autofill IS desired for the TOTP slot.

Standalone single-factor email-only surfaces (signup verify,
accept-invite) are intentionally not changed: the user has not enrolled
TOTP yet, so there is no second 6-digit field on the page for 1Password
to confuse with the email code.

Also strips the [signin-flow] console.info breadcrumbs added in the
previous commit now that the email-step bypass is confirmed fixed.
Adds <meta name="google" content="notranslate"> via the Metadata.other
field plus translate="no" on the root <html> element. External
translators (Chrome's built-in translator and translation extensions)
swap text nodes in place; React's fiber tree keeps pointing at the
original parents, so the next insertBefore/removeChild commits throw
NotFoundError and crash the route.

Three production Sentry groups (insertBefore on /, removeChild on / and
on /workflows/:workflowId) share the same fingerprint: zh-CN locale,
Asia/Shanghai timezone, no first-party frames in the stack, all
manifesting on the same client. This is the canonical
react/react#11538 pattern.
…ofill

fix(auth): dual-factor email step hardening and redirect sanitization
…nd-translation

fix(layout): opt out of in-page translation to stop React DOM crashes
@joelorzet joelorzet merged commit 2c46e49 into prod May 28, 2026
41 of 42 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.

1 participant