Skip to content

Commit 19eb1e1

Browse files
NRL-1928 Generate asdf SBOM and merge into big python + tf one
1 parent ba07f6e commit 19eb1e1

5 files changed

Lines changed: 119 additions & 9 deletions

File tree

.github/workflows/release.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ jobs:
7272
- name: Create SBOM
7373
run: bash scripts/sbom-create.sh
7474

75+
- name: Generate ASDF SBOM
76+
working-directory: ./main-repo
77+
run: poetry run python scripts/asdf_to_sbom.py
78+
7579
- name: Upload SBOM artifact
7680
uses: actions/upload-artifact@v4
7781
with:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,6 @@ producer-internal-*.json
8484
producer-public-*.json
8585
consumer-internal-*.json
8686
consumer-public-*.json
87+
88+
# SBOM files
89+
sbom*.spdx.json

scripts/sbom-create.sh

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,4 @@ REPO_ROOT=$(git rev-parse --show-toplevel)
22

33
syft -o spdx-json . > sbom.spdx.json
44

5-
# for tool in "$@"; do
6-
# echo "Creating SBOM for $tool and merging"
7-
# # syft -q -o spdx-json "$(which "$tool")" | python "$REPO_ROOT/scripts/sbom-update.py"
8-
# syft -q -o spdx-json "$(which "$tool")"
9-
# done
5+
poetry run python "$REPO_ROOT/scripts/sbom_from_asdf.py" | poetry run python "$REPO_ROOT/scripts/sbom_update.py"

scripts/sbom_from_asdf.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env python3
2+
"""Generate an SBOM-looking document for our asdf dependencies"""
3+
4+
import json
5+
import re
6+
from pathlib import Path
7+
8+
9+
def parse_tool_versions(file_path=".tool-versions"):
10+
tools = []
11+
12+
if not Path(file_path).exists():
13+
return tools
14+
15+
with open(file_path, "r") as f:
16+
for line in f:
17+
line = line.strip()
18+
if not line or line.startswith("#"):
19+
continue
20+
21+
parts = line.split()
22+
if len(parts) >= 2:
23+
tool_name = parts[0]
24+
version = parts[1]
25+
tools.append({"name": tool_name, "version": version})
26+
27+
return tools
28+
29+
30+
# def create_spdx_package(tool, index):
31+
# package_id = f"SPDXRef-Package-asdf-{tool['name']}-{index}"
32+
33+
# return {
34+
# "name": tool["name"],
35+
# "SPDXID": package_id,
36+
# "versionInfo": tool["version"],
37+
# "supplier": "NOASSERTION",
38+
# "downloadLocation": "NOASSERTION",
39+
# "filesAnalyzed": False,
40+
# "sourceInfo": "ASDF-managed tool: acquired package info from /.tool-versions",
41+
# "licenseConcluded": "NOASSERTION",
42+
# "licenseDeclared": "NOASSERTION",
43+
# "copyrightText": "NOASSERTION",
44+
# "externalRefs": [
45+
# {
46+
# "referenceCategory": "PACKAGE-MANAGER",
47+
# "referenceType": "purl",
48+
# "referenceLocator": f"pkg:generic/{tool['name']}@{tool['version']}",
49+
# }
50+
# ],
51+
# }
52+
53+
54+
def generate_asdf_sbom(output_file="sbom-asdf.spdx.json"):
55+
tools = parse_tool_versions()
56+
57+
print(f"Found {len(tools)} ASDF-managed tools")
58+
59+
sbom = {
60+
"spdxVersion": "SPDX-2.3",
61+
"dataLicense": "CC0-1.0",
62+
"SPDXID": "SPDXRef-DOCUMENT",
63+
"name": "asdf-tools",
64+
"packages": [
65+
{
66+
"name": tool["name"],
67+
"SPDXID": f"SPDXRef-Package-asdf-{tool['name']}-{index}",
68+
"versionInfo": tool["version"],
69+
"supplier": "NOASSERTION",
70+
"downloadLocation": "NOASSERTION",
71+
"filesAnalyzed": False,
72+
"sourceInfo": "ASDF-managed tool: acquired package info from /.tool-versions",
73+
"licenseConcluded": "NOASSERTION",
74+
"licenseDeclared": "NOASSERTION",
75+
"copyrightText": "NOASSERTION",
76+
"externalRefs": [
77+
{
78+
"referenceCategory": "PACKAGE-MANAGER",
79+
"referenceType": "purl",
80+
"referenceLocator": f"pkg:generic/{tool['name']}@{tool['version']}",
81+
}
82+
],
83+
}
84+
for index, tool in enumerate(tools)
85+
],
86+
# "packages": [create_spdx_package(tool, idx) for idx, tool in enumerate(tools)],
87+
"relationships": [
88+
{
89+
"spdxElementId": "SPDXRef-DOCUMENT",
90+
"relationshipType": "DESCRIBES",
91+
"relatedSpdxElement": f"SPDXRef-Package-asdf-{tool['name']}-{index}",
92+
}
93+
for index, tool in enumerate(tools)
94+
],
95+
}
96+
97+
with open(output_file, "w") as f:
98+
json.dump(sbom, f, indent=2)
99+
100+
print(f"Generated SBOM with {len(tools)} ASDF-managed tools")
101+
return output_file
102+
103+
104+
if __name__ == "__main__":
105+
generate_asdf_sbom()
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
import sys
33
from pathlib import Path
44

5+
import fire
56

6-
def main() -> None:
7-
with Path("sbom.spdx.json").open("r") as f:
7+
8+
def update_sbom(existing_sbom="sbom.spdx.json") -> None:
9+
with Path(existing_sbom).open("r") as f:
810
sbom = json.load(f)
911

1012
tool = json.loads(sys.stdin.read())
@@ -13,9 +15,9 @@ def main() -> None:
1315
sbom.setdefault("files", []).extend(tool.setdefault("files", []))
1416
sbom.setdefault("relationships", []).extend(tool.setdefault("relationships", []))
1517

16-
with Path("sbom.spdx.json").open("w") as f:
18+
with Path(existing_sbom).open("w") as f:
1719
json.dump(sbom, f)
1820

1921

2022
if __name__ == "__main__":
21-
main()
23+
fire.Fire(update_sbom)

0 commit comments

Comments
 (0)