Skip to content

test: pin provision-first gate-submit, recipients, and argv leaks - #118

Draft
cursor[bot] wants to merge 1 commit into
productionfrom
cursor/missing-test-coverage-362d
Draft

test: pin provision-first gate-submit, recipients, and argv leaks#118
cursor[bot] wants to merge 1 commit into
productionfrom
cursor/missing-test-coverage-362d

Conversation

@cursor

@cursor cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown

Risky behavior now covered

  • Gate-submit provision-first: a missing break-glass key or an unconfigured key box refuses the submission with 503 and never sends answers to the Rust gate. The previous suite treated that 503 as a gate refusal, so the fail-closed contract was a false pass. The linkage INSERT still binds NULL for both answer columns (plus session pubkey and encrypted email). storeEncryptedAnswer runs last because the gate has no delete.
  • Store client payload: storeEncryptedAnswer forwards recipients and skipped in the JSON body. Omitted recipients travel as [] (the gate's "use my default" contract), not as an absent field that would encrypt to the wrong key.
  • Typst argv and cleanup: answers never appear on argv; Typst stderr is discarded; data.json is 0600; a failed render leaves the working directory empty. These run in CI — render_test.ts skips without typst.
  • Web-tier mailer: python3 is invoked with the sender and the spec path only; clearEnv so DATABASE_URL and JWT_SECRET are not inherited; a permanent 5xx is not retried.
  • Default ssh transport: the session identity travels on stdin, never argv; StrictHostKeyChecking=yes and BatchMode=yes; the key box destination comes from the environment, not a baked-in IP.
  • Contact form: a PGP failure returns before fetch (no plaintext fallback); console.error is a category string, never the caught error (which can quote the message body).
  • Boot: unhandledrejection calls preventDefault before Fresh starts, and logs only a class name. The gate logs that the age recipient loaded, not which one.
  • Render service: skipped or empty-ciphertext answers are never handed to age; notifyDelivered checks res.ok so a 404 cannot hide.

CI now also runs the existing hermetic audience, client-ip, QR, email, keystore, bundle-validation, co-op QR, privacy, and rewritten gate-submit tests that were passing locally and running nowhere.

Test files added/updated

  • routes/api/gate-submit_test.ts (rewritten) — provision-first fail-closed
  • lib/gate_encrypt_test.ts (updated) — recipients/skipped payload
  • romania/tests/render_argv_test.ts (added)
  • romania/tests/render_service_contract_test.ts (added)
  • lib/email_argv_test.ts (added)
  • lib/session-keys_transport_test.ts (added)
  • routes/contact-form_script_test.ts (added)
  • lib/unhandled_rejection_test.ts (added)
  • lib/rust_recipient_log_test.ts (added)
  • .github/workflows/ci.yml — runs the new files plus existing audience/client-ip/qr-scans/email/keystore/validateBundle/WillyStCo-op/privacy/gate-submit suites

Why these tests materially reduce regression risk

These are the production paths that take plaintext answers, private keys, and mail envelopes off this host. A provisioning failure that still posted answers, a dropped recipients field, answers on /proc/<pid>/cmdline, an identity on ssh argv, a PGP checkbox that silently posted cleartext, or an unhandled rejection that took the site down would all ship as silent security or availability failures. None of this overlaps the open coverage PRs (#112 JWT/callback, #114 consent/session-keys injection/contact, #115 gate API/beacon/verify/wearable, #116 profile/store-bounds/metrics/gate cookies, #117 audience-count/questionnaire-auth/session-cleanup/mailer-argv).

Hermetic: no Postgres, no SMTP dialogue, no qpdf, no typst binary required for the new render tests. 181 Deno tests passed locally, including the full CI set.

No production behavior changes.

Open in Web View Automation 

Gate-submit tests still treated a provisioning 503 as a gate refusal,
so answers-never-leave was a false pass. Align them with provision
first. Also pin the store client's recipient payload, Typst/email argv,
ssh stdin for identities, the contact form's PGP fail-closed path, and
boot-time unhandled-rejection suppression.

Co-authored-by: Ralphie B. <nyagrodha@users.noreply.github.com>
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