Skip to content

fuzzy1337.sbom_graph

This Experimental library adds an explicit opt-in SPDX 2.3 local package graph profile. The supported surface is SPDX_GRAPH_IMPORT_VERSION and ApplyVerifiedSpdxGraph; all remaining helpers are Internal. The existing flat SPDX inventory profile and canonical image/package identities remain unchanged.

Admission revalidates exact typed inputs and verifies the original immutable offline evidence manifest and bytes. One described CONTAINER root requires a checksum matching the caller's explicit config/manifest image identity. Nested containment must form a rooted acyclic graph covering every package, including after canonical PURL aliases collapse. Only direct source containment edges are emitted. Local dependency claims and their inverses use attributed RELATED_TO relations; cycles imply no runtime reachability or transitive relation.

Original relationship coordinates retain manifest, content, image and local-to- canonical endpoint bindings. Declared/concluded licenses and missing/NONE/ NOASSERTION states remain distinct inert facts without compliance evaluation. The returned model/delta requires explicit model-store CAS saving. Actual save/reopen/relocate/replay preserves original evidence and existing finding triage. No scanner receipt or execution/retrieval authorization is created. File/external-document graphs, scoped LicenseRef definitions, vulnerability/VEX graphs, signatures and broader layer/runtime coverage remain outside this profile. See Verified local SPDX graph claims.

fuzzy1337.sbom_graph

Experimental original-evidence-backed local SPDX containment and dependency claims.

SourceEdge dataclass

Retain an original relationship coordinate beside its normalized direction.

Source code in fuzzy1337/sbom_graph.py
52
53
54
55
56
57
58
59
60
61
62
@dataclass(frozen=True, slots=True)
class SourceEdge:
    """Retain an original relationship coordinate beside its normalized direction."""

    index: int
    original_source: str
    original_kind: str
    original_target: str
    source: str
    kind: str
    target: str

SourceCatalog dataclass

Hold an internal validated local catalog without accepting detached graphs as evidence.

Source code in fuzzy1337/sbom_graph.py
65
66
67
68
69
70
71
@dataclass(frozen=True, slots=True)
class SourceCatalog:
    """Hold an internal validated local catalog without accepting detached graphs as evidence."""

    root_id: str
    packages: dict[str, dict[str, object]]
    edges: tuple[SourceEdge, ...]

CheckContainment(root: str, nodes: set[str], edges: set[tuple[str, str]]) -> None

Require a bounded rooted DAG covering every catalog node without recursive traversal.

Parameters:

Name Type Description Default
root str

Explicitly described image, not a guessed dependency root.

required
nodes set[str]

Local source IDs or canonical references after package alias correlation.

required
edges set[tuple[str, str]]

Explicit containment claims only; dependencies never establish membership.

required

Raises:

Type Description
ValueError

A containment cycle, incoming root edge or disconnected node exists.

Source code in fuzzy1337/sbom_graph.py
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def CheckContainment(root: str, nodes: set[str], edges: set[tuple[str, str]]) -> None:
    """Require a bounded rooted DAG covering every catalog node without recursive traversal.

    Args:
        root: Explicitly described image, not a guessed dependency root.
        nodes: Local source IDs or canonical references after package alias correlation.
        edges: Explicit containment claims only; dependencies never establish membership.

    Raises:
        ValueError: A containment cycle, incoming root edge or disconnected node exists.
    """

    incoming = dict.fromkeys(nodes, 0)
    children: dict[str, set[str]] = {node: set() for node in nodes}

    for source, target in edges:
        children[source].add(target)
        incoming[target] += 1

    if incoming[root]:
        raise ValueError("SPDX graph image root cannot be contained by another package")

    pending = [root]
    visited = set()

    while pending:
        source = pending.pop()
        visited.add(source)

        for target in children[source]:
            incoming[target] -= 1

            if incoming[target] == 0:
                pending.append(target)

    if visited != nodes:
        raise ValueError("SPDX graph containment must be acyclic and cover every package")

GraphCatalog(payload: dict[str, object], image_identity: ImageIdentity) -> SourceCatalog

Validate the explicit local graph profile as a pure transformation of original JSON.

Parameters:

Name Type Description Default
payload dict[str, object]

Strictly decoded SPDX 2.3 document whose envelope was already validated.

required
image_identity ImageIdentity

Caller-declared config/manifest semantics, never inferred from checksums.

required

Returns:

Type Description
SourceCatalog

One checksum-bound root, local package rows and exact original relationship coordinates.

Raises:

Type Description
ValueError

Package, root, relationship, checksum or containment claims are unsupported.

Source code in fuzzy1337/sbom_graph.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def GraphCatalog(payload: dict[str, object], image_identity: ImageIdentity) -> SourceCatalog:
    """Validate the explicit local graph profile as a pure transformation of original JSON.

    Args:
        payload: Strictly decoded SPDX 2.3 document whose envelope was already validated.
        image_identity: Caller-declared config/manifest semantics, never inferred from checksums.

    Returns:
        One checksum-bound root, local package rows and exact original relationship coordinates.

    Raises:
        ValueError: Package, root, relationship, checksum or containment claims are unsupported.
    """

    packages = {}

    for value in Items(payload.get("packages")):
        package = Record(value)
        identifier = SpdxIdentifier(package.get("SPDXID"))

        if identifier in packages or package.get("filesAnalyzed") is not False or any(
            name in package for name in (
                "hasFiles", "packageVerificationCode", "licenseInfoFromFiles",
            )
        ):
            raise ValueError("SPDX graph requires unique package IDs with filesAnalyzed false")

        Text(package.get("name"))
        Text(package.get("downloadLocation"))
        SpdxUnsupported(package)
        packages[identifier] = package

    declared = [SpdxIdentifier(value) for value in Items(payload.get("documentDescribes", []))]

    if len(set(declared)) != len(declared):
        raise ValueError("SPDX graph described roots must be unique")

    described = set(declared)
    coordinates = set()
    edges = []

    for index, value in enumerate(Items(payload.get("relationships", []))):
        relation = Record(value)
        original_source = SpdxIdentifier(relation.get("spdxElementId"), document=True)
        original_target = SpdxIdentifier(relation.get("relatedSpdxElement"), document=True)
        original_kind = Text(relation.get("relationshipType"))
        source, kind, target = original_source, original_kind, original_target

        if kind in _INVERSES:
            source, kind, target = target, _INVERSES[kind], source

        coordinate = source, kind, target

        if coordinate in coordinates or source == target or any(
            endpoint not in packages and endpoint != _DOCUMENT for endpoint in (source, target)
        ):
            raise ValueError("SPDX graph edges must be unique, local and resolved")

        coordinates.add(coordinate)

        if kind == "DESCRIBES" and source == _DOCUMENT and target in packages:
            described.add(target)

        elif kind in {"CONTAINS", "DEPENDS_ON"} and source in packages and target in packages:
            edges.append(SourceEdge(index, original_source, original_kind, original_target,
                                    source, kind, target))

        else:
            raise ValueError("SPDX graph supports local description, containment and dependency")

    if len(described) != 1 or (declared and set(declared) != described):
        raise ValueError("SPDX graph requires one consistently described container root")

    root_id = next(iter(described))

    if root_id not in packages or packages[root_id].get("primaryPackagePurpose") != "CONTAINER":
        raise ValueError("SPDX graph described root must resolve to a CONTAINER package")

    if any(package.get("primaryPackagePurpose") == "CONTAINER" for identifier, package
           in packages.items() if identifier != root_id):
        raise ValueError("SPDX graph supports exactly one container package")

    CheckContainment(root_id, set(packages), {
        (edge.source, edge.target) for edge in edges if edge.kind == "CONTAINS"
    })
    hashes = []

    for value in Items(packages[root_id].get("checksums")):
        checksum = Record(value)

        if Text(checksum.get("algorithm")) == "SHA256":
            hashes.append(Digest("sha256:" + Text(checksum.get("checksumValue"))))

    if hashes != [image_identity.digest]:
        raise ValueError("SPDX graph root requires one explicitly bound SHA256 checksum")

    return SourceCatalog(root_id, packages, tuple(edges))

RevalidateInputs(state: ModelState, record: EvidenceRecord, provenance: ModelProvenance, image_identity: ImageIdentity) -> None

Reconstruct exact typed inputs before reading evidence or trusting frozen instance fields.

Parameters:

Name Type Description Default
state ModelState

Original canonical basis snapshot, including its existing triage history.

required
record EvidenceRecord

Original manifest identity with exact typed reference and acquisition provenance.

required
provenance ModelProvenance

Offline attribution bound to the original source by VerifyRecords.

required
image_identity ImageIdentity

Explicit validated hash-kind identity.

required

Raises:

Type Description
ValueError

Subclasses, untyped inputs, mutated frozen fields or offline execution appear.

Source code in fuzzy1337/sbom_graph.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
def RevalidateInputs(state: ModelState, record: EvidenceRecord, provenance: ModelProvenance,
                     image_identity: ImageIdentity) -> None:
    """Reconstruct exact typed inputs before reading evidence or trusting frozen instance fields.

    Args:
        state: Original canonical basis snapshot, including its existing triage history.
        record: Original manifest identity with exact typed reference and acquisition provenance.
        provenance: Offline attribution bound to the original source by VerifyRecords.
        image_identity: Explicit validated hash-kind identity.

    Raises:
        ValueError: Subclasses, untyped inputs, mutated frozen fields or offline execution appear.
    """

    if type(state) is not ModelState or type(record) is not EvidenceRecord or (
        type(provenance) is not ModelProvenance or type(image_identity) is not ImageIdentity
    ):
        raise ValueError("SPDX graph requires exact typed model, evidence, attribution and image")

    if type(record.reference) is not EvidenceReference or (
        type(record.provenance) is not EvidenceProvenance
        or type(provenance.evidence_references) is not tuple
        or any(type(item) is not EvidenceReference for item in provenance.evidence_references)
        or provenance.execution is not None or record.provenance.execution is not None
        or record.provenance.invocation_sha256 is not None or record.reference.role != "sbom"
    ):
        raise ValueError("SPDX graph requires exact original offline sbom acquisition fields")

    for field_name, expected in (
        ("objects", SecurityObject), ("relations", Relation), ("observations", Observation),
    ):
        values = getattr(state, field_name)

        if type(values) is not tuple or any(type(value) is not expected for value in values):
            raise ValueError("SPDX graph basis requires exact typed model collections")

    entities: tuple[SecurityObject | Relation, ...] = (*state.objects, *state.relations)

    if any(type(item.identity) is not ObjectIdentity for item in state.objects) or any(
        type(item.provenance) is not tuple for item in entities
    ):
        raise ValueError("SPDX graph basis requires exact typed identities and attribution")

    records: tuple[SecurityObject | Relation | Observation, ...] = (*entities, *state.observations)

    if any(type(item.attributes) is not MappingProxyType for item in records):
        raise ValueError("SPDX graph basis requires exact typed immutable model attributes")

    attribution = [provenance, *(item.provenance for item in state.observations)]

    for item in entities:
        attribution.extend(item.provenance)

    for context in attribution:
        if type(context) is not ModelProvenance or (
            type(context.evidence_references) is not tuple
            or any(type(reference) is not EvidenceReference
                   for reference in context.evidence_references)
            or (context.execution is not None and type(context.execution) is not AdapterExecution)
        ):
            raise ValueError("SPDX graph basis requires exact typed provenance and references")

    try:
        rebuilt_record = ParseEvidenceManifest(record.Serialize())
        rebuilt_provenance = ModelProvenance.FromDict(JsonValue(provenance))
        rebuilt_image = ImageIdentity(image_identity.digest, image_identity.digest_kind)
        rebuilt_state = ModelState.FromDict(state.ToDict())

        if rebuilt_record != record or rebuilt_provenance != provenance or (
            rebuilt_image != image_identity or rebuilt_state != state
        ):
            raise ValueError("changed frozen graph input")

    except (ValueError, TypeError, AttributeError, OverflowError, RecursionError):
        raise ValueError("SPDX graph input differs from its validated original fields") from None

GraphCandidates(raw: bytes, workspace_id: str, record: EvidenceRecord, provenance: ModelProvenance, image_identity: ImageIdentity) -> tuple[list[SecurityObject], list[Relation], list[Observation]]

Produce source-bound graph interpretations without filesystem, process or network I/O.

Parameters:

Name Type Description Default
raw bytes

Original bytes already verified against the exact immutable source manifest.

required
workspace_id str

Existing model workspace identity.

required
record EvidenceRecord

Verified original manifest, never a fabricated producer receipt.

required
provenance ModelProvenance

Revalidated matching source acquisition attribution.

required
image_identity ImageIdentity

Explicit root checksum and hash-kind semantics.

required

Returns:

Type Description
tuple[list[SecurityObject], list[Relation], list[Observation]]

Fully validated canonical objects, exact source relations and inert licensing facts.

Raises:

Type Description
ValueError

Source profile, licensing, package linkage or canonical containment fails.

Source code in fuzzy1337/sbom_graph.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
def GraphCandidates(raw: bytes, workspace_id: str, record: EvidenceRecord,
                    provenance: ModelProvenance, image_identity: ImageIdentity
                    ) -> tuple[list[SecurityObject], list[Relation], list[Observation]]:
    """Produce source-bound graph interpretations without filesystem, process or network I/O.

    Args:
        raw: Original bytes already verified against the exact immutable source manifest.
        workspace_id: Existing model workspace identity.
        record: Verified original manifest, never a fabricated producer receipt.
        provenance: Revalidated matching source acquisition attribution.
        image_identity: Explicit root checksum and hash-kind semantics.

    Returns:
        Fully validated canonical objects, exact source relations and inert licensing facts.

    Raises:
        ValueError: Source profile, licensing, package linkage or canonical containment fails.
    """

    payload = SpdxJson(raw)
    SpdxHeader(payload)
    catalog = GraphCatalog(payload, image_identity)
    image = SecurityObject(image_identity.Object(workspace_id), {
        "asset_type": "image", "digest": image_identity.digest,
        "digest_kind": image_identity.digest_kind,
    }, (provenance,))
    objects = [image]
    entities = {}
    relations = []
    observations = []
    basis = {"document_sha256": record.reference.sha256, "evidence_id": record.evidence_id,
             "image_reference": image.Reference()}

    for identifier in sorted(catalog.packages):
        package = catalog.packages[identifier]
        identity = SpdxPurl(package, root=identifier == catalog.root_id)
        entity = image if identity is None else SecurityObject(
            identity.Object(workspace_id), PackageFields(identity), (provenance,),
        )
        entities[identifier] = entity

        if identity is not None:
            objects.append(entity)

        declared = SpdxLicense(package.get("licenseDeclared"), present="licenseDeclared" in package)
        concluded = SpdxLicense(
            package.get("licenseConcluded"), present="licenseConcluded" in package,
        )
        alias = {**basis, "spdx_id": identifier}
        observations.append(Observation("spdx-source-alias", entity.Reference(), alias, provenance))
        observations.append(Observation("spdx-package-license", entity.Reference(), {
            **alias, "declared": declared, "concluded": concluded,
        }, provenance))

        if declared["state"] == "expression":
            licenses, links = LicenseObjects(workspace_id, entity, [declared["expression"]],
                                            provenance)
            objects.extend(licenses)
            relations.extend(links)

    CheckContainment(image.Reference(), {entity.Reference() for entity in entities.values()}, {
        (entities[edge.source].Reference(), entities[edge.target].Reference())
        for edge in catalog.edges if edge.kind == "CONTAINS"
    })

    for edge in catalog.edges:
        source, target = entities[edge.source].Reference(), entities[edge.target].Reference()
        relation = Relation(RelationKind.CONTAINS if edge.kind == "CONTAINS"
                            else RelationKind.RELATED_TO, source, target,
                            {} if edge.kind == "CONTAINS"
                            else {"association": "spdx-dependency-claim"}, (provenance,))
        relations.append(relation)
        observations.append(Observation("spdx-relationship-claim", relation.Reference(), {
            **basis, "relationship_index": edge.index,
            "original_source_id": edge.original_source, "original_type": edge.original_kind,
            "original_target_id": edge.original_target, "source_id": edge.source,
            "relationship_type": edge.kind, "target_id": edge.target,
            "source_reference": source, "target_reference": target,
        }, provenance))

    observations.append(Observation("image-sbom-inventory", image.Reference(), {
        **basis, "format": "SPDX", "spec_version": "2.3", "profile": "local-package-graph-v1",
    }, provenance))

    return objects, relations, observations

ApplyVerifiedSpdxGraph(state: ModelState, record: EvidenceRecord, provenance: ModelProvenance, image_identity: ImageIdentity, workspace_root: Path) -> tuple[ModelState, ModelDelta]

Opt in to bounded local SPDX graph claims through original evidence and canonical model.

Parameters:

Name Type Description Default
state ModelState

Original validated same-workspace basis snapshot; existing triage is retained.

required
record EvidenceRecord

Explicit immutable independently acquired offline sbom EvidenceRecord.

required
provenance ModelProvenance

Matching acquisition attribution with no invocation or execution fabrication.

required
image_identity ImageIdentity

Caller-declared config or manifest identity bound to one root checksum.

required
workspace_root Path

Owned existing or relocated workspace retaining the original source.

required

Returns:

Type Description
ModelState

One atomic in-memory transition. The caller owns LocalModelStore.Save and its CAS check.

ModelDelta

Dependency relations describe source claims; they assert no runtime reachability.

Raises:

Type Description
ValueError

Typed inputs, manifest bindings, package/graph/license profile or basis fail.

EvidenceError

Original immutable manifest or raw source bytes fail verification.

OSError

Owning workspace metadata or evidence cannot be read.

Source code in fuzzy1337/sbom_graph.py
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
def ApplyVerifiedSpdxGraph(state: ModelState, record: EvidenceRecord,
                          provenance: ModelProvenance, image_identity: ImageIdentity,
                          workspace_root: Path) -> tuple[ModelState, ModelDelta]:
    """Opt in to bounded local SPDX graph claims through original evidence and canonical model.

    Args:
        state: Original validated same-workspace basis snapshot; existing triage is retained.
        record: Explicit immutable independently acquired offline sbom EvidenceRecord.
        provenance: Matching acquisition attribution with no invocation or execution fabrication.
        image_identity: Caller-declared config or manifest identity bound to one root checksum.
        workspace_root: Owned existing or relocated workspace retaining the original source.

    Returns:
        One atomic in-memory transition. The caller owns LocalModelStore.Save and its CAS check.
        Dependency relations describe source claims; they assert no runtime reachability.

    Raises:
        ValueError: Typed inputs, manifest bindings, package/graph/license profile or basis fail.
        EvidenceError: Original immutable manifest or raw source bytes fail verification.
        OSError: Owning workspace metadata or evidence cannot be read.
    """

    RevalidateInputs(state, record, provenance, image_identity)
    raw = VerifyRecords(state, provenance, (record,), workspace_root)["sbom"]
    objects, relations, observations = GraphCandidates(raw, state.workspace_id, record,
                                                       provenance, image_identity)

    return ApplyBatch(state, objects, relations, observations, [], workspace_root)