Compliance Pack
A Compliance Pack is a self-contained ZIP bundle DriftWise produces on demand for SOC 2 Type I / Type II evidence. One click produces a portable artifact your auditor can verify offline — no DriftWise login required for them to review, no screenshot dance, no manual CSV export.
Who it's for
- Compliance leads collecting CC7.x (continuous monitoring) and CC8.x (change management) evidence against the DriftWise-managed control surface.
- Auditors receiving the bundle from the customer and performing walkthrough / evidence inspection.
Plan requirements
| Plan | Availability | Window |
|---|---|---|
| Free | Upsell only | — |
| Team | Included | 30-day window (matches plan retention) |
| Enterprise | Included | Unlimited window |
Free-plan users see an upsell prompt in the Compliance tab. Backend
requests from a Free-plan org return 402 Payment Required with
required_feature: "audit_compliance".
Generating a pack
In the DriftWise UI, navigate to Compliance in the nav rail. Pick a
period_start and period_end (server re-validates against your
plan's retention window), then click Generate Compliance Pack.
Generation is asynchronous. The row appears immediately with status
pending, transitions to running while the worker builds the bundle,
and lands at done when the artifact is ready for download. Expect
10–30 seconds for typical windows; 12-month enterprise exports can
take up to a minute.
You can also generate via API:
curl -X POST "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/audit-exports" \
-H "Authorization: Bearer $OIDC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"period_start": "2026-01-01T00:00:00Z",
"period_end": "2026-04-01T00:00:00Z"
}'
Returns 202 Accepted with the newly-created row. Poll GET /api/v2/orgs/$ORG_ID/audit-exports/$ID until status == "done".
Auth:
POST /audit-exports(generate),GET /audit-exports/:id/download, andDELETE /audit-exports/:idrequire OIDC authentication and owner or admin role. API keys are rejected with403. Compliance-evidence generation, download, and deletion must be attributable to a specific human — the audit log entry records the actor's user UUID.GET /audit-exports(list) andGET /audit-exports/:id(row metadata) accept any org member, including API-key callers. Read- only polling from CI is a supported workflow; the actual bundle bytes are still gated on OIDC owner/admin via/download.
What's in the bundle
compliance-pack-<org-slug>-<period-start>_<period-end>.zip
├── summary.pdf ← cover letter + headline metrics (see note)
├── data.json ← structured JSON of every section
├── coverage_monthly.csv ← per-month drift coverage %
├── findings.csv ← every drift_item in the period
├── scans.csv ← scan cadence record
├── remediation_sla.csv ← average time-to-resolve per risk level
├── custom_rules.csv ← custom detection rules at period end
├── state_sources.csv ← Terraform state sources at period end
├── chain-attestation.json ← verifiable audit-log chain snapshot
├── AUDIT_LOG_VERIFY.md ← auditor's walkthrough
└── MANIFEST.txt ← SHA-256 of every other entry
summary.pdf is emitted when the drift-worker has PDF rendering enabled
(DRIFTWISE_PDF_ENABLED=true, which is required in production and enforced
at boot). Local-dev or test deployments without Chromium omit the PDF; every
other entry — including the CSVs, data.json, chain-attestation.json, and
MANIFEST.txt — still ships, and MANIFEST.txt reflects exactly the set of
files present.
Integrity verification
The bundle is designed to be verifiable without DriftWise assistance:
unzip compliance-pack-acme-2026-01-01_2026-04-01.zip -d bundle/
cd bundle
shasum -a 256 -c MANIFEST.txt
Every line prints OK when the bundle is intact. A FAILED line means
a file was modified after bundle creation — either in transit or
locally. Re-download from DriftWise and compare.
Chain attestation
chain-attestation.json captures the audit-log chain state at bundle
generation time — head_seq, head_hash_hex, and the chain verify
status. An auditor independently re-runs
the verify endpoint and checks that:
response.status == "ok"response.head_seq >= attestation.head_seq(chain only grows)- If equal, hashes match byte-for-byte
See AUDIT_LOG_VERIFY.md inside the ZIP for the copy-paste walkthrough.
What this proves — and what it doesn't. The attestation ties the
bundle to the org's live audit-log chain: when the auditor re-runs
/verify, a matching head_hash at equal head_seq shows the
server's chain state at generation time was authentic. Bundle files
(PDF, CSVs, data.json) are tied to each other through MANIFEST.txt
SHA-256s, so tampering with one file without re-running shasum -c
is detectable. The bundle is NOT offline-tamper-evident on its own —
it is not cryptographically signed, so the live /verify round-trip
is load-bearing. Don't treat an unchecked bundle as proof; the
trust chain is bundle + live verify = evidence.
Audit log events
Every lifecycle transition emits a row to admin_audit_log, and those
rows themselves are part of the hash chain the attestation covers:
| Action | When | Detail |
|---|---|---|
audit_export.requested | POST /audit-exports succeeded | { "export_id": "..." } |
audit_export.downloaded | GET /download succeeded | { "export_id": "...", "bytes": N } |
audit_export.deleted | DELETE succeeded | { "export_id": "..." } |
Query them via the audit log endpoint.
Rate limit
Per-org: 5 Compliance Packs / rolling 24h. Exceeding the limit
returns 429 Too Many Requests with retry_after in the body. The
limit exists to cap worst-case Chromium + storage cost; typical
auditor workflows generate 1–3 packs per audit cycle.
Retention
Artifacts live in storage for 90 days after the enqueue (request)
timestamp — expires_at is stamped at request time, not at
finished_at. In practice jobs finish in seconds, so the difference
is negligible; the clock starts when you click Generate. After 90 days
the scheduler GC job deletes the ZIP and transitions the row to
status: "expired". The row itself remains for historical reference;
re-generate to download again.
What's NOT included (intentional)
- Login / sign-in events. DriftWise delegates authentication to
Casdoor; login-level telemetry is outside the
admin_audit_logboundary by design. Your Casdoor or SAML IdP is the authoritative source for session records. - SCIM provisioning events. Event names (
scim.user.provisioned, etc.) are reserved in the audit catalog, but emission from the Casdoor webhook activates only for orgs with SCIM configured. If your org doesn't use SCIM, these events never fire — which is correct, not a gap.
The summary.pdf cover letter names both exclusions explicitly so an
auditor doesn't expect them and then find them missing.
Frameworks
The v1 bundle positions as SOC 2 CC7/CC8 evidence. Most controls map naturally because the underlying data (drift snapshots, scan runs, audit log, custom rules) is what SOC 2 auditors actually ask for:
- CC7.1 / CC7.2 (system monitoring) →
scans.csv,coverage_monthly.csv,state_sources.csv - CC7.3 (incident handling) →
findings.csvresolutioncolumn,remediation_sla.csv - CC8.1 (change management authorization) → audit log excerpt via the tamper-evident chain
- CC8.1 (change management monitoring) →
findings.csv,custom_rules.csv
Cross-framework mapping (ISO 27001, PCI DSS, HIPAA, CIS) is on the roadmap — see the export plan for details.
See also
- Audit Logs — the underlying hash-chained log the bundle's attestation covers.
- Plans & Billing — plan comparison including Compliance Pack availability.