Raxx · internal docs

internal · gated ↑ index

ADR 0002 — No Stored Credentials (Enforcement)

Status: Accepted Date: 2026-04-21 Deciders: product owner (user), software-architect Related: ADR 0001, docs/architecture/auth.md

Context

Invariant: the backend must never store a credential it could replay. ADR 0001 picks passkeys as the auth factor, which makes compliance possible (public keys are not credentials). This ADR is about how we enforce that the invariant is never quietly violated by a future commit — a well-meaning "just add a backup password column" PR, or a migration that re-introduces a secret field under a harmless name.

We need the invariant to be defended at three levels: schema, code, and CI.

Decision

Enforcement is layered — defense in depth. A single layer is insufficient; all three ship together.

1. Schema-level

2. Code-level

3. CI-level

Consequences

Positive

Negative

Alternatives considered

Schema-only enforcement

Rejected. A migration is a fleeting moment in review; a CI grep is running continuously.

Database-level users/roles (revoke CREATE on password-like columns)

Rejected as primary mechanism. SQLite doesn't really support this, and we don't want the enforcement to vanish when we switch DB engines.

Pre-commit hook only

Rejected as sole mechanism; accepted as an additional layer. Pre-commit hooks can be bypassed locally, CI cannot.

Runtime assertion

Rejected as primary. Catching at runtime means the bad code shipped. CI-time is preferable.

Compliance checklist

Revisit when