Cette page n'est publiée qu'en anglais. Le texte anglais fait foi : une traduction automatique d'un engagement contractuel n'est pas un engagement contractuel, et nous ne la présenterons pas comme si un avocat l'avait examinée.
Compliance
The homepage says “audit trail — built in.” This page is what that sentence has to survive: the actual mechanism, the actual code, and a tool an auditor can run without asking us to trust a dashboard.
The audit record: hash-chained, on by default
Every audit event Odysseus writes is chained to the one before it. Each row stores entry_hash = SHA-256(prev_hash || canonical_json(event)), so altering or deleting a row breaks the hash of everything written after it — not just that row.
This is not an opt-in feature you have to remember to turn on. HashChainConfig's own doc comment states it plainly: “The chain is ENABLED BY DEFAULT — the zero value (Disabled: false) … omits the HashChain block gets tamper-evident audit at no extra” configuration step (pkg/audit/hash_chain.go:19-23). The control plane announces it at boot: “Audit hash chain enabled (default-on; set HashChain.Disabled=true to opt out)” (pkg/audit/postgres_logger.go:247). Turning it off is a deliberate, logged action, not a default you have to discover.
Anchoring and an external witness — both optional, both pluggable
On top of the chain, Odysseus can periodically anchor a hash to two places you don't have to trust us for:
- Vault Transit signing. When
HashChainConfig.VaultTransitKeyis set, each anchor's entry hash is signed via Vault'stransit/sign/{key}endpoint before it is stored (pkg/audit/hash_chain.go:43-46,pkg/audit/postgres_logger.go:850-861). Leave the key unset and no signing happens — it is opt-in, not a hidden dependency. - An external witness. The anchor publisher accepts any witness that implements a small interface — Consul KV, an S3 WORM bucket, or another store of your choosing — and mirrors the anchor there after it is durably written locally. A
nilwitness simply disables external mirroring; nothing about local integrity depends on it (pkg/audit/hash_chain.go:51-56,pkg/audit/postgres_logger.go:863-889).
A tool, not a screenshot
odysseus-audit-verify is a standalone binary — its own main package at cmd/odysseus-audit-verify/main.go, built and shipped separately from the control plane. Give it credentials for the audit database and it walks every row in sequence_num order, recomputes each hash, and cross-checks every anchor. It does not go through the Odysseus API, the dashboard, or anything the platform itself renders. It connects directly to Postgres, so it is not a zero-network tool, but it is independent of the running control plane: an auditor can point it at a database replica and get an answer nobody at Delta Telematics can shape.
It reports a distinct exit code for each class of problem, documented in the binary's own header comment:
| Exit code | Meaning |
|---|---|
0 | Chain intact, all anchors match |
1 | Chain integrity defect — broken link, mismatched hash, missing entry |
2 | Anchor verification failure — anchor hash mismatch or bad signature |
3 | Operational error — database unreachable, malformed row, etc. |
Source: cmd/odysseus-audit-verify/main.go, lines 12–18 (documented behavior) and 56–59 (the exit-code constants themselves).
Tenant isolation the database enforces, not just the application
Three separate boundaries, each independently checkable in code:
- Postgres row-level security, fail-closed. The audit table runs with both
ENABLE ROW LEVEL SECURITYandFORCE ROW LEVEL SECURITYset — a dedicated test asserts both aretrueand explains why: without them, “every test here would pass while tenants read each other's audit trail” (pkg/audit/postgres_rls_test.go:197). If the tenant security context can't be set for a query, the query does not run — the code path is labelled// Fail-closed: if we can't set RLS context, don't proceed with the query(pkg/audit/postgres_logger.go:1067). - Per-tenant Vault paths. Every tenant's secrets live under
tenants/<tenantID>/, and path validation rejects anything outside that prefix (pkg/vault/validation.go:25,51,61). - Per-tenant Docker networks. Internal networks are named
<tenantID>-<network>, and a tenant's default network isodysseus-<tenantID>-default— there is no shared internal network a tenant's containers land on by default (pkg/docker/client.go:1647-1652,1697-1700).
Where we actually stand
We do not hold a certification, and we don't imply one. What we do have is a documented, self-assessed mapping of our controls against five frameworks, carried in the security team's own audit document rather than in marketing copy:
| Framework | Internal readiness | Notes |
|---|---|---|
| SOC 2 Type II | 85% | Access control, audit logging |
| ISO 27001 | 80% | Information security controls |
| GDPR | 75% | Data protection controls |
| PCI DSS | 70% | Not handling payment data |
| HIPAA | 60% | Not our primary use case |
Source: docs/security/02-owasp-security-audit.md, “Compliance Mapping” table, lines 490–498.
These are self-assessed readiness percentages, not audit results from an accredited third party. We say so on the pricing page too: the wording there is “SOC 2- and ITSG-33-aligned controls and audit evidence,” not compliance itself — a wording change made specifically because no certification exists. If that changes, this page will name the certifying body and the date; until it does, treat every percentage above as our own homework, not an external attestation.
For the audit that produced the security posture these controls sit on, see the security audit page. For the day-to-day security architecture — authentication, secrets, infrastructure hardening — see Security.
How these numbers and claims were arrived at
- Every claim on this page was checked directly against the source at the file and line cited beside it, on 21 August 2026, rather than taken from an earlier description of the feature. Where a mechanism is optional (Vault Transit signing, the external witness), we say so explicitly rather than letting the surrounding sentence imply it always runs.
- The offline verifier's independence from the control plane is a real property — it is a separate binary that talks to Postgres directly — but it is not a zero-dependency tool: it still needs credentials and network access to the audit database (or a replica of it). We describe it that way rather than as fully offline.
- The compliance percentages are our own internal self-assessment, dated to the document that carries them, not a claim of certification by any outside body. If that document is revised, this table goes stale until it is re-checked against the new version.