Repository navigation
Description
Context
Once Waymark answers other people over the network, an admin must be able to answer "who read this document?", "which token was used from where?" and "who wrote this note?". This issue adds an append-only audit log and a CLI to read it. Producers are added by later issues (#95, #96, epic #19); this issue defines the format, the writer and the admin commands, and logs the account changes from #93.
Part of epic #18. Depends on #93.
Goal
Every security-relevant event is appended as one JSON line to a monthly file under $WAYMARK_HOME/audit/, and waymark audit filters and prints it.
Evidence
- OWASP Logging Cheat Sheet: when / where / who / what fields (timestamp, source address, user identity, event type, action, object, result status, reason); never log tokens, passwords, keys or connection strings (verified 2026-11-01): https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html
- OWASP REST Security: write audit logs before and after security events, log token validation failures, sanitise against log injection (verified 2026-11-01): https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html
- JSON Lines format: https://jsonlines.org/
- Dates are ISO 8601 UTC (
AGENTS.md).
Exact decisions
Storage
$WAYMARK_HOME/audit/YYYY-MM.jsonl(UTC month), created with0o600/ directory0o700where supported. Append-only: the writer only opens with append; nothing in Waymark rewrites or deletes these files. Retention is the admin's job (documented).- One event = one line of JSON, written synchronously enough that an event logged before a response is on disk before the response is sent (a crash may lose at most the line being written).
Event shape
{ "at": "2026-11-01T12:00:00.000Z", "event": "search", "outcome": "ok", "user": "alan", "tokenId": "tok_1a2b3c4d", "via": "mcp-http", "ip": "10.0.0.5", "object": null, "detail": { "query": "why sqlite", "results": 7 } }event(closed list, extended by later issues):auth.denied,user.created,user.updated,user.linked,user.unlinked,token.created,token.revoked,search,document.read,note.saved,handoff.created,handoff.claimed,session.saved,bot.ask.outcome:ok|denied|error.via:cli|mcp-http|api|bot:<platform>.object: doc id or user/token id when relevant.user= Waymark user name orownerfor local CLI actions;iponly for network requests.detail: event-specific, small. Search query text is logged only when configaudit.queriesistrue(defaultfalse); otherwisedetail.queryChars(length) is logged instead. Never tokens, hashes, request bodies or document text. All strings pass throughredact()and control characters are escaped (log injection).auth.denieddetail:reason(missing|invalid|expired|revoked|disabled|forbidden) and the token id when known; never the presented token.
Who logs in this issue
The #93 CLI commands (user …, token …) log their events with via: cli, user: owner. Read/write events over the network are added by #95/#96; local CLI search/show are not logged (owner reading their own files).
waymark audit
waymark audit [--since <ISO or Nd>] [--until <ISO>] [--user <name>] [--event <e>]... [--outcome ok|denied|error] [--limit <n, default 100>] [--json]
- Reads only the monthly files overlapping the range, newest first.
- Text line:
2026-11-01 12:00:00Z search ok alan mcp-http 10.0.0.5 "why sqlite" (7 results)(one compact summary per event type; unknown types printdetailas JSON). --jsonprints matching events as JSON Lines.- Malformed lines are skipped with one stderr warning per file.
Docs
docs/server.md "Audit log": location, fields, privacy switch audit.queries, retention advice, example jq queries.
Acceptance criteria
- Writing events produces valid JSONL in the right monthly file (fixed clock in tests across a month boundary).
-
audit.queries: false→ no query text in the file, only its length;true→ redacted query text. - A token-like string or control characters in a detail field are redacted/escaped (test).
- ADR-0003 team server model + users, groups, linked identities and API tokens #93 commands emit their events.
-
waymark auditfilters by since/user/event/outcome and limit; text and JSON formats tested. -
npm run checkpasses.
Out of scope
Shipping logs to SIEM/syslog (users can tail the files), tamper-evidence (hash chains), log rotation by size.
Activity