Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add/update metadata in SBOM #7

Merged
merged 3 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion complassist/_clearlydefined.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def get_clearlydefined_license_and_copyright(coordinates: str) -> tuple[str, str
declared_license, copyrights = _extract_license_copyright(api_return)

# Declared license couldn't be extracted. Add to harvest
if declared_license is None:
if not declared_license:
logging.info(
"Adding %s to be harvest by ClearlyDefined. "
"Make sure the package and this version actually exists, and try again later.",
Expand Down
61 changes: 61 additions & 0 deletions complassist/_sbom_full.py → complassist/_sbom_enrich.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"""Generate a CycloneDX SBOM and enrich its licensing data via ClearlyDefined"""

import logging
from datetime import datetime

from . import __version__
from ._clearlydefined import (
get_clearlydefined_license_and_copyright,
purl_to_cd_coordinates,
Expand Down Expand Up @@ -170,6 +172,62 @@ def _enrich_component_with_cd_data(component: dict) -> None:
logging.debug("[%s] %s", purl, msg)


def _update_sbom_metadata(sbom: dict) -> dict:
"""
Updates the Software Bill of Materials (SBOM) with additional metadata.

This function updates the SBOM dictionary by incrementing its version,
adding a current timestamp, and appending metadata about the tool used for
compliance assistance. If necessary, it creates missing sections in the
SBOM metadata.

Args:
sbom (dict): The SBOM dictionary to be updated.

Returns:
dict: The updated SBOM dictionary with the new metadata values.
"""

# Prepare new/additional metadata values
version = int(sbom.get("version", 1)) + 1
timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
tool = {
"name": "compliance-assistant",
"group": "OpenRailAssociation",
"version": __version__,
"purl": f"pkg:pypi/compliance-assistant@{__version__}",
"bom-ref": f"pkg:pypi/compliance-assistant@{__version__}",
"type": "application",
"author": "OpenRail Association",
"publisher": "OpenRail Association",
}
author = {
"name": "compliance-assistant by OpenRail Association",
}

# Set new version
sbom["version"] = version
# Add timestamp (and metadata if missing)
try:
sbom["metadata"]["timestamp"] = timestamp
except KeyError:
sbom["metadata"] = {"timestamp": timestamp}
# Add tool component
try:
sbom["metadata"]["tools"]["components"].append(tool)
except KeyError:
if "tools" not in sbom["metadata"]:
sbom["metadata"]["tools"] = {}
sbom["metadata"]["tools"]["components"] = [tool]
# Add author
try:
sbom["metadata"]["authors"].append(author)
except KeyError:
sbom["metadata"]["authors"] = [author]

return sbom


def enrich_sbom_with_clearlydefined(sbom_file: str, output_file: str) -> None:
"""
Parse a SBOM and enrich license/copyright data of each component with
Expand All @@ -194,4 +252,7 @@ def enrich_sbom_with_clearlydefined(sbom_file: str, output_file: str) -> None:
for component in sbom.get("components", []):
_enrich_component_with_cd_data(component)

# Update SBOM metadata
sbom = _update_sbom_metadata(sbom)

write_json_file(sbom, output_file)
18 changes: 9 additions & 9 deletions complassist/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
purl_to_cd_coordinates,
)
from ._helpers import dict_to_json
from ._sbom_full import enrich_sbom_with_clearlydefined
from ._sbom_enrich import enrich_sbom_with_clearlydefined
from ._sbom_generate import generate_cdx_sbom
from ._sbom_parse import extract_items_from_cdx_sbom

Expand Down Expand Up @@ -167,14 +167,14 @@ def main():
elif args.command == "clearlydefined":
if args.purl_to_coordinates:
print(purl_to_cd_coordinates(args.purl_to_coordinates))
elif args.purl:
print_clearlydefined_result(
get_clearlydefined_license_and_copyright(
coordinates=purl_to_cd_coordinates(args.purl)
)
)
elif args.coordinates:
print_clearlydefined_result(get_clearlydefined_license_and_copyright(args.coordinates))

elif args.coordinates or args.purl:
if args.purl:
coordinates = purl_to_cd_coordinates(args.purl)
else:
coordinates = args.coordinates

print_clearlydefined_result(get_clearlydefined_license_and_copyright(coordinates))

else:
logging.critical("No valid command provided!")
Expand Down