import json
import sys
from typing import Set, List, Dict
ATTRIBUTION_REQUIRED_LICENSES: Set[str] = {
"Apache-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"BSD-4-Clause",
"MIT",
}
def extract_license_from_component(component: Dict) -> Set[str]:
licenses: Set[str] = set()
if "licenses" not in component:
return licenses
for lic_entry in component["licenses"]:
if "license" in lic_entry and "id" in lic_entry["license"]:
licenses.add(lic_entry["license"]["id"])
if "expression" in lic_entry:
expr = lic_entry["expression"]
parts = expr.replace("(", "").replace(")", "")
parts = parts.replace(" OR ", " ").replace(" AND ", " ").replace(" WITH ", " ")
for part in parts.split():
if part and not part.isspace():
licenses.add(part)
return licenses
def requires_attribution(licenses: Set[str]) -> bool:
return bool(licenses.intersection(ATTRIBUTION_REQUIRED_LICENSES))
def generate_notice(sbom_path: str) -> str:
try:
with open(sbom_path, 'r') as f:
sbom = json.load(f)
except Exception as e:
print(f"Error reading SBOM: {e}", file=sys.stderr)
sys.exit(1)
components = sbom.get("components", [])
attribution_components: List[tuple[str, str, Set[str]]] = []
for component in components:
name = component.get("name", "unknown")
version = component.get("version", "unknown")
licenses = extract_license_from_component(component)
if licenses and requires_attribution(licenses):
attribution_components.append((name, version, licenses))
attribution_components.sort(key=lambda x: x[0].lower())
notice = []
notice.append("EdgeFirst Perception Schemas")
notice.append("Copyright © 2025 Au-Zone Technologies. All Rights Reserved.")
notice.append("")
notice.append("This product includes software developed at Au-Zone Technologies")
notice.append("(https://au-zone.com/).")
notice.append("")
notice.append("This software contains components from the following third-party projects")
notice.append("that require attribution:")
notice.append("")
if attribution_components:
for name, version, licenses in attribution_components:
license_str = ", ".join(sorted(licenses))
notice.append(f" * {name} {version} ({license_str})")
else:
notice.append(" (No third-party components requiring attribution)")
notice.append("")
notice.append("For a complete Software Content Register (SBOM) including all dependencies,")
notice.append("licenses, and version information, see the sbom.json file generated via")
notice.append("GitHub Actions in this repository or included in release artifacts.")
notice.append("")
return "\n".join(notice)
def main():
if len(sys.argv) != 2:
print("Usage: generate_notice.py <sbom.json>", file=sys.stderr)
sys.exit(1)
sbom_path = sys.argv[1]
notice_content = generate_notice(sbom_path)
print(notice_content)
if __name__ == "__main__":
main()