Part of the sequenced cleanup tracked in issue #1. Scaffolding only — no rotation executed, no secret values committed. - docs/runbooks/PHOENIX_VAULT_ROTATION_RUNBOOK.md: authoritative Phoenix Vault rotation procedure (9-step: new root → rekey unseal → regenerate AppRoles → flip consumers → revoke old). Verification table + rollback path + Phase 2 handoff notes. - docs/04-configuration/VAULT_SHARD_CUSTODY_POLICY.md: decision record for the next rotation. Three options documented (named-operator / cloud-KMS auto-unseal / Transit auto-unseal); selection pending operator sign-off before rotation executes. - scripts/verify/enumerate-vault-consumers.sh: read-only grep over the tree for VAULT_ROLE_ID / VAULT_SECRET_ID / auth/approle/login references; flags which top-level consumers need a coordinated .env update at §1.6 of the runbook. - scripts/verify/verify-vault-approle-auth.sh: post-rotation sanity check — posts AppRole login + token lookup-self; returns PASS/FAIL without echoing the Role ID, Secret ID, or client token. - phoenix-deploy-api/.env.example: added VAULT_ADDR / VAULT_ROLE_ID / VAULT_SECRET_ID placeholder block with a pointer to the runbook. No values committed. - mission-control/.env.example: NEW file (previously had none); documents the launchpad NEXT_PUBLIC_* vars and the same Vault AppRole placeholder block. Server-side only — never NEXT_PUBLIC_*. Rotation execution stays with Phoenix ops; this commit only stages the runbook + env scaffolding so the eventual rotation does not require inventing infrastructure mid-incident. Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
Phoenix Deploy API
Gitea webhook receiver and deploy endpoint stub for Gitea → Phoenix deployment integration.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /webhook/gitea | Receives Gitea push/tag/PR webhooks |
| POST | /api/deploy | Deploy request (repo, branch, target) |
| GET | /api/v1/infra/nodes | Cluster nodes (Proxmox; stub if PROXMOX_* unset) |
| GET | /api/v1/infra/storage | Storage pools (Proxmox; stub if unset) |
| GET | /api/v1/ve/vms | List VMs/CTs (optional ?node=) |
| GET | /api/v1/ve/vms/:node/:vmid/status | VM/CT status (?type=lxc for containers) |
| POST | /api/v1/ve/vms/:node/:vmid/start, stop, reboot | VM/CT lifecycle (set PHOENIX_VE_LIFECYCLE_ENABLED=1) |
| GET | /api/v1/health/metrics | Prometheus query proxy (?query=<PromQL>) |
| GET | /api/v1/health/alerts | Active alerts (optional PROMETHEUS_ALERTS_URL) |
| GET | /api/v1/health/summary | Aggregated health for Portal |
| GET | /api/v1/public-sector/programs | Public-sector / eIDAS program manifest (JSON; no API key) |
| GET | /health | Health check |
All /api/v1/* routes except GET /api/v1/public-sector/programs accept optional partner API key when PHOENIX_PARTNER_KEYS is set (X-API-Key or Authorization: Bearer <key>).
Environment
Copy .env.example to .env and set GITEA_TOKEN (and optionally PHOENIX_DEPLOY_SECRET).
| Variable | Default | Description |
|---|---|---|
| PORT | 4001 | Listen port |
| GITEA_URL | https://gitea.d-bis.org | Gitea instance URL |
| GITEA_TOKEN | Token for commit status API | |
| PHOENIX_DEPLOY_SECRET | Optional secret for webhook/deploy auth | |
| PROXMOX_HOST | Proxmox host (IP or hostname) for API Railing | |
| PROXMOX_PORT | 8006 | Proxmox API port |
| PROXMOX_USER | root@pam | Proxmox API user |
| PROXMOX_TOKEN_NAME | Proxmox API token name | |
| PROXMOX_TOKEN_VALUE | Proxmox API token secret | |
| PROXMOX_TLS_VERIFY | 1 | Set to 0 to allow self-signed Proxmox certs |
| PHOENIX_VE_LIFECYCLE_ENABLED | 0 | Set to 1 to enable VM/CT start/stop/reboot |
| PROMETHEUS_URL | http://localhost:9090 | Prometheus base URL for Health API |
| PROMETHEUS_ALERTS_URL | (PROMETHEUS_URL)/api/v1/alerts | Optional; use Alertmanager URL for firing alerts |
| PHOENIX_WEBHOOK_URL | Outbound webhook URL; POST deploy events with X-Phoenix-Signature | |
| PHOENIX_WEBHOOK_SECRET | Secret to sign webhook payloads (HMAC-SHA256) | |
| PHOENIX_PARTNER_KEYS | Comma-separated API keys for /api/v1/* (optional) | |
| PUBLIC_SECTOR_MANIFEST_PATH | Override JSON path for /api/v1/public-sector/programs |
|
| PHOENIX_REPO_ROOT | Proxmox repo root; loads config/public-sector-program-manifest.json if present |
Program manifest: From a full repo checkout, the file is config/public-sector-program-manifest.json. scripts/install-systemd.sh copies it next to server.js on /opt/phoenix-deploy-api so the endpoint works without a full tree.
Gitea Webhook Configuration
In Gitea: Repository → Settings → Webhooks → Add Webhook
- URL:
https://phoenix-api-host/api/webhook/gitea(or your Phoenix API URL) - Content type: application/json
- Events: Push events, Tag creation (and optionally Pull requests)
- Secret: Optional, set PHOENIX_DEPLOY_SECRET to match
Deploy API (Trigger from Gitea Actions)
curl -X POST "https://phoenix-api-host/api/deploy" \
-H "Authorization: Bearer $PHOENIX_DEPLOY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"repo":"d-bis/proxmox","branch":"main","sha":"abc123","target":"default"}'
Integration with Sankofa Phoenix
This service is a standalone stub. Full deployment logic should be implemented in the Sankofa Phoenix API (VMID 8600). Migrate the webhook handler and deploy logic into the Phoenix API when ready.
OpenAPI / Swagger
- Spec: openapi.yaml
- HTML doc: docs/index.html — static Swagger UI; open locally or serve from
phoenix-deploy-api/docs/(loads../openapi.yaml). To serve in-app, addswagger-ui-expressand mount at e.g./api-docs.
Run
npm install
GITEA_TOKEN=xxx npm start