railiance-platform/Makefile

545 lines
30 KiB
Makefile
Raw Permalink Normal View History

SHELL := /usr/bin/env bash
.DEFAULT_GOAL := help
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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)
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
# 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 ?=
2026-06-01 23:57:00 +02:00
OPENBAO_RESTORE_EVIDENCE ?= /tmp/netkingdom-openbao-restore-drill/evidence.json
OPENBAO_EMERGENCY_EVIDENCE ?= /tmp/netkingdom-openbao-emergency-drill/evidence.json
2026-06-25 20:08:36 +02:00
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 ?=
2026-06-27 22:48:24 +02:00
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
2026-07-04 13:26:07 +02:00
##@ 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)
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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
2026-05-23 13:59:58 +02:00
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)
2026-06-25 20:08:36 +02:00
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
2026-06-27 22:48:24 +02:00
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)
2026-06-01 23:57:00 +02:00
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)
2026-06-28 00:21:02 +02:00
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) \
2026-06-25 20:08:36 +02:00
railiance-bootstrap railiance-tenants railiance-platform-addons
$(KUBECTL) get applications.argoproj.io -n $(ARGOCD_NAMESPACE) \
2026-06-25 20:08:36 +02:00
railiance-apps-root external-secrets openbao-secretstore issue-core
$(KUBECTL) get secrets -n $(ARGOCD_NAMESPACE) \
-l argocd.argoproj.io/secret-type=repository
##@ Backup
Pin apps-pg targets to railiance01 by cluster identity; seed RPF-WP-0020 Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:18:37 +02:00
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