SPDX AI BOM for Reproducible Model Releases
Build a bounded release graph connecting model files, datasets, licenses, suppliers, provenance, checksums, and evaluation evidence.
An SPDX AI BOM makes a model release reproducible only when every artifact, dataset, license, supplier, and evidence edge identifies a concrete object. This guide builds one bounded SPDX 3.0.1 AI-profile graph and mutates it until missing relationships fail visibly.
SPDX AI BOM begins with the release closure
Start by naming the exact release whose closure must be reproduced: weights or shards, configuration, tokenizer, adapters, runtime requirements, evaluation evidence, licenses, and declared datasets. An AI bill of materials is weak when it lists product names but cannot bind those names to versions, digests, or relationships.
The versioned SPDX 3.0.1 AI Profile supplies model vocabulary for AI artifacts and their domain properties. Use that vocabulary as a graph, not as a decorative document attached after the release has already been assembled.
The committed example is a synthetic release closure containing placeholder bytes and invented identifiers. It teaches graph validation only; it does not claim full SPDX conformance, verify signatures, describe a production model, or establish rights to any external dataset.
The committed graph closes around one synthetic AIPackage, exact model bytes, a dataset record, evaluation evidence, two license conclusions, and a separate provenance node. Its scope string says educational SPDX 3 AI Profile subset, preventing schema validation from masquerading as full SPDX conformance.
| Material | HAS_FILE and TRAINED_ON |
|---|---|
| Evidence | HAS_EVIDENCE and GENERATED_FROM_PROVENANCE |
| Rights | DECLARED_LICENSE and CONCLUDED_LICENSE |
Choose stable identities before adding relationships
Give every element a unique SPDX identifier and a stable human-readable name. For external objects, record locators and content identifiers that a verifier can resolve under the release's access policy; for local files, include cryptographic digests over the exact shipped bytes.
The AIPackage class is the center of the teaching graph, but a type name alone is insufficient. The fixture requires a version and supplier, then links weights, dataset records, and evaluation evidence through explicit relationships.
An SPDX AI BOM should distinguish an unavailable private dataset from an unidentified dataset. A restricted object may still have a controlled identity, owner, license status, version, and digest receipt without exposing its contents to unauthorized readers.
Stable identifiers are tested for uniqueness before relationships are traversed. Missing version and supplier fields have distinct failure names, which keeps identity defects separate from dangling references or malformed cryptographic digests.
Runnable artifact — Validate the enumerated educational AI-profile subset with separate provenance and five committed graph mutations.
import assert from "node:assert/strict";import{createHash}from"node:crypto";
const digest=value=>createHash("sha256").update(value).digest("hex");
const rules=["unique SPDX identifiers","AIPackage name version supplier","SHA-256 syntax on files datasets evidence and provenance","referential integrity","declared and concluded license edges","separate provenance relationship"];
const bom={scope:"educational SPDX 3.0.1 AI subset; not full conformance",elements:[{spdxId:"ai:release",type:"AIPackage",name:"Synthetic Atlas",version:"1.0.0",supplier:"Person: Example Builder"},{spdxId:"file:weights",type:"File",sha256:digest("generated-weights")},{spdxId:"data:cards",type:"Dataset",sha256:digest("generated-cards")},{spdxId:"eval:receipt",type:"Evidence",sha256:digest("generated-eval")},{spdxId:"prov:build",type:"Provenance",spec:"SLSA-1.2",sha256:digest("generated-provenance")}],relationships:[{from:"ai:release",type:"HAS_FILE",to:"file:weights"},{from:"ai:release",type:"TRAINED_ON",to:"data:cards"},{from:"ai:release",type:"HAS_EVIDENCE",to:"eval:receipt"},{from:"ai:release",type:"GENERATED_FROM_PROVENANCE",to:"prov:build"},{from:"ai:release",type:"DECLARED_LICENSE",to:"lic:apache-2.0"},{from:"ai:release",type:"CONCLUDED_LICENSE",to:"lic:apache-2.0"}]};
const validate=value=>{const errors=[],ids=value.elements.map(x=>x.spdxId),known=new Set([...ids,"lic:apache-2.0"]),root=value.elements.find(x=>x.type==="AIPackage");if(new Set(ids).size!==ids.length)errors.push("duplicate-id");for(const key of ["name","version","supplier"])if(!root?.[key])errors.push("missing-"+key);for(const item of value.elements.filter(x=>["File","Dataset","Evidence","Provenance"].includes(x.type)))if(!/^[a-f0-9]{64}$/.test(item.sha256||""))errors.push("bad-digest:"+item.spdxId);for(const edge of value.relationships)if(!known.has(edge.from)||!known.has(edge.to))errors.push("dangling:"+edge.to);for(const type of ["DECLARED_LICENSE","CONCLUDED_LICENSE","GENERATED_FROM_PROVENANCE"])if(!value.relationships.some(x=>x.type===type))errors.push("missing-edge:"+type);return{valid:errors.length===0,errors,rules}};
const mutate=fn=>{const value=structuredClone(bom);fn(value);return validate(value)};const mutations={missingVersion:mutate(x=>delete x.elements[0].version),badDigest:mutate(x=>x.elements[1].sha256="abcd"),danglingEdge:mutate(x=>x.relationships.push({from:"ai:release",type:"HAS_EVIDENCE",to:"eval:missing"})),missingLicense:mutate(x=>x.relationships=x.relationships.filter(e=>e.type!=="CONCLUDED_LICENSE")),missingProvenance:mutate(x=>x.relationships=x.relationships.filter(e=>e.type!=="GENERATED_FROM_PROVENANCE"))};
assert.equal(validate(bom).valid,true);assert.deepEqual(mutations.missingVersion.errors,["missing-version"]);assert.deepEqual(mutations.badDigest.errors,["bad-digest:file:weights"]);assert.deepEqual(mutations.danglingEdge.errors,["dangling:eval:missing"]);assert.deepEqual(mutations.missingLicense.errors,["missing-edge:CONCLUDED_LICENSE"]);assert.deepEqual(mutations.missingProvenance.errors,["missing-edge:GENERATED_FROM_PROVENANCE"]);console.log(JSON.stringify({scope:bom.scope,rules,valid:validate(bom),provenance:bom.elements.find(x=>x.type==="Provenance"),mutations},null,2));console.log("PASS: SPDX subset enumerates rules provenance and hostile mutations");
Represent licenses as conclusions and evidence
Capture declared licenses from the upstream release and concluded licenses from the review process without pretending they are always identical. Preserve the source of each conclusion and route unresolved or conflicting terms to a human owner before distribution.
Weights, code, tokenizer assets, training datasets, evaluation datasets, and generated documentation can have different rights. The model supply chain graph should attach each obligation to its actual object rather than assigning one umbrella label that quietly erases incompatibilities.
The synthetic validator requires both declared and concluded license relationships for its package. That is a local educational policy inside this SPDX AI BOM example, not a claim that two edges alone settle legal compliance or replace counsel.
License evidence is attacked by removing the concluded-license edge while leaving the declared edge intact. The SPDX AI BOM receipt therefore demonstrates the local two-edge policy without implying that those relationships settle legal interpretation. The validator names the missing conclusion without attempting a legal judgment.
Link datasets without overstating training knowledge
A release publisher may know that a model was trained on a named dataset, evaluated on another, or derived from an upstream artifact, while still lacking a complete account of every source sample. Model the known relationships and make unknown scope explicit instead of inventing completeness.
Keep dataset version, acquisition or publication reference, access conditions, license evidence, preprocessing lineage, and content digest where possible. If only a dataset card or registry entry is available, identify that record as metadata rather than implying the underlying corpus was hashed.
An SPDX AI BOM can improve disclosure structure but cannot recover undocumented history. Pair the graph with artifact integrity verification so an identified model file is also bound to the bytes actually released.
Dataset disclosure is bounded to what the synthetic publisher knows: an identified dataset node and its digest. The graph does not invent complete training history, sample-level lineage, access permission, or reproducibility for unavailable upstream material.
- Each mutation changes one frozen graph property.
- Each expected error has its own exact identifier.
- A mutation passes the test only by being rejected.
- No verdict claims complete SPDX validation.
Keep provenance beside, not inside, the BOM
A bill of materials describes objects and relationships; build provenance describes how a subject was produced. Connect those records by digest and identity while retaining their distinct schemas, issuers, verification rules, and update lifecycles.
The SLSA 1.2 provenance specification provides a versioned reference for describing build subjects and external parameters. The teaching validator checks only that evidence nodes have well-formed digests and are referenced; it does not parse a SLSA envelope or authenticate its signer.
Use provenance that travels with releases to make the production path concrete. The SPDX AI BOM remains the release relationship map, while provenance answers how selected nodes came into being.
Model provenance lives in its own SLSA-labeled node and reaches the package through a dedicated generated-from relationship. A missing-provenance mutation fails independently, preserving the conceptual boundary between inventory and build history. Its separate digest lets provenance change without quietly renaming the package inventory.
Validate the graph with hostile mutations
Begin with uniqueness, required root properties, digest syntax, allowed relationship types, and referential integrity. Then delete a supplier, duplicate an identifier, corrupt a checksum, remove each required license edge, and point a relationship at an absent node.
Every mutation should fail for one named reason, and the valid fixture should remain small enough for a reviewer to inspect without a specialized viewer. A validator that accepts its own happy-path serialization but has no negative corpus has not demonstrated useful release protection.
This SPDX AI BOM fixture checks an intentionally narrow subset and labels that boundary in its output. A full implementation should validate the official model, serialization, namespace rules, profiles, extensions, and organization-specific policy separately.
Five hostile mutations are archived: missing version, bad file digest, dangling evidence target, absent concluded license, and absent provenance edge. Their exact error arrays are part of the SPDX AI BOM evidence, not illustrative labels added after execution.
Package graph and artifacts as one discoverable release
Store the BOM, provenance, signatures, evaluations, and model assets as separately addressable objects connected through immutable digests. OCI distribution for AI artifacts is one way to publish that graph while preserving media types and referrer relationships.
Do not hide mutable URLs inside an otherwise content-addressed release. When an external record cannot be mirrored, preserve its expected version, retrieval policy, and verification status, then treat later content changes as a new review event.
An SPDX AI BOM should support an offline inventory even when some restricted objects cannot be fetched. The inventory can still reveal missing relationships, expiring licenses, absent evaluations, or an artifact whose digest no longer matches the packaged closure.
Packaging retains each BOM, signature, provenance statement, evaluation, and artifact as a separately digestible object. A mutable locator may help discovery, but it cannot replace the immutable subject identity used by verification. Every retrieval step should compare that subject identity before graph traversal begins.
- Left record answers
- What objects and relationships form this release?
- Right record answers
- How was a selected subject produced?
- Connecting evidence
- Immutable digest and stable identifier, never a vague provenance badge.
Turn validation into a release decision
Run the educational validator, read every accepted node and edge, then map a real release into the same closure worksheet before adopting a complete SPDX toolchain. Record profile version, serialization, validator version, policy checks, unresolved exceptions, and the identity of the reviewer who accepts them.
Keep content credentials for AI art separate when media provenance has its own trust and presentation needs. Joining references is useful; flattening distinct standards into one vague provenance badge is not.
The SPDX AI BOM succeeds when another authorized reviewer can identify the release, locate its constituent objects, understand known dataset and license relationships, verify digests, and see what remains unknown. That outcome is reproducibility evidence, not a universal certification claim.
Release promotion should compare the rule enumeration with the validator output. If a new organizational requirement appears, the rule list, negative corpus, graph fixture, and documentation change in the same evidence freeze. Promotion records which exact negative mutations were required for that release.
Define ownership for updates and revocation
A release graph changes when a dataset statement is corrected, a license conclusion changes, an evaluation is superseded, a vulnerability affects the runtime, or a model artifact is withdrawn. Decide whether the event creates a new BOM version, a signed advisory linked to the old graph, or both; never rewrite historical evidence without preserving its prior digest and publication time.
Assign owners for model nodes, data records, license review, build provenance, evaluation evidence, and distribution. Each owner needs a response window and a way to mark an object unavailable or disputed without deleting the relationship that explains why the release was previously assembled.
The SPDX AI BOM should therefore include lifecycle status alongside static inventory. A verifier needs to tell an intact but superseded closure from a currently approved one, and an operator needs a deterministic route from an alert to the affected artifacts, deployments, and downstream derivatives.
Revocation leaves history addressable. A withdrawn model or corrected dataset statement receives a new lifecycle record linked to the prior closure rather than a silent rewrite of the graph that reviewers previously accepted.
Test reproducibility from a clean environment
Give an authorized reviewer only the published graph, permitted artifacts, tool versions, and documented build or conversion instructions. Ask them to resolve every identifier, verify every accessible digest, reconstruct the intended package, and list unavailable evidence; compare that result with the publisher's expected closure instead of declaring success from schema validation alone.
Some model releases cannot be rebuilt bit for bit because training infrastructure, randomness, private data, or nondeterministic kernels are unavailable. Say so directly. Reproducibility may mean identifying the shipped bytes and their provenance rather than recreating training, while repeatability may cover only a downstream conversion or packaging step.
An SPDX AI BOM earns trust by making those levels explicit. Archive the clean-room checklist, failures, environment, graph digest, and reviewer notes beside the validator output, then revisit the release when a previously unavailable object, changed standard, or new risk alters what another party can actually verify.
The clean-environment review asks another authorized operator to resolve identifiers and report inaccessible objects. Success means the published closure can be inspected at its stated level, not that private training can be recreated from an SPDX AI BOM.