Skip to content

fix: pre-launch hardening for the app (mock payees, pending sends, CSP, vendored SDK 0.3.3) - #91

Merged
YazarAyobami merged 10 commits into
mainfrom
fix/prelaunch-hardening
Nov 9, 2026
Merged

YazarAyobami merged 10 commits into
mainfrom
fix/prelaunch-hardening

Conversation

@YazarAyobami

@YazarAyobami YazarAyobami commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Fixes from the pre-launch review: the mock payee fallback is removed, direct mode is gated behind a flag, pending sends no longer invite a double payment, preflight asks for acknowledgement when a blocking check is unknown, the nonce CSP applies site-wide, and the SDK is vendored with an integrity hash. A follow-up verification pass found that several of those fixes didn't work in practice, and those problems are fixed here too.

Changes

  • Mock payees removed (M3-36): when the indexer is down, pages show the unavailable state, and mock-data.ts is deleted.

  • Direct mode gated (M3-37): NEXT_PUBLIC_ENABLE_DIRECT_PAYMENTS defaults to false, because the deployed contract predates create_direct_lock.

  • Pending sends (M3-38, M3-42):

    • The claim-link secrets are saved locally before submitting.
    • On TX_PENDING the app polls getTransaction instead of re-enabling Send.
    • It never builds a claim link from a default lock id (it used to fall back to lock 1).
    • A pending send is resumed after a reload.
  • Preflight (M3-39): an unknown result on a blocking check now requires acknowledgement.

  • CSP (M3-40, M3-43): the nonce CSP applies to every route, and every route is rendered per request. Before this, prerendered / and /attester had every script blocked.

  • SDK vendoring (M3-41, M3-42): @kinlock/sdk is vendored at 0.3.3 with a sha512 in the lockfile. The previous 0.3.2 tarball had neither TX_PENDING nor the trustline fix.

  • Error class: lib/sdk.ts re-exports the SDK's own KinlockError, so instanceof in the request form matches SDK errors again.

  • CI (M3-44): the PR e2e job no longer starts the indexer. It was failing at startup because E2E_START_LEDGER (5421502) is older than testnet RPC's ~7-day event history (startLedger must be within the ledger range: 5511598 - 5632557). The PR job only runs the claim-fragment privacy test, which reads chain state, so it doesn't need the indexer. The indexer now runs only for the signed run on main.

Hard rules / invariants touched

None. Claim-link secrets stay in browser storage only, and the CSP is stricter than before.

Tests

  • New tests:
    • confirmedLockId never returns a default id.
    • lib.KinlockError is the SDK class.
    • pollTransaction throws the SDK's KinlockError.
    • Preflight verdict covers unknown blocking checks.
    • CSP and config cases.
  • Ran pnpm lint, pnpm typecheck, pnpm test (206/206 pass) and pnpm build. All green, and every page builds as dynamic.
  • Checked by hand against pnpm start:
    • / and /attester hydrate with every script carrying the request nonce and no CSP violations.
    • With a seeded pending record, /send shows the pending screen after a reload and keeps the record when confirmation times out.
  • claim-fragment-privacy.spec.ts passes locally against a production build with no indexer running (the same setup as the PR job now).
  • Not run: the full signed pnpm e2e, or a real wallet send on testnet.

Docs / ADR

.env.example documents NEXT_PUBLIC_ENABLE_DIRECT_PAYMENTS. No ADR changes.

Roadmap

Rows M3-36 through M3-44 are all DONE, and M3-45 is added as TODO, with a Changelog entry for each. Progress counts were computed with scripts/roadmap-progress on a copy, because the script can't parse this file's column-padded §3 header, then updated by hand.

Assumptions and open questions

  • Depends on fix: pre-launch hardening for indexer and SDK (direct locks, TX_PENDING, trustline, retry, upgrade events) kinlock-sdk#83 (fix/prelaunch-hardening). The vendored vendor/kinlock-sdk-0.3.3.tgz was packed from that branch, so merge the SDK PR first and re-vendor if the published tarball differs.
  • The CSP connect-src allows https://*.stellar.org and https://albedo.link for the wallet kit. Other wallets (e.g. WalletConnect-based ones) are untested under this CSP.
  • Pending records without a tx hash (the tab closed mid-signing) are kept but can't be recovered automatically.
  • @kinlock/contract (bindings) is still pulled from a GitHub release URL with no integrity hash in the lockfile, the same supply-chain gap that item 9 fixed for the SDK. It is not changed here.
  • The signed main e2e is still broken (M3-45). The fixture contract's payee registration has aged out of RPC history, so the indexer can't ingest the fixture payee. It needs a fixture contract redeployed per run, or on a schedule shorter than RPC retention. That isn't fixed here.

The vendored 0.3.2 tarball had neither TX_PENDING nor the trustline fix, so
the pending-send flow never ran. Vendor 0.3.3 (sha512 pinned), never build a
claim link from a default lock id when the id can't be read, resume a
pending send after a reload, match only lock_created in the event fallback,
and re-export the SDK's own KinlockError so instanceof checks (request form)
match SDK errors again.
Prerendered pages (/ and /attester) can't carry the request's nonce, so the
site-wide CSP blocked all of their scripts and they never hydrated. Force
dynamic rendering at the root layout.

Roadmap: M3-42 DONE, M3-43 DONE.
@YazarAyobami
YazarAyobami requested review from a team as code owners November 9, 2026 01:06
The indexer exited at startup because E2E_START_LEDGER (5421502) is older
than testnet RPC's ~7-day event history, failing every PR. The PR job only
runs the claim-fragment privacy test, which reads chain state, so start the
indexer only for the signed run on main. That run still needs a fixture
contract inside RPC retention (M3-45).

Roadmap: M3-44 DONE, M3-45 TODO.
@YazarAyobami
YazarAyobami merged commit c9e8c1c into main Nov 9, 2026
9 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