.PHONY: install install-cli db db-tools migrate seed api dashboard check start clean register-project validate-adr add-domain rename-domain add-repo list-repos COMPOSE = docker compose -f infra/docker-compose.yml --env-file .env install: uv sync ## Symlink the custodian CLI into ~/.local/bin so it's on PATH system-wide install-cli: install mkdir -p ~/.local/bin ln -sf "$(shell pwd)/.venv/bin/custodian" ~/.local/bin/custodian @echo "Installed: custodian → $$(readlink -f ~/.local/bin/custodian)" @echo "Make sure ~/.local/bin is on your PATH:" @echo " echo 'export PATH=\"\$$HOME/.local/bin:\$$PATH\"' >> ~/.bashrc && source ~/.bashrc" db: $(COMPOSE) up -d postgres db-tools: $(COMPOSE) --profile tools up -d migrate: uv run alembic upgrade head seed: uv run python scripts/seed.py api: uv run uvicorn api.main:app --reload --host 127.0.0.1 --port 8000 dashboard: cd dashboard && npm run dev check: curl -sf http://127.0.0.1:8000/state/health | python3 -m json.tool start: db sleep 3 $(MAKE) migrate $(MAKE) api ## Register a project: make register-project DOMAIN=railiance PROJECT_PATH=/home/worsch/railiance register-project: @test -n "$(DOMAIN)" || (echo "ERROR: DOMAIN is required. Usage: make register-project DOMAIN= PROJECT_PATH="; exit 1) @test -n "$(PROJECT_PATH)" || (echo "ERROR: PROJECT_PATH is required."; exit 1) scripts/register_project.sh "$(DOMAIN)" "$(PROJECT_PATH)" ## Add a second repo to an existing domain: make add-repo DOMAIN=railiance REPO_PATH=/home/worsch/railiance-infra add-repo: @test -n "$(DOMAIN)" || (echo "ERROR: DOMAIN is required."; exit 1) @test -n "$(REPO_PATH)" || (echo "ERROR: REPO_PATH is required."; exit 1) scripts/register_project.sh "$(DOMAIN)" "$(REPO_PATH)" --additional ## Create a new domain: make add-domain DOMAIN=my_domain NAME="My Domain" add-domain: @test -n "$(DOMAIN)" || (echo "ERROR: DOMAIN is required (slug)."; exit 1) @test -n "$(NAME)" || (echo "ERROR: NAME is required (display name)."; exit 1) curl -sf -X POST http://127.0.0.1:8000/domains/ \ -H "Content-Type: application/json" \ -d "{\"slug\": \"$(DOMAIN)\", \"name\": \"$(NAME)\"}" | python3 -m json.tool ## Rename a domain: make rename-domain DOMAIN=old_slug NEW_SLUG=new_slug NEW_NAME="New Name" rename-domain: @test -n "$(DOMAIN)" || (echo "ERROR: DOMAIN (old slug) is required."; exit 1) @test -n "$(NEW_SLUG)" || (echo "ERROR: NEW_SLUG is required."; exit 1) @test -n "$(NEW_NAME)" || (echo "ERROR: NEW_NAME is required."; exit 1) curl -sf -X PATCH http://127.0.0.1:8000/domains/$(DOMAIN)/rename \ -H "Content-Type: application/json" \ -d "{\"new_slug\": \"$(NEW_SLUG)\", \"new_name\": \"$(NEW_NAME)\"}" | python3 -m json.tool ## List repos for a domain: make list-repos DOMAIN=railiance list-repos: @test -n "$(DOMAIN)" || (echo "ERROR: DOMAIN is required."; exit 1) curl -sf "http://127.0.0.1:8000/repos/?domain=$(DOMAIN)" | python3 -m json.tool ## Ingest SBOM data for a repo. ## Single lockfile (explicit): make ingest-sbom REPO=the-custodian LOCKFILE=/path/to/uv.lock ## Scan all lockfiles in tree: make ingest-sbom REPO=the-custodian SCAN=1 REPO_PATH=/home/worsch/the-custodian ## Auto-detect at repo root: make ingest-sbom REPO=the-custodian REPO_PATH=/home/worsch/the-custodian ingest-sbom: @test -n "$(REPO)" || (echo "ERROR: REPO is required."; exit 1) uv run python scripts/ingest_sbom.py --repo "$(REPO)" \ $(if $(LOCKFILE),--lockfile "$(LOCKFILE)") \ $(if $(SCAN),--scan) \ $(if $(REPO_PATH),--repo-path "$(REPO_PATH)") ## Check a repo for ADR-001 compliance: make validate-adr REPO=/path/to/repo [DOMAIN=custodian] validate-adr: @test -n "$(REPO)" || (echo "ERROR: REPO is required. Usage: make validate-adr REPO= [DOMAIN=]"; exit 1) uv run python scripts/validate_repo_adr.py "$(REPO)" $(if $(DOMAIN),--domain "$(DOMAIN)",) clean: $(COMPOSE) down -v