13 — Forgeyard Supply Chain, SBOM, Provenance & Signing System Architecture
Document type: Core Software Supply-Chain Security System & Architecture
Project: Forgeyard CI/CD
Subsystem: SBOM, VEX, provenance, attestations, signatures, verification, policy evidence, reproducibility evidence, release evidence, in-toto/SLSA-aligned metadata, signing workers, artifact identity binding, dependency/license/vulnerability evidence, and promotion of verified bytes
Architecture style: Evidence-first, digest-bound, immutable, reproducibility-aware, signing-separated, policy-verifiable, provider-neutral
Status: Target production architecture for the new Forgeyard repository
Relationship to prior work: Builds on the CAS/Data Plane, Pipeline IR, Run/Job, Secrets & Trust, Policy/Authz/Identity, hermetic/reproducible build architecture, Change Proposal system, VCS-neutral snapshots, and the future Release/Packaging systems. It does not redefine package building or deployment; it defines the evidence and trust chain that proves what was built, from what, by whom, where, and under which policy.
1. Purpose
Forgeyard must make builds verifiable.
A production artifact should not merely exist.
Forgeyard should be able to answer:
what exact source produced this artifact?
which pipeline and JobSpec produced it?
which toolchains/dependencies were used?
which runner/executor produced it?
was the build hermetic?
was it reproduced independently?
which SBOM belongs to it?
which vulnerabilities were known?
which VEX statements apply?
which policy approved it?
who requested signing?
which key signed it?
which exact bytes were promoted?
The central rule is:
Every supply-chain claim is bound to immutable identities and cryptographic digests, never mutable names.
A second rule is:
Forgeyard builds, verifies, signs, and promotes exact bytes. Signing or promotion must never silently rebuild the artifact.
A third rule is:
Private signing keys remain outside general build runners. General runners produce evidence and unsigned artifacts; restricted signing workers/providers perform signing operations.
2. Architectural Position
SourceSnapshotId
│
▼
PipelinePlanId
│
▼
JobSpecId
│
▼
Hermetic Build
│
▼
Artifact Digest
│
├──────────────┐
▼ ▼
SBOM Provenance
│ │
▼ ▼
Vulnerability Repro
Evidence Evidence
│ │
└───────┬──────┘
▼
Policy Verify
│
▼
Signing Request
│
▼
Restricted Signer
│
▼
Signed Artifact
│
▼
Release Promote
3. Goals
The subsystem MUST:
- generate artifact-bound SBOMs;
- support SPDX;
- support CycloneDX where useful;
- generate provenance;
- support SLSA/in-toto-aligned attestations;
- store evidence in CAS;
- store semantic evidence metadata in SQL;
- bind evidence to exact artifact digest;
- bind provenance to exact source snapshot;
- bind provenance to exact pipeline plan/job spec;
- record builder identity;
- record executor/runner identity where appropriate;
- record toolchain/dependency identities;
- record hermeticity/reproducibility level;
- generate VEX;
- ingest scanner evidence;
- evaluate supply-chain policy;
- verify before signing;
- keep signing keys out of general runners;
- support KMS/HSM/provider signing;
- support package-format signing;
- support detached signatures;
- support attestation signatures;
- support key rotation;
- support verification of historical releases;
- support air-gap verification;
- support release evidence bundles;
- support audit;
- support external interoperability;
- remain independent from any one package ecosystem.
4. Non-Goals
This subsystem does not:
replace package managers
replace vulnerability databases
replace external certificate authorities
replace artifact packaging
replace release orchestration
replace policy engine
It integrates those systems.
5. Workspace Structure
crates/supply-chain/
├── forgeyard-supply-chain/
├── forgeyard-supply-chain-model/
├── forgeyard-sbom/
├── forgeyard-sbom-spdx/
├── forgeyard-sbom-cyclonedx/
├── forgeyard-vex/
├── forgeyard-provenance/
├── forgeyard-attestation/
├── forgeyard-in-toto/
├── forgeyard-slsa/
├── forgeyard-signature/
├── forgeyard-signature-verify/
├── forgeyard-evidence/
├── forgeyard-evidence-store/
├── forgeyard-evidence-policy/
├── forgeyard-evidence-bundle/
├── forgeyard-repro-evidence/
├── forgeyard-license-evidence/
├── forgeyard-vulnerability-evidence/
├── forgeyard-dependency-evidence/
├── forgeyard-builder-identity/
├── forgeyard-supply-chain-health/
└── forgeyard-supply-chain-testkit/
Signing-related application/worker:
apps/forgeyard-signing-worker/
6. Core Evidence Identity
#![allow(unused)]
fn main() {
pub struct EvidenceId(Ulid);
}
Semantic evidence entity.
7. Evidence Object
#![allow(unused)]
fn main() {
pub struct EvidenceRecord {
pub id: EvidenceId,
pub kind: EvidenceKind,
pub subject: EvidenceSubject,
pub object: CasObjectRef,
pub generated_at: Timestamp,
pub generator: PrincipalId,
}
}
8. Evidence Subject
#![allow(unused)]
fn main() {
pub enum EvidenceSubject {
Artifact(ArtifactId),
CasObject(CasObjectId),
SourceSnapshot(SourceSnapshotId),
Release(ReleaseId),
Run(RunId),
Job(JobId),
}
}
9. Evidence Kind
#![allow(unused)]
fn main() {
pub enum EvidenceKind {
Sbom,
Vex,
Provenance,
Attestation,
Signature,
Reproducibility,
VulnerabilityScan,
LicenseScan,
DependencyGraph,
PolicyDecision,
BuildManifest,
Custom(EvidenceKindId),
}
}
10. Evidence Storage Rule
Actual document bytes:
CAS
Metadata:
ForgeyardStore
11. Evidence Immutability
Once an evidence document is generated:
content immutable
Corrections create new evidence version/entity.
12. Subject Digest Binding
Evidence for artifact must include exact digest.
Never:
artifact name only
version string only
release tag only
13. Artifact Subject
#![allow(unused)]
fn main() {
pub struct ArtifactSubject {
pub artifact: ArtifactId,
pub object: CasObjectRef,
}
}
14. Provenance
Provenance states:
this artifact was produced
from these inputs
by this build definition
by this builder
under these conditions
15. Provenance Model
#![allow(unused)]
fn main() {
pub struct BuildProvenance {
pub subject: Vec<ProvenanceSubject>,
pub source: SourceSnapshotId,
pub plan: PipelinePlanId,
pub job_spec: JobSpecId,
pub run: RunId,
pub job: JobId,
pub builder: BuilderIdentity,
pub inputs: Vec<ProvenanceInput>,
pub invocation: ProvenanceInvocation,
pub environment: ProvenanceEnvironment,
pub reproducibility: ReproducibilitySummary,
}
}
16. Provenance Subject
#![allow(unused)]
fn main() {
pub struct ProvenanceSubject {
pub name: Option<ArtifactName>,
pub digest: DigestSet,
}
}
17. Digest Set
#![allow(unused)]
fn main() {
pub struct DigestSet {
pub blake3: Digest,
pub sha256: Option<Digest>,
}
}
18. Source Provenance
Include:
SourceSnapshotId
native VCS revision
repository identity
source provenance
19. VCS Neutrality
Provenance does not assume Git.
Possible source:
Git commit
Mercurial changeset
Jujutsu change
local archive
all normalize to:
SourceSnapshotId
20. Build Definition Identity
Use:
PipelineDefinitionId
PipelinePlanId
JobSpecId
21. Builder Identity
#![allow(unused)]
fn main() {
pub struct BuilderIdentity {
pub forgeyard_version: Version,
pub builder_class: BuilderClass,
pub runner: Option<RunnerId>,
pub agent_session: Option<AgentSessionId>,
pub executor: ExecutorIdentity,
}
}
22. Builder Class
#![allow(unused)]
fn main() {
pub enum BuilderClass {
Standalone,
DistributedRunner,
Reproducer,
SigningWorker,
}
}
23. Executor Identity
Include:
executor type
sandbox profile
platform
isolation level
24. Provenance Environment
Do not dump all environment variables.
Record only relevant non-secret semantic environment.
25. Secret Handling in Provenance
Record:
secret reference/purpose if required
not value.
26. Toolchain Evidence
Include immutable:
ToolchainId
toolchain digest
target
27. Dependency Evidence
Include:
lockfile digest
resolved dependency graph
dependency artifacts
28. Hermeticity Evidence
#![allow(unused)]
fn main() {
pub struct HermeticityEvidence {
pub network: NetworkPolicy,
pub declared_inputs_only: bool,
pub managed_toolchains: bool,
pub host_env_sanitized: bool,
}
}
29. Reproducibility Evidence
Integrates existing FRBS architecture.
30. Reproducibility Level
Use existing:
#![allow(unused)]
fn main() {
pub enum ReproducibilityLevel {
Impure,
Declared,
Hermetic,
DeterministicExpected,
Reproduced,
MultiPartyReproduced,
}
}
31. Reproduction Evidence
#![allow(unused)]
fn main() {
pub struct ReproductionEvidence {
pub original: CasObjectRef,
pub reproduction: CasObjectRef,
pub level: ReproducibilityLevel,
pub reproducer: BuilderIdentity,
pub comparison: ReproductionComparison,
}
}
32. Reproduction Comparison
#![allow(unused)]
fn main() {
pub enum ReproductionComparison {
BitForBit,
NormalizedTree,
Semantic,
Mismatch(ReproductionMismatchRef),
}
}
33. Multi-Party Reproduction
Policy may require:
different runner
different site
different trust domain
34. SBOM
SBOM describes components included in a produced artifact.
35. SBOM Formats
First-class:
SPDX
CycloneDX
36. Internal SBOM Model
Do not make SPDX structs the core domain.
#![allow(unused)]
fn main() {
pub struct SbomDocument {
pub subject: ArtifactSubject,
pub components: Vec<SbomComponent>,
pub relationships: Vec<SbomRelationship>,
pub generator: SbomGenerator,
}
}
37. SPDX Adapter
Converts internal SBOM to/from supported SPDX representation.
38. CycloneDX Adapter
Same.
39. SBOM Sources
Components can come from:
ecosystem dependency graph
native linker/object analysis
package manifest
binary inspection
container layers
explicit user declaration
40. Ecosystem Integration
Each ecosystem adapter provides dependency evidence.
Examples:
Cargo.lock
go.sum
package-lock/pnpm-lock
uv.lock/poetry.lock
Gradle/Maven resolved graph
pubspec.lock
Package.resolved
41. Native Dependency Evidence
C/C++ and assembly-native subsystem contributes:
linked libraries
object files
runtime dependencies
sysroot/libc
42. Binary Dependency Scan
Post-build binary inspection can validate actual runtime linkage.
43. Declared vs Observed Dependency
Track both.
44. Dependency Component
#![allow(unused)]
fn main() {
pub struct SbomComponent {
pub id: ComponentId,
pub name: String,
pub version: Option<String>,
pub purl: Option<PackageUrl>,
pub hashes: DigestSet,
pub licenses: Vec<LicenseExpression>,
pub origin: ComponentOrigin,
}
}
45. Component Origin
#![allow(unused)]
fn main() {
pub enum ComponentOrigin {
EcosystemResolved,
NativeLinked,
BinaryObserved,
UserDeclared,
}
}
46. SBOM Coverage
Evidence should indicate completeness/coverage.
47. SBOM Completeness
#![allow(unused)]
fn main() {
pub enum SbomCompleteness {
Partial,
DeclaredDependencies,
ResolvedDependencies,
ResolvedAndObserved,
}
}
48. No False Completeness
Forgeyard must not claim complete SBOM when only lockfile data available.
49. License Evidence
Separate normalized license analysis.
50. License Expression
Use SPDX license expressions where interoperable.
51. License Policy
Policy engine can reject:
forbidden license
unknown license
incompatible license
52. License Scan Evidence
#![allow(unused)]
fn main() {
pub struct LicenseEvidence {
pub components: Vec<ComponentLicenseEvidence>,
pub policy_digest: PolicyDigest,
}
}
53. Vulnerability Evidence
Scanner output normalized into internal model.
54. Vulnerability Finding
#![allow(unused)]
fn main() {
pub struct VulnerabilityFinding {
pub vulnerability: VulnerabilityId,
pub component: ComponentId,
pub severity: VulnerabilitySeverity,
pub status: VulnerabilityStatus,
pub source: VulnerabilitySource,
}
}
55. Scanner Independence
Forgeyard may integrate:
OSV
Trivy
Grype
ecosystem-native scanner
commercial scanner
via adapters.
56. Vulnerability Database Snapshot
Evidence should record:
database/provider
database version/digest/time
57. Reproducible Scan Interpretation
A scan result can change as databases update.
Therefore evidence must include scanner/database context.
58. VEX
Vulnerability Exploitability eXchange communicates whether a known vulnerability affects the artifact.
59. VEX Status
Typical internal:
#![allow(unused)]
fn main() {
pub enum VexStatus {
Affected,
NotAffected,
Fixed,
UnderInvestigation,
}
}
60. VEX Statement
#![allow(unused)]
fn main() {
pub struct VexStatement {
pub subject: ArtifactSubject,
pub vulnerability: VulnerabilityId,
pub status: VexStatus,
pub justification: Option<VexJustification>,
pub evidence: Vec<EvidenceId>,
}
}
61. VEX Authorization
Manual NotAffected claims should require:
security permission
reason
evidence
audit
62. VEX Never Deletes Finding
It qualifies interpretation.
63. Attestation
Generic signed statement over subject/predicate.
64. Attestation Model
#![allow(unused)]
fn main() {
pub struct Attestation {
pub subject: Vec<AttestationSubject>,
pub predicate_type: AttestationPredicateType,
pub predicate: CasObjectRef,
pub signer: SigningIdentityRef,
}
}
65. in-toto
Use standard in-toto concepts for interoperability.
66. Statement Envelope
Forgeyard can produce:
in-toto Statement
with supported predicates.
67. SLSA
Forgeyard should support SLSA-aligned provenance/evidence.
Do not hardcode marketing claims.
68. SLSA Evidence
Record actual capabilities:
build service identity
source integrity
build definition
isolated execution
provenance generation
69. SLSA Claim
Only claim level/requirements when evidence genuinely satisfies current standard/profile.
70. Standard Version
Record standard version/profile.
71. Policy Evidence
Supply-chain policy can require:
SBOM
provenance
reproducibility
no critical vulns
approved VEX
license compliance
signature
trusted builder
72. Evidence Requirement
#![allow(unused)]
fn main() {
pub enum EvidenceRequirement {
Sbom { minimum: SbomCompleteness },
Provenance,
Reproducibility { minimum: ReproducibilityLevel },
VulnerabilityPolicy(PolicyRef),
LicensePolicy(PolicyRef),
Signature(SignaturePolicy),
Attestation(AttestationPredicateType),
}
}
73. Evidence Verification
#![allow(unused)]
fn main() {
pub struct EvidenceVerificationResult {
pub subject: CasObjectRef,
pub satisfied: Vec<EvidenceRequirement>,
pub failed: Vec<EvidenceViolation>,
pub policy_digest: PolicyDigest,
}
}
74. Verification Before Signing
Signing worker/request path must verify required evidence.
75. Signing Request Input
#![allow(unused)]
fn main() {
pub struct SupplyChainSigningRequest {
pub subject: CasObjectRef,
pub artifact: ArtifactId,
pub evidence_bundle: EvidenceBundleId,
pub policy_digest: PolicyDigest,
pub key: SigningKeyRef,
}
}
76. Signing Key Boundary
Private key remains provider/restricted worker.
77. Signing Worker Must Not Build
Signing worker receives immutable subject only.
78. Signing Worker Must Not Resolve Source
It should not fetch arbitrary repo/build code.
79. Signing Worker Capability
Typed:
verify evidence
sign exact digest
package-specific signing operation
80. General Runner Restriction
General build runner cannot request arbitrary production signing.
Authorization/policy proof required.
81. Detached Signature
Generic:
signature object
+
subject digest
+
signer identity
82. Embedded Signature
Formats such as:
Windows Authenticode
Apple codesign
APK signing
modify package bytes.
83. Byte Mutation Rule
If signing modifies artifact bytes:
unsigned digest != signed digest
Both are separately stored.
84. Signing Lineage
Metadata links:
UnsignedArtifact
↓
SignedArtifact
↓
NotarizedArtifact
85. No In-Place Artifact Mutation
Never replace CAS object under same identity.
86. Apple Signing
Restricted Apple signing worker/environment.
87. Windows Authenticode
Restricted signing worker/provider.
88. Android Signing
Restricted Android release signing path.
89. OCI Signing
Can produce external-standard signatures/attestations.
90. Package Registry Signing
Ecosystem-specific signing adapters may be integrated.
91. Signature Model
#![allow(unused)]
fn main() {
pub struct SignatureRecord {
pub id: SignatureId,
pub subject: CasObjectRef,
pub algorithm: SignatureAlgorithm,
pub signer: SigningIdentityRef,
pub key_version: SigningKeyVersion,
pub signature: CasObjectRef,
pub signed_at: Timestamp,
}
}
92. Signing Identity
#![allow(unused)]
fn main() {
pub struct SigningIdentityRef {
pub principal: PrincipalId,
pub key: SigningKeyRef,
}
}
93. Signature Verification
#![allow(unused)]
fn main() {
pub struct SignatureVerification {
pub signature: SignatureId,
pub valid: bool,
pub trust: SignatureTrustResult,
}
}
94. Signature Trust
#![allow(unused)]
fn main() {
pub enum SignatureTrustResult {
Trusted,
ValidButUntrusted,
RevokedAfterSigning,
RevokedAtSigning,
Invalid,
Unknown,
}
}
95. Historical Verification
Must use:
key validity interval
revocation time
trust root history
96. Key Rotation
New signatures use new version.
Old public verification key retained.
97. Key Compromise
Policy can mark old signatures:
untrusted retroactively
if compromise window demands.
98. Timestamping
External trusted timestamp service may improve long-term signature validity for some formats.
99. Timestamp Evidence
Store response/token in CAS.
100. Notarization
Apple notarization result/evidence stored.
101. Provenance Signature
Provenance/attestation itself can be signed.
102. Evidence Bundle
#![allow(unused)]
fn main() {
pub struct EvidenceBundle {
pub id: EvidenceBundleId,
pub subject: CasObjectRef,
pub evidence: Vec<EvidenceId>,
pub manifest: CasObjectRef,
}
}
103. Bundle Manifest
Contains exact digests of:
artifact
SBOM
VEX
provenance
repro evidence
license evidence
vuln evidence
signatures
policy decisions
104. Release Evidence Bundle
Release can pin exact bundle.
105. Evidence Bundle Immutability
Adding new evidence creates a new bundle version/id.
106. Policy Decision Evidence
Persist high-level policy verification result.
107. Policy Digest Binding
Every release/signing decision includes exact:
PolicyDigest
108. Change Proposal Evidence
Release can link:
ProposalRevisionId
approval evidence
check runs
integration candidate/result
109. Exact Source Binding
Release artifact provenance binds the exact source snapshot that produced it.
110. Integration Snapshot
If artifact produced from integration candidate, provenance references exact resulting snapshot.
111. Build Once
Release path:
build
↓
verify
↓
sign same bytes
↓
promote same signed bytes
112. No Release Rebuild
Do not:
CI build passes
then release server rebuilds separately
unless intentionally performing independent reproduction and comparing.
113. Reproduction Is Not Promotion Build
Reproducer validates.
Promoted artifact remains approved original/signed lineage.
114. Provenance Builder ID
Use a Forgeyard builder namespace/version.
115. Builder Trust
Policy may distinguish:
local developer build
general shared runner
trusted release runner
independent reproducer
116. Local Build Provenance
Can still generate provenance.
Marked:
Standalone / Impure / Local
appropriately.
117. No False Trust Upgrade
Local artifact cannot gain enterprise release trust merely by uploading it.
118. Imported Artifact
Can enter as:
ExternalArtifact
with unknown/untrusted provenance.
119. External Evidence
Forgeyard can ingest external SBOM/provenance/signature.
Must distinguish:
Forgeyard-generated
external
verified external
120. Evidence Origin
#![allow(unused)]
fn main() {
pub enum EvidenceOrigin {
ForgeyardGenerated,
ExternalImported,
ProviderGenerated,
}
}
121. External Evidence Verification
Validate:
signature
subject digest
schema
trust
122. SBOM Generation Timing
Recommended:
after build/package artifact exists
using both resolved dependency graph and final binary/package observation.
123. Intermediate SBOM
Could be generated earlier for dependency policy.
124. Final SBOM
Artifact-bound final evidence.
125. SBOM Drift
If artifact bytes change after signing/notarization:
signed artifact may need its own SBOM subject if content semantics changed materially.
126. Signature-Only Byte Change
Policy may link SBOM from unsigned artifact to signed artifact through lineage if component payload unchanged.
127. Explicit Lineage
Do not assume.
128. Package Manifest Evidence
Packaging subsystem emits:
file manifest
package metadata
target
format
129. Binary Analysis
Optional post-build analysis:
symbols
dynamic dependencies
ABI
debug linkage
130. Security Scan Pipeline
Potential stages:
source scan
dependency scan
binary/package scan
SBOM scan
131. Source Scan
Secret scan/static security separate evidence.
132. Dependency Scan
Uses SBOM/dependency graph.
133. Binary Scan
Finds embedded components/runtime libraries.
134. Container Scan
Layer/package analysis.
135. Vulnerability Severity
Use normalized model.
136. Severity Source
Different databases may score differently.
Record source.
137. Vulnerability Policy
Examples:
deny critical affected
allow fixed
allow NotAffected with approved VEX
warn high
138. Scan Freshness
Release policy may require scan less than N hours old.
139. Freshness Timer
Evidence metadata includes generated time/database snapshot.
140. Re-scan Existing Artifact
Can generate new vulnerability evidence without rebuilding artifact.
141. New Evidence Same Subject
Correct.
142. Continuous Vulnerability Monitoring
Future optional workflow.
Artifact digest remains same while known vulnerabilities evolve.
143. VEX Update
New VEX evidence can be added to new evidence bundle.
144. Release Status
Previously released artifact may become:
security advisory needed
without changing bytes.
145. License Scan Freshness
Generally less time-sensitive but tooling/rules version recorded.
146. Provenance Generation Authority
Control plane/runner jointly provide data.
147. Runner-Supplied Evidence
Runner can report observed environment/resource details.
Control plane binds authoritative:
RunId
JobId
PlanId
LeaseId
148. Evidence Tamper Prevention
Generated evidence bytes hashed into CAS.
149. Evidence Signing
Critical provenance/attestations should be signed.
150. Builder Attestation Key
Could be:
Forgeyard service signing identity
separate from package code-signing key.
151. Key Separation
Different keys for:
provenance attestation
release/package signing
TLS
CA
152. In-Toto Layout
If used, policy may define expected steps/materials/products.
153. Forgeyard Mapping
source snapshot = material
toolchain/dependency closure = materials
job output = product
job/run identity = step metadata
154. Attestation Predicate Registry
#![allow(unused)]
fn main() {
pub enum AttestationPredicateType {
BuildProvenance,
Sbom,
Vex,
Reproducibility,
VulnerabilityScan,
LicenseScan,
Custom(PredicateTypeId),
}
}
155. Predicate Versioning
Explicit.
156. Standard Export
Convert to:
SPDX
CycloneDX
in-toto
SLSA provenance
DSSE
where appropriate.
157. DSSE
Useful as signed envelope for attestations.
158. Internal vs Standard Model
Maintain internal typed model.
Adapters serialize to standards.
159. JSON Necessity
Many external standards use JSON.
This is an appropriate JSON use despite Forgeyard’s internal RON/Postcard preference.
160. Canonical Signing Representation
When signing JSON-based attestation, use standard-defined canonical/DSSE procedure.
Do not invent ad-hoc JSON signature.
161. Evidence Parsing
External evidence is untrusted input.
Bound:
document size
component count
nesting
string length
162. SBOM Bomb Defense
Prevent millions of components causing memory exhaustion.
163. Signature Parser Defense
Use vetted libraries/format parsers.
164. Supply Chain Policy Engine Integration
Core policy remains in forgeyard-policy.
Supply-chain subsystem provides facts/evidence to policy evaluator.
165. Policy Facts
#![allow(unused)]
fn main() {
pub struct SupplyChainFacts {
pub sbom: Option<SbomSummary>,
pub vulnerabilities: VulnerabilitySummary,
pub licenses: LicenseSummary,
pub reproducibility: ReproducibilityLevel,
pub signatures: Vec<SignatureSummary>,
pub provenance: Option<ProvenanceSummary>,
}
}
166. No Duplicate Policy Engine
Do not implement a second policy language here.
167. Evidence Graph
Artifact
├── SBOM
├── Provenance
├── Vuln Scan
├── VEX
├── License
├── Repro
└── Signature
168. Graph Store
Semantic edges in metadata.
Documents in CAS.
169. Reverse Query
Given artifact:
find all evidence
170. Forward Query
Given evidence:
subject exact digest
171. Release Gate
Before release promotion:
resolve exact artifact
↓
resolve evidence bundle
↓
verify evidence requirements
↓
verify signatures
↓
verify policy
↓
promote
172. Signing Gate
Before signing:
unsigned artifact
↓
required evidence
↓
policy
↓
approved SigningRequest
173. Signing Idempotency
Same:
subject digest
key version
signing mode
may be idempotent if signing algorithm/provider deterministic or recorded request identity.
174. Non-Deterministic Signatures
ECDSA/etc may produce different bytes.
Use SigningRequestId and provider idempotency where available.
175. Do Not Assume Signature Byte Determinism
Subject trust does not require identical signature bytes.
176. Signed Package Determinism
Some packaging/signing formats embed timestamps/nonces.
Reproducibility semantics must distinguish unsigned vs signed stages.
177. Reproducible Unsigned Build
Strong baseline.
178. Deterministic Signing
Optional where format/provider supports.
179. Timestamping Impact
Trusted timestamps intentionally make bytes time-dependent.
Record as signing-stage evidence.
180. Supply Chain Stage Model
#![allow(unused)]
fn main() {
pub enum ArtifactStage {
Built,
Verified,
Signed,
Notarized,
Promoted,
}
}
181. Stage Is Metadata
Each byte-changing stage creates new artifact object.
182. Stage Transition
Built Artifact A
↓ verification
Verified A
↓ signing
Signed Artifact B
↓ notarization/stapling
Artifact C
183. Verification Does Not Rewrite Bytes
Verified may reference same CAS object.
184. Signature Changes Bytes
New object.
185. Promotion Does Not Rewrite Bytes
Release metadata points to exact already-approved object.
186. Evidence Retention
Release evidence:
long-lived
Build-only evidence may follow run retention.
187. Audit Retention
Signing/release decision long-lived.
188. Evidence GC Roots
Release pins all required evidence objects.
189. Artifact Delete
Cannot GC evidence still rooted by release/audit/legal hold.
190. Historical Verification
Must remain possible after:
runner deleted
user removed
key rotated
provider migrated
191. Historical Identity
Store immutable principal IDs and public verification material/history.
192. Evidence Bundle Export
Air-gap:
artifact
evidence manifest
SBOM
provenance
VEX
signatures
public verification chain
193. Air-Gap Verification
No external network required if bundle contains trusted verification data/policy snapshot.
194. Vulnerability DB Air-Gap
Can include scan evidence rather than live rescan.
Optional offline database mirror for re-scan.
195. Supply Chain CLI
forgeyard sbom generate
forgeyard sbom show
forgeyard sbom export
forgeyard provenance show
forgeyard provenance verify
forgeyard vex list
forgeyard vex create
forgeyard vex verify
forgeyard evidence list
forgeyard evidence verify
forgeyard evidence bundle
forgeyard sign request
forgeyard sign verify
forgeyard supply-chain verify
196. supply-chain verify
Given artifact/release:
verify digest
verify evidence bundle
verify provenance
verify signature
evaluate policy
197. Release Verify
Future forgeyard release verify calls supply-chain verifier.
198. UI
Artifact/release supply-chain tabs:
Overview
Provenance
SBOM
Vulnerabilities
VEX
Licenses
Reproducibility
Signatures
Policy
Evidence Graph
199. Provenance UI
Show:
source snapshot
VCS revision
pipeline
run/job
runner
toolchain
sandbox
repro level
200. SBOM UI
Search/filter components.
201. Vulnerability UI
Show source/database freshness.
202. VEX UI
Show justification/evidence/approver.
203. Signature UI
Show:
key identity
key version
trust result
signed at
revocation status
204. Evidence Graph UI
Useful for release audit.
205. API
Potential:
GET /v1/artifacts/{id}/sbom
GET /v1/artifacts/{id}/provenance
GET /v1/artifacts/{id}/evidence
POST /v1/artifacts/{id}/verify
POST /v1/signing/requests
GET /v1/signatures/{id}
206. Authorization
Permissions:
artifact.read
supplychain.read
vex.create
vex.approve
signing.request
signing.admin
207. Signing Worker Protocol
Already separated from general agent protocol.
208. Signing Request Authority
Must include:
requester
artifact digest
evidence bundle
policy digest
key ref
expiration
209. Signing Request TTL
Short.
210. Signing Worker Recheck
Before operation:
request valid
subject digest exists
policy proof valid
key authorized
211. Signing Completion
Returns:
signature
signed object ref if modified
signing evidence
212. Ambiguous Signing Result
If provider times out:
query provider/request status if supported.
Do not blindly duplicate destructive format operation.
213. Signature Provider Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait SigningProvider {
async fn sign(
&self,
request: ProviderSigningRequest,
) -> Result<ProviderSigningResult, SigningError>;
}
}
214. Package Signer Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait PackageSigner {
async fn sign_artifact(
&self,
artifact: CasObjectRef,
context: PackageSigningContext,
) -> Result<SignedArtifactResult, SigningError>;
}
}
215. Detached vs Package Signer
Separate interfaces because embedded package signing semantics differ.
216. Verification Provider
#![allow(unused)]
fn main() {
pub trait SignatureVerifier {
fn verify(
&self,
subject: &[u8],
signature: &SignatureRecord,
) -> Result<SignatureVerification, VerificationError>;
}
}
Streaming for large subjects.
217. Key Trust Store
Integrates Trust subsystem.
218. Certificate Chains
Store public cert chain/evidence as CAS objects if needed.
219. Transparency Logs
Optional future integration:
Sigstore/Rekor-style transparency
where desired.
220. Transparency Evidence
Store inclusion proof/reference.
221. Sigstore
Potential interoperability adapter.
Not architectural dependency.
222. Keyless Signing
Future/useful option via workload OIDC identities.
223. Keyless Identity
Policy must validate issuer/subject/workflow binding.
224. Ephemeral Signing Certificate
Store certificate/identity evidence.
225. Keyless vs Managed Key
Both fit SigningIdentityRef.
226. Artifact Verification at Download
CLI may verify:
digest
signature
automatically for Forgeyard releases.
227. Self-Update
Future Forgeyard agent/daemon self-update must verify signed release/evidence.
228. Supply-Chain Bootstrapping
First trusted Forgeyard release needs documented root key/bootstrap trust.
229. Trust Root Distribution
Package/installers include public release verification root(s).
230. Root Rotation
Release verifier supports overlap.
231. Compromise Response
Publish revocation/security metadata.
232. Provenance Privacy
Do not include secret values, private environment, unnecessary personal data.
233. Runner Identity Exposure
Public provenance may use builder service identity rather than internal hostname.
234. Internal Provenance
Can retain more operational details.
235. Public Export Profile
Redacted/standardized.
236. Evidence Visibility
Tenant/project authz applies.
237. Public Release Evidence
Can be made public intentionally.
238. Vulnerability Embargo
Security evidence may have restricted visibility.
239. VEX Privacy
Could reveal sensitive exploitability reasoning.
Access control needed.
240. Evidence Event Model
Examples:
SbomGenerated
ProvenanceGenerated
VulnerabilityScanCompleted
VexPublished
ArtifactVerified
SigningRequested
ArtifactSigned
SignatureRevoked
EvidenceBundleCreated
241. Reconciliation
Supply-chain reconciler checks:
artifact missing required evidence
signature metadata/object mismatch
release evidence incomplete
stale vulnerability scan
signing request stuck
242. Signing Request States
#![allow(unused)]
fn main() {
pub enum SigningRequestState {
Pending,
Authorized,
InProgress,
Succeeded,
Failed,
Unknown,
Cancelled,
}
}
243. Unknown
Used after ambiguous provider result.
244. Signing Reconciler
Queries provider or inspects artifact/signature state.
245. Evidence Generation Failure
Artifact remains built but not verified/releasable.
246. Supply Chain Status
#![allow(unused)]
fn main() {
pub enum SupplyChainStatus {
Incomplete,
Verified,
Failed,
Stale,
}
}
247. Stale Evidence
Example vulnerability scan freshness expired.
248. Release Gate on Stale
Policy decides.
249. Evidence Freshness
#![allow(unused)]
fn main() {
pub struct EvidenceFreshness {
pub generated_at: Timestamp,
pub valid_until: Option<Timestamp>,
}
}
250. SBOM Usually Immutable
No short freshness expiry.
251. Vulnerability Scan Time-Sensitive
Yes.
252. Provenance Immutable
Yes.
253. Signature Trust Can Change
Due to revocation/trust changes.
Verification recomputes.
254. Evidence Verification Cache
Cache by:
subject digest
evidence bundle digest
policy digest
trust epoch
vulnerability policy/database context
255. Invalidate on Trust Change
Signature verification cache includes TrustEpoch.
256. Invalidate on Policy Change
Policy digest key naturally changes.
257. Scanner Adapter Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait VulnerabilityScanner {
async fn scan(
&self,
subject: ScanSubject,
) -> Result<VulnerabilityEvidence, ScanError>;
}
}
258. License Scanner Trait
Similar.
259. SBOM Generator Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait SbomGenerator {
async fn generate(
&self,
input: SbomGenerationInput,
) -> Result<SbomDocument, SbomError>;
}
}
260. Provenance Generator
Mostly internal deterministic assembler.
261. Provenance Data Sources
pipeline plan
run/job state
runner/executor metadata
toolchain locks
source snapshot
CAS outputs
repro result
262. Provenance Completeness
If some field unavailable:
explicit Unknown/NotAvailable
not omit ambiguously.
263. Builder Clock
Use control-plane timestamps where authority matters.
264. Monotonic Phase Times
Optional internal.
265. Supply Chain Doctor
forgeyard supply-chain doctor
Checks:
signing worker
trust roots
scanner availability
SBOM generator
provenance signer
evidence store
266. Health
Separate optional scanner degradation from required release signer availability.
267. Metrics
sbom_generation_duration
provenance_generation_duration
vulnerability_scan_duration
evidence_verification_duration
signing_requests
signing_failures
signature_verify_failures
evidence_incomplete
repro_verified
268. Scanner Metrics
By scanner type, not component ID.
269. Signing Metrics
By provider/key class, not secret key ID if sensitive.
270. Tracing
sbom.generate
provenance.generate
scan.vulnerability
vex.evaluate
evidence.verify
signing.authorize
signing.sign
signature.verify
271. Audit
Mandatory:
manual VEX statement
policy exception
signing request
key selection
release evidence approval
signature revocation
272. Evidence Testkit
forgeyard-supply-chain-testkit/src/
├── lib.rs
├── artifact.rs
├── sbom.rs
├── provenance.rs
├── vulnerability.rs
├── vex.rs
├── signature.rs
├── evidence_bundle.rs
└── assertions.rs
273. SBOM Tests
- lockfile dependencies captured;
- native linked dependency captured where supported;
- final artifact digest bound;
- stable export;
- partial completeness labeled.
274. Provenance Tests
- exact SourceSnapshotId;
- exact PipelinePlanId;
- exact JobSpecId;
- exact artifact digest;
- no secret values;
- hermeticity level correct.
275. Repro Tests
Bit-for-bit match upgrades evidence.
Mismatch preserves both outputs.
276. VEX Tests
NotAffected requires justification/policy.
277. Signature Tests
- correct digest verifies;
- modified subject fails;
- wrong key fails;
- historical key rotation verifies;
- revoked-at-signing fails policy.
278. Signing Isolation Test
General agent cannot access signing key operation.
279. Signing Lineage Test
Unsigned and signed object IDs differ if bytes changed.
280. Release Promotion Test
Promoted object equals previously verified signed digest exactly.
281. No Rebuild Test
Release promotion never invokes build executor.
282. Air-Gap Test
Evidence bundle verifies offline.
283. External Evidence Test
Untrusted imported provenance does not become Forgeyard-trusted automatically.
284. Scanner Freshness Test
Stale vulnerability evidence fails policy when freshness required.
285. Policy Digest Test
Evidence verification result changes when policy digest changes.
286. Trust Epoch Test
Signature cache invalidated by root/key revocation.
287. Fuzzing
Fuzz:
SBOM parser
VEX parser
provenance parser
attestation envelope
signature metadata
evidence bundle manifest
288. External JSON Limits
Bound size/nesting/components.
289. Failure Injection
scanner unavailable
signing provider timeout
CAS evidence upload fail
trust store unavailable
vulnerability DB unavailable
290. Ambiguous Signing Test
Provider timeout after sign -> reconcile rather than duplicate blindly.
291. Concurrency Tests
Duplicate signing requests with same request ID produce one semantic operation.
292. Scale Tests
Large monorepo:
100k+ dependencies/components
without pathological memory behavior.
293. Performance
Stream large SBOM/evidence serialization where useful.
294. Implementation Phase 1 — Evidence Model
Implement:
EvidenceId
EvidenceKind
EvidenceSubject
EvidenceStore
295. Phase 2 — Provenance
Generate Forgeyard-native provenance from Run/Job/source/toolchain data.
296. Phase 3 — SBOM
Implement internal SBOM + SPDX export.
297. Phase 4 — Vulnerability/License Evidence
Normalize scanner results.
298. Phase 5 — VEX
Manual/automated VEX statements and policy integration.
299. Phase 6 — Evidence Verification
Supply-chain facts -> policy.
300. Phase 7 — Restricted Signing
Signing worker/provider path.
301. Phase 8 — Embedded Package Signing
Windows/Apple/Android/OCI adapters.
302. Phase 9 — SLSA/in-toto/DSSE Interop
Standard export/verification.
303. Phase 10 — Reproducibility Evidence
Integrate independent reproduction policy.
304. Phase 11 — Release Evidence Bundles
Pin artifact/evidence/signature closure.
305. Phase 12 — Hardening
Air-gap, historical verification, scale, fuzzing, compromise response.
306. Acceptance Tests
- Every release artifact can be resolved to exact CAS digest.
- Provenance references exact SourceSnapshotId.
- Provenance references exact PipelinePlanId and JobSpecId.
- Provenance contains no secret values.
- SBOM subject is exact artifact digest.
- SBOM completeness is explicit.
- Vulnerability evidence records scanner/database context.
- VEX does not erase original vulnerability finding.
- Manual NotAffected statement requires authorization/evidence.
- Reproducibility evidence records actual comparison method.
- Multi-party reproduction can require distinct failure domains.
- General build runner has no production signing key.
- Signing request binds exact artifact digest.
- Signing request binds exact evidence/policy proof.
- Embedded signing creates new CAS object when bytes change.
- Unsigned object is preserved.
- Signed object lineage is preserved.
- Promotion uses exact verified signed bytes.
- Release promotion does not rebuild.
- Signature verification honors historical key validity/revocation.
- Key rotation preserves old verification material.
- Evidence documents are immutable.
- Updating vulnerability scan creates new evidence, not artifact.
- Stale vulnerability evidence can block release by policy.
- Evidence bundle includes all required release evidence.
- Air-gap evidence bundle verifies without network.
- Imported external evidence remains distinguishable from Forgeyard-generated evidence.
- Public evidence export can redact internal runner details.
- Supply-chain policy reuses central Forgeyard policy engine.
- JSON standards remain adapter-layer concerns.
- Same evidence model works across all language ecosystems.
- Same evidence model works standalone/distributed.
- Signing provider timeout is reconciled safely.
- Audit captures signing/VEX/exceptions.
- Forgeyard’s own releases are built, verified, signed, and promoted using this exact system.
307. Production Readiness Gates
Do not call supply-chain subsystem production-ready until:
artifact digest binding stable
provenance generation stable
SBOM generation/export stable
evidence store/CAS integration stable
signature verification stable
restricted signing boundary proven
policy verification integrated
key rotation/history supported
release evidence bundle defined
no-rebuild promotion rule enforced
security/fuzz tests pass
VEX, SLSA profiles, keyless signing, transparency logs, and advanced scanner adapters can mature incrementally.
308. Architectural Invariants
- all supply-chain claims bind immutable digests;
- mutable tags/names are never evidence authority;
- source identity is SourceSnapshotId;
- build identity includes PipelinePlanId/JobSpecId;
- artifact bytes are CAS-addressed;
- evidence bytes are CAS-addressed;
- evidence metadata stays separate;
- provenance contains no secret values;
- SBOM completeness is explicit;
- vulnerability evidence records scanner/database context;
- VEX qualifies findings but does not erase them;
- general runners never receive production signing keys;
- signing worker cannot run arbitrary build code;
- signing request binds exact subject digest;
- byte-changing signing creates new object identity;
- unsigned/signed/notarized lineage is explicit;
- verification never mutates artifact bytes;
- promotion never rebuilds artifact;
- release uses exact previously verified bytes;
- signature verification considers trust history;
- key rotation preserves historical verification;
- policy engine remains centralized;
- evidence generation is provider/ecosystem neutral;
- imported evidence does not become trusted automatically;
- JSON standards are interoperability adapters;
- evidence parsers are bounded/untrusted-input safe;
- release evidence is retained with release;
- reproducibility evidence integrates FRBS levels;
- air-gap verification is supported;
- Forgeyard dogfoods its own supply-chain system.
309. Final Target Architecture
SourceSnapshotId
│
▼
PipelinePlanId
│
▼
JobSpecId
│
▼
Hermetic Execution
│
▼
Artifact Digest
│
┌────────────────┼────────────────┐
▼ ▼ ▼
SBOM Provenance Repro Evidence
│ │ │
▼ ▼ ▼
Vuln/License SLSA/ Independent
Evidence in-toto Verification
│ │ │
└────────────────┼────────────────┘
▼
VEX / Policy
│
▼
Evidence Bundle
│
▼
Signing Authorization
│
▼
Restricted Signer/KMS
│
▼
Signed Artifact
│
▼
Verification
│
▼
Release Promotion
310. Final Architectural Position
Build evidence:
SourceSnapshotId
+
PipelinePlanId
+
JobSpecId
+
Toolchain IDs
+
Builder identity
+
Artifact digest
↓
Provenance
Security evidence:
Artifact digest
+
SBOM
+
Vulnerability scan
+
VEX
+
License evidence
+
Reproducibility evidence
↓
Supply-chain facts
↓
Central policy engine
Signing:
exact artifact digest
+
evidence bundle
+
policy digest
+
SigningKeyRef
↓
restricted signing worker/provider
↓
signature / signed artifact
Release:
verified signed digest
↓
promote exact bytes
↓
never rebuild
The key guarantee is:
Forgeyard can prove the lineage and trust of every production artifact from immutable source snapshot to exact promoted bytes, while keeping build execution, evidence generation, signing authority, and release promotion as separate, auditable trust boundaries.
311. New-Repository Sequence
01 Core Domain & Foundation
02 Storage & Metadata
03 CAS & Artifact Data Plane
04 Pipeline IR / Parsing / Planning
05 Run / Job State Machine
06 Scheduler
07 Runner / Agent
08 Sandbox & Executor
09 Transport / QUIC / Protocol
10 Events / Reconciliation
11 Policy / Authorization / Identity
12 Secrets & Trust
13 Supply Chain / SBOM / Provenance / Signing
14 Packaging
15 Release
16 Deployment
17 Observability / Health / Doctor
18 API / Axum
19 Dioxus UI
20 Device Lab
21 SCM Provider Integrations
22 HA / Coordination / Raft
23 RBE Interop
24 Plugin / Extension Architecture
25 Operations / Backup / Upgrade / DR
26 Self-Hosting / Bootstrap / Release of Forgeyard