feat(sbom): project immutable Forgejo source refs

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
This commit is contained in:
tegwick 2026-08-22 23:34:01 +02:00
parent b068e9da42
commit e6cc18bf18
6 changed files with 543 additions and 3 deletions

View file

@ -361,6 +361,18 @@ def main(argv: list[str] | None = None) -> int:
)
p_sbom_report.add_argument("--path", default=".")
p_sbom_report.add_argument("--slug", default=None)
p_sbom_source = sbom_sub.add_parser(
"source-ref",
help="Resolve a controlled Forgejo source reference and optionally project it",
)
p_sbom_source.add_argument("--path", default=".")
p_sbom_source.add_argument("--slug", default=None)
p_sbom_source.add_argument("--remote", default="origin")
p_sbom_source.add_argument(
"--forgejo-base", default="https://forgejo.coulomb.social"
)
p_sbom_source.add_argument("--project", action="store_true")
p_sbom_source.add_argument("--confirm-authoritative", action="store_true")
p_authority = sub.add_parser("authority", help="Resolve the one authoritative record owner")
authority_sub = p_authority.add_subparsers(dest="authority_command")
@ -811,6 +823,60 @@ def main(argv: list[str] | None = None) -> int:
if not args.sbom_command:
p_sbom.print_help()
return 2
if args.sbom_command == "source-ref":
from repo_manager.sbom_client import (
SBOMNexusClient,
SBOMNexusConfig,
SBOMServiceError,
)
from repo_manager.source_ref import ForgejoSourceResolver
resolution = ForgejoSourceResolver(base_url=args.forgejo_base).resolve(
Path(args.path),
repo_slug=args.slug,
remote_name=args.remote,
)
if not args.project:
print(json.dumps(resolution, indent=2))
return 0 if resolution.get("supported") else 1
if not args.confirm_authoritative:
print(
json.dumps(
{
"ok": False,
"error": "--project requires --confirm-authoritative",
"resolution": resolution,
},
indent=2,
)
)
return 2
if not resolution.get("supported"):
print(json.dumps(resolution, indent=2))
return 1
try:
client = SBOMNexusClient(SBOMNexusConfig.from_environment())
projection = client.upsert_repository(
resolution["repo_slug"],
nexus_checkout_path=None,
source_ref=resolution["source_ref"],
)
except (ValueError, SBOMServiceError) as exc:
error = exc.to_dict() if isinstance(exc, SBOMServiceError) else {"code": "config_error"}
print(
json.dumps(
{"ok": False, "error": error, "resolution": resolution},
indent=2,
)
)
return 1
print(
json.dumps(
{"ok": True, "resolution": resolution, "projection": projection},
indent=2,
)
)
return 0
from repo_manager.sbom_client import (
licence_report_from_snapshot,
scan_repository_via_nexus,