- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138 - Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices - Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts Made-with: Cursor
Phoenix Deploy API
Gitea webhook receiver and deploy endpoint for Gitea → Phoenix / Proxmox deployment integration.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /webhook/gitea | Receives Gitea push/tag/PR webhooks; executes deploys only when PHOENIX_WEBHOOK_DEPLOY_ENABLED=1 |
| POST | /api/deploy | Deploy request (repo, branch, target); resolves a target from deploy-targets.json and runs its command |
| GET | /api/deploy-targets | Lists configured deploy targets and whether each has a health check |
| 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 | |
| PHOENIX_WEBHOOK_DEPLOY_ENABLED | 0 | Set to 1 to allow /webhook/gitea to execute the default target on matching pushes |
| PROXMOX_HOST | proxmox-api.d-bis.org | 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; bare token name preferred, full token id also accepted | |
| 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 |
|
| DEPLOY_TARGETS_PATH | Override deploy target file; default is phoenix-deploy-api/deploy-targets.json |
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/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
Use webhook-triggered deploys only for repos that are not already deploying through Gitea Actions, unless you intentionally want both paths.
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"}'
The API returns 404 when no matching deploy target exists for {repo, branch, target} and 500 when the target command fails.
If a target defines healthcheck, the deploy is only marked successful after the post-deploy URL check passes.
Deploy target configuration
Targets live in deploy-targets.json. Each entry maps a {repo, branch, target} tuple to a command array and working directory.
Example:
{
"repo": "d-bis/proxmox",
"branch": "main",
"target": "default",
"cwd": "${PHOENIX_REPO_ROOT}",
"command": ["bash", "scripts/deployment/deploy-phoenix-deploy-api-to-dev-vm.sh", "--apply", "--start-ct"],
"required_env": ["PHOENIX_REPO_ROOT"]
}
Use this to promote different repos to different VMIDs or CTs by adding more entries.
Optional per-target health check:
{
"healthcheck": {
"url": "http://192.168.11.59:4001/health",
"expect_status": 200,
"expect_body_includes": "phoenix-deploy-api",
"attempts": 8,
"delay_ms": 3000,
"timeout_ms": 10000
}
}
Manual smoke trigger
From the repo root:
bash scripts/dev-vm/trigger-phoenix-deploy.sh
This calls /api/deploy directly using PHOENIX_DEPLOY_URL and PHOENIX_DEPLOY_TOKEN from root .env.
Integration with Sankofa Phoenix
This service is still standalone, but it now executes real target commands. If you later fold it into the Sankofa Phoenix API (VMID 8600), keep the same target-file pattern so repo-to-VM routing stays declarative.
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