feat(api): add bunyip-e2e-bootstrap test-account seeder (BUNYIP-52) #84

Merged
nrupard merged 2 commits from feat/bunyip-52-e2e-bootstrap-binary into main 2026-06-09 20:28:29 +02:00
Owner

Scope

First slice of BUNYIP-52 (per the agreed decomposition): the idempotent E2E test-account seeder only. The Playwright suite (e2e/), the CI workflow (.forgejo/workflows/e2e.yml), the CI compose file (compose.e2e.yml), the Stripe test-mode wiring, and the Infisical secret provisioning land in follow-up PRs. This piece is fully self-contained and verifiable with just check-container; the later pieces depend on external infra (Infisical vault, Stripe test keys, a CI runner with Node + Playwright) and a running stack.

What this adds

  • bunyip-api/src/bin/bunyip_e2e_bootstrap.rs plus a second [[bin]] target bunyip-e2e-bootstrap. Standalone tool (not a server subcommand) that reuses the bunyip-api lib for config / repositories / services.
  • Upserts e2e-user@a8n.run (subscriber) and e2e-admin@a8n.run (admin) via INSERT ... ON CONFLICT (email) DO UPDATE. Idempotent: a re-run resets password/role/email_verified and revives a cleaned-up row, so CI re-runs are no-ops in effect. Rows are seeded email_verified = TRUE so the suite signs in without the verification gate.
  • Shared Argon2-hashed password read from BUNYIP_E2E_TEST_USER_PASSWORD (CI maps Infisical /bunyip/e2e/test_user_password to it; the _FILE secret convention is honoured). No plaintext in any fixture.
  • --cleanup hard-deletes the rows by exact email; --dry-run previews without writing and composes with --cleanup; --help documents usage.
  • just e2e-bootstrap *args recipe, running the binary inside the api container against the dev DB (mirrors just migrate).

Safety

Refuses to run unless BOTH BUNYIP_E2E_BOOTSTRAP_ALLOW=true AND a non-production ENVIRONMENT. Config defaults ENVIRONMENT to production when unset, so unset is treated as production and blocked; production and prod are blocked explicitly. Both checks sit in enforce_guards so a single missing guard cannot let it through.

Test

just check-container green (fmt + clippy -D warnings over --all-targets, which compiles the new bin, + workspace lib tests). Targeted cargo clippy -p bunyip-api --bin bunyip-e2e-bootstrap -- -D warnings also clean. Not exercised against a live DB in this PR (no dev stack in CI yet); that happens once compose.e2e.yml + the workflow land.

Follow-ups (remaining BUNYIP-52 ACs)

  • e2e/ Playwright scaffold + first-cut specs (auth, account, memberships, billing, oidc).
  • compose.e2e.yml + .forgejo/workflows/e2e.yml (+ email sink for the email-driven specs).
  • Infisical /bunyip/e2e/ (test_user_password) and /bunyip/e2e/stripe/ provisioning.
  • just e2e runner recipe.

#BUNYIP-52

## Scope First slice of BUNYIP-52 (per the agreed decomposition): the idempotent E2E test-account seeder only. The Playwright suite (`e2e/`), the CI workflow (`.forgejo/workflows/e2e.yml`), the CI compose file (`compose.e2e.yml`), the Stripe test-mode wiring, and the Infisical secret provisioning land in follow-up PRs. This piece is fully self-contained and verifiable with `just check-container`; the later pieces depend on external infra (Infisical vault, Stripe test keys, a CI runner with Node + Playwright) and a running stack. ## What this adds - `bunyip-api/src/bin/bunyip_e2e_bootstrap.rs` plus a second `[[bin]]` target `bunyip-e2e-bootstrap`. Standalone tool (not a server subcommand) that reuses the bunyip-api lib for config / repositories / services. - Upserts `e2e-user@a8n.run` (subscriber) and `e2e-admin@a8n.run` (admin) via `INSERT ... ON CONFLICT (email) DO UPDATE`. Idempotent: a re-run resets password/role/`email_verified` and revives a cleaned-up row, so CI re-runs are no-ops in effect. Rows are seeded `email_verified = TRUE` so the suite signs in without the verification gate. - Shared Argon2-hashed password read from `BUNYIP_E2E_TEST_USER_PASSWORD` (CI maps Infisical `/bunyip/e2e/test_user_password` to it; the `_FILE` secret convention is honoured). No plaintext in any fixture. - `--cleanup` hard-deletes the rows by exact email; `--dry-run` previews without writing and composes with `--cleanup`; `--help` documents usage. - `just e2e-bootstrap *args` recipe, running the binary inside the api container against the dev DB (mirrors `just migrate`). ## Safety Refuses to run unless BOTH `BUNYIP_E2E_BOOTSTRAP_ALLOW=true` AND a non-production `ENVIRONMENT`. `Config` defaults `ENVIRONMENT` to `production` when unset, so unset is treated as production and blocked; `production` and `prod` are blocked explicitly. Both checks sit in `enforce_guards` so a single missing guard cannot let it through. ## Test `just check-container` green (fmt + clippy `-D warnings` over `--all-targets`, which compiles the new bin, + workspace lib tests). Targeted `cargo clippy -p bunyip-api --bin bunyip-e2e-bootstrap -- -D warnings` also clean. Not exercised against a live DB in this PR (no dev stack in CI yet); that happens once `compose.e2e.yml` + the workflow land. ## Follow-ups (remaining BUNYIP-52 ACs) - `e2e/` Playwright scaffold + first-cut specs (auth, account, memberships, billing, oidc). - `compose.e2e.yml` + `.forgejo/workflows/e2e.yml` (+ email sink for the email-driven specs). - Infisical `/bunyip/e2e/` (`test_user_password`) and `/bunyip/e2e/stripe/` provisioning. - `just e2e` runner recipe. #BUNYIP-52
feat(api): add bunyip-e2e-bootstrap test-account seeder (BUNYIP-52)
All checks were successful
Check / fmt / clippy / build / test (pull_request) Successful in 1m5s
aad41de472
First slice of the BUNYIP-52 E2E work: the idempotent test-account seeder the Playwright suite will log in as. The browser suite, CI workflow, CI compose file, and Infisical secret provisioning land in follow-up PRs.

Adds a standalone `bunyip-e2e-bootstrap` binary (a second `[[bin]]` target in bunyip-api, reusing the bunyip-api lib for config/repositories/services, not a server subcommand). It upserts `e2e-user@a8n.run` (subscriber) and `e2e-admin@a8n.run` (admin) under the default tenant via `INSERT ... ON CONFLICT (email) DO UPDATE`, so a re-run resets the password/role/verified flag and revives a cleaned-up row, making CI re-runs no-ops. Both accounts share one Argon2-hashed password read from `BUNYIP_E2E_TEST_USER_PASSWORD` (CI injects it from Infisical `/bunyip/e2e/test_user_password`, `_FILE` secret convention honoured), so no plaintext lives in a fixture. The seeded rows are marked `email_verified = TRUE` so the suite can sign in without the verification gate.

Safety: the tool refuses to run unless BOTH `BUNYIP_E2E_BOOTSTRAP_ALLOW=true` AND a non-production `ENVIRONMENT`. `Config` defaults `ENVIRONMENT` to `production` when unset, so an unset environment is treated as production and blocked; `production` and `prod` are blocked explicitly. Both checks live in `enforce_guards` so one missing guard cannot let it through. `--cleanup` hard-deletes the rows by exact email; `--dry-run` prints the actions without writing and composes with `--cleanup`.

Adds a `just e2e-bootstrap *args` recipe that runs the binary inside the api container against the dev database, mirroring the `just migrate` pattern.

#BUNYIP-52

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(api): note ENVIRONMENT-vs-DATABASE_URL residual risk on e2e guard (BUNYIP-52)
All checks were successful
Create release / Create release from merged PR (pull_request) Has been skipped
Check / fmt / clippy / build / test (pull_request) Successful in 1m36s
f9e51d6975
Code-review follow-up. Document the accepted residual risk in `enforce_guards`: the production gate keys on `ENVIRONMENT`, not on `DATABASE_URL`, so a non-production `ENVIRONMENT` pointed at a production database is not caught. Records why (a DB-host allow-list is brittle), the bounded blast radius (only the two known e2e-*@a8n.run rows; cleanup deletes only those exact emails), and the trigger to revisit. No behavior change.

#BUNYIP-52

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard deleted branch feat/bunyip-52-e2e-bootstrap-binary 2026-06-09 20:28:30 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!84
No description provided.