Applicant Portal Seed Credentials

On this page

Overview

The default generative seed (cargo xtask seed) mints a small cast of login-capable applicant-portal households so the applicant-side walk and the applicant-portal / portal-recover Playwright projects can sign in deterministically. The cast is built by phase14_cast in tools/canopy-seed/src/datagen.rs; each member carries a byte-stable, fixed Application ID code + passcode (the household names + case UUIDs are RNG-drawn per seed, but the credentials are constants), so a human demo and the e2e specs use the same login every run regardless of the seed number.

The demo seed profile that these credentials once lived under was retired in #716 (the demo dataset folded into the default seed); the cast is its successor — one seed, one login surface.

IMPORTANT

These passcodes are seed fixtures — fake applicants in a throwaway devstack database, already public in datagen.rs. They are not secrets (Kerckhoffs: the system is secure with its source public). Production credentials are minted by the applicant-portal lookup/recovery flow (canopy_common::credentials), never seeded.

The cast

Role (manifest key) Application ID code Passcode Case state (Home hero)

approved_with_issuances

HH-ca570001

2059-3318-7642

Approved — active SNAP benefits + issuances + 2 letters; the "Your year" recap
fresh-approval hero (renews far off).

submitted_with_verifications

HH-ca570002

4821-0073-9156

Submitted — under review with pending verifications + an IEVS discrepancy; es-locale head (the Spanish action-needed walk).

confidential

HH-ca570003

1234-5678-9012

Confidential — self-service recovery routes to the helpline (portal-recover project).

ele

HH-ca570004

7300-2914-8856

Submitted — SNAP+TANF, adult + one minor child, with an ELE consent + a gating identity verification (the cross-portal worker walk; full stack only — the ELE consent lands in canopy_medicaid). Backs tests/e2e/specs/worker-determination-ele.spec.ts.

Specs never hardcode these constants — they discover a member structurally through the manifest finders in tests/e2e/lib/fixtures.ts (findApprovedWithIssuances, findSubmittedWithVerifications, findConfidential, findEleConsented), which read SEED.cast and return the member’s code / passcode / householdId + published state facts. A human tester uses the fixed codes above directly.

How the cast is seeded

Each member is built into SeedData and rendered by the seal-aware render_* writers (so its PII is crypto-shred-sealed like every other seeded person):

  • Household + person(s) + membership + address → canopy_persons.sql.

  • Application + program row(s) + Application ID code + active passcode hash → canopy_applications.sql.

  • Pending verifications + any IEVS hit → canopy_verification.sql.

  • The ele member’s Express Lane consent → canopy_medicaid.sql (full-stack only).

The argon2id passcode_hash for each member is a precomputed constant (canopy_common::credentials::hash_passcode draws a random salt, so hashing at generation time would break the seed’s byte-stable-output contract). A unit test (cast_passcode_hashes_verify) re-verifies every embedded hash against its documented passcode, so a copy-paste error fails the build; the cleartext passcodes never appear in the emitted SQL (passcodes_never_appear_in_sql), only their hashes.

Verifying the seed

cargo xtask dev refresh
cargo xtask seed

# The non-program services share one Postgres instance with a database per
# service. The host port lands in .ports.env as CANOPY_PORT_POSTGRES_5432.
PG=$(grep '^CANOPY_PORT_POSTGRES_5432=' .ports.env | cut -d= -f2)

# Every cast code is present and matches ^HH-[a-f0-9]{8}$:
psql "postgres://canopy:canopy@localhost:${PG}/canopy_applications" \
  -c "SELECT code FROM application_id_codes WHERE code LIKE 'HH-ca5700%' ORDER BY code;"
#   HH-ca570001  HH-ca570002  HH-ca570003  HH-ca570004

Sign in through the portal (native lookup form):

PORTAL_PORT=$(grep '^CANOPY_PORT_CANOPY_PORTAL_8090=' .ports.env | cut -d= -f2)
curl -i -X POST "http://localhost:${PORTAL_PORT}/lookup/submit" \
  --data-urlencode "code=HH-ca570002" \
  --data-urlencode "passcode=4821-0073-9156"
# 303 → Set-Cookie: canopy_portal_session=…  (then GET /home, /verifications, …)

See also

  • tools/canopy-seed/src/datagen.rsphase14_cast + the CAST constant + tests.

  • tests/e2e/lib/fixtures.ts — the role finders specs discover the cast through.

  • Secret Management & Rotation — how real (non-demo) credentials are handled.

Edit this page · default