8000 Create utility for generating SBOM from artifacts by sethmlarson · Pull Request #82 · python/release-tools · GitHub
[go: up one dir, main page]

Skip to content

Create utility for generating SBOM from artifacts #82

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

Merged
merged 5 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add SBOM build step to run_release.py
  • Loading branch information
sethmlarson committed Jan 17, 2024
commit b1ce47207e412ff8403a0c53f7ceea42cf5c40d7
23 changes: 23 additions & 0 deletions run_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import functools
import getpass
import itertools
import json
import os
import pathlib
import re
Expand All @@ -34,6 +35,7 @@

import release as release_mod
from buildbotapi import BuildBotAPI
import sbom

API_KEY_REGEXP = re.compile(r"(?P<major>\w+):(?P<minor>\w+)")

Expand Down Expand Up @@ -486,6 +488,26 @@ def test_release_artifacts(db: DbfilenameShelf) -> None:
raise ReleaseException("Test failed!")


def build_sbom_artifacts(db):

# Skip building an SBOM if there isn't an 'Misc/sbom.spdx.json' file.
if not (db["git_repo"] / "Misc/sbom.spdx.json").exists():
print("Skipping building an SBOM, missing 'Misc/sbom.spdx.json'")
return

release_version = db["release"]
# For each source tarball build an SBOM.
for ext in (".tgz", ".tar.xz"):
tarball_name = f"Python-{release_version}{ext}"
tarball_path = str(db["git_repo"] / str(db["release"]) / "src" / tarball_name)

print(f"Building an SBOM for artifact '{tarball_name}'")
sbom_data = sbom.create_sbom_for_source_tarball(tarball_path)

with open(tarball_path + ".spdx.json", mode="w") as f:
f.write(json.dumps(sbom_data, indent=2, sort_keys=True))


class MySFTPClient(paramiko.SFTPClient):
def put_dir(self, source, target, progress=None):
for item in os.listdir(source):
Expand Down Expand Up @@ -1020,6 +1042,7 @@ def _api_key(api_key):
Task(create_tag, "Create tag"),
Task(build_release_artifacts, "Building release artifacts"),
Task(test_release_artifacts, "Test release artifacts"),
Task(build_sbom_artifacts, "Building SBOM artifacts"),
Task(upload_files_to_server, "Upload files to the PSF server"),
Task(place_files_in_download_folder, "Place files in the download folder"),
Task(upload_docs_to_the_docs_server, "Upload docs to the PSF docs server"),
Expand Down
19 changes: 15 additions & 4 deletions sbom.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""
Utility which creates Software Bill-of-Materials (SBOM)
for CPython release artifacts.
for CPython release artifacts. Can also be run manually with:

$ python sbom.py <artifact>

"""

import datetime
Expand Down Expand Up @@ -94,7 +97,10 @@ def calculate_package_verification_codes(sbom) -> None:
def get_release_tools_commit_sha() -> str:
"""Gets the git commit SHA of the release-tools repository"""
git_prefix = os.path.abspath(os.path.dirname(__file__))
stdout = subprocess.check_output(["git", "rev-parse", "--prefix", git_prefix, "HEAD"]).decode("ascii")
stdout = subprocess.check_output(
["git", "rev-parse", "--prefix", git_prefix, "HEAD"],
cwd=git_prefix
).decode("ascii")
assert re.match(r"^[a-f0-9]{40,}$", stdout)
return stdout

Expand All @@ -117,13 +123,18 @@ def create_sbom_for_source_tarball(tarball_path: str):
cpython_version_without_suffix = re.match(r"^([0-9.]+)", cpython_version).group(1)
tarball_download_location = f"https://www.python.org/ftp/python/{cpython_version_without_suffix}/{tarball_name}"

# Take some hashes of the tarball
# Take a hash of the tarball
with open(tarball_path, mode="rb") as f:
tarball_checksum_sha256 = hashlib.sha256(f.read()).hexdigest()

# There should be an SBOM included in the tarball.
# If there's not we can't create an SBOM.
sbom_tarball_member = tarball.getmember(f"Python-{cpython_version}/Misc/sbom.spdx.json")
try:
sbom_tarball_member = tarball.getmember(f"Python-{cpython_version}/Misc/sbom.spdx.json")
except KeyError:
raise ValueError(
"Tarball doesn't contain an SBOM at 'Misc/sbom.spdx.json'"
) from None
sbom_bytes = tarball.extractfile(sbom_tarball_member).read()

sbom = json.loads(sbom_bytes)
Expand Down
0