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_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
|
||||
RAILIANCE01_KUBECONFIG ?= $(HOME)/.kube/config-hosteurope
|
||||
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)
|
||||
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: ## 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 } \
|
||||
/^##@/ { 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-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-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 |
|
||||
|
|
@ -22,3 +23,7 @@
|
|||
| 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-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