3.4 KiB
3.4 KiB
Quality gates — roles and rights
LLM-verified gates for architecture/roles-auth.md. Automatic tests
live in crabidy-server/src/auth.rs, crabidy-server/src/main.rs
(hash helper) and cbd-tui/src/rpc.rs.
Security posture
- Fail-closed everywhere: an unknown/future gRPC method requires
owner; a present-but-malformed
crabidy-server.tomlaborts server startup instead of silently running open; a missing file (or empty[auth]) is the documented open mode. - Guarding order enforced: valid guarded sets are prefixes of
[owner, queue_owner, queue_appender]. A config guarding a lower role while a higher one is open (queue_ownerwithoutowner, orqueue_appenderwithoutqueue_owner) aborts startup, andcrabidy-server guardrefuses to write it. - A present-but-wrong credential is denied (
UNAUTHENTICATED), never silently downgraded to the anonymous role. - No panics on request input: malformed
authorizationheaders (bad base64, missing colon, non-UTF-8, wrong scheme), unknown role names, and oversized values all produceUNAUTHENTICATED, never a panic. - Indistinguishable failures: wrong user and wrong password both
answer plain
UNAUTHENTICATEDwith the same message. - Secrets redacted: passwords, authorization header values, and
PHC hashes never appear in logs, traces, or error messages
(including the
hash-passwordhelper and TUI logs). - Authorization is enforced in exactly one place (the tower layer), before any handler runs; RPC handlers did not change.
Semantics
- Rights matrix implemented as specified: appender = reads +
Append+CreateLibraryNode; queue-owner adds every queue and playback verb; owner-only =CaptureLibraryNode,SaveQueue,RenameLibraryNode,DeleteLibraryNode. Higher roles include lower ones. A test pins the full method list of the proto service so an unmapped new RPC fails the suite. - A caller (anonymous or credentialed) below a method's minimum
role gets
PERMISSION_DENIED(notUNAUTHENTICATED). - Anonymous callers inherit the highest unguarded role: nothing
guarded ⇒ owner (today's open server);
ownerguarded ⇒ queue-owner;owner+queue_ownerguarded ⇒ queue-appender; all guarded ⇒ nothing (UNAUTHENTICATED). A credential elevates above that floor. - No
[auth]hashes ⇒ exactly today's behavior: no header required, all methods allowed. - A role without a configured hash cannot authenticate (a login attempt as it is denied; anonymous callers may still inherit it).
Performance
- Argon2 verification runs once per credential: successful verifications are cached (header value → role) and the cache is only fed by successes, keeping it bounded by the number of valid credentials.
Client
- Without configured credentials the TUI sends no header
(zero-config local use unchanged); with credentials, every
request — including update-stream reconnects — carries the same
authorization: Basicheader. - The client config documents that
passwordis plaintext and the file must be kept private.
Tooling
crabidy-server hash-passwordreads the password from stdin (nothing echoed by the tool itself), prints only the PHC string, and its output verifies against the same server code path.