sbom-nexus/src/sbom_nexus/cli.py
tegwick 879012c776
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 38s
feat: add controlled source ingestion and replay
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02b22-9638-76d2-bbff-b7ea1770b118
2026-08-22 23:57:37 +02:00

73 lines
2.2 KiB
Python

"""Operator CLI for SBOM Nexus."""
from __future__ import annotations
import argparse
import json
import os
from pathlib import Path
from sbom_nexus.scanner import scan_repository
def _serve(args: argparse.Namespace) -> None:
if args.database_url:
os.environ["SBOM_NEXUS_DATABASE_URL"] = args.database_url
elif args.database:
os.environ["SBOM_NEXUS_DATABASE_PATH"] = str(Path(args.database).resolve())
import uvicorn
uvicorn.run(
"sbom_nexus.api:create_app",
host=args.host,
port=args.port,
reload=args.reload,
factory=True,
)
def _scan(args: argparse.Namespace) -> None:
result = scan_repository(
Path(args.path), slug=args.slug, source_revision=args.source_revision
)
rendered = json.dumps(result, indent=2, sort_keys=True)
if args.output:
output = Path(args.output)
if output.exists() and not args.force:
raise SystemExit(f"Refusing to overwrite {output}; pass --force")
output.write_text(rendered + "\n", encoding="utf-8")
else:
print(rendered)
if not result["ok"]:
raise SystemExit(1)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="sbom-nexus")
subparsers = parser.add_subparsers(dest="command", required=True)
serve = subparsers.add_parser("serve", help="Run the SBOM Nexus HTTP API")
serve.add_argument("--host", default="127.0.0.1")
serve.add_argument("--port", type=int, default=8010)
serve.add_argument("--database", help="SQLite database path")
serve.add_argument("--database-url", help="SQLAlchemy database URL (PostgreSQL in production)")
serve.add_argument("--reload", action="store_true")
serve.set_defaults(handler=_serve)
scan = subparsers.add_parser("scan", help="Derive a snapshot from repository sources")
scan.add_argument("path", nargs="?", default=".")
scan.add_argument("--slug")
scan.add_argument("--source-revision")
scan.add_argument("--output")
scan.add_argument("--force", action="store_true")
scan.set_defaults(handler=_scan)
return parser
def main() -> None:
args = build_parser().parse_args()
args.handler(args)
if __name__ == "__main__":
main()