Add reuse-webhook-smoke and rotation runbook links
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

RAILIANCE-WP-0011-T04: smoke checks unsigned 401, signed no-op 200, ESO Ready,
and /v1/federated; point operator docs at platform rotation runbook.
This commit is contained in:
tegwick 2026-07-08 00:01:21 +02:00
parent 85e9163bb0
commit 0968f1d5d5
3 changed files with 101 additions and 8 deletions

View file

@ -330,6 +330,9 @@ reuse-runtime-es-deploy: check-railiance01-kubeconfig reuse-openbao-store-deploy
reuse-runtime-es-status: check-railiance01-kubeconfig ## Show reuse-surface runtime ExternalSecret sync status
KUBECONFIG="$(REUSE_KUBECONFIG)" kubectl get externalsecret,secret -n $(REUSE_NAMESPACE) reuse-surface-runtime reuse-surface-env
reuse-webhook-smoke: check-railiance01-kubeconfig ## Webhook + ESO + federated smoke (RAILIANCE-WP-0011-T04)
bash tools/reuse-webhook-smoke.sh
##@ Help
help: ## Show this help
@ -337,4 +340,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 check-railiance01-kubeconfig check-inter-hub-image-tag check-inter-hub-image vergabe-dry-run vergabe-deploy vergabe-ingress-deploy vergabe-status vergabe-migrate vergabe-seed vergabe-superuser vergabe-logs vergabe-db-url-secret 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 help
.PHONY: check-tools check-sops k8s-server-dry-run apps-pg-status check-railiance01-kubeconfig check-inter-hub-image-tag check-inter-hub-image vergabe-dry-run vergabe-deploy vergabe-ingress-deploy vergabe-status vergabe-migrate vergabe-seed vergabe-superuser vergabe-logs vergabe-db-url-secret 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

View file

@ -69,13 +69,18 @@ kubectl --kubeconfig ~/.kube/config-hosteurope rollout restart deployment/reuse-
kubectl --kubeconfig ~/.kube/config-hosteurope rollout status deployment/reuse-surface -n reuse
```
**Bootstrap / rotate** (update OpenBao fields — never commit or paste into chat):
**Rotation** (never commit or paste values into chat):
Full procedure: `railiance-platform/docs/reuse-surface-runtime-secrets-rotation-runbook.md`
```bash
# Operator: update both fields in OpenBao, then refresh ESO and roll the Deployment
# After updating field(s) in OpenBao — force ESO sync, roll hub, reconcile webhook if needed
kubectl --kubeconfig ~/.kube/config-hosteurope annotate externalsecret \
reuse-surface-runtime -n reuse force-sync="$(date +%s)" --overwrite
make reuse-runtime-es-status
kubectl --kubeconfig ~/.kube/config-hosteurope rollout restart deployment/reuse-surface -n reuse
make reuse-forgejo-webhook # required when rotating REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET
make reuse-forgejo-webhook # required when REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET changed
make reuse-webhook-smoke
```
One-time lane bootstrap (CCR-2026-0005):
@ -113,12 +118,10 @@ Requires a Forgejo admin API token at `/tmp/forgejo-tegwick-api-token` (or
make reuse-forgejo-webhook
```
Manual verification (unsigned body should return `401`, not `503`):
Smoke (unsigned `401`, signed no-op `200`, ESO Ready, `/v1/federated`):
```bash
curl -fsS -o /dev/null -w "%{http_code}\n" -X POST \
https://reuse.coulomb.social/v1/webhooks/forgejo \
-H "Content-Type: application/json" -d '{}'
make reuse-webhook-smoke
```
Live status (2026-07-07): org webhook id `1` on `coulomb`

87
tools/reuse-webhook-smoke.sh Executable file
View file

@ -0,0 +1,87 @@
#!/usr/bin/env bash
# Smoke checks for reuse-surface Forgejo webhook receiver (RAILIANCE-WP-0011-T04).
# Uses the live cluster Secret for HMAC — never prints the secret value.
set -euo pipefail
REUSE_URL="${REUSE_URL:-https://reuse.coulomb.social}"
WEBHOOK_PATH="${REUSE_WEBHOOK_PATH:-/v1/webhooks/forgejo}"
KUBECONFIG_PATH="${KUBECONFIG:-$HOME/.kube/config-hosteurope}"
SECRET_NS="${REUSE_SECRET_NAMESPACE:-reuse}"
SECRET_NAME="${REUSE_SECRET_NAME:-reuse-surface-env}"
SECRET_KEY="${REUSE_WEBHOOK_SECRET_KEY:-REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET}"
pass=0
fail=0
ok() { echo " PASS $*"; pass=$((pass + 1)); }
bad() { echo " FAIL $*" >&2; fail=$((fail + 1)); }
echo "reuse-surface webhook smoke — ${REUSE_URL}${WEBHOOK_PATH}"
echo "kubeconfig: ${KUBECONFIG_PATH}"
echo
unsigned_code="$(
curl -sS -o /dev/null -w "%{http_code}" -X POST \
"${REUSE_URL}${WEBHOOK_PATH}" \
-H "Content-Type: application/json" -d '{}' 2>/dev/null || true
)"
unsigned_code="${unsigned_code:-000}"
if [[ "${unsigned_code}" == "401" ]]; then
ok "unsigned POST returns 401"
else
bad "unsigned POST expected 401, got ${unsigned_code}"
fi
if kubectl --kubeconfig "${KUBECONFIG_PATH}" get externalsecret reuse-surface-runtime \
-n "${SECRET_NS}" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null \
| grep -q True; then
ok "ExternalSecret reuse-surface-runtime Ready"
else
bad "ExternalSecret reuse-surface-runtime not Ready"
fi
export REUSE_URL WEBHOOK_PATH KUBECONFIG_PATH SECRET_NS SECRET_NAME SECRET_KEY
if python3 <<'PY'
import base64, hashlib, hmac, json, os, subprocess, sys, urllib.error, urllib.request
reuse_url = os.environ["REUSE_URL"]
webhook_path = os.environ["WEBHOOK_PATH"]
kc = os.environ["KUBECONFIG_PATH"]
ns = os.environ["SECRET_NS"]
name = os.environ["SECRET_NAME"]
key = os.environ["SECRET_KEY"]
raw = subprocess.check_output([
"kubectl", "--kubeconfig", kc, "get", "secret", name, "-n", ns,
"-o", f"jsonpath={{.data.{key}}}",
], text=True)
secret = base64.b64decode(raw).decode()
payload = {"commits": [{"added": ["README.md"], "modified": [], "removed": []}]}
body = json.dumps(payload).encode()
sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
req = urllib.request.Request(
f"{reuse_url.rstrip('/')}{webhook_path}",
data=body,
headers={"Content-Type": "application/json", "X-Forgejo-Signature": sig},
method="POST",
)
with urllib.request.urlopen(req, timeout=15) as resp:
data = json.loads(resp.read().decode())
if resp.status != 200 or data.get("accepted") is not False:
raise SystemExit(f"unexpected response: {data!r}")
PY
then
ok "signed no-op POST returns 200 accepted=false"
else
bad "signed no-op POST failed"
fi
if curl -fsS "${REUSE_URL}/v1/federated" -o /dev/null 2>/dev/null; then
ok "GET /v1/federated returns 200"
else
bad "GET /v1/federated failed"
fi
echo
echo "summary: ${pass} passed, ${fail} failed"
[[ "${fail}" -eq 0 ]]