the certificate, the archive, the bundle, the audit trail
What an auditor opens.
The certificate field by field, the write-once archive it lives in, the bundle an auditor can carry out and check offline, and the audit trail underneath. Every field name below is the schema's own.
The certificate, field by field.
- id
- The sha256 of the certificate's own canonical body: every field below except the id itself, with keys deep-sorted before hashing. Editing any field produces a different id.
- subjectTreeHash
- The sha256 of the canonical file tree the certificate attests to. Unique: one certificate per tree, and a tree already certified is reused rather than re-minted.
- subjectCommitSha
- The commit the certificate was minted for.
- verdict
- The roll-up across frameworks: pass, warn or fail. Fail-closed: a verdict with no framework evidence is fail, never pass.
- frameworkResults
- Per-framework outcome keyed by framework id, each with a verdict, the underlying scan status and a finding count. On a fleet certificate: hipaa, soc2, hitrust.
- warnings
- Disclosed warnings surfaced at mint time, as deduplicated finding messages.
- evidenceHtml
- The compliance report body, embedded as human-readable evidence. Finding counts, never source code.
- issuer
- The issuing service, in the shape softwerk-fleet@production.
- issuedAt
- Mint time, ISO-8601 UTC.
- expiresAt
- Expiry, ISO-8601 UTC. The default is thirty days after mint.
- packages/compliance/src/verification/certificate.ts VerificationCertificateBody
- apps/web/prisma/schema.prisma VerificationCertificate
- apps/worker/src/fleet-certificate.ts issuer softwerk-fleet@<env>
What the certificate does not carry.
No source code. No name of the model that reviewed the diff: the schema has an optional reviewer constituent, and the fleet mint input passes none, so a fleet certificate records the verdict and not the reviewer. No PHI-guard result on a fleet certificate for the same reason. A readout that drew either field would be drawing something the fleet does not write.
- apps/worker/src/fleet-certificate.ts mint input: files, subjectCommitSha, issuer, scans, reportContext, tenantId
Write-once archive.
Certificates are archived into an S3 Object Lock bucket in COMPLIANCE mode with a 2190-day default retention. COMPLIANCE mode cannot be downgraded to GOVERNANCE and the retention cannot be shortened, by anyone, root included. The worker's role may put an object and set its retention, and has no delete on the bucket. Minting is fail-closed: without the bucket the verifier returns nothing and no certificate exists, and the refusal is written on the run as a fixed skip reason.
packages/compliance/src/verification/s3-object-lock-archive.ts ObjectLockMode; cdk/lib/worm-bucket.ts ObjectLockRetention.compliance
cdk/lib/worm-bucket.ts WORM_RETENTION_YEARS = 6
cdk/lib/eks-stack.ts grants s3:PutObject, s3:PutObjectRetention, s3:GetObject, s3:ListBucket on the WORM bucket, and nothing else
Evidence pages.
In the app, /evidence/<certificateId> renders one certificate and /evidence/runs/<missionId> renders the mission's full report. Every Linear activity the fleet posts links to both, so the ticket carries the way to its own evidence. Viewing a certificate is an audit row (evidence.certificate_viewed).
- apps/web/src/app/(dashboard)/evidence/[certificateId]/page.tsx
- apps/web/src/app/(dashboard)/evidence/runs/[missionId]/page.tsx
- apps/agent/src/tracker.ts runUrlFor, evidenceUrlFor
The bundle and the offline verifier.
Evidence exports as a deterministic bundle of canonical bytes, signed with a detached ed25519 signature when the deployment holds a signing key, which production does not today. A zero-dependency script checks it offline, with no network, no database and no Softwerk software, and it duplicates the canonicalisation inline rather than importing it, on purpose: a verifier that needs the thing it verifies is not independent. It recomputes each certificate's content address, verifies the signature over the canonical bundle bytes when one is present, optionally recomputes the tree hash of a checked-out source tree, and reports expiry against the clock.
On a signed bundle it proves the bytes have not changed since Softwerk signed them; on any bundle it proves each certificate's attested fields hash to its stated identity. It does not prove the checks described inside were correct; that is what the certificate's fields and the report are for. Signing needs EVIDENCE_SIGNING_PRIVATE_KEY on the deployment, and production carries no such property in its overlay, its CDK stacks or its deploy workflows, so a production export today is unsigned with the reason not_configured written in the bundle; the verifier fails its signature check on it, says why, and still checks every certificate's content address.
- apps/web/src/app/api/v1/evidence/export/route.ts unsigned, unsignedReason
- apps/web/src/lib/evidence/build-bundle.ts
- apps/web/src/lib/evidence/sign-bundle.ts not_configured
- k8s/overlays/softwerk-prod/external-secret.yaml (no EVIDENCE_SIGNING_PRIVATE_KEY property)
- scripts/verify-evidence-bundle.mjs (OFFLINE, no network, zero dependencies)
The audit log.
Postgres triggers refuse UPDATE and DELETE on the audit table, so a row that was written stays written. Named actions on the factory surface include evidence.exported, evidence.certificate_viewed, mission_gate.decided, mission.credential_issued and connection.connected.
- apps/web/prisma/migrations/20260412_audit_log_immutability/migration.sql
- apps/web/src/lib/audit.ts
- apps/web/src/lib/fleet/issue-credential.ts mission.credential_issued
- apps/web/src/lib/factory/mission-gate-ingest.ts mission_gate.decided
Gate review record.
A blocked release has one review screen: the certificate verdict, the per-framework results, the stored evidence and a computed reviewer-independence attribute. A decision is approve, reject or override with justification, recorded by admins only; non-admins see everything and the form is disabled. Decisions are append-only, and requiring an admin to approve what an editor deploys gives segregation of duties a structural footing.
- apps/web/src/lib/gate-review/service.ts
- apps/web/prisma/migrations/20260904000000_gate_review
- apps/web/src/app/(dashboard)/gate-review/[releaseId]/page.tsx
Which control sets produce results.
HIPAA, SOC 2 and HITRUST run on every fleet scan and their results land on the certificate. ISO 27001, GxP, 21 CFR Part 11 and PCI-DSS are registered control sets with their own scanners; the fleet passes no profile, so no fleet certificate carries their result today. Custom frameworks can be registered.
| control set | state | on a fleet certificate |
|---|---|---|
| HIPAA | live | runs on every scan; result on the certificate |
| SOC 2 | live | runs on every scan; result on the certificate |
| HITRUST | live | runs on every scan; result on the certificate |
| ISO 27001 | not live | registered control set with its own Annex A rules; no fleet certificate carries its result |
| GxP | not live | registered control set; neither scans nor vetoes a fleet build |
| 21 CFR Part 11 | not live | registered control set; neither scans nor vetoes a fleet build |
| PCI-DSS | not live | registered control set; neither scans nor vetoes a fleet build |
- packages/compliance/src/verify.ts DEFAULT_VERIFY_FRAMEWORKS
- apps/worker/src/fleet-certificate.ts runComplianceVerify(files, {})
- packages/compliance/src/frameworks/iso27001.ts, gxp-21cfr11.ts, pci-dss.ts, registry.ts
Connect a repository, a Linear team and an API key. Keep everything else.
Softwerk is not self-serve: sign-in is Google SSO on an allowlisted workspace domain, and a workspace is set up by Softwerk on request. The GitHub App and the Linear application are configured once for the whole deployment by Softwerk, not per workspace, and the app offers each connect step only when that deployment-level configuration is in place. On production today the Linear application is not yet seeded, so its connect step is not offered, and the GitHub App private key is a placeholder, so no mission can clone a repository or open a pull request yet. Once both are seeded, you connect your Anthropic key, your GitHub App installation and your Linear team, and the first mission ends in a pull request with its certificate beside it.
Book a factory walkthrough