Skip to content

Commit

Permalink
Add CLI, SBOM merger util
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuatz committed Oct 1, 2024
1 parent 4f04654 commit bfe9ff9
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 1 deletion.
25 changes: 25 additions & 0 deletions django_utils_lib/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from pathlib import Path
from typing import List

import typer
from rich.console import Console

from django_utils_lib.commands import generate_combined_spdx_sbom_json as generate_combined_spdx_sbom_json_cmd

app = typer.Typer()
console = Console()


@app.command()
def generate_combined_spdx_sbom_json(
sbom_paths: List[str],
out_path: Path,
merged_name="Combined SBOM",
merged_namespace="https//localhost",
):
out_json = generate_combined_spdx_sbom_json_cmd(sbom_paths, merged_name, merged_namespace)
out_path.write_text(out_json)


if __name__ == "__main__":
app()
25 changes: 25 additions & 0 deletions django_utils_lib/cli_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from typing import Any

import rich.markup as rich_markup
from rich.console import Console


class AlwaysEscapeMarkupConsole(Console):
"""
Wrapper around Rich's Console to force logging to alway use markup AND escape output
Note: It would be nice to be able to use `console.push_render_hook` to implement
escaping through a custom renderer hook, rather than having to subclass the
entire `Console` class, but the render hook appears to come too late in the
processing chain to be able to auto-escape.
"""

def __init__(self, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs)
self._markup = True

def log(self, *objects: Any, **kwargs: Any) -> None:
return super().log(*[rich_markup.escape(o) for o in objects], **kwargs)

def print(self, *objects: Any, **kwargs: Any) -> None:
return super().print(*[rich_markup.escape(o) for o in objects], **kwargs)
30 changes: 30 additions & 0 deletions django_utils_lib/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import json
from pathlib import Path
from typing import Dict, List


def generate_combined_spdx_sbom_json(
sbom_paths: List[str],
merged_name="Combined SBOM",
merged_namespace="https//localhost",
) -> str:
"""
Combine multiple SPDX formatted JSON SBOMs, into a single JSON file
Warning: This is a basic implementation that makes some assumptions about the
validity of the input files and what sort of output is desired.
"""
with open(sbom_paths[0], "r") as file:
combined_sbom_json: Dict = json.load(file)
expected_spdx_version = combined_sbom_json["spdxVersion"]
combined_sbom_json["name"] = merged_name
combined_sbom_json["documentNamespace"] = merged_namespace

for sbom_path in sbom_paths:
sbom_json = json.loads(Path(sbom_path).read_text())
# Don't allow combining outputs with different versions
assert sbom_json["spdxVersion"] == expected_spdx_version
for sbom_key in ["files", "packages", "relationships"]:
combined_sbom_json[sbom_key] += sbom_json[sbom_key]

return json.dumps(combined_sbom_json, indent=2)
112 changes: 111 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ description = "A utility library for working with Django"
authors = ["Innolitics"]
readme = "README.md"

[tool.poetry.scripts]
dul-cli = "django_utils_lib.cli:app"

[tool.poetry.dependencies]
python = "^3.9"
typer = "^0.12.5"


[tool.poetry.group.dev.dependencies]
Expand Down Expand Up @@ -39,6 +43,7 @@ testpaths = [
]
pythonpath = ". django_utils_lib"
auto_debug = true
auto_debug_wait_for_connect = false

[build-system]
requires = ["poetry-core"]
Expand Down

0 comments on commit bfe9ff9

Please sign in to comment.