"""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()