Skip to content

Commit e626ad2

Browse files
committed
scripts: Add syft-license-summary
Takes a Syft JSON file as a the first argument and outputs a human-readable summary of source packages and their licenses. Signed-off-by: Loïc Minier <[email protected]>
1 parent 2e54e35 commit e626ad2

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

scripts/syft-license-summary.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
5+
# input is a Syft JSON file as the first argument; output is a
6+
# human-readable summary of source packages and their licenses in CSV
7+
# format
8+
9+
import json
10+
import sys
11+
import hashlib
12+
from collections import defaultdict
13+
14+
15+
def load_syft_json(file_path):
16+
with open(file_path, 'r') as f:
17+
return json.load(f)
18+
19+
20+
def sha256_of_file(path):
21+
try:
22+
with open(path, 'rb') as f:
23+
return hashlib.sha256(f.read()).hexdigest()
24+
except Exception:
25+
return "unreadable"
26+
27+
28+
def group_by_source_package(data):
29+
grouped = defaultdict(lambda: {
30+
"binaries": set(),
31+
"licenses": set(),
32+
"copyrights": {},
33+
"source_version": None
34+
})
35+
36+
for artifact in data.get("artifacts", []):
37+
metadata = artifact.get("metadata", {})
38+
binary = metadata.get("package", "unknown")
39+
source = metadata.get("source") or binary
40+
version = metadata.get("version", "")
41+
source_version = metadata.get("sourceVersion") or version
42+
grouped[source]["binaries"].add(binary)
43+
grouped[source]["source_version"] = source_version
44+
45+
for lic in artifact.get("licenses", []):
46+
grouped[source]["licenses"].add(lic.get("value", "unknown"))
47+
48+
for loc in artifact.get("locations", []):
49+
path = loc.get("path", "")
50+
if "copyright" in path:
51+
grouped[source]["copyrights"][binary] = path
52+
53+
return grouped
54+
55+
56+
def print_table(grouped):
57+
print("source,version,binaries,licenses,copyright_sha256")
58+
for source, data in grouped.items():
59+
binaries = " ".join(sorted(data["binaries"]))
60+
licenses = " ".join(sorted(data["licenses"]))
61+
version = data["source_version"] or "unknown"
62+
63+
# Compute SHA256 hashes
64+
hashes = set()
65+
for path in data["copyrights"].values():
66+
hashes.add(sha256_of_file(path.lstrip('/')))
67+
hash_summary = " ".join(sorted(hashes))
68+
69+
print(f"{source},{version},{binaries},{licenses},{hash_summary}")
70+
71+
72+
if __name__ == "__main__":
73+
if len(sys.argv) != 2:
74+
print("Usage: syft-license-summary.py <syft-json-file>")
75+
sys.exit(1)
76+
77+
syft_file = sys.argv[1]
78+
syft_data = load_syft_json(syft_file)
79+
syft_grouped = group_by_source_package(syft_data)
80+
print_table(syft_grouped)

0 commit comments

Comments
 (0)