Add Neo4j output writer for Surfactant SBOM exports#629
Open
willis89pr wants to merge 6 commits into
Open
Conversation
Add a Neo4j output plugin that exports SBOM software, logical graph, filesystem tree, path, and hash data into Neo4j with stable node and relationship IDs. Register the Neo4j writer with the plugin manager and add a standalone loader script for importing existing CyTRICS SBOM JSON files. Also add generation-time logging for selected input/output plugins, loaded SBOM graph counts, and SBOM write progress.
for more information, see https://pre-commit.ci
✅ No SBOM Changes DetectedFor commit 8843037 (Run 27221309320) |
|
|
||
| def _rel_id(bom_uuid: str, graph_name: str, *parts: Any) -> str: | ||
| joined = "|".join(str(part) for part in (bom_uuid, graph_name, *parts)) | ||
| return f"{bom_uuid}:rel:{hashlib.sha1(joined.encode('utf-8')).hexdigest()}" |
nightlark
reviewed
Jun 9, 2026
added 4 commits
June 9, 2026 13:56
Skip path nodes and symlink/path edges mirrored into sbom.graph when building Neo4j logical relationship rows. Treat sbom.fs_tree as the authoritative source for filesystem topology to avoid duplicate Neo4j relationships. Update generate and Neo4j writer logging to report filtered logical relationship counts separately from total graph edge counts. Also split Neo4j import summary counts into logical graph edges, filesystem tree edges, and installed-at edges. Improve Neo4j loader/operator validation by adding clearer missing-driver handling and rejecting invalid batch sizes.
Declare the Neo4j Python driver dependency in inline script metadata so compatible runners can resolve the standalone loader's runtime dependency.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a built-in Neo4j output writer that exports Surfactant/CyTRICS SBOM data into a Neo4j graph database. It also adds a standalone import script for loading an existing SBOM JSON directly into Neo4j.
The writer exports logical SBOM relationships separately from filesystem topology. Logical relationships come from
sbom.graph, while filesystem/path topology comes fromsbom.fs_tree; mirrored path/symlink edges insbom.graphare filtered out to avoid duplicate Neo4j relationships.This PR also improves generate-time logging around input/output plugin selection, filtered logical relationship counts, total graph counts, filesystem tree counts, and SBOM output writing.
What changed
Added
surfactant/output/neo4j_writer.pyneo4joutput plugin.:SBOMEntity(id)to make repeated imports of the same content idempotent.sbom.graph.sbom.graphso filesystem topology is not exported twice.sbom.fs_tree.logical_graph_edges,fs_tree_edges, andinstalled_at_edgesin the import summary.NEO4J_BATCH_SIZE.NEO4J_BATCH_SIZEso invalid, zero, or negative values fail clearly.Added
scripts/load_sbom_to_neo4j.py--databaseand--batch-sizeCLI options.--batch-sizeso zero or negative values fail clearly.Registered the Neo4j writer in
surfactant/plugin/manager.pyImproved logging in
surfactant/cmd/generate.pyNeo4j graph model
The writer maps SBOM data into these node labels:
:SBOM:SBOMEntity:Software:SBOMEntity:Path:SBOMEntity:Hash:SBOMEntity:GraphEntity:SBOMEntityLogical SBOM relationships from
sbom.graphare written using sanitized NetworkX edge keys as Neo4j relationship types.Filesystem/path edges mirrored into
sbom.graphare intentionally skipped during logical relationship export.sbom.fs_treeis treated as the authoritative source for filesystem topology.Filesystem relationships from
sbom.fs_treeare written as:FS_CONTAINSSYMLINKHAS_CONTENT_HASHSoftware install-location relationships are written as:
INSTALLED_ATEach node and relationship includes stable IDs derived from the SBOM UUID and source graph data, so imports can be safely re-run without creating duplicate graph entities.
Usage
Using the output plugin through
surfactant generate:Using the standalone loader:
Optional environment variables:
The standalone loader also supports equivalent CLI options:
Testing
neo4joutput writer:Notes for reviewers
The Neo4j Python driver is required at runtime for the new writer and standalone loader. Both entry points now handle a missing driver with a clear error message, but this PR does not add dependency metadata for
neo4jto the project packaging configuration.Imports are idempotent for repeated imports of the same SBOM content because nodes and relationships use stable IDs. This PR does not implement replace/sync behavior for removing stale Neo4j entities if a later import uses the same
bomUUIDbut omits entities that were imported previously.