testing/cross_backend/conformance_case.ts

Declarative conformance-case schema for the cross-backend behavioral + security suite.

A conformance case is a single request → expected-response assertion, carried as data. The case references a method (an RPC method name or a REST auth-route suffix); the runner (describe_conformance_table_tests) resolves the input / output Zod schemas from the live action-spec registry / RouteSpec — the case never carries a schema. This is the opinionated behavioral/security layer on top of the spec-derived auto-enumeration (describe_rpc_round_trip_tests / describe_rpc_attack_surface_tests): the same case definition runs in-process (fast, every gro test) and cross-process (the conformance gate) against each impl's real auth resolution.

The table is for single-request matrices (credential-type ceiling, privilege gates, IDOR masks, enumeration-equivalence, validation). Multi-step flows stay imperative in their own describe_* suites, sharing assertion primitives — there is deliberately no declarative setup DSL.

view source

Declarations
#

5 declarations

ConformanceCase
#

testing/cross_backend/conformance_case.ts view source

ZodObject<{ name: ZodString; request: ZodObject<{ method: ZodString; params: ZodOptional<ZodUnknown>; as: ZodEnum<{ token: "token"; keeper: "keeper"; daemon: "daemon"; ... 7 more ...; expired_session: "expired_session"; }>; verb: ZodOptional<...>; }, $strict>; expect: ZodObject<...>; note: ZodOptional<...>; xfail: Z... import type {ConformanceCase} from '@fuzdev/fuz_app/testing/cross_backend/conformance_case.js';

A single conformance case. name is the assertion; the optional free-text note is printed in the test label / failure output. A security case's note should reference a public fuz_app doc property (security.md / architecture.md / module TSDoc), since the table ships in a public package — not an internal planning doc. The note is documentation, not a gate: it stays free-text by design because a non-empty-string check never catches a *wrong* citation — the citation is verified in review.

ConformanceCaseExpectation
#

testing/cross_backend/conformance_case.ts view source

ZodObject<{ status: ZodNumber; error_reason: ZodOptional<ZodString>; fields: ZodOptional<ZodRecord<ZodString, ZodUnknown>>; absent_fields: ZodOptional<...>; headers: ZodOptional<...>; equivalence_group: ZodOptional<...>; }, $strict> import type {ConformanceCaseExpectation} from '@fuzdev/fuz_app/testing/cross_backend/conformance_case.js';

The expected response shape a conformance case asserts.

ConformanceCaseRequest
#

testing/cross_backend/conformance_case.ts view source

ZodObject<{ method: ZodString; params: ZodOptional<ZodUnknown>; as: ZodEnum<{ token: "token"; keeper: "keeper"; daemon: "daemon"; invalid_daemon: "invalid_daemon"; ... 6 more ...; expired_session: "expired_session"; }>; verb: ZodOptional<...>; }, $strict> import type {ConformanceCaseRequest} from '@fuzdev/fuz_app/testing/cross_backend/conformance_case.js';

The request a conformance case issues.

ConformanceCaseXfail
#

testing/cross_backend/conformance_case.ts view source

ZodObject<{ tracking_id: ZodString; reason: ZodString; }, $strict> import type {ConformanceCaseXfail} from '@fuzdev/fuz_app/testing/cross_backend/conformance_case.js';

Marks a case as a deferred-by-design gap. The runner routes it through xfail_until instead of a normal test — visible (distinct from pass) and self-cleaning (flips red when the impl starts passing, forcing the marker's removal). Use for declared gaps (e.g. facts), never for in-scope gaps (those fail loud as a red test).

ConformancePrincipal
#

testing/cross_backend/conformance_case.ts view source

ZodEnum<{ token: "token"; keeper: "keeper"; daemon: "daemon"; invalid_daemon: "invalid_daemon"; daemon_browser: "daemon_browser"; bearer_browser: "bearer_browser"; anonymous: "anonymous"; fresh_non_admin: "fresh_non_admin"; role_holder: "role_holder"; wrong_role: "wrong_role"; expired_session: "expired_session"; }> import type {ConformancePrincipal} from '@fuzdev/fuz_app/testing/cross_backend/conformance_case.js';

Closed enum of fixture-provisioned principals a case runs as. Each value maps to a TestFixture accessor (or a seeded extra_accounts entry) in the runner's resolve_principal — there is no inline credential minting in a case (that would be the setup-DSL trap).

  • keeper — the per-test bootstrapped keeper (holds ROLE_KEEPER + ROLE_ADMIN), session credential.
  • daemon — the keeper authenticated via the daemon-token header.
  • invalid_daemon — a *malformed/invalid* X-Daemon-Token carried alongside the keeper's session cookie, over a non-browser (no-Origin) transport. The middleware soft-fail-discards the invalid daemon token (matching the Rust spine's None), so auth falls through to the session leg: the request authenticates as the keeper-via-session and a daemon-gated action then refuses the session credential with credential_type_required — not a hard invalid_daemon_token 401. The no-Origin transport keeps the daemon token on the invalid-token path rather than the browser-context discard; the session base credential is what makes the credential-type gate (not the auth gate) the refusing layer (without it the discard would 401 anonymous).
  • daemon_browser — a *valid* X-Daemon-Token carried in a browser context (default Origin present) alongside the keeper's session cookie. Browsers attach Origin automatically; the daemon-token middleware discards a header-bearing daemon token as browser context (mirroring the bearer guard and the Rust spine's is_browser_context), so the *valid* token is dropped and auth falls through to the session leg → a daemon-gated action then refuses the session credential with credential_type_required. Distinct from invalid_daemon: here the token is well-formed and current, so a 403 (not a 400 confirm-guard hit like daemon) proves the browser-context discard fired — a valid daemon token does NOT authenticate when an Origin is present. Origin is deliberately NOT suppressed; its presence is the signal under test.
  • token — the keeper authenticated via a bearer api-token (non-browser context; the runner suppresses Origin so the token isn't discarded).
  • bearer_browser — a *valid* bearer api-token carried in a browser context (default Origin present), fresh jar so NO session rides alongside. The bearer middleware discards the token as browser context (mirroring the daemon guard + the Rust spine's is_browser_context), so the request arrives anonymous and an authed action 401s. Proves a stolen bearer cannot be replayed from a browser — wire-indistinguishable from sending no credential (the token principal is the honored counterpart: it suppresses Origin, so the same token authenticates).
  • anonymous — no credential, fresh cookie jar.
  • fresh_non_admin — a freshly minted account with no roles, session credential (via the production invite → signup → login flow).
  • role_holder — a seeded extra_accounts principal holding a specific role; the runner reads it by the username named in ConformanceTableOptions.principals.role_holder.
  • wrong_role — a seeded extra_accounts principal holding a role other than the one a route requires; named via ConformanceTableOptions.principals.wrong_role.
  • expired_session — the keeper account presented via an *expired server-side session* cookie (minted by fixture.mint_expired_session(): a backdated auth_session row behind a still-valid signed cookie payload, so the authoritative DB-row expiry gate is what refuses it).

Depends on
#

Imported by
#