Server (harnessd)

Audit log

What harnessd records, the format of each record, and how to check that nobody has edited or deleted entries.

harnessd keeps an append-only, hash-chained audit log at data_dir/audit/audit.jsonl (mode 0600). It records sign-ins, denials, every write action, account changes from the CLI, agent tool calls and run outcomes. Each record includes the hash of the one before it, so editing or deleting any line breaks the chain.

Verify the chain#

Shell
sudo -u harness harnessd audit verify --config /etc/harness/harnessd.yaml
# ok: 18342 record(s), hash chain intact

If a line was changed, removed or reordered, the command exits with an error naming the first broken line:

TEXT
harnessd: audit chain broken at line 912 of 18342

Run it from a cron job or your monitoring, and ship the file to your log store if you want an off-host copy.

Record format#

One JSON object per line:

JSON
{"action":"login","actor":"user:maria","detail":{"role":"operator"},"hash":"9c1f…","ip":"10.8.0.31","outcome":"completed","prev":"4b7e…","ts":"2026-11-06T09:14:03Z"}
FieldDescription
tsISO 8601 time
actorWho: user:<name>, anonymous, cli, system, orchestrator or agent:<task>
actionWhat, for example login, secret_set, POST /api/v1/refresh
outcomecompleted, or why it didn't happen
ipThe client's address, when there is one
detailExtra fields: names (never values), project, role, and so on
prevThe previous record's hash (64 zeros for the first)
hashSHA-256 of prev followed by the record without hash

What's recorded#

ActorActions
systemstartup (with the listen address and whether TLS is on), shutdown
anonymousRequests without a valid session (unauthenticated), requests from a browser origin (denied_origin)
user:<name>login and logout; every non-GET request as <METHOD> <path> with completed, failed_<status> or forbidden (with the role and the role required); secret_set, secret_remove, login_set, login_remove, settings_change (sections, reset sections, variable names set and removed), container_stop, image_build_start, workspace_remove, project_add, project_remove; wrong step-up codes (bad_totp)
cliuser_add, user_passwd, user_totp_enable, user_totp_disable, user_disable, user_enable, user_remove
orchestratorrun_finished, with the project, task, outcome, tokens and seconds
agent:<task>tool_call, with the tool name and whether it succeeded

Sign-in outcomes:

OutcomeMeaning
completedSigned in
bad_credentialsUnknown user or wrong password (indistinguishable to the client)
totp_requiredRight password, no code sent
bad_totpWrong or reused code
totp_not_enrolledAn admin without TOTP while require_totp_for_admins is on
locked_outThe account or IP is locked

Other logs#

The audit log is for security events. Operational logs (key=value lines like the app's Activity screen) go to standard error, which systemd sends to the journal:

Shell
journalctl -u harnessd -f

Per-project logs and raw agent streams are under data_dir/logs/.

See also#