Documentation
¶
Overview ¶
Package authstoretest provides a shared, engine-agnostic behavioral contract suite for the composite auth store (cplieger/auth/store.Composite). It depends ONLY on the cplieger/auth library (the domain types and the store interface), so it can be driven against any concrete engine — the legacy SQLite authdb.AuthDB and the new bbolt authstore.Store — without importing either, proving behavioural parity at the AuthStore seam (Requirements 14.1, 14.2).
What this suite is ¶
Suite asserts EXACT observable values, not merely "does not error", for the behaviours that are TRUE PARITY between the old SQLite store and the new bbolt store:
- uniqueness: duplicate username (case-insensitive), duplicate (oidc_issuer, oidc_sub), duplicate passkey credential id, and duplicate API-key hash are each rejected with a non-nil error and no partial write (Requirements 9.3, 16.1);
- user-delete cascade: a deleted user's passkeys, API keys, and sessions are all removed, the freed username can be recreated, and ANOTHER user's records are untouched (Requirement 9.4);
- single-use ConsumeOIDCState: the first consume returns the stored values exactly, the second returns not-found (Requirement 16.3);
- credential ownership: a non-owner cannot delete or rename a passkey, nor delete an API key (Requirement 16.4);
- session expiry: CleanupExpiredSessions evicts idle-expired and absolute-expired sessions, keeps live ones, with an exact count and an exclusive boundary (Requirement 10.3);
- sign_count durability across a simulated restart: a raised sign_count survives a Reopen, and so do the durable user/passkey records (Requirement 9.5, the durable-and-monotonic half that BOTH engines share).
Deliberate DIVERGENCES between the two engines are intentionally NOT asserted here, because they would make the shared suite fail against one engine. They are covered by new-store-only tests in the authstore package and documented there:
- sign_count never REGRESSES on a lower incoming count: the bbolt store stores max(stored, incoming) (CVE-2023-45669 hardening); the SQLite store overwrote unconditionally.
- the CloneWarning flag round-trips: the bbolt store persists it; the SQLite schema has no clone_warning column.
- sessions/OIDC states are empty after a restart: they are ephemeral (in-memory) in the bbolt design; the SQLite store persisted sessions in a table.
Backing-store dependency ¶
The sign_count-durability case needs to survive a simulated process restart, so the suite drives it through a Harness whose Reopen closes the current store and reopens durable state from the SAME backing file. Each engine's test package supplies the Harness; the suite stays engine-agnostic.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Harness ¶
type Harness interface {
// Store returns the live store to exercise.
Store() authlibstore.Composite
// Reopen simulates a process restart: it closes the current store and
// reopens durable state from the same backing file, returning a fresh
// store. Durable records (users, passkeys, API keys) MUST survive; whether
// ephemeral records (sessions, OIDC states) survive is engine-specific and
// is not asserted by the shared suite.
Reopen(t *testing.T) authlibstore.Composite
}
Harness builds AuthStore instances over durable storage that survives a simulated restart, so durability can be asserted engine-agnostically. Each engine's test package implements it: the bbolt store over a real *.bolt file, the SQLite store over a file-backed database.