RAILIANCE-WP-0011-T04: smoke checks unsigned 401, signed no-op 200, ESO Ready, and /v1/federated; point operator docs at platform rotation runbook.
7.8 KiB
reuse-surface on railiance01
Federation service deployment for https://reuse.coulomb.social.
Companion workplans: RAILIANCE-WP-0007 (Helm release), REUSE-WP-0011 (service + CLI).
Hosts and DNS
| Server | IP | Role |
|---|---|---|
| Railiance01 | 92.205.62.239 |
Production k3s — deploy here |
| CoulombCore | 92.205.130.254 |
Bootstrap / prerelease only |
| Record | Production target | Current public DNS (2026-06-15) |
|---|---|---|
reuse.coulomb.social A |
92.205.62.239 |
Propagated on 8.8.8.8 / 1.1.1.1; drop any AAAA/forwarding still pointing elsewhere |
hub.coulomb.social A |
92.205.62.239 (future) |
92.205.130.254 (CoulombCore bootstrap OK for now) |
Let's Encrypt HTTP-01 on Railiance01 requires the public A record to reach
92.205.62.239. Service and TLS are live on the production cluster.
dig +short reuse.coulomb.social A
KUBECONFIG=~/.kube/config-hosteurope kubectl get certificate -n reuse
If DNS is being changed in the future, use an explicit resolve only during propagation:
curl -k --resolve reuse.coulomb.social:443:92.205.62.239 https://reuse.coulomb.social/health
KUBECONFIG=~/.kube/config-hosteurope kubectl port-forward -n reuse svc/reuse-surface 18001:8000
export REUSE_SURFACE_URL=http://127.0.0.1:18001
Release surface
| Item | Value |
|---|---|
| Namespace | reuse |
| Helm release | reuse |
| Chart | charts/reuse-surface |
| Values | helm/reuse-surface-values.yaml |
| Image | gitea.coulomb.social/coulomb/reuse-surface:<tag> |
| Landing image | nginxinc/nginx-unprivileged:1.27-alpine |
| Secret | reuse-surface-env (see Runtime secrets) |
Runtime secrets
Custody is OpenBao KV at
platform/workloads/reuse/reuse-surface/runtime-secrets on coulombcore
(https://bao.coulomb.social), delivered to the workload through External
Secrets (ExternalSecret reuse/reuse-surface-runtime → Secret reuse-surface-env,
ClusterSecretStore openbao-reuse). Lane: CCR-2026-0005 /
RAILIANCE-WP-0011.
| Key | Required | Purpose |
|---|---|---|
REUSE_SURFACE_TOKEN |
yes | Bearer token for hub write API (POST /v1/repos, compose, etc.) |
REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET |
for webhooks | HMAC secret for POST /v1/webhooks/forgejo (REUSE-WP-0019-T02) |
The chart injects both keys via envFrom.secretRef on the reuse-surface
Deployment. After patching the Secret, restart the Deployment so new values
are picked up:
kubectl --kubeconfig ~/.kube/config-hosteurope rollout restart deployment/reuse-surface -n reuse
kubectl --kubeconfig ~/.kube/config-hosteurope rollout status deployment/reuse-surface -n reuse
Rotation (never commit or paste values into chat):
Full procedure: railiance-platform/docs/reuse-surface-runtime-secrets-rotation-runbook.md
# 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 REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET changed
make reuse-webhook-smoke
One-time lane bootstrap (CCR-2026-0005):
make reuse-openbao-eso-token-apply
make reuse-runtime-es-deploy
make reuse-runtime-es-status
Export for a shell session (streams to your terminal only):
export REUSE_SURFACE_TOKEN=$(
bao kv get -field=REUSE_SURFACE_TOKEN \
platform/workloads/reuse/reuse-surface/runtime-secrets
)
Or proxy via ops-warden: warden access reuse-surface-hub-write-token --fetch.
Break-glass (OpenBao unreachable): read materialized Secret reuse-surface-env
via kubectl — see ops-warden/wiki/playbooks/reuse-surface-hub-write-token.md.
Forgejo org webhook
Org-level push webhook on Forgejo (coulomb) triggers hub recompose when any
repo changes paths under registry/indexes/. The HMAC secret must match
REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET in reuse-surface-env.
Requires a Forgejo admin API token at /tmp/forgejo-tegwick-api-token (or
FORGEJO_ADMIN_TOKEN). Idempotent setup:
make reuse-forgejo-webhook
Smoke (unsigned 401, signed no-op 200, ESO Ready, /v1/federated):
make reuse-webhook-smoke
Live status (2026-07-07): org webhook id 1 on coulomb →
https://reuse.coulomb.social/v1/webhooks/forgejo, push events only.
Browser landing page
https://reuse.coulomb.social/ serves a static no-login landing page from the
Helm-managed reuse-surface-landing Deployment and Service. It exists for
humans who open the hostname in a browser; it does not change the API service.
Ingress routing is intentionally split:
- HTTP
/redirects permanently tohttps://reuse.coulomb.social/; - HTTPS
/healthand/v1/*route tosvc/reuse-surface; - HTTPS
/and other non-API browser paths route tosvc/reuse-surface-landing.
The rendered page includes noindex,nofollow, a short service description, and
links to /health, /v1/federated, and this operator runbook. It must not
include REUSE_SURFACE_TOKEN or any other runtime secret.
Rollback: set landing.enabled: false in helm/reuse-surface-values.yaml and
run make reuse-deploy; the ingress will return to routing all / traffic to
the API service.
Deploy
# 1. Pin image tag in helm/reuse-surface-values.yaml
# 2. Ensure reuse-surface-env has both keys (see Runtime secrets above)
# 3. Production (Railiance01, defaults to ~/.kube/config-hosteurope)
make reuse-deploy
make reuse-forgejo-webhook # after webhook secret is in the cluster Secret
make reuse-status
# Restore kubeconfig from the node if missing:
# ssh tegwick@92.205.62.239 'sudo cat /etc/rancher/k3s/k3s.yaml' \
# | sed 's|127.0.0.1|92.205.62.239|' > ~/.kube/config-hosteurope
Smoke checks
make reuse-smoke
curl -I http://reuse.coulomb.social/
curl -fsS https://reuse.coulomb.social/
curl -fsS https://reuse.coulomb.social/health
curl -fsS https://reuse.coulomb.social/v1/federated
export REUSE_SURFACE_TOKEN=$(kubectl --kubeconfig ~/.kube/config-hosteurope get secret reuse-surface-env -n reuse \
-o jsonpath='{.data.REUSE_SURFACE_TOKEN}' | base64 -d)
export REUSE_SURFACE_URL=https://reuse.coulomb.social
reuse-surface hub status
reuse-surface hub list
curl -fsS "$REUSE_SURFACE_URL/v1/federated" | jq '.capabilities | length'
Deployed image tag: see helm/reuse-surface-values.yaml (currently e3ae22e,
deployed 2026-07-07 for REUSE-WP-0019-T01/T02).
Dogfood: reuse-surface repo registered; federated index returns 61 capabilities.
Known issue (found 2026-07-07, not fixed): the public ingress serves
GET /v1/* correctly but 404s on the exact-path /health rule — Traefik
appears to shadow it with the catch-all / rule routed to
reuse-surface-landing. Confirmed NOT a pod/service problem: /health
works correctly via direct port-forward to svc/reuse-surface, and the
Deployment's own internal readiness/liveness probes (which hit /health
directly, bypassing ingress) pass fine — the pod is 1/1 Ready. Only
public external monitoring against https://reuse.coulomb.social/health
is affected; real API clients using /v1/* are unaffected. Needs an
explicit Traefik router priority annotation (or a path-rule reorder) on
charts/reuse-surface/templates/ingress.yaml — deliberately not changed
here since it's a shared production ingress edit outside this task's scope.
Operations
make reuse-logs
make reuse-status
Image promotion: build from coulomb/reuse-surface, push to Gitea OCI, update
helm/reuse-surface-values.yaml image.tag, then:
make reuse-deploy
Bootstrap copy on CoulombCore (92.205.130.254) was removed 2026-06-15 — use
config-hosteurope only.