Bind Policy Nexus production release
This commit is contained in:
parent
a15d80da94
commit
234cdfa4bb
5 changed files with 161 additions and 1 deletions
50
Makefile
50
Makefile
|
|
@ -39,6 +39,14 @@ REUSE_VALUES ?= helm/reuse-surface-values.yaml
|
||||||
REUSE_URL ?= https://reuse.coulomb.social
|
REUSE_URL ?= https://reuse.coulomb.social
|
||||||
REUSE_CERTIFICATE ?= reuse-surface-tls
|
REUSE_CERTIFICATE ?= reuse-surface-tls
|
||||||
|
|
||||||
|
POLICY_NEXUS_RAPP ?= ../rapp-policy-nexus
|
||||||
|
POLICY_NEXUS_BINDING ?= bindings/policy-nexus-production.json
|
||||||
|
POLICY_NEXUS_TARGET ?= railiance01
|
||||||
|
POLICY_NEXUS_IMAGE_REPOSITORY ?= $(shell python3 -c 'import json; print(json.load(open("$(POLICY_NEXUS_BINDING)"))["image_repository"])')
|
||||||
|
POLICY_NEXUS_IMAGE_DIGEST ?= $(shell python3 -c 'import json; print(json.load(open("$(POLICY_NEXUS_BINDING)")).get("image_digest") or "")')
|
||||||
|
POLICY_NEXUS_PUBLICATION_DIGEST ?= $(shell python3 -c 'import json; print(json.load(open("$(POLICY_NEXUS_BINDING)")).get("publication_manifest_digest") or "")')
|
||||||
|
POLICY_NEXUS_REVISION ?=
|
||||||
|
|
||||||
COULOMBCORE_KUBECONFIG ?= $(HOME)/.kube/config
|
COULOMBCORE_KUBECONFIG ?= $(HOME)/.kube/config
|
||||||
RAILIANCE01_KUBECONFIG ?= $(HOME)/.kube/config-hosteurope
|
RAILIANCE01_KUBECONFIG ?= $(HOME)/.kube/config-hosteurope
|
||||||
PRODUCTION_KUBECONFIG ?= $(COULOMBCORE_KUBECONFIG)
|
PRODUCTION_KUBECONFIG ?= $(COULOMBCORE_KUBECONFIG)
|
||||||
|
|
@ -577,6 +585,46 @@ reuse-runtime-es-status: check-railiance01-kubeconfig ## Show reuse-surface runt
|
||||||
reuse-webhook-smoke: check-railiance01-kubeconfig ## Webhook + ESO + federated smoke (RAILIANCE-WP-0011-T04)
|
reuse-webhook-smoke: check-railiance01-kubeconfig ## Webhook + ESO + federated smoke (RAILIANCE-WP-0011-T04)
|
||||||
bash tools/reuse-webhook-smoke.sh
|
bash tools/reuse-webhook-smoke.sh
|
||||||
|
|
||||||
|
##@ policy-nexus (policy.coulomb.social)
|
||||||
|
|
||||||
|
policy-nexus-check-binding: ## Require a source-controlled, immutable production binding
|
||||||
|
@test -d "$(POLICY_NEXUS_RAPP)" || { echo "Missing sibling rApp repo: $(POLICY_NEXUS_RAPP)" >&2; exit 2; }
|
||||||
|
python3 tools/check-policy-nexus-binding.py "$(POLICY_NEXUS_BINDING)"
|
||||||
|
|
||||||
|
policy-nexus-check-image: policy-nexus-check-binding ## Verify the bound OCI digest exists in Forgejo
|
||||||
|
tools/check-oci-image.sh "$(POLICY_NEXUS_IMAGE_REPOSITORY)@$(POLICY_NEXUS_IMAGE_DIGEST)"
|
||||||
|
|
||||||
|
policy-nexus-render: policy-nexus-check-binding ## Render the rApp chart with the approved production binding
|
||||||
|
$(MAKE) -C "$(POLICY_NEXUS_RAPP)" render \
|
||||||
|
IMAGE_REPOSITORY="$(POLICY_NEXUS_IMAGE_REPOSITORY)" \
|
||||||
|
IMAGE_DIGEST="$(POLICY_NEXUS_IMAGE_DIGEST)" \
|
||||||
|
PUBLICATION_MANIFEST_DIGEST="$(POLICY_NEXUS_PUBLICATION_DIGEST)"
|
||||||
|
|
||||||
|
policy-nexus-server-dry-run: policy-nexus-check-binding ## Validate the approved policy package against Railiance01
|
||||||
|
$(MAKE) -C "$(POLICY_NEXUS_RAPP)" server-dry-run TARGET="$(POLICY_NEXUS_TARGET)" \
|
||||||
|
IMAGE_REPOSITORY="$(POLICY_NEXUS_IMAGE_REPOSITORY)" \
|
||||||
|
IMAGE_DIGEST="$(POLICY_NEXUS_IMAGE_DIGEST)" \
|
||||||
|
PUBLICATION_MANIFEST_DIGEST="$(POLICY_NEXUS_PUBLICATION_DIGEST)"
|
||||||
|
|
||||||
|
policy-nexus-deploy: policy-nexus-check-binding ## Deploy the approved policy release through its rApp package
|
||||||
|
$(MAKE) -C "$(POLICY_NEXUS_RAPP)" deploy TARGET="$(POLICY_NEXUS_TARGET)" \
|
||||||
|
IMAGE_REPOSITORY="$(POLICY_NEXUS_IMAGE_REPOSITORY)" \
|
||||||
|
IMAGE_DIGEST="$(POLICY_NEXUS_IMAGE_DIGEST)" \
|
||||||
|
PUBLICATION_MANIFEST_DIGEST="$(POLICY_NEXUS_PUBLICATION_DIGEST)"
|
||||||
|
|
||||||
|
policy-nexus-status: ## Show the policy-nexus Helm release state
|
||||||
|
$(MAKE) -C "$(POLICY_NEXUS_RAPP)" status TARGET="$(POLICY_NEXUS_TARGET)"
|
||||||
|
|
||||||
|
policy-nexus-smoke: policy-nexus-check-binding ## Verify public content, TLS, and both immutable release identities
|
||||||
|
$(MAKE) -C "$(POLICY_NEXUS_RAPP)" verify-live TARGET="$(POLICY_NEXUS_TARGET)" \
|
||||||
|
IMAGE_REPOSITORY="$(POLICY_NEXUS_IMAGE_REPOSITORY)" \
|
||||||
|
IMAGE_DIGEST="$(POLICY_NEXUS_IMAGE_DIGEST)" \
|
||||||
|
PUBLICATION_MANIFEST_DIGEST="$(POLICY_NEXUS_PUBLICATION_DIGEST)"
|
||||||
|
|
||||||
|
policy-nexus-rollback: ## Roll back to a named previous Helm revision
|
||||||
|
@test -n "$(POLICY_NEXUS_REVISION)" || { echo "POLICY_NEXUS_REVISION is required" >&2; exit 2; }
|
||||||
|
$(MAKE) -C "$(POLICY_NEXUS_RAPP)" rollback TARGET="$(POLICY_NEXUS_TARGET)" REVISION="$(POLICY_NEXUS_REVISION)"
|
||||||
|
|
||||||
##@ Help
|
##@ Help
|
||||||
|
|
||||||
help: ## Show this help
|
help: ## Show this help
|
||||||
|
|
@ -584,4 +632,4 @@ help: ## Show this help
|
||||||
/^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } \
|
/^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } \
|
||||||
/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
|
/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
.PHONY: check-tools check-sops k8s-server-dry-run apps-pg-status apps-pg-restore-drill check-railiance01-kubeconfig check-inter-hub-image-tag check-inter-hub-image check-vergabe-image-tag check-vergabe-image vergabe-dry-run vergabe-deploy vergabe-ingress-deploy vergabe-status vergabe-migrate vergabe-seed vergabe-superuser vergabe-logs vergabe-db-url-secret check-coulomb-social-image-tag coulomb-social-dry-run coulomb-social-deploy coulomb-social-ingress-deploy coulomb-social-status coulomb-social-logs coulomb-social-env-secret coulomb-social-env-secret-dry-run eso-deploy forgejo-openbao-eso-token-apply forgejo-openbao-store-deploy forgejo-mailer-es-deploy forgejo-mailer-es-status forgejo-dry-run forgejo-server-dry-run forgejo-deploy forgejo-ingress-deploy forgejo-ssh-nodeport-deploy forgejo-status forgejo-smoke forgejo-npm-smoke forgejo-verify forgejo-operator-bootstrap forgejo-runner-registration-sops-bootstrap forgejo-secrets-check forgejo-logs forgejo-runner-registration-deploy forgejo-runner-deploy forgejo-runner-status forgejo-runner-logs inter-hub-render-baseline inter-hub-dry-run inter-hub-server-dry-run inter-hub-deploy inter-hub-status inter-hub-release-info inter-hub-smoke inter-hub-logs reuse-dry-run reuse-deploy reuse-status reuse-smoke reuse-logs reuse-forgejo-webhook reuse-openbao-eso-token-apply reuse-openbao-store-deploy reuse-runtime-es-deploy reuse-runtime-es-status reuse-webhook-smoke help
|
.PHONY: check-tools check-sops k8s-server-dry-run apps-pg-status apps-pg-restore-drill check-railiance01-kubeconfig check-inter-hub-image-tag check-inter-hub-image check-vergabe-image-tag check-vergabe-image vergabe-dry-run vergabe-deploy vergabe-ingress-deploy vergabe-status vergabe-migrate vergabe-seed vergabe-superuser vergabe-logs vergabe-db-url-secret check-coulomb-social-image-tag coulomb-social-dry-run coulomb-social-deploy coulomb-social-ingress-deploy coulomb-social-status coulomb-social-logs coulomb-social-env-secret coulomb-social-env-secret-dry-run eso-deploy forgejo-openbao-eso-token-apply forgejo-openbao-store-deploy forgejo-mailer-es-deploy forgejo-mailer-es-status forgejo-dry-run forgejo-server-dry-run forgejo-deploy forgejo-ingress-deploy forgejo-ssh-nodeport-deploy forgejo-status forgejo-smoke forgejo-npm-smoke forgejo-verify forgejo-operator-bootstrap forgejo-runner-registration-sops-bootstrap forgejo-secrets-check forgejo-logs forgejo-runner-registration-deploy forgejo-runner-deploy forgejo-runner-status forgejo-runner-logs inter-hub-render-baseline inter-hub-dry-run inter-hub-server-dry-run inter-hub-deploy inter-hub-status inter-hub-release-info inter-hub-smoke inter-hub-logs reuse-dry-run reuse-deploy reuse-status reuse-smoke reuse-logs reuse-forgejo-webhook reuse-openbao-eso-token-apply reuse-openbao-store-deploy reuse-runtime-es-deploy reuse-runtime-es-status reuse-webhook-smoke policy-nexus-check-binding policy-nexus-check-image policy-nexus-render policy-nexus-server-dry-run policy-nexus-deploy policy-nexus-status policy-nexus-smoke policy-nexus-rollback help
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| workplan | RAILIANCE-WP-0015 | finished | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
| workplan | RAILIANCE-WP-0015 | finished | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
||||||
| workplan | RAILIANCE-WP-0016 | finished | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
| workplan | RAILIANCE-WP-0016 | finished | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
||||||
|
| workplan | RAILIANCE-WP-0018 | active | — | workplans/RAILIANCE-WP-0018-policy-nexus-production-binding.md |
|
||||||
| task | RAILIANCE-WP-0015-T01 | done | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
| task | RAILIANCE-WP-0015-T01 | done | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
||||||
| task | RAILIANCE-WP-0015-T02 | done | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
| task | RAILIANCE-WP-0015-T02 | done | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
||||||
| task | RAILIANCE-WP-0015-T03 | done | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
| task | RAILIANCE-WP-0015-T03 | done | — | workplans/RAILIANCE-WP-0015-cnpg-backup-scheduledbackup-coverage.md |
|
||||||
|
|
@ -22,3 +23,7 @@
|
||||||
| task | RAILIANCE-WP-0016-T05 | done | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
| task | RAILIANCE-WP-0016-T05 | done | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
||||||
| task | RAILIANCE-WP-0016-T06 | done | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
| task | RAILIANCE-WP-0016-T06 | done | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
||||||
| task | RAILIANCE-WP-0016-T07 | done | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
| task | RAILIANCE-WP-0016-T07 | done | — | workplans/RAILIANCE-WP-0016-railiance01-activity-core-backup-automation.md |
|
||||||
|
| task | RAILIANCE-WP-0018-T01 | done | — | workplans/RAILIANCE-WP-0018-policy-nexus-production-binding.md |
|
||||||
|
| task | RAILIANCE-WP-0018-T02 | done | — | workplans/RAILIANCE-WP-0018-policy-nexus-production-binding.md |
|
||||||
|
| task | RAILIANCE-WP-0018-T03 | done | — | workplans/RAILIANCE-WP-0018-policy-nexus-production-binding.md |
|
||||||
|
| task | RAILIANCE-WP-0018-T04 | progress | — | workplans/RAILIANCE-WP-0018-policy-nexus-production-binding.md |
|
||||||
|
|
|
||||||
15
bindings/policy-nexus-production.json
Normal file
15
bindings/policy-nexus-production.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"schema_version": "policy-nexus-production-binding/v1",
|
||||||
|
"status": "release-approved",
|
||||||
|
"approved_on": "2026-08-18",
|
||||||
|
"rapp_repo": "rapp-policy-nexus",
|
||||||
|
"reef": "reef-railiance",
|
||||||
|
"rail": "rail-kubernetes",
|
||||||
|
"namespace": "policy-nexus",
|
||||||
|
"release": "policy-nexus",
|
||||||
|
"hostname": "policy.coulomb.social",
|
||||||
|
"image_repository": "forgejo.coulomb.social/coulomb/policy-nexus",
|
||||||
|
"image_digest": "sha256:23318442d1b3a5bdced54f0b407fa5b32834020b80c60d72dea04c03bfbf51e7",
|
||||||
|
"publication_manifest_digest": "1d8ae5cd683e385d82d29a78729948f7be95d902401a5fbdcfb5e8230cdbfee6",
|
||||||
|
"residual_risk_owner": "the-custodian"
|
||||||
|
}
|
||||||
56
docs/policy-nexus-production.md
Normal file
56
docs/policy-nexus-production.md
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
# policy-nexus production release
|
||||||
|
|
||||||
|
`railiance-apps` owns only the approved production binding for
|
||||||
|
`policy.coulomb.social`. Policy sources and the OCI artifact belong to
|
||||||
|
`policy-nexus`; the Helm chart, hardening, verification, and rollback belong to
|
||||||
|
`rapp-policy-nexus`. This repository must not copy either the generated site or
|
||||||
|
the chart.
|
||||||
|
|
||||||
|
## Binding a release
|
||||||
|
|
||||||
|
The source-controlled binding is
|
||||||
|
`bindings/policy-nexus-production.json`. Before deployment, replace both null
|
||||||
|
values and set `status` to `release-approved`:
|
||||||
|
|
||||||
|
- `image_digest`: the registry-resolved `sha256:...` digest of the image
|
||||||
|
published by `policy-nexus`;
|
||||||
|
- `publication_manifest_digest`: the 64-hex SHA-256 printed by the release
|
||||||
|
verifier for the exact `publication-manifest.json` in that image.
|
||||||
|
|
||||||
|
Tags are not accepted as production identity. The image digest and publication
|
||||||
|
digest must be reviewed in the same change; this binds runtime bytes to policy
|
||||||
|
source provenance without making this repository a second policy authority.
|
||||||
|
|
||||||
|
## Preflight and deployment
|
||||||
|
|
||||||
|
With sibling checkouts of `railiance-apps` and `rapp-policy-nexus`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make policy-nexus-check-binding
|
||||||
|
make policy-nexus-check-image
|
||||||
|
make policy-nexus-render
|
||||||
|
make policy-nexus-server-dry-run
|
||||||
|
make policy-nexus-deploy
|
||||||
|
make policy-nexus-status
|
||||||
|
make policy-nexus-smoke
|
||||||
|
```
|
||||||
|
|
||||||
|
Production deployment is an operator action. The current Forgejo build runner
|
||||||
|
has registry-publication authority but intentionally has no cluster-deploy
|
||||||
|
authority, kubeconfig, or SSH lane. Do not add those credentials to make this
|
||||||
|
release automatic. The guarded Make targets refuse the current
|
||||||
|
`approved-awaiting-artifact` binding and provide the reviewed execution path
|
||||||
|
from an authorized operator workstation.
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
Find the last known-good Helm revision with `make policy-nexus-status`, then:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make policy-nexus-rollback POLICY_NEXUS_REVISION=<revision>
|
||||||
|
make policy-nexus-smoke
|
||||||
|
```
|
||||||
|
|
||||||
|
After an emergency rollback, restore the binding file to the two immutable
|
||||||
|
identities actually serving and capture the smoke output. The package promises
|
||||||
|
restart recovery on the single-node reef, not multi-node high availability.
|
||||||
36
tools/check-policy-nexus-binding.py
Normal file
36
tools/check-policy-nexus-binding.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Validate the source-controlled policy-nexus production release identity."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("binding", type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
binding = json.loads(args.binding.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
if binding.get("schema_version") != "policy-nexus-production-binding/v1":
|
||||||
|
parser.error("unsupported policy-nexus binding schema")
|
||||||
|
if binding.get("status") != "release-approved":
|
||||||
|
parser.error("binding status must be release-approved")
|
||||||
|
if not re.fullmatch(r"sha256:[a-f0-9]{64}", binding.get("image_digest") or ""):
|
||||||
|
parser.error("binding image_digest must be sha256:<64 lowercase hex>")
|
||||||
|
if not re.fullmatch(
|
||||||
|
r"[a-f0-9]{64}", binding.get("publication_manifest_digest") or ""
|
||||||
|
):
|
||||||
|
parser.error("binding publication_manifest_digest must be 64 lowercase hex")
|
||||||
|
if binding.get("hostname") != "policy.coulomb.social":
|
||||||
|
parser.error("binding hostname must be policy.coulomb.social")
|
||||||
|
|
||||||
|
print("policy-nexus production binding is complete")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Loading…
Add table
Add a link
Reference in a new issue