test(security): independent AuthN contract suite vs frozen Security API (#243) - #249
Conversation
…[skip ci] Contract/integration tests for /api/v1/security AuthN endpoints, schema-validated (Ajv, OpenAPI 3.1) against packages/security/openapi.yaml: session CRUD+exchange, social 302, signup, methods, SessionResult MFA union, MFA factor lifecycle + step-up, email/phone verification, M2M tokens. Provider-swap proof via a second IdentityProvider; boundary/vendor-neutrality + fail-closed; pagination gate. Co-Authored-By: Claude claude-opus-4-8 <noreply@anthropic.com> Claude-Session-Id: cf830721-b1ef-4fe0-a024-035ad280dcf7
…-mock server + uuid-conformant swap fixture Root-caused 6 red tests to a harness bug (independent verification, not a product bug): the no-arg agent() built a fresh app+MockIdentityProvider per call, so a token minted at login was unknown to the follow-up authed request (401). The single reference-app + one persistent in-memory provider IS the in-process stand-in for the running server, so agent() now reuses one instance per test file (explicit-provider callers still get a fresh app). provider-swap reuses one AltIdentityProvider app for the same reason. Also fixed the provider-swap fixture to emit uuid-format User.id (the contract's User.id format) — a conformant provider must; MockIdentityProvider already did. Suite now: 9 suites, 57 passed, 1 todo (AuthZ Phase-2 runtime pagination walk, out of AuthN scope). Type-clean under noUnusedLocals. Co-Authored-By: Claude claude-opus-4-8 <noreply@anthropic.com> Claude-Session-Id: cf830721-b1ef-4fe0-a024-035ad280dcf7
CI Fix — lock file regeneratedRoot cause: This PR added in both the Fix: Ran Branch with fix: This branch targets |
CI fix: regenerated package-lock.jsonRoot cause: The `backend/security/package.json` added four new devDependencies for the AuthN contract test suite but the root `package-lock.json` was not updated, causing `npm ci` to fail at the "Build & start backend" step with: ``` Fix: Ran `npm install --package-lock-only` to regenerate the lock file, adding proper entries for `@types/js-yaml`, `ajv@8.20.0`, `ajv-formats@3.0.1`, and `js-yaml` under the `backend/security` workspace. Branch: `claude-auto-fix-ci-claude/authn-contract-tests-29353746278` (commit cb3b68e) — ready to merge into `claude/authn-contract-tests` once CI passes.
|
Automated code review (gate-code-review)Verified the suite against the frozen spec ( One genuine wrong-condition (fail-open) defect:
Report-only — this check never blocks merge. |
CI autofix: gate-frontend-build (ajv@8.20.0 missing from lock file)Root cause: Fix: Ran Branch with fix: To merge this fix into the PR branch, run: |
CI fix pushed — branch `claude-auto-fix-ci-claude/authn-contract-tests-29353750237`Root cause: All three failing CI jobs (Backend tests Node 22.x/24.x and Permit.io integration tests) failed at the `npm ci` step with: ``` When the AuthN contract test suite added `ajv`, `ajv-formats`, and `@types/js-yaml` to `backend/security/package.json`, the workspace root `package-lock.json` was never regenerated. Since `npm ci` failed, no `node_modules` were installed, causing all subsequent test steps to also fail with exit code 127 (jest not found). Fix: Ran `npm install` at the workspace root to regenerate `package-lock.json` with the three missing packages. Verified `npm ci --dry-run` succeeds. The fix is committed to `claude-auto-fix-ci-claude/authn-contract-tests-29353750237` (1 file changed: `package-lock.json`, +67/-10 lines). Please merge this branch into `claude/authn-contract-tests` to unblock CI. |
Independent AuthN contract/verification suite vs the frozen Security API (#243)
Independent, spec-driven verification of the provider-agnostic Security layer's AuthN slice, authored by
test-engineer(not the implementer). Every assertion is against the FROZEN contractpackages/security/openapi.yaml(Ajv/OpenAPI-3.1 schema validation) + the internalIdentityProviderswap interface — never an implementation's internals.What it covers (
backend/security/tests/security-api/)SessionResultunion (authenticated /mfa_required),GET /session("me"), logout (204, idempotent),POST /session/exchangeopaque-code, fail-closed 401 on bad creds/unknown code.302semantics for/social/{provider}/start+/social/callback, opaque?code=return (no token in URL), cross-originredirectTorejection.201 LoginResponse,409on existing email, neutralAuthMethodsdescriptor.{ active: false }).IdentityProvider(different token format/storage) — objective evidence the consumer contract has zero vendor coupling.auth.fuzefront.comor a vendor (authentik/permit/…).x-pagination: exemptwith a reason; the spec's paginated AuthZ collections asserted to declare limit+cursor + the{ items, page }envelope at the contract level (runtime cursor-walk is AuthZ Phase-2, flaggedit.todo, not silently skipped).Run results
Type-clean (
tsc --noEmit,noUnusedLocals). Runs against the in-process contract-mock today; setSECURITY_BASE_URLto run the identical assertions against the real implementation once it lands (harness.ts).Scope
Independent API/contract/event verification only. OUT OF SCOPE: backend impl, UI/browser e2e (
frontend-test-engineer), deploy wiring. A failing test here against a real backend bug is a valid deliverable, not a blocker to hide.🤖 Generated with Claude Code