Docs / Trust & compliance
Audit trail
Planned design. TractorStack is in development. This page describes how it is designed to work; nothing here is available to install yet. See the roadmap for the status of each part.
In design The approach below is the current design and may change before the first release.
Audit logging for infrastructure changes in TractorStack is mostly a side effect of how changes are made. Every change starts as a commit, is approved in a GitLab merge request and is applied by a GitLab CI pipeline on the site runner. Each of those steps already leaves a record. The design keeps those records together, keeps them long enough, and makes them hard to edit after the fact.
Audit logging: where the records come from
| Source | What it records |
|---|---|
| Git history | Who wrote each change, what changed line by line, and when it was committed |
| Merge request approvals | Who reviewed it, who approved it under the project’s approval rules, and the discussion before it merged |
| GitLab CI pipeline logs | The plan or check output, the exact commit applied, start and end time, and the result |
| Routine checks | Drift results, restore tests and certificate checks, with dates |
| Argo CD history | From stage 3, which commit each Kubernetes application was synced to, and when |
Put together, they answer the questions an auditor or an incident review usually asks: who changed this firewall rule, who approved it, when did it go live, and was the system checked afterwards? See Change requests & sign-off for how approvals are planned to work.
Linking the records
Each run is planned to record the commit it applied and the merge request it came from, and to store that summary in PostgreSQL alongside the full log. From any run you can find the approval; from any commit you can find every run that applied it.
# planned example: one run record
run: 2026-11-03T02:14Z env: production site: site-a
commit: 4f2c9e1 merge request: !212 approved by: j.rai
action: ansible apply result: success log: runs/4f2c9e1.log
Retention
How long to keep records is a customer decision, driven by contracts and regulation. The design keeps Git history for the life of the repository, and run logs and check results in PostgreSQL and RustFS for an agreed period written into the repository. Audit records are backed up with everything else, and the restore tests are planned to check that they come back too.
Tamper resistance
An audit log that an admin can quietly edit proves little. The measures we plan:
- Protected branches. In GitLab the main branch is protected: it cannot be force-pushed or rewritten, and merges require the approvals the project’s rules ask for.
- Signed commits where the customer wants them, so authorship can be checked.
- Write-once storage for run logs. Logs are copied to a RustFS bucket with object lock, so they cannot be changed or deleted before their retention ends, even by an admin. See RustFS.
- Copies outside the site along with off-site backups, so losing the server doesn’t lose the history.
What the audit trail does not cover
Being clear about the gaps matters as much as the coverage:
- Changes made by hand. If someone logs in and edits a server directly, GitLab knows nothing about it. Nightly drift checks find the effect within a day, but not who did it. Host logs and
sudorecords, sent to central logging, are where that answer comes from. - What applications do with data. Application-level audit logs, such as who viewed a customer record, belong to the application.
- Reads of secrets when using SOPS. A secrets service such as OpenBao or Vault logs reads; encrypted files in Git do not. See Secrets & credentials.
The audit trail is also the raw material for evidence packs, which we are exploring for compliance work.
Last updated 25 October 2026 · Questions or corrections: sales@infratractor.com