Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02b90-83bf-75c2-81c8-aa705414e4d4
544 lines
30 KiB
Makefile
544 lines
30 KiB
Makefile
SHELL := /usr/bin/env bash
|
|
.DEFAULT_GOAL := help
|
|
|
|
KUBECONFIG ?= $(firstword $(wildcard $(HOME)/.kube/config-railiance01) $(wildcard $(HOME)/.kube/config))
|
|
KUBECTL_BIN ?= $(firstword $(shell command -v kubectl 2>/dev/null) $(wildcard $(HOME)/.local/bin/kubectl) kubectl)
|
|
KUBECTL := $(KUBECTL_BIN) --kubeconfig=$(KUBECONFIG)
|
|
|
|
# Cluster identity pin (RPF-WP-0019).
|
|
#
|
|
# Two reachable clusters each carry a CNPG Cluster named `apps-pg` in a
|
|
# namespace named `databases`. Selecting by kubeconfig FILENAME does not
|
|
# protect against applying to the wrong one: KUBECONFIG is an environment
|
|
# variable, `?=` does not override it, and both files resolve to a
|
|
# 127.0.0.1 tunnel port. So the guard pins cluster IDENTITY instead —
|
|
# the kube-system namespace UID, which is unique per cluster and stable
|
|
# for its lifetime.
|
|
#
|
|
# railiance01 (k3s v1.35.1) carries platform-pg, forgejo-db and both
|
|
# apps-pg consumers. The other cluster carries gitea-db and only one
|
|
# apps-pg consumer; `db-status` legitimately targets it, which is why the
|
|
# guard is applied per-target rather than globally.
|
|
RAILIANCE01_CLUSTER_UID ?= a553c742-0115-43d4-99a4-a5ca56fe0786
|
|
HELM := helm --kubeconfig=$(KUBECONFIG)
|
|
NAMESPACE := platform
|
|
|
|
PG_CHART_VERSION ?= 16.2.2
|
|
VALKEY_CHART_VERSION ?= 2.x
|
|
OPENBAO_CHART_VERSION ?= 0.28.2
|
|
OPENBAO_NAMESPACE ?= openbao
|
|
OPENBAO_RELEASE ?= openbao
|
|
OPENBAO_VALUES ?= helm/openbao-values.yaml
|
|
OPENBAO_MIDDLEWARE ?= helm/openbao-middleware.yaml
|
|
OPENBAO_UI_OVERLAY_DIR ?= helm/openbao-ui-overlay
|
|
OPENBAO_UI_OVERLAY_K8S ?= helm/openbao-ui-overlay-k8s.yaml
|
|
OPENBAO_PUBLIC_INGRESS_ROLLBACK ?= helm/openbao-public-ingress.rollback.yaml
|
|
OPENBAO_VERIFY_AUTH_ARGS ?=
|
|
OPENBAO_RESTORE_EVIDENCE ?= /tmp/netkingdom-openbao-restore-drill/evidence.json
|
|
OPENBAO_EMERGENCY_EVIDENCE ?= /tmp/netkingdom-openbao-emergency-drill/evidence.json
|
|
EXTERNAL_SECRETS_NAMESPACE ?= external-secrets
|
|
ARGOCD_NAMESPACE ?= argocd
|
|
ARGOCD_BOOTSTRAP_DIR ?= argocd/bootstrap
|
|
ARGOCD_REPOSITORY_SECRET ?=
|
|
CREDENTIAL_GRANTS ?= credential-grants/catalog.yaml
|
|
CREDENTIAL_CHANGE ?= CCR-2026-0001
|
|
CREDENTIAL_CHANGE_EVIDENCE_ARGS ?=
|
|
CREDENTIAL_CHANGE_LIFECYCLE_ACTION ?= deactivate
|
|
CREDENTIAL_CHANGE_LIFECYCLE_ARGS ?=
|
|
CREDENTIAL_CHANGE_IMPORT_ARGS ?=
|
|
STATE_HUB_URL ?= http://127.0.0.1:8000
|
|
OPENBAO_TOKEN_GRANT_ARGS ?=
|
|
OPENBAO_CREDENTIAL_CHANGE_APPLIER_ARGS ?=
|
|
OPENBAO_WORKLOAD_KV_ARGS ?=
|
|
CREDENTIAL_HELPER_GLOBAL_ARGS ?=
|
|
CREDENTIAL_HELPER_ARGS ?=
|
|
CREDENTIAL_HELPER_CHILD_ENV ?=
|
|
CREDENTIAL_HELPER_PURPOSE ?= flex-auth-openbao-smoke
|
|
|
|
##@ CloudNative PG (cnpg) — primary database operator
|
|
|
|
db-deploy: ## Apply Gitea cnpg Cluster (creates gitea-db in databases namespace)
|
|
$(KUBECTL) apply -f helm/gitea-db-cluster.yaml
|
|
|
|
db-status: ## Show cnpg cluster health
|
|
$(KUBECTL) cnpg status gitea-db -n databases 2>/dev/null || \
|
|
$(KUBECTL) get cluster gitea-db -n databases -o wide
|
|
|
|
db-shell: ## Open psql shell on gitea-db primary
|
|
$(KUBECTL) cnpg psql gitea-db -n databases -- -U gitea gitea
|
|
|
|
db-logs: ## Tail gitea-db primary logs
|
|
$(KUBECTL) logs -n databases -l cnpg.io/cluster=gitea-db -f --tail=50
|
|
|
|
##@ Forgejo database (railiance01 production forge)
|
|
|
|
forgejo-db-deploy: ## Apply forgejo-db cnpg Cluster + NetworkPolicies on railiance01
|
|
$(KUBECTL) apply -f helm/forgejo-db-cluster.yaml
|
|
$(KUBECTL) apply -f helm/forgejo-db-networkpolicies.yaml
|
|
|
|
forgejo-db-status: ## Show forgejo-db cnpg cluster health
|
|
$(KUBECTL) cnpg status forgejo-db -n databases 2>/dev/null || \
|
|
$(KUBECTL) get cluster forgejo-db -n databases -o wide
|
|
|
|
forgejo-db-shell: ## Open psql shell on forgejo-db primary
|
|
$(KUBECTL) cnpg psql forgejo-db -n databases -- -U forgejo forgejo
|
|
|
|
CONSUMING_ENTITY ?=
|
|
ESTIMATE_EUR ?=
|
|
CONSUMPTION_CLASS ?= new-order
|
|
CONSUMPTION_MODE_FILE ?= data/consumption-mode/current.json
|
|
|
|
##@ Consumption mode (RAILIANCE-WP-0017)
|
|
|
|
consumption-preflight: ## Refuse a new order that exceeds a restricted entity's allowance
|
|
@test -n "$(CONSUMING_ENTITY)" || { echo 'set CONSUMING_ENTITY=entity:<slug>' >&2; exit 2; }
|
|
CONSUMPTION_MODE_FILE='$(CONSUMPTION_MODE_FILE)' python3 scripts/consumption_mode.py check \
|
|
--entity '$(CONSUMING_ENTITY)' \
|
|
--class '$(CONSUMPTION_CLASS)' \
|
|
$(if $(ESTIMATE_EUR),--estimate-eur '$(ESTIMATE_EUR)')
|
|
|
|
##@ Shared apps-pg (S5 application databases)
|
|
|
|
cluster-id: ## Print the kube-system UID of the cluster KUBECONFIG currently selects
|
|
@echo "kubeconfig: $(KUBECONFIG)"
|
|
@echo "cluster-uid: $$($(KUBECTL) get ns kube-system -o jsonpath='{.metadata.uid}' 2>/dev/null || echo UNREACHABLE)"
|
|
|
|
railiance01-guard: ## Fail closed unless KUBECONFIG selects railiance01
|
|
@uid=$$($(KUBECTL) get ns kube-system -o jsonpath='{.metadata.uid}' 2>/dev/null); \
|
|
if [ -z "$$uid" ]; then \
|
|
echo "railiance01-guard: cluster unreachable via $(KUBECONFIG)" >&2; \
|
|
echo " hint: unset KUBECONFIG, or set it to ~/.kube/config-railiance01" >&2; \
|
|
exit 2; \
|
|
fi; \
|
|
if [ "$$uid" != "$(RAILIANCE01_CLUSTER_UID)" ]; then \
|
|
echo "railiance01-guard: REFUSING - wrong cluster" >&2; \
|
|
echo " kubeconfig: $(KUBECONFIG)" >&2; \
|
|
echo " expected: $(RAILIANCE01_CLUSTER_UID)" >&2; \
|
|
echo " found: $$uid" >&2; \
|
|
echo " both clusters carry apps-pg in namespace databases; applying here would hit the wrong one." >&2; \
|
|
exit 2; \
|
|
fi; \
|
|
echo "railiance01-guard: ok ($$uid)"
|
|
|
|
apps-pg-verify-capacity: ## Verify cell ceiling, role limits and distinct backup prefixes
|
|
python3 tools/verify_apps_pg_capacity.py helm/apps-pg-cluster.yaml helm/apps-pg-2-cluster.yaml
|
|
|
|
apps-pg-deploy: railiance01-guard apps-pg-verify-capacity ## Apply shared apps-pg cnpg Cluster + NetworkPolicies
|
|
@if [ -n "$(CONSUMING_ENTITY)" ]; then \
|
|
$(MAKE) consumption-preflight CONSUMING_ENTITY='$(CONSUMING_ENTITY)' \
|
|
ESTIMATE_EUR='$(ESTIMATE_EUR)' CONSUMPTION_CLASS=new-order; \
|
|
fi
|
|
$(KUBECTL) apply -f helm/apps-pg-cluster.yaml
|
|
$(KUBECTL) apply -f helm/apps-pg-networkpolicies.yaml
|
|
|
|
apps-pg-backup-deploy: railiance01-guard ## Apply the daily backup after the governed S3 Secret exists
|
|
@$(KUBECTL) get secret platform-pg-backup-s3 -n databases >/dev/null || { echo 'missing governed platform-pg-backup-s3 secret' >&2; exit 2; }
|
|
$(KUBECTL) apply -f helm/apps-pg-backup.yaml
|
|
|
|
apps-pg-isolation-probe: railiance01-guard ## Run bounded live consumer-boundary and connection-saturation probes
|
|
KUBECONFIG='$(KUBECONFIG)' KUBECTL_BIN='$(KUBECTL_BIN)' tools/apps-pg-isolation-probe.sh
|
|
|
|
apps-pg-overflow-dry-run: railiance01-guard apps-pg-verify-capacity ## Server-validate the unapplied overflow cell
|
|
@$(KUBECTL) get secret apps-pg-2-credentials -n databases >/dev/null || { echo 'missing distinct apps-pg-2-credentials secret' >&2; exit 2; }
|
|
$(KUBECTL) apply --dry-run=server -f helm/apps-pg-2-cluster.yaml
|
|
$(KUBECTL) apply --dry-run=server -f helm/apps-pg-2-networkpolicies.yaml
|
|
$(KUBECTL) apply --dry-run=server -f helm/apps-pg-2-backup.yaml
|
|
|
|
apps-pg-overflow-deploy: apps-pg-overflow-dry-run ## Provision only for an approved fourth consumer
|
|
$(KUBECTL) apply -f helm/apps-pg-2-cluster.yaml
|
|
$(KUBECTL) apply -f helm/apps-pg-2-networkpolicies.yaml
|
|
$(KUBECTL) apply -f helm/apps-pg-2-backup.yaml
|
|
|
|
apps-pg-status: railiance01-guard ## Show apps-pg cnpg cluster health
|
|
$(KUBECTL) cnpg status apps-pg -n databases 2>/dev/null || \
|
|
$(KUBECTL) get cluster apps-pg -n databases -o wide
|
|
|
|
apps-pg-shell: railiance01-guard ## Open psql shell on apps-pg primary as apps_admin / apps_meta
|
|
$(KUBECTL) cnpg psql apps-pg -n databases -- -U apps_admin apps_meta 2>/dev/null || \
|
|
$(KUBECTL) exec -it -n databases apps-pg-1 -- psql -U apps_admin apps_meta
|
|
|
|
apps-pg-logs: ## Tail apps-pg primary logs
|
|
$(KUBECTL) logs -n databases -l cnpg.io/cluster=apps-pg -f --tail=50
|
|
|
|
net-kingdom-pg-inter-hub-networkpolicy-deploy: ## Allow inter-hub to reach net-kingdom-pg
|
|
$(KUBECTL) apply -f helm/net-kingdom-pg-inter-hub-networkpolicy.yaml
|
|
|
|
##@ PostgreSQL HA (retired — CNPG superseded this)
|
|
|
|
pg-deploy: ## Retired: refuse to deploy Bitnami postgresql-ha
|
|
@echo 'pg-deploy is retired (RAILIANCE-WP-0016 item 14). Use apps-pg / forgejo-db / rapp-postgres.' >&2; exit 2
|
|
|
|
pg-status: ## Confirm Bitnami postgresql-ha is absent
|
|
@if $(KUBECTL) get ns $(NAMESPACE) >/dev/null 2>&1; then \
|
|
$(KUBECTL) get pods -n $(NAMESPACE) -l app.kubernetes.io/name=postgresql-ha; \
|
|
else \
|
|
echo 'postgresql-ha retired: namespace $(NAMESPACE) is absent'; \
|
|
fi
|
|
|
|
pg-pgpool-check: ## Retired: no pgpool secret to check
|
|
@echo 'pg-pgpool-check is retired with postgresql-ha (RAILIANCE-WP-0016 item 14).' >&2; exit 2
|
|
|
|
##@ Valkey (cache) — declared, not deployed
|
|
|
|
valkey-deploy: ## Gated: do not deploy Valkey until a consumer rapp exists
|
|
@echo 'valkey-deploy is gated (RAILIANCE-WP-0016 item 14): no live consumer, nothing to extract from S2.' >&2; exit 2
|
|
|
|
valkey-status: ## Confirm Valkey is absent
|
|
@if $(KUBECTL) get ns $(NAMESPACE) >/dev/null 2>&1; then \
|
|
$(KUBECTL) get pods -n $(NAMESPACE) -l app.kubernetes.io/name=valkey; \
|
|
else \
|
|
echo 'valkey undeployed: namespace $(NAMESPACE) is absent'; \
|
|
fi
|
|
|
|
##@ OpenBao (secrets)
|
|
|
|
openbao-repo: ## Add / update the official OpenBao Helm repository
|
|
$(HELM) repo add openbao https://openbao.github.io/openbao-helm --force-update
|
|
$(HELM) repo update openbao
|
|
|
|
openbao-dry-run: openbao-repo ## Render the OpenBao Helm release without applying it
|
|
$(HELM) upgrade --install $(OPENBAO_RELEASE) openbao/openbao \
|
|
--version $(OPENBAO_CHART_VERSION) \
|
|
--namespace $(OPENBAO_NAMESPACE) \
|
|
--create-namespace \
|
|
-f $(OPENBAO_VALUES) \
|
|
--dry-run
|
|
|
|
openbao-overlay-apply: ## Apply KeyCape login overlay gateway and assets
|
|
OPENBAO_UI_OVERLAY_DIR=$(OPENBAO_UI_OVERLAY_DIR) \
|
|
OPENBAO_UI_OVERLAY_K8S=$(OPENBAO_UI_OVERLAY_K8S) \
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
scripts/openbao-ui-overlay-apply.sh
|
|
|
|
openbao-verify-login-overlay: ## Verify public KeyCape login overlay is active
|
|
OPENBAO_UI_OVERLAY_DIR=$(OPENBAO_UI_OVERLAY_DIR) \
|
|
scripts/openbao-verify-login-overlay.sh $(OPENBAO_VERIFY_LOGIN_OVERLAY_ARGS)
|
|
|
|
openbao-deploy: openbao-repo ## Deploy / upgrade OpenBao to the openbao namespace
|
|
$(KUBECTL) create namespace $(OPENBAO_NAMESPACE) --dry-run=client -o yaml | $(KUBECTL) apply -f -
|
|
$(HELM) upgrade --install $(OPENBAO_RELEASE) openbao/openbao \
|
|
--version $(OPENBAO_CHART_VERSION) \
|
|
--namespace $(OPENBAO_NAMESPACE) \
|
|
-f $(OPENBAO_VALUES) \
|
|
--wait --timeout 5m
|
|
$(MAKE) openbao-overlay-apply
|
|
|
|
.PHONY: openbao-public-listener-dry-run openbao-public-listener-status openbao-public-listener-retract openbao-public-listener-rollback
|
|
|
|
openbao-public-listener-dry-run: ## Validate the guarded public-listener retraction without mutation
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_UI_OVERLAY_K8S=$(OPENBAO_UI_OVERLAY_K8S) \
|
|
OPENBAO_PUBLIC_INGRESS_ROLLBACK=$(OPENBAO_PUBLIC_INGRESS_ROLLBACK) \
|
|
scripts/openbao-public-listener-transition.sh dry-run
|
|
|
|
openbao-public-listener-status: ## Report public Ingress and private tunnel readiness
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
scripts/openbao-public-listener-transition.sh status
|
|
|
|
openbao-public-listener-retract: ## Attended deletion after exact tunnel/login confirmation
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_PUBLIC_INGRESS_ROLLBACK=$(OPENBAO_PUBLIC_INGRESS_ROLLBACK) \
|
|
scripts/openbao-public-listener-transition.sh apply
|
|
|
|
openbao-public-listener-rollback: ## Attended restoration of the prior public Ingress
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_MIDDLEWARE=$(OPENBAO_MIDDLEWARE) \
|
|
OPENBAO_PUBLIC_INGRESS_ROLLBACK=$(OPENBAO_PUBLIC_INGRESS_ROLLBACK) \
|
|
scripts/openbao-public-listener-transition.sh rollback
|
|
|
|
openbao-status: ## Show OpenBao pods, services, PVCs, and seal/init status
|
|
$(KUBECTL) get pods,svc,pvc -n $(OPENBAO_NAMESPACE) \
|
|
-l app.kubernetes.io/instance=$(OPENBAO_RELEASE) -o wide
|
|
-$(KUBECTL) exec -n $(OPENBAO_NAMESPACE) $(OPENBAO_RELEASE)-0 -- bao status
|
|
|
|
openbao-verify: ## Run non-secret OpenBao deployment checks
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify.sh basic
|
|
|
|
openbao-verify-post-unseal: ## Run post-unseal OpenBao filesystem checks
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify.sh post-unseal
|
|
|
|
openbao-configure-initial: ## Apply first post-unseal audit, auth, mounts, and policies
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-apply-initial-config.sh
|
|
|
|
openbao-configure-ssh: ## Enable SSH secrets engine, roles, and warden-sign policy
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-apply-ssh-engine.sh
|
|
|
|
openbao-verify-ssh: ## Verify SSH engine mount, roles, and warden-sign policy
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify-ssh-engine.sh
|
|
|
|
openbao-verify-authenticated: ## Run authenticated non-mutating OpenBao audit/auth/mount checks
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify-authenticated.sh $(OPENBAO_VERIFY_AUTH_ARGS)
|
|
|
|
openbao-configure-external-secrets-issue-core: ## Configure OpenBao policy/role for issue-core ESO pilot
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) ESO_NAMESPACE=$(EXTERNAL_SECRETS_NAMESPACE) \
|
|
scripts/openbao-apply-external-secrets-issue-core.sh
|
|
|
|
openbao-configure-external-secrets-activity-core: ## Configure OpenBao policy/role for activity-core ESO lane
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) OPENBAO_RELEASE=$(OPENBAO_RELEASE) ESO_NAMESPACE=$(EXTERNAL_SECRETS_NAMESPACE) OPENBAO_ESO_ROLE=external-secrets-activity-core OPENBAO_ESO_POLICY=external-secrets-activity-core POLICY_FILE='$(CURDIR)/openbao/policies/external-secrets-activity-core.hcl' OPENBAO_ESO_NEXT_PATH=platform/workloads/issue-core/issue-core/issue-core-runtime OPENBAO_ESO_NEXT_FIELDS=ISSUE_CORE_API_KEY OPENBAO_ESO_NEXT_TARGET=ExternalSecret/activity-core/actcore-issue-core-runtime scripts/openbao-apply-external-secrets-issue-core.sh
|
|
|
|
openbao-configure-external-secrets-forgejo: ## Configure OpenBao policy/role for Forgejo mailer ESO lane
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) ESO_NAMESPACE=$(EXTERNAL_SECRETS_NAMESPACE) \
|
|
OPENBAO_ESO_ROLE=external-secrets-forgejo \
|
|
OPENBAO_ESO_POLICY=external-secrets-forgejo \
|
|
POLICY_FILE='$(CURDIR)/openbao/policies/external-secrets-forgejo.hcl' \
|
|
OPENBAO_ESO_NEXT_PATH=platform/workloads/forgejo/forgejo-mailer \
|
|
OPENBAO_ESO_NEXT_FIELDS=MAILER_PASSWD \
|
|
OPENBAO_ESO_NEXT_TARGET=ExternalSecret/forgejo/forgejo-mailer \
|
|
scripts/openbao-apply-external-secrets-issue-core.sh
|
|
|
|
openbao-workload-kv-lanes-dry-run: ## Dry-run OpenBao workload KV read-lane policy apply
|
|
scripts/openbao-apply-workload-kv-lanes.sh --dry-run $(OPENBAO_WORKLOAD_KV_ARGS)
|
|
|
|
openbao-configure-workload-kv-lanes: ## Configure OpenBao workload KV read-lane policies
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-apply-workload-kv-lanes.sh $(OPENBAO_WORKLOAD_KV_ARGS)
|
|
|
|
openbao-validate-restore-evidence: ## Validate non-secret OpenBao restore-drill evidence JSON
|
|
OPENBAO_RESTORE_EVIDENCE='$(OPENBAO_RESTORE_EVIDENCE)' \
|
|
scripts/openbao-validate-restore-evidence.sh
|
|
|
|
openbao-validate-emergency-evidence: ## Validate non-secret OpenBao emergency seal/unseal drill evidence JSON
|
|
OPENBAO_EMERGENCY_EVIDENCE='$(OPENBAO_EMERGENCY_EVIDENCE)' \
|
|
scripts/openbao-validate-emergency-drill-evidence.sh
|
|
|
|
##@ Credential broker
|
|
|
|
credential-grants-validate: ## Validate non-secret credential grant catalog
|
|
scripts/credential-grants-validate.py $(CREDENTIAL_GRANTS)
|
|
|
|
credential-change-validate: ## Validate non-secret credential change requests
|
|
scripts/credential-change.py validate
|
|
|
|
credential-change-render: ## Render a credential change request review summary
|
|
scripts/credential-change.py render $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-plan: ## Render a credential change request apply plan for review
|
|
scripts/credential-change.py plan $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-decision-templates: ## Render CCR approve/deny/needs-changes templates
|
|
scripts/credential-change.py decision-templates $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-status: ## Render credential change request readiness status
|
|
scripts/credential-change.py status $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-status-json: ## Render credential change request readiness status as JSON
|
|
scripts/credential-change.py status --json $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-sync-decision: ## Sync resolved State Hub decision back into a CCR
|
|
scripts/credential-change.py sync-decision $(CREDENTIAL_CHANGE) --state-hub-url $(STATE_HUB_URL)
|
|
|
|
credential-change-apply-plan: ## Render approved-only operator apply plan
|
|
scripts/credential-change.py apply-plan $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-operator-commands: ## Render approved-only non-secret OpenBao operator commands
|
|
scripts/credential-change.py operator-commands $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-applier-dry-run: ## Validate delegated OpenBao metadata mutations for a CCR
|
|
scripts/credential-change.py applier-dry-run $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-applier-apply-plan: ## Render delegated OpenBao metadata apply plan
|
|
scripts/credential-change.py applier-apply $(CREDENTIAL_CHANGE) --plan-only
|
|
|
|
credential-change-applier-apply: ## Apply delegated metadata; pass confirmation/actor args via CREDENTIAL_CHANGE_EVIDENCE_ARGS
|
|
scripts/credential-change.py applier-apply $(CREDENTIAL_CHANGE) $(CREDENTIAL_CHANGE_EVIDENCE_ARGS)
|
|
|
|
credential-change-runbook: ## Render the attended CCR apply/verify runbook
|
|
scripts/credential-change.py runbook $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-record-evidence: ## Record non-secret CCR evidence; pass CREDENTIAL_CHANGE_EVIDENCE_ARGS
|
|
scripts/credential-change.py record-evidence $(CREDENTIAL_CHANGE) $(CREDENTIAL_CHANGE_EVIDENCE_ARGS)
|
|
|
|
credential-change-lifecycle-plan: ## Render deactivation/rotation/compromise lifecycle guidance
|
|
scripts/credential-change.py lifecycle-plan $(CREDENTIAL_CHANGE) --action $(CREDENTIAL_CHANGE_LIFECYCLE_ACTION)
|
|
|
|
credential-change-lifecycle-event: ## Record lifecycle event; pass CREDENTIAL_CHANGE_LIFECYCLE_ARGS
|
|
scripts/credential-change.py lifecycle-event $(CREDENTIAL_CHANGE) --action $(CREDENTIAL_CHANGE_LIFECYCLE_ACTION) $(CREDENTIAL_CHANGE_LIFECYCLE_ARGS)
|
|
|
|
agent-high-risk-boundary-check: ## Check policy against the versioned ops-warden high-risk path input
|
|
python3 scripts/agent_high_risk_boundary.py --json
|
|
|
|
credential-change-import-inventory: ## Import existing lane as non-secret CCR; pass CREDENTIAL_CHANGE_IMPORT_ARGS
|
|
scripts/credential-change.py import-inventory $(CREDENTIAL_CHANGE_IMPORT_ARGS)
|
|
|
|
openbao-credential-change-appliers-dry-run: ## Dry-run credential-change applier policies/token roles
|
|
scripts/openbao-apply-credential-change-appliers.py --dry-run $(OPENBAO_CREDENTIAL_CHANGE_APPLIER_ARGS)
|
|
|
|
openbao-configure-credential-change-appliers: ## Apply credential-change applier policies/token roles
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-apply-credential-change-appliers.py $(OPENBAO_CREDENTIAL_CHANGE_APPLIER_ARGS)
|
|
|
|
openbao-token-grants-dry-run: ## Dry-run OpenBao token roles and issuer policies for credential grants
|
|
scripts/openbao-apply-token-grants.py --dry-run $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-configure-token-grants: ## Apply OpenBao token roles and issuer policies for credential grants
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-apply-token-grants.py $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-verify-token-grants-dry-run: ## Dry-run OpenBao token grant verification
|
|
scripts/openbao-verify-token-grants.py --dry-run $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-verify-token-grants: ## Verify OpenBao token roles and issuer policies for credential grants
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-verify-token-grants.py $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-verify-token-grants-smoke: ## Mint/revoke a child token and prove bounded warden-sign capabilities
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-verify-token-grants.py --issue-smoke-token $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
credential-helper-dry-run: ## Dry-run credential request, exec, status, and revoke helper flows
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) request --dry-run \
|
|
--grant ops-warden/warden-sign --purpose $(CREDENTIAL_HELPER_PURPOSE) \
|
|
$(CREDENTIAL_HELPER_ARGS)
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) request --dry-run \
|
|
--grant ops-warden/warden-sign --purpose $(CREDENTIAL_HELPER_PURPOSE) \
|
|
--delivery kubernetes-auth $(CREDENTIAL_HELPER_ARGS)
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) exec --dry-run \
|
|
--grant ops-warden/warden-sign --purpose $(CREDENTIAL_HELPER_PURPOSE) \
|
|
$(CREDENTIAL_HELPER_ARGS) -- SMOKE_VAULT=1 /bin/true
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) status --dry-run example-accessor
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) revoke --dry-run example-accessor
|
|
|
|
credential-tests: ## Run offline credential broker unit tests
|
|
python3 -m unittest discover -s tests -p 'test_credential*.py'
|
|
|
|
credential-change-tests: ## Run credential change request unit tests
|
|
python3 -m unittest discover -s tests -p 'test_credential_change.py'
|
|
|
|
credential-exec-ops-warden-smoke: ## Run ops-warden smoke with an exec-injected warden-sign token
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) exec \
|
|
--grant ops-warden/warden-sign --purpose ops-warden-production-sign-smoke \
|
|
$(CREDENTIAL_HELPER_ARGS) -- \
|
|
$(CREDENTIAL_HELPER_CHILD_ENV) \
|
|
SMOKE_VAULT=1 /home/worsch/ops-warden/scripts/policy_gate_production_smoke.sh
|
|
|
|
##@ ArgoCD GitOps bootstrap
|
|
|
|
argocd-bootstrap-dry-run: ## Server-side dry-run ArgoCD AppProjects and root Application
|
|
$(KUBECTL) apply --dry-run=server -k $(ARGOCD_BOOTSTRAP_DIR)
|
|
|
|
argocd-bootstrap-deploy: ## Apply ArgoCD AppProjects and root Application
|
|
$(KUBECTL) apply -k $(ARGOCD_BOOTSTRAP_DIR)
|
|
|
|
argocd-repo-apply: ## Apply a SOPS-encrypted ArgoCD repository Secret (set ARGOCD_REPOSITORY_SECRET)
|
|
@test -n "$(ARGOCD_REPOSITORY_SECRET)" || \
|
|
(echo "ERROR: set ARGOCD_REPOSITORY_SECRET=argocd/repositories/<repo>.repository.sops.yaml"; exit 1)
|
|
sops -d $(ARGOCD_REPOSITORY_SECRET) | $(KUBECTL) apply -f -
|
|
|
|
argocd-status: ## Show Railiance ArgoCD projects, root app, and registered repos
|
|
$(KUBECTL) get appprojects.argoproj.io -n $(ARGOCD_NAMESPACE) \
|
|
railiance-bootstrap railiance-tenants railiance-platform-addons
|
|
$(KUBECTL) get applications.argoproj.io -n $(ARGOCD_NAMESPACE) \
|
|
railiance-apps-root external-secrets openbao-secretstore issue-core
|
|
$(KUBECTL) get secrets -n $(ARGOCD_NAMESPACE) \
|
|
-l argocd.argoproj.io/secret-type=repository
|
|
|
|
##@ Backup
|
|
|
|
RAILIANCE01_KUBECONFIG ?= $(HOME)/.kube/config-railiance01
|
|
|
|
backup: ## Backup platform services (PostgreSQL logical dump) — age-encrypted to Nextcloud
|
|
@test -x tools/cmd/railiance-backup || { echo "tools/cmd/railiance-backup not installed; use forgejo-backup for Forgejo." >&2; exit 1; }
|
|
sudo tools/cmd/railiance-backup
|
|
|
|
forgejo-backup: ## Forgejo dump + forgejo-db pg_dump → age → Nextcloud (T04/T09 Option A)
|
|
KUBECONFIG="$(RAILIANCE01_KUBECONFIG)" tools/cmd/forgejo-backup
|
|
|
|
forgejo-backup-dry-run: ## Forgejo backup without Nextcloud upload
|
|
KUBECONFIG="$(RAILIANCE01_KUBECONFIG)" RAILIANCE_BACKUP_DRY_RUN=1 tools/cmd/forgejo-backup
|
|
|
|
forgejo-backup-status: ## Show last Forgejo backup success and 7-day gate
|
|
@STAMP="$(HOME)/.cache/railiance/backups/forgejo/success-log"; \
|
|
if [[ ! -f "$$STAMP" ]]; then echo "No forgejo backups recorded yet."; exit 1; fi; \
|
|
echo "Last success: $$(tail -1 "$$STAMP")"; \
|
|
echo "Recent successes:"; tail -7 "$$STAMP"; \
|
|
echo "7-day gate: $$(tail -7 "$$STAMP" | wc -l)/7 consecutive days logged (verify cron separately)"
|
|
|
|
forgejo-package-prune-dry-run: ## List Forgejo package versions beyond retention depth (no deletes)
|
|
tools/cmd/forgejo-package-prune
|
|
|
|
forgejo-package-prune: ## Prune Forgejo packages — keep newest 3 versions per package
|
|
tools/cmd/forgejo-package-prune --apply
|
|
|
|
##@ Family declarations
|
|
|
|
reef-deployables: ## Capture live reef-railiance deployables for the family validator
|
|
python3 scripts/capture-reef-deployables.py -o docs/evidence/reef-railiance-deployables.json
|
|
|
|
apps-pg-evidence: ## Capture non-secret apps-pg capacity evidence for resource-control
|
|
python3 scripts/capture-apps-pg-evidence.py -o docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json
|
|
|
|
##@ Help
|
|
|
|
help: ## Show this help
|
|
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} \
|
|
/^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-22s\033[0m %s\n", $$1, $$2 } \
|
|
/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
|
|
|
|
audit-whitehat-e2-preflight: ## Value-safe live preflight for the approved audit-core E2 window
|
|
python3 scripts/audit-core-whitehat-e2-credentials.py preflight
|
|
|
|
audit-whitehat-e2-project: ## Project two exact mount-only credentials during the approved window
|
|
python3 scripts/audit-core-whitehat-e2-credentials.py project --confirm WH-ENG-20260822-AUDIT-E2-01:attended
|
|
|
|
audit-whitehat-e2-cleanup: ## Remove the exact engagement credentials and reload audit-core
|
|
python3 scripts/audit-core-whitehat-e2-credentials.py cleanup --confirm WH-ENG-20260822-AUDIT-E2-01:attended
|
|
|
|
audit-database-lease-recovery-preflight: ## Read-only gate for the restart-free database lease exercise
|
|
python3 scripts/audit-core-recovery-preflight.py database-lease $(AUDIT_DATABASE_LEASE_PREFLIGHT_ARGS)
|
|
|
|
audit-database-lease-approval-check: ## Validate an approved T02 receipt without mutation
|
|
@test -n "$(AUDIT_DATABASE_LEASE_APPROVAL)" || { echo 'set AUDIT_DATABASE_LEASE_APPROVAL=/path/to/approved-receipt.json' >&2; exit 2; }
|
|
python3 scripts/audit-core-database-lease-recovery.py validate-approval \
|
|
--approval "$(AUDIT_DATABASE_LEASE_APPROVAL)"
|
|
|
|
audit-database-lease-recovery-exercise: ## Run the separately approved attended T02 exercise
|
|
@test -n "$(AUDIT_DATABASE_LEASE_APPROVAL)" || { echo 'set AUDIT_DATABASE_LEASE_APPROVAL=/path/to/approved-receipt.json' >&2; exit 2; }
|
|
@test -n "$(AUDIT_DATABASE_LEASE_DRIVER)" || { echo 'set AUDIT_DATABASE_LEASE_DRIVER=/path/to/approved-load-driver' >&2; exit 2; }
|
|
python3 scripts/audit-core-database-lease-recovery.py exercise \
|
|
--approval "$(AUDIT_DATABASE_LEASE_APPROVAL)" \
|
|
--load-driver "$(AUDIT_DATABASE_LEASE_DRIVER)" \
|
|
--confirm RAILIANCE-WP-0024-T02:attended
|
|
|
|
railiance01-reboot-preflight: ## Read-only gate for the coordinated single-node reboot
|
|
python3 scripts/audit-core-recovery-preflight.py node-reboot $(RAILIANCE01_REBOOT_PREFLIGHT_ARGS)
|
|
|
|
wp0024-owner-show: ## Show one owner's hash-bound review contract (set OWNER)
|
|
@test -n "$(OWNER)" || { echo 'set OWNER=audit-core|rapp-postgres|railiance-cluster|railiance-infra' >&2; exit 2; }
|
|
@python3 scripts/wp0024-owner-review.py show --owner "$(OWNER)"
|
|
|
|
wp0024-owner-verify: ## Run one owner's named read-only checks (set OWNER)
|
|
@test -n "$(OWNER)" || { echo 'set OWNER=audit-core|rapp-postgres|railiance-cluster|railiance-infra' >&2; exit 2; }
|
|
@python3 scripts/wp0024-owner-review.py verify --owner "$(OWNER)"
|
|
|
|
wp0024-owner-status: ## Collect current hash-bound owner receipts from State Hub
|
|
@python3 scripts/wp0024-owner-review.py status
|
|
|
|
wp0024-t02-driver-show: ## Show the exact T02 synthetic-load driver interface
|
|
@python3 scripts/wp0024-t02-driver-candidate.py show
|
|
|
|
wp0024-t02-driver-status: ## Collect a revision-pinned audit-core driver candidate
|
|
@python3 scripts/wp0024-t02-driver-candidate.py status
|
|
|
|
wp0024-t02-driver-register: ## Register committed audit-core driver source without executing it
|
|
@test -n "$(DRIVER)" || { echo 'set DRIVER to a path relative to the audit-core repo' >&2; exit 2; }
|
|
@test -n "$(REVIEWER)" || { echo 'set REVIEWER to the audit-core reviewer identifier' >&2; exit 2; }
|
|
@python3 scripts/wp0024-t02-driver-candidate.py register \
|
|
--repo "$(abspath ../audit-core)" --driver "$(DRIVER)" --reviewer "$(REVIEWER)"
|
|
|
|
.PHONY: audit-whitehat-e2-preflight audit-whitehat-e2-project audit-whitehat-e2-cleanup audit-database-lease-recovery-preflight audit-database-lease-approval-check audit-database-lease-recovery-exercise railiance01-reboot-preflight wp0024-owner-show wp0024-owner-verify wp0024-owner-status wp0024-t02-driver-show wp0024-t02-driver-status wp0024-t02-driver-register apps-pg-isolation-probe
|
|
.PHONY: db-deploy db-status db-shell db-logs forgejo-db-deploy forgejo-db-status forgejo-db-shell apps-pg-deploy apps-pg-status apps-pg-shell apps-pg-logs net-kingdom-pg-inter-hub-networkpolicy-deploy pg-deploy pg-status pg-pgpool-check valkey-deploy valkey-status openbao-repo openbao-dry-run openbao-overlay-apply openbao-verify-login-overlay openbao-deploy openbao-status openbao-verify openbao-verify-post-unseal openbao-configure-initial openbao-configure-ssh openbao-verify-ssh openbao-verify-authenticated openbao-configure-external-secrets-issue-core openbao-configure-external-secrets-activity-core openbao-configure-external-secrets-forgejo openbao-validate-restore-evidence openbao-validate-emergency-evidence credential-grants-validate credential-change-applier-dry-run credential-change-applier-apply-plan credential-change-applier-apply credential-change-runbook credential-change-record-evidence credential-change-lifecycle-plan credential-change-lifecycle-event credential-change-import-inventory agent-high-risk-boundary-check openbao-credential-change-appliers-dry-run openbao-configure-credential-change-appliers openbao-token-grants-dry-run openbao-configure-token-grants openbao-verify-token-grants-dry-run openbao-verify-token-grants openbao-verify-token-grants-smoke credential-helper-dry-run credential-tests credential-exec-ops-warden-smoke argocd-bootstrap-dry-run argocd-bootstrap-deploy argocd-repo-apply argocd-status backup forgejo-backup forgejo-backup-dry-run forgejo-backup-status forgejo-package-prune forgejo-package-prune-dry-run reef-deployables apps-pg-evidence consumption-preflight help
|