| name | logging |
| description | Logging discipline for sagent. log.rs is the only logging seam; daemon, auth, source and cache modules surface their events through it. Read when adding log output, touching auth or source error paths, or deciding what may appear in a log line of a secret daemon. |
| paths | ["src/**/*.rs"] |
| disable-model-invocation | true |
logging
Invariant
All daemon logging goes through log() in src/log.rs: one function, it prefixes a Unix timestamp and writes to stderr. The daemon points stderr at a 0600 logfile at startup; in CLI mode stderr is the terminal. No other module calls eprintln! or println! or writes to stderr directly. auth.rs, source.rs, cache.rs, daemon.rs and proto.rs pass their events up as strings or errors; log.rs decides format and sink. That keeps cache and auth logic free of transport decisions, and the sink stays swappable in one place (stderr, syslog, later an audit file).
Falsifiable check:
rg -n 'eprintln!|println!' src/ | rg -v 'src/log.rs|src/main.rs'
Must be empty. Every hit outside log.rs and main.rs breaks the invariant. main.rs may write directly for CLI output (a fetched secret goes to stdout by design) and usage text; the running daemon may not.
[CRITICAL] What is NOT logged
sagent hands out secrets. A secret value, a secret fragment or a reference name must NEVER reach a log line. Not truncated, not inside the debug output of an error. This matches the audit-trail rule in security.md.
SecretBytes (secret.rs) has no Debug/Display that shows the plaintext; it renders [REDACTED]. Check on every change to that type: a derived #[derive(Debug)] on a wrapper holding secret bytes leaks the value.
- Reference names (
op://..., keychain://...) are sensitive metadata and stay out of the log as well. Source names, pids, counters and error texts without reference names are fine.
- Errors from
source.rs (the op and security CLIs) can carry subprocess stderr, and that stderr can contain the requested item path. Reduce it to known fields before logging; never pass the full stderr through blindly.
proto.rs: never log request or response frames as a whole. The response carries the secret. Log the operation and the outcome, not the payload.
When in doubt: log pid, operation, source name and counters; drop names and values.
When to extend this skill
- A new module with logging needs: settle here first what its lines carry, so modules do not invent their own shape.
- A new secret-bearing type: record in the NOT-logged list above how it is redacted.
Verify
cargo fmt -- --check
cargo clippy --all-targets -- -D warnings
cargo test
For logging changes additionally run the invariant check (rg above). After changes to secret.rs check manually that no Debug/Display shows the plaintext.