Docs · reference
Compliance reference — SOC 2 scope, RBAC, audit trail, SBOM, signing, retention.
The six sections a security reviewer reads end to end on audit day. SOC 2 Type I scope plus the Type II continuous-operation roadmap, six roles × eleven actions grant matrix, the seven columns a merge audit-trail row carries, the SPDX 2.3 document emitted per merged PR and where it lands, the cosign ECDSA P-256 signing identity — KMS-resident by default, HSM on Enterprise — the data-retention windows per class in one table, and the four commands a reviewer runs against any signature.
SOC 2 roadmap
Type I certified · Type II in window
Four phases (readiness · Type I · Type II observation window · Type II report) across all five Trust Services Criteria — the artefact your regulator asks for in the second meeting.
RBAC + merge audit trail
Six roles, eleven actions, seven columns
admin · security-reviewer · operator · watcher-bot · sandbox-runner · signing-controller — grant matrix with approval-required cells surfaced explicitly. Audit-trail row carries alert, triage, drafted-fix, sandboxed-test, approver-chain, signed-commit, sbom.
SBOM + signing + retention
SPDX, cosign ECDSA P-256, per-class windows
SPDX 2.3 emitted per merged PR, signed by the KMS-resident SBOM key (HSM on Enterprise), KMS-managed 90-day rotation on the commit-signer key. Retention table covers audit trail · SBOM · signed commits · Rekor log · CMK — one glance, no paging past SBOM.
SOC 2 Type I · Type II · rbac · audit trail · sbom (SPDX) · cosign ECDSA P-256 · KMS-resident · HSM on Enterprise · retention per class
SOC 2 roadmap
Type I certified · Type II on schedule.
The compliance-record view of Driftlock's SOC 2 posture — the four phases a regulator reads on a single page, scoped to the controls operating in production. The narrative lives on /security#soc2; this block is the auditable record (firm, observation window, target report month) for the same controls.
Phase
Status
Scope
Framework anchor
phase readiness
Readiness & gap assessment
CompleteInternal controls mapping against the Trust Services Criteria (CC, A, C, PI). Risk register, control owners, evidence capture. Closed before audit kick-off.
framework
TSC · CC1–CC9 · AICPA 2017 (revised 2022)
phase type-i
SOC 2 Type I report
CertifiedAuditor attestation that control design is suitably designed and operational at a point in time — the artefact a buyer requests most often.
framework
Type I · point-in-time design attestation
phase type-ii-window
SOC 2 Type II observation window
In progressTwelve-month continuous-operation evidence across all five Trust Services Criteria — production traffic, every egress boundary, every signed artefact. Reviewed quarterly with the auditor.
framework
Type II · observation window · quarterly checkpoints
phase type-ii
SOC 2 Type II report
On scheduleAuditor attestation that controls operated effectively throughout the observation window. Refreshed annually; the previous report stays available as a historical reference.
framework
Type II · continuous-operation attestation · annual refresh
Auditor · window · target
- auditor of record
- Independent CPA firm · AICPA SOC 2 (revised 2022) engagement
- Type II observation window starts
- 2025-08-01
- Type II report target
- 2026-08
SOC 2 Type I · Type II observation window · all five TSC · four phases · continuous-operation attestation
RBAC matrix
Six roles, eleven actions — one grant per cell.
The platform team owns one .driftlock/config.yaml with a rbac: block. Every row in the matrix below is one grant the platform team sets; every DENY is a hard deny — no implicit promotion from AUDIT-ONLY to ALLOW at runtime. Approval-required cells surface a ' + sign-off ' tag — the runtime enforces a dual-sign-off gate before the grant executes.
human
admin
Owns the platform: installs the chart, rotates KMS keys, holds the root Rekor policy. Custody refuses any delegation to reviewers or operators.
human
security reviewer
Read-only access to the audit trail + SBOM registry, sign-off on approver-chain edits, query the Rekor log. Cannot mutate chart values or rotate keys.
human
operator
Day-to-day helm upgrades, sandbox knob diffs, retention-tier changes. Every action lands an approver-chain row signed by the actor.
automation
watcher (bot)
Ingests inbound webhooks from the GitHub App + CI + dependency feeds; correlates signals against alerts and advisories. Cannot sign or approve.
workload
sandbox runner (workload)
Executes hermetic runs under the assigned toolchain; emits SBOMs and Rekor claims. Cannot mutate the chart or the RBAC matrix itself.
workload
signing controller (workload)
Reads the cosign commitment, fetches an OIDC token, stamps the Driftlock-attributed commit. Single-writer; signer_kid + Rekor uuid chain to the prior emission.
admin · security-reviewer · operator · watcher-bot · sandbox-runner · signing-controller
Action · risk
admin
security reviewer
operator
watcher (bot)
sandbox runner (workload)
signing controller (workload)
chart.install
risk · high
helm install driftlock (first install on a fresh namespace).
+ sign-off
chart.upgrade
risk · high
helm upgrade driftlock (rolling, blue/green, or rollback).
+ sign-off
kms.rotate
risk · high
Rotate the KMS-resident commit-signer or SBOM-signer key.
rbac.set
risk · high
Edit .driftlock/config.yaml `rbac:` grants.
egress.set
risk · medium
Add / remove CIDRs from `driftlock.egress.allowed`.
+ sign-off
retention.set
risk · medium
Bump a hot/cold tier window on the audit trail row.
+ sign-off
sign.commit
risk · high
Stamp the cosign signature on a merged PR.
approver.signoff
risk · medium
Approve / request-changes on a merged PR (lands in approver-chain).
audit.read
risk · low
Read the merge audit-trail log + the Rekor transparency log.
sbom.read
risk · low
Pull a SBOM document from the registry, verify the cosign signature.
sbom.emit
risk · medium
Generate the CycloneDX/SPDX document and write it (signed) to the registry.
RBAC block — .driftlock/config.yaml snippet
The block below is the canonical RBAC surface a platform team commits to their chart repo. The matrix above is the same data, declared oracle- side and enforced at the watcher / signing-controller tier. Copy it, set the role members, commit it to the chart repo, hand the diff to your compliance alongside the audit-trail retention window.
# .driftlock/config.yaml — RBAC surface the platform team owns.
# The matrix below locks down: admin grants every high-risk action,
# security-reviewer gets read + sign-off only, operator gets helm + knob
# diffs only, and bots / workloads are scoped to the action they were
# written for. Every deny is hard — no implicit allow.
rbac:
version: 1
roles:
- id: role-admin
identity: human
members:
- github:acme/platform-team
- email:platform@acme.example
- id: role-security-reviewer
identity: human
members:
- github:acme/security-team
- email:security@acme.example
- id: role-operator
identity: human
members:
- github:acme/sre-on-call
- id: role-watcher-bot
identity: automation
members:
- spiffe:spiffe://acme.example/ns/driftlock/sa/watcher
- id: role-sandbox-runner
identity: workload
members:
- spiffe:spiffe://acme.example/ns/driftlock/sa/sandbox-runner
- id: role-signing-controller
identity: workload
members:
- spiffe:spiffe://acme.example/ns/driftlock/sa/signing-controller
grants:
- role: role-admin
actions: [chart.install, chart.upgrade, kms.rotate, rbac.set,
egress.set, retention.set, sign.commit,
approver.signoff, audit.read, sbom.read, sbom.emit]
approval: none
- role: role-security-reviewer
actions: [audit.read, sbom.read, approver.signoff]
approval: none
- role: role-operator
actions: [chart.install, chart.upgrade, egress.set,
retention.set, approver.signoff, audit.read, sbom.read]
approval: dual # two-person rule — two operators sign
- role: role-watcher-bot
actions: [audit.read, sbom.read]
approval: none
- role: role-sandbox-runner
actions: [audit.read, sbom.read, sbom.emit]
approval: none
- role: role-signing-controller
actions: [audit.read, sbom.read, sign.commit]
approval: none
deny_overrides:
# Hard deny on the key-rotation path for every non-admin identity.
- action: kms.rotate
except_roles: [role-admin]
# Bots / workloads cannot mutate anything they don't already own.
- action: rbac.set
except_roles: [role-admin]
six roles · eleven actions · deny override · dual sign-off
Merge audit trail
Seven columns a per-PR row carries — append-only, Rekor-anchored.
Every merged PR produces one audit row. The watcher's seven columns match the governance vocabulary on /governance so a tightening reviewer moves between the explainer and this deep-dive without re-aligning vocabulary. Retention is 7 years hot, 10 years cold, plus an indefinite Rekor-logged pin on the signature + SBOM rows.
Field · id
Recorded
Retention
alert
Trigger source
The originating signal — Dependabot advisory GUID, CI job URL, on-call incident id, or NVD / OSV / GHSA record pulled into the watcher. Pinned to the per-PR row by `alert_id`.
7 years hot · 10 years cold
triage
Triage record
Reachability call + call-graph path + the rule the watcher applied to mark the diff in-scope. Stored alongside the alert id that was triaged.
7 years hot · 10 years cold
drafted-fix
Diff
The exact patch proposed — bytes-stable, byte-identical across reruns, pinned to the sandbox run id that produced it.
7 years hot · 10 years cold
sandboxed-test
Sandbox test results
Toolchain identity + hermetic-build hash + the failing test that triggered the run + the full sandbox log. Verifiable by replaying the run id.
7 years hot · 10 years cold
approver-chain
Approver chain
Every reviewer who comments, approves, requests changes, or merges — GitHub identity + ISO-8601 timestamp + the review verdict, signed at each handoff.
7 years hot · 10 years cold
signed-commit
Signature
Cosign / Sigstore signature over the commit + the Rekor transparency-log entry + the OIDC claim payload tying the signature to the sandbox run.
Indefinite · Rekor-logged
sbom
SBOM hash
SHA-256 of the SPDX document emitted in the same run + the cosign signature over the SBOM itself, so the audit revision and the SBOM hash diff together.
10 years hot · indefinite cold
alert · triage · drafted-fix · sandboxed-test · approver-chain · signed-commit · sbom
Immutability + retention
- format
- Append-only signed JSONL · one row per merged PR · SHA-256 line-anchored
- immutability
- Append-only log (no UPDATE / DELETE on the row table) + per-row HMAC chained to the previous row + a Rekor transparency entry that includes the row SHA-256. Rewriting a row invalidates the chain + breaks the Rekor inclusion.
- retention window
- 7 years hot · 10 years cold · indefinite Rekor-logged
Sample row — one merged PR
The block below is the row shape a tightening reviewer diffs against any merged PR. The signed_commit and sbom sub-objects anchor the row to the Rekor transparency log — rewriting either field invalidates the row SHA-256 the Rekor entry references.
{
"pr_id": "acme/checkout-svc#4215",
"head_sha": "8f6c1d5b9c2f6c1d5b9c2f6c1d5b9c2f6c1d5b9c",
"run_id": "driftlock-run-2026-08-08-7421",
"alert": {
"id": "GHSA-xxxx-yyyy-zzzz",
"source": "GHSA",
"cve": "CVE-2026-9999",
"ingested_at": "2026-08-08T11:23:14Z"
},
"triage": {
"reachable": true,
"call_graph": ["api/users", "middleware/audit"],
"rule_id": "deps.reachable.npm.lodash"
},
"drafted_fix": {
"patch_sha256": "7a4b…",
"bytes_stable": true,
"pinned_to_run_id": "driftlock-run-2026-08-08-7421"
},
"sandboxed_test": {
"toolchain_identity": "nix:node-22",
"hermetic_build_hash": "9e2f…",
"failing_test": "test/checkout/refund.round_trip",
"replay_status": "REPLAYED_OK",
"log_ref": "/var/lib/driftlock/runs/7421/sandbox.log"
},
"approver_chain": [
{ "actor": "ren-bot[bot]", "verdict": "merge", "ts": "2026-08-08T13:01:22Z" },
{ "actor": "alex@acme", "verdict": "approve","ts": "2026-08-08T13:08:55Z" },
{ "actor": "security@acme", "verdict": "approve","ts": "2026-08-08T13:15:40Z" }
],
"signed_commit": {
"cosign_signature_sha256": "c1d2…",
"rekor_uuid": "rekor.driftlock.dev/entries/242a8c…",
"oidc_claim": {
"iss": "https://oidc.acme.example",
"sub": "spiffe://acme.example/ns/driftlock/sa/signing-controller",
"aud": "driftlock",
"claim_payload": ["run_id", "sbom_sha256", "approver_chain_root"]
}
},
"sbom": {
"format": "SPDX-2.3",
"sha256": "3f6e…",
"cosign_signature_sha256": "b4a1…",
"registry_path": "registry.internal/acme/checkout-svc/sha256:3f6e…"
}
}append-only · HMAC-chained · Rekor-anchored · 7y hot / 10y cold
SBOM emission per merged PR
SPDX 2.3 emitted per merged PR — content-addressed, cosign-signed.
Every merged PR that touches a dependency boundary emits one SBOM. The compliance record prefers SPDX 2.3 (JSON) for the ingest dependencies — deps.dev, Dependency-Track, internal compliance dashboards. CycloneDX 1.5 is kept alongside for the SBOM-driven vulnerability scanner side (Grype et al.) so a single emission covers both surfaces without transformation.
Surface
Notes
preferred format
SPDX 2.3 · JSON (preferred for compliance-tooling ingest)
Compliance tooling reads SPDX natively — no transformation layer.
fallback format
CycloneDX 1.5 · JSON + XML (kept for SBOM-driven vuln scanners)
SBOM-driven vulnerability scanners (Grype, Dependency-Track).
trigger
Every PR that touches a dependency boundary — lockfile, manifest, vendor path, or a base image bump in .driftlock/config.yaml sbom.track.
registry path
registry.internal/<org>/<repo>/spdx/<sbom_sha256>.spdx.json — content-addressed, immutable, retention-pinned 10 years.
Content-addressed — the SBOM sha256 is in the path; rewrites are detectable by hash mismatch.
attestation
cosign sign-blob over the SBOM document keyed by driftlock/sbom-signer; the signature sits in registry.internal/.../sbom/<sbom_sha256>.bundle and the Rekor inclusion claim carries the SBOM sha256 + the run id alongside the commit claim.
ingest targets
- deps.dev · supplier risk and dependency graph
- Dependency-Track · SBOM-driven vulnerability triage
- Grype · container and repository vulnerability scan
- internal compliance dashboards · pull directly from the registry
Sample SPDX 2.3 JSON
The block below is the SPDX 2.3 document emitted for one merged PR. The documentNamespace carries the SBOM sha256 in its path; the package checksums array signs the head SHA off. Reader tooling diffs the SPDX sha256 against the sbom field on the audit-trail row.
{
"SPDXID": "SPDXRef-DOCUMENT",
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "acme/checkout-svc",
"documentNamespace": "https://registry.internal/acme/checkout-svc/spdx/3f6e…",
"creationInfo": {
"created": "2026-08-08T13:21:02Z",
"creators": ["Tool: driftlock-sbom-emitter-vX.Y.Z",
"Organization: acme"]
},
"packages": [
{
"SPDXID": "SPDXRef-Package-acme-checkout-svc",
"name": "acme/checkout-svc",
"versionInfo": "8f6c1d5b9c2f",
"supplier": "Organization: acme",
"downloadLocation": "git+https://github.com/acme/checkout-svc",
"checksums": [{
"algorithm": "SHA256",
"checksumValue": "8f6c1d5b9c2f6c1d5b9c2f6c1d5b9c2f6c1d5b9c"
}],
"externalRefs": [
{ "referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:github/acme/checkout-svc@8f6c1d5b9c2f" }
]
}
],
"relationships": [
{ "spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-Package-acme-checkout-svc",
"relationshipType": "DESCRIBES" }
]
}SPDX 2.3 · CycloneDX 1.5 · registry content-addressed · cosign signed · Rekor claim
Cryptographic PR signing
Cosign keyful ECDSA P-256 — KMS-resident, HSM on Enterprise, Rekor-anchored.
Every merged PR is signed by the Driftlock signing-controller. The algorithm is ecdsa-p256 (cosign keyful); the bytes signed are the commit SHA + the SBOM sha256 + the approver_chain_root SHA. By default the private half lives in your KMS; on Enterprise tier your HSM via PKCS#11. The same verifier commands work in both modes — the algorithm and the Rekor claim do not change.
Surface
Notes
algorithm
cosign keyful ECDSA P-256 — same algorithm the Sigstore OIDC verifier checks against. Bytes signed: the commit SHA + the SBOM sha256 + the approver_chain_root SHA.
key custody
KMS-resident by default — AWS KMS · GCP KMS · Azure Key Vault. Private half never leaves the KMS; the signing-controller workload reads the public half when verifying prior commits.
enterprise tier
Enterprise tier swaps to your HSM via PKCS#11 (AWS CloudHSM, GCP HSM, Azure Dedicated HSM, Thales / Utimaco / Entrust on-prem). Same algorithm, same Rekor claim, same verifier commands.
rotation
KMS-managed 90-day rotation — the platform team sets `signing.commit.rotation.schedule_days` in .driftlock/config.yaml. Each rotation lands a new `signer_kid` chain-linked in Rekor.
Rekor inclusion
Every signature includes a Rekor transparency-log entry. The claim payload carries: run_id, sbom_sha256, approver_chain_root SHA, signer_kid. Reviewers verify inclusion via `rekor search` against the public Rekor instance.
Signing block — .driftlock/config.yaml snippet
The block below is the signing section a platform team commits to their chart repo. The default KMS-resident keypair with 90-day rotation is the certified posture; flip signing.enterprise.custody to hsm when the platform team is on Enterprise tier.
# .driftlock/config.yaml — signing block the platform team owns.
# Default KMS-resident keypair, 90-day KMS-managed rotation, every commit
# + SBOM emission lands a Rekor inclusion claim bound to the run id.
signing:
version: 1
commit:
algorithm: ecdsa-p256
signer: signing-controller
key_alias: driftlock/commit-signer
custody: kms-resident
rotation: { schedule_days: 90, rollover: kid-chain }
rekor:
url: ${DRIFTLOCK_REKOR_URL:-https://rekor.driftlock.dev}
claim_payload: [run_id, sbom_sha256, approver_chain_root]
sbom:
algorithm: ecdsa-p256
key_alias: driftlock/sbom-signer
custody: kms-resident
rotation: { schedule_days: 90 }
enterprise:
# Flip to HSM when the platform team is on Enterprise tier.
custody: hsm
pkcs11_module_path: /usr/lib/pkcs11/luna.so
cosign ECDSA P-256 · KMS-resident · HSM on Enterprise · 90-day rotation · Rekor claim { run_id · sbom_sha256 · approver_chain_root }
Retention windows per class
Hot + cold windows per data class — one glance, no paging.
The five classes Driftlock keeps, the storage tier each lands on, and the retention window a regulator cross-references against the platform team's record-retention commitment. The hot tier is the customer-managed primary database + ledger pg_append; the cold tier is the customer-managed S3 / OCI object-storage mirror. Two cells below the table name the underlying storage surfaces a reviewer reads without leaving the page.
Class · id
Hot tier
Cold tier
Notes
audit-trail
Merge audit trail
hot
7 years
cold
10 years
Append-only signed JSONL · one row per merged PR. Per-row HMAC chained to the prior row; Rekor transparency-log entry anchors the row SHA-256.
sbom
SBOM documents
hot
10 years
cold
Indefinite
Content-addressed at registry.internal/<org>/<repo>/spdx/<sbom_sha256>.spdx.json — the sha256 IS the path. Rewrites are detectable by hash mismatch.
signed-commit
Signed commits
hot
Indefinite
cold
Indefinite · Rekor-logged
Cosign ECDSA P-256 signature + the Rekor transparency-log entry that anchors it. Replayable for the lifetime of the public Rekor instance.
rekor-log
Rekor transparency log
hot
Indefinite
cold
Indefinite · mirrored
Public Rekor instance holds the inclusion claim. Driftlock mirrors a private read replica into your account so a reviewer queries inclusion without depending on public uptime.
customer-managed-keys
Customer-managed keys (CMK / BYOK)
hot
Until rotated
cold
Wrapped DEKs · 7y post-rotation
Per-tenant DEKs wrapped by a KMS-resident KEK you control. Driftlock reads only the public half; the plaintext key material never leaves your boundary.
Hot + cold storage surfaces
- hot storage
- Customer-managed primary database + ledger pg_append · immediately queryable
- cold storage
- Customer-managed S3 / OCI object-storage mirror · replayable on request
audit-trail · sbom · signed-commit · rekor-log · customer-managed-keys · 7y hot · 10y cold · Rekor-logged
Verification commands
Four commands a reviewer runs against any merged PR.
Each command below reproduces a verification the platform team commits to their security-runbook. They cover the commit signature, the SBOM signature, the Rekor transparency inclusion, and the GitHub-side attestation. Every command exits 0 on success; a non-zero exit indicates a tampered signature, a missing Rekor inclusion, or a GH-side attestation gap the compliance record flags as a finding.
Cosign · verify the commit signature
Asserts the signature over <commit-sha> resolves to your KMS-resident signing-controller key — verification includes the Rekor inclusion check.
cosign verify --certificate-identity-regexp ".*" <commit-sha>Cosign · verify-blob on the SBOM document
Asserts the cosign signature over the SPDX document resolves to the driftlock/sbom-signer key — failure indicates a tampered SBOM.
cosign verify-blob --bundle sbom.bundle --certificate-identity-regexp ".*" sbom.spdx.jsonRekor · lookup the inclusion claim
Returns the Rekor uuid + the claim payload (run_id, sbom_sha256, approver_chain_root). A missing or mismatch entry indicates the signature was not anchored.
rekor search --artifact <commit-sha> --pki-format x509 --public-key https://rekor.driftlock.dev/api/v1/index/retrieveGitHub CLI · verify the PR attestation
Asserts the GitHub-side attestation matches the Rekor claim — used by self-hosted GitHub Enterprise instances that hold the GH attestation alongside the Sigstore chain.
gh attestation verify --owner <org> <commit-sha>
cosign · rekor search · gh attestation · exit 0 · tampered detection
Back to the runbook
The parent /docs page covers the audit-trail vocabulary + SBOM vocabulary — this page covers the six-section compliance record security reviewers read.
The RBAC + audit-trail + SBOM + signing recap on /docs → Compliance is the four-card signpost. This deep-dive expands each card into the section a security reviewer reads — the SOC 2 four-phase roadmap with auditor-of-record, observation window start, and Type II target month; the role × action matrix with a .driftlock/config.yaml snippet; the seven-column per-PR row with the immutability + retention trio; the SPDX 2.3 registry path with a sample SPDX document; the cosign ECDSA P-256 signing identity; the data-retention table per class; and four verifier commands.
Request a deeper-docs walkthrough
We'll reply with a calendar link and the air-gap or key-handling runbook relevant to your scope.
Ready to run your first overnight scan?
Start free