feat(gitea-phoenix): gov runtime, deploy/template parity, workflow dedupe docs
- Add gov-portals-runtime.v1.json + schema; jq gate in validate-config-files - Python: parity-deploy-targets, parity-operational-template (IP strict, hostname WARN), parity-gov-portals-runtime; validate-vm-routing-parity.sh wrapper - check-gov-portal-workflow-canonical-strings.sh for monorepo Pattern A - PORTAL_WORKFLOW_PARITY.md; template headers; repos README; operator checklist secrets - report-gitea-cd-parity runs full VM routing parity; task doc marked complete - GOV_PORTALS_XOM_DEV + GITEA_GOV + MASTER_INDEX + matrix doc cross-links Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,6 +7,8 @@ Machine-readable coverage of **cluster guests that are not Besu-fleet nodes** (s
|
||||
| `besu-vmid-exclusions.v1.json` | Hostname rules marking Besu validators/sentries/RPC (excluded from matrix closure). |
|
||||
| `non-blockchain-vm-routing-matrix.v1.json` | One row per in-scope **running** guest from the last committed `reports/status/live_inventory.json` snapshot. |
|
||||
| `non-blockchain-vm-routing-matrix.v1.schema.json` | JSON Schema for the matrix file. |
|
||||
| `gov-portals-runtime.v1.json` | CT **7804** xom-dev: ports **3001–3004**, Gitea repos, Phoenix **`target`** names, `pnpm` filters (kept in sync with deploy-targets + monorepo CI). |
|
||||
| `gov-portals-runtime.v1.schema.json` | JSON Schema for the runtime file. |
|
||||
|
||||
## Regenerate after inventory export
|
||||
|
||||
@@ -19,15 +21,28 @@ python3 scripts/lib/non_blockchain_vm_routing_matrix.py generate \
|
||||
--out config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json
|
||||
```
|
||||
|
||||
Then hand-fill `gitea_repos`, `deploy_target`, `workflow_glob`, and `health_url` for Phoenix-backed services; use `allowed_missing` only with an explicit reason for intentional gaps.
|
||||
Then hand-fill `gitea_repos`, `deploy_target`, `workflow_glob`, and `health_url` for Phoenix-backed services; use `allowed_missing` only with an explicit reason for intentional gaps. When **7804** portal list changes, update **`gov-portals-runtime.v1.json`** in the same change set.
|
||||
|
||||
## Validate
|
||||
## Validate (inventory + parity gates)
|
||||
|
||||
```bash
|
||||
python3 scripts/lib/non_blockchain_vm_routing_matrix.py validate \
|
||||
--inventory reports/status/live_inventory.json \
|
||||
--exclusions config/gitea-phoenix/besu-vmid-exclusions.v1.json \
|
||||
--matrix config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json
|
||||
bash scripts/verify/validate-vm-routing-parity.sh
|
||||
```
|
||||
|
||||
Subcommands (see `scripts/lib/non_blockchain_vm_routing_matrix.py`):
|
||||
|
||||
- `validate` — inventory closure vs matrix
|
||||
- `parity-deploy-targets` — each Phoenix deploy target’s `repo` appears on the matrix row for its VMID (health URL match for single-repo rows)
|
||||
- `parity-operational-template` — IPv4 alignment vs `config/proxmox-operational-template.json` (hostname drift warns only; NPMplus **10233** dual-homed `.166`/`.167` documented)
|
||||
- `parity-gov-portals-runtime` — matrix **7804** `gitea_repos` equals runtime portal list
|
||||
|
||||
## Gov portal workflow dedupe
|
||||
|
||||
Canonical doc: [`../gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md`](../gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md). Optional drift check when the monorepo clone exists:
|
||||
|
||||
```bash
|
||||
bash scripts/verify/check-gov-portal-workflow-canonical-strings.sh
|
||||
# or: GOV_PORTALS_MONOREPO_ROOT=/path/to/gov-portals-monorepo bash ...
|
||||
```
|
||||
|
||||
Task narrative: [docs/04-configuration/GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md](../../docs/04-configuration/GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md).
|
||||
|
||||
42
config/gitea-phoenix/gov-portals-runtime.v1.json
Normal file
42
config/gitea-phoenix/gov-portals-runtime.v1.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"schemaVersion": "1",
|
||||
"lxc_vmid": 7804,
|
||||
"lan_ipv4": "192.168.11.54",
|
||||
"systemd_unit_prefix": "gov-portal-",
|
||||
"public_wildcard_fqdn_pattern": "*.xom-dev.phoenix.sankofa.nexus",
|
||||
"npmplus_doc": "docs/04-configuration/GOV_PORTALS_XOM_DEV_DEPLOYMENT.md",
|
||||
"portals": [
|
||||
{
|
||||
"id": "DBIS",
|
||||
"port": 3001,
|
||||
"dev_fqdn": "https://dbis.xom-dev.phoenix.sankofa.nexus/",
|
||||
"gitea_repo": "Gov_Web_Portals/DBIS",
|
||||
"deploy_target": "dbis-portal-live",
|
||||
"pnpm_filter": "portal-dbis"
|
||||
},
|
||||
{
|
||||
"id": "ICCC",
|
||||
"port": 3002,
|
||||
"dev_fqdn": "https://iccc.xom-dev.phoenix.sankofa.nexus/",
|
||||
"gitea_repo": "Gov_Web_Portals/ICCC",
|
||||
"deploy_target": "iccc-portal-live",
|
||||
"pnpm_filter": "portal-iccc"
|
||||
},
|
||||
{
|
||||
"id": "OMNL",
|
||||
"port": 3003,
|
||||
"dev_fqdn": "https://omnl.xom-dev.phoenix.sankofa.nexus/",
|
||||
"gitea_repo": "Gov_Web_Portals/OMNL",
|
||||
"deploy_target": "omnl-portal-live",
|
||||
"pnpm_filter": "portal-omnl"
|
||||
},
|
||||
{
|
||||
"id": "XOM",
|
||||
"port": 3004,
|
||||
"dev_fqdn": "https://xom.xom-dev.phoenix.sankofa.nexus/",
|
||||
"gitea_repo": "Gov_Web_Portals/XOM",
|
||||
"deploy_target": "xom-portal-live",
|
||||
"pnpm_filter": "portal-xom"
|
||||
}
|
||||
]
|
||||
}
|
||||
33
config/gitea-phoenix/gov-portals-runtime.v1.schema.json
Normal file
33
config/gitea-phoenix/gov-portals-runtime.v1.schema.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://gitea.d-bis.org/d-bis/proxmox/gov-portals-runtime.v1.schema.json",
|
||||
"title": "Gov portals xom-dev runtime (CT 7804)",
|
||||
"type": "object",
|
||||
"required": ["schemaVersion", "lxc_vmid", "lan_ipv4", "portals"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"schemaVersion": { "type": "string", "const": "1" },
|
||||
"lxc_vmid": { "type": "integer", "minimum": 1 },
|
||||
"lan_ipv4": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
||||
"systemd_unit_prefix": { "type": "string" },
|
||||
"public_wildcard_fqdn_pattern": { "type": "string" },
|
||||
"npmplus_doc": { "type": "string" },
|
||||
"portals": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "port", "dev_fqdn", "gitea_repo", "deploy_target", "pnpm_filter"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[A-Z]+$" },
|
||||
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
||||
"dev_fqdn": { "type": "string", "minLength": 8 },
|
||||
"gitea_repo": { "type": "string", "pattern": "^Gov_Web_Portals/[A-Za-z0-9_-]+$" },
|
||||
"deploy_target": { "type": "string", "minLength": 1 },
|
||||
"pnpm_filter": { "type": "string", "minLength": 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md
Normal file
44
config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Gov portal Gitea workflows — canonical patterns (dedupe)
|
||||
|
||||
There are **two valid layouts** for `Gov_Web_Portals/{DBIS,ICCC,OMNL,XOM}` on Gitea. Pick **one per repo** and avoid silently drifting between them.
|
||||
|
||||
## Pattern A — Split workflows (current monorepo submodules)
|
||||
|
||||
Used under **`Gov_Web_Portals/gov-portals-monorepo`** checkouts: `DBIS/.gitea/workflows/ci.yml` + `deploy-live.yml` (same for ICCC, OMNL, XOM).
|
||||
|
||||
| Concern | Convention |
|
||||
|--------|-------------|
|
||||
| Monorepo clone | **`GOV_PORTALS_TOKEN`** (or unset for public read if ever enabled) + `http.extraHeader=Authorization: token …` |
|
||||
| Overlay | `tar` or `rsync` from standalone repo checkout into `gov-portals/<Portal>/` |
|
||||
| CI on PR | `ci.yml` — `pnpm install --frozen-lockfile` at monorepo root, `pnpm --filter portal-*` lint/build/typecheck |
|
||||
| Deploy on `main` | `deploy-live.yml` — validate job then `curl` POST Phoenix with **`target`** = `dbis-portal-live` / `iccc-portal-live` / `omnl-portal-live` / `xom-portal-live` |
|
||||
| Secrets | `PHOENIX_DEPLOY_URL`, `PHOENIX_DEPLOY_TOKEN`, **`GOV_PORTALS_TOKEN`** (read monorepo) |
|
||||
|
||||
**Canonical strings** (must stay aligned with `phoenix-deploy-api/deploy-targets.json`):
|
||||
|
||||
- `Gov_Web_Portals/DBIS` → `"target":"dbis-portal-live"`
|
||||
- `Gov_Web_Portals/ICCC` → `"target":"iccc-portal-live"`
|
||||
- `Gov_Web_Portals/OMNL` → `"target":"omnl-portal-live"`
|
||||
- `Gov_Web_Portals/XOM` → `"target":"xom-portal-live"`
|
||||
|
||||
## Pattern B — Single combined file (template reference)
|
||||
|
||||
Files under **`config/gitea-workflow-templates/repos/*-portal-ci-and-live.yml`**: one workflow with `verify` + `deploy` jobs, **`GITEA_TOKEN`** + `oauth2:${GITEA_TOKEN}@` clone URL.
|
||||
|
||||
Use when bootstrapping a **standalone** portal repo that does not yet use Pattern A. Copy into `.gitea/workflows/` and set secrets per [GITEA_CD_OPERATOR_CHECKLIST.md](../../docs/00-meta/GITEA_CD_OPERATOR_CHECKLIST.md).
|
||||
|
||||
## Single source of truth for ports / FQDN / systemd
|
||||
|
||||
**`config/gitea-phoenix/gov-portals-runtime.v1.json`** — LXC **7804** port map and deploy targets. Update it when `GOV_PORTALS_XOM_DEV_DEPLOYMENT.md` changes; Phoenix healthchecks and matrix enrichment should stay consistent.
|
||||
|
||||
## Drift checks (proxmox repo)
|
||||
|
||||
```bash
|
||||
# If monorepo clone exists (default ~/projects/gov-portals-monorepo):
|
||||
bash scripts/verify/check-gov-portal-workflow-canonical-strings.sh
|
||||
|
||||
# Full VM routing + parity (inventory, matrix, deploy-targets, operational template):
|
||||
bash scripts/verify/validate-vm-routing-parity.sh
|
||||
```
|
||||
|
||||
When you change **semantic** steps (pnpm filter names, Phoenix `target`, monorepo URL), update **Pattern A** repos **and** Pattern B templates **and** `gov-portals-runtime.v1.json` in one commit series.
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
Copy the matching file into **that** Gitea repo as `.gitea/workflows/<name>.yml`, then set secrets **`PHOENIX_DEPLOY_URL`**, **`PHOENIX_DEPLOY_TOKEN`**.
|
||||
|
||||
**Pattern A (monorepo split `ci.yml` + `deploy-live.yml`) vs Pattern B (single template file):** [PORTAL_WORKFLOW_PARITY.md](../PORTAL_WORKFLOW_PARITY.md).
|
||||
|
||||
| File | Gitea `repo` | `target` | Notes |
|
||||
|------|----------------|----------|--------|
|
||||
| [`dbis-portal-ci-and-live.yml`](dbis-portal-ci-and-live.yml) | `Gov_Web_Portals/DBIS` | `dbis-portal-live` | Recommended: monorepo overlay CI + deploy; secrets include **`GITEA_TOKEN`** |
|
||||
| [`dbis-portal-ci-and-live.yml`](dbis-portal-ci-and-live.yml) | `Gov_Web_Portals/DBIS` | `dbis-portal-live` | Pattern B single file; secrets include **`GITEA_TOKEN`**; monorepo uses Pattern A |
|
||||
| [`iccc-portal-ci-and-live.yml`](iccc-portal-ci-and-live.yml) | `Gov_Web_Portals/ICCC` | `iccc-portal-live` | Same pattern as DBIS |
|
||||
| [`omnl-portal-ci-and-live.yml`](omnl-portal-ci-and-live.yml) | `Gov_Web_Portals/OMNL` | `omnl-portal-live` | Same pattern |
|
||||
| [`xom-portal-ci-and-live.yml`](xom-portal-ci-and-live.yml) | `Gov_Web_Portals/XOM` | `xom-portal-live` | Same pattern |
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copy to Gov_Web_Portals/DBIS → .gitea/workflows/deploy-portal-live.yml (or a second workflow file).
|
||||
# Pattern B (single file). Monorepo submodules use Pattern A — see ../PORTAL_WORKFLOW_PARITY.md
|
||||
# Secrets: PHOENIX_DEPLOY_URL, PHOENIX_DEPLOY_TOKEN, GITEA_TOKEN (read access to gov-portals-monorepo for CI).
|
||||
#
|
||||
# verify: shallow-clone monorepo, overlay this repo into DBIS/, run lint + typecheck (workspace deps).
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Minimal deploy-only workflow (no monorepo CI). Prefer dbis-portal-ci-and-live.yml when the repo
|
||||
# can store GITEA_TOKEN for cloning Gov_Web_Portals/gov-portals-monorepo in Actions.
|
||||
# Monorepo Pattern A: ../PORTAL_WORKFLOW_PARITY.md
|
||||
# Copy to Gov_Web_Portals/DBIS → .gitea/workflows/deploy-portal-live.yml
|
||||
# Secrets: PHOENIX_DEPLOY_URL, PHOENIX_DEPLOY_TOKEN
|
||||
name: Deploy DBIS portal (Phoenix)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copy to Gov_Web_Portals/ICCC → .gitea/workflows/deploy-portal-live.yml
|
||||
# Pattern B (single file). Monorepo: ../PORTAL_WORKFLOW_PARITY.md
|
||||
# Secrets: PHOENIX_DEPLOY_URL, PHOENIX_DEPLOY_TOKEN, GITEA_TOKEN
|
||||
name: CI and deploy ICCC portal (Phoenix)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copy to Gov_Web_Portals/OMNL → .gitea/workflows/deploy-portal-live.yml
|
||||
# Pattern B (single file). Monorepo: ../PORTAL_WORKFLOW_PARITY.md
|
||||
# Secrets: PHOENIX_DEPLOY_URL, PHOENIX_DEPLOY_TOKEN, GITEA_TOKEN
|
||||
name: CI and deploy OMNL portal (Phoenix)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copy to Gov_Web_Portals/XOM → .gitea/workflows/deploy-portal-live.yml
|
||||
# Pattern B (single file). Monorepo: ../PORTAL_WORKFLOW_PARITY.md
|
||||
# Secrets: PHOENIX_DEPLOY_URL, PHOENIX_DEPLOY_TOKEN, GITEA_TOKEN
|
||||
name: CI and deploy XOM portal (Phoenix)
|
||||
|
||||
|
||||
@@ -8,8 +8,19 @@ Use this after changing **`phoenix-deploy-api/deploy-targets.json`** or adding w
|
||||
2. **Secrets** on **that repo** (not only global):
|
||||
- **`PHOENIX_DEPLOY_URL`** — full URL for `POST` (same shape as **`d-bis/proxmox`** workflows use), typically `http://<dev-vm>:4001/api/deploy` or HTTPS equivalent.
|
||||
- **`PHOENIX_DEPLOY_TOKEN`** — bearer token accepted by Phoenix deploy API.
|
||||
- **`GITEA_TOKEN`** — required for **gov portal CI** workflows that clone `Gov_Web_Portals/gov-portals-monorepo` (read-only token is enough).
|
||||
3. **Workflow file** in the repo: copy from [`config/gitea-workflow-templates/repos/README.md`](../config/gitea-workflow-templates/repos/README.md) or use the repo’s existing `.gitea/workflows/*.yml`.
|
||||
- **`GITEA_TOKEN`** — used by **Pattern B** single-file portal templates under `config/gitea-workflow-templates/repos/*-portal-ci-and-live.yml` when cloning the monorepo with `oauth2:${GITEA_TOKEN}@…` (read-only is enough).
|
||||
- **`GOV_PORTALS_TOKEN`** — used by **Pattern A** split workflows in `Gov_Web_Portals/gov-portals-monorepo` submodules (`GOV_PORTALS_TOKEN` + `http.extraHeader=Authorization: token …`); same minimum scope: read `Gov_Web_Portals/gov-portals-monorepo` on Gitea.
|
||||
3. **Workflow file** in the repo: copy from [`config/gitea-workflow-templates/repos/README.md`](../config/gitea-workflow-templates/repos/README.md) or use the repo’s existing `.gitea/workflows/*.yml`. **Pattern A vs B:** [`config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md`](../config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md).
|
||||
|
||||
### Secrets hygiene (Gitea-only, least privilege)
|
||||
|
||||
| Secret | Typical scope | Never |
|
||||
|--------|----------------|-------|
|
||||
| **`GITEA_TOKEN`** / **`GOV_PORTALS_TOKEN`** | Read `Gov_Web_Portals/gov-portals-monorepo` (and overlay subtree) for CI | Commit into repo YAML, `.git/config` remote URLs, or logs |
|
||||
| **`PHOENIX_DEPLOY_TOKEN`** | `POST` Phoenix deploy API only | Reuse as full Gitea admin token |
|
||||
| **`NPM_PASSWORD`** (operator) | NPMplus API on LAN | Same token as Gitea |
|
||||
|
||||
Rotate any token that was ever pasted into a `git remote` URL. Prefer `source scripts/lib/load-project-env.sh` and `git -c "http.extraHeader=Authorization: token …"` for one-off pushes (see [GITEA_GOV_PORTALS_LIVE_SOURCE_OF_TRUTH.md](../04-configuration/GITEA_GOV_PORTALS_LIVE_SOURCE_OF_TRUTH.md)).
|
||||
|
||||
## Phoenix deploy host (LAN)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ This document ties together **Gitea repos**, the **gov-portals-monorepo** umbrel
|
||||
|
||||
- **Forge policy (Gitea-only):** `Gov_Web_Portals/*` repos and the monorepo use **only Gitea** as authoritative remote — no GitHub `origin` for those trees. **`d-bis/proxmox`** uses **`gitea`** as canonical for pushes; a GitHub remote may exist only as a **non-authoritative** mirror. See [GOV_PORTALS_REPO_DIRECTORY_VM_FQDN_TABLE.md](./GOV_PORTALS_REPO_DIRECTORY_VM_FQDN_TABLE.md).
|
||||
- **Authoritative application code** for each portal lives in its **Gitea repo** under `Gov_Web_Portals/` (DBIS, ICCC, OMNL, XOM), with **`main`** as the integration branch unless you have agreed otherwise.
|
||||
- **Integration / shared layout** lives in **`Gov_Web_Portals/gov-portals-monorepo`** (workspace + `packages/shared`). Portal repos use `workspace:*` for `@public-web-portals/shared`, so **CI that runs `pnpm install` in the portal repo alone is insufficient** unless you vendor shared — the recommended Actions flow clones the monorepo and **overlays** the pushed portal tree (see templates below).
|
||||
- **Integration / shared layout** lives in **`Gov_Web_Portals/gov-portals-monorepo`** (workspace + `packages/shared`). Portal repos use `workspace:*` for `@public-web-portals/shared`, so **CI that runs `pnpm install` in the portal repo alone is insufficient** unless you vendor shared — the recommended Actions flow clones the monorepo and **overlays** the pushed portal tree (see templates below). **Runtime map (7804 ports / FQDNs / Phoenix targets):** [`config/gitea-phoenix/gov-portals-runtime.v1.json`](../../config/gitea-phoenix/gov-portals-runtime.v1.json) (see also [PORTAL_WORKFLOW_PARITY.md](../../config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md)).
|
||||
- **Live runtime** for the xom-dev stack is **LXC 7804** (`IP_GOV_PORTALS_DEV`, default `192.168.11.54`) with systemd units `gov-portal-DBIS` … `gov-portal-XOM` on ports **3001–3004**. Public hostnames are documented in [GOV_PORTALS_XOM_DEV_DEPLOYMENT.md](./GOV_PORTALS_XOM_DEV_DEPLOYMENT.md).
|
||||
|
||||
## Two operator paths (pick deliberately)
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
# Task — Gitea / Phoenix routing cleanup scoped to all non-blockchain VMIDs
|
||||
|
||||
**Status:** In progress (matrix + validator landed; workflow dedupe / optional runtime JSON still open)
|
||||
**Status:** Complete (ongoing maintenance: regenerate matrix after each inventory export; resolve operational hostname **WARN** lines when template design names are reconciled)
|
||||
|
||||
**Created:** 2026-05-12
|
||||
**Owner:** Operator + repo maintainers
|
||||
|
||||
## Implemented (repo)
|
||||
|
||||
- **`config/gitea-phoenix/besu-vmid-exclusions.v1.json`** — Besu-fleet hostname prefix rules (excluded from closure).
|
||||
- **`config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json`** — One row per in-scope running guest (last committed `reports/status/live_inventory.json`); partial enrichment from `phoenix-deploy-api/deploy-targets.json`.
|
||||
- **`config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json`** — One row per in-scope running guest (last committed `reports/status/live_inventory.json`); enrichment from `phoenix-deploy-api/deploy-targets.json`.
|
||||
- **`config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.schema.json`** — JSON Schema for matrix rows.
|
||||
- **`scripts/lib/non_blockchain_vm_routing_matrix.py`** — `generate` / `validate` subcommands.
|
||||
- **`scripts/verify/validate-non-blockchain-vm-routing-matrix.sh`** — invoked from `scripts/validation/validate-config-files.sh`.
|
||||
- **`config/gitea-phoenix/gov-portals-runtime.v1.json`** + **`.schema.json`** — CT **7804** ports **3001–3004**, repos, Phoenix targets, `pnpm` filters; parity-checked against matrix **7804** row.
|
||||
- **`scripts/lib/non_blockchain_vm_routing_matrix.py`** — `generate`, `validate`, `parity-deploy-targets`, `parity-operational-template`, `parity-gov-portals-runtime`.
|
||||
- **`scripts/verify/validate-vm-routing-parity.sh`** — full gate chain.
|
||||
- **`scripts/verify/validate-non-blockchain-vm-routing-matrix.sh`** — delegates to `validate-vm-routing-parity.sh` (used by `validate-config-files.sh`).
|
||||
- **`scripts/verify/check-gov-portal-workflow-canonical-strings.sh`** — optional monorepo drift check (`GOV_PORTALS_MONOREPO_ROOT`, skips if path missing).
|
||||
- **`config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md`** — Pattern A vs B, secrets, canonical Phoenix `target` strings.
|
||||
- **Operational / ALL_VMIDS sweep:** `parity-operational-template` compares **IPv4** to `config/proxmox-operational-template.json` (fails on true drift); **hostname** mismatches emit **WARN** (inventory Proxmox names vs template design names; NPMplus **10233** `.166`/`.167` dual-homed note per [ALL_VMIDS_ENDPOINTS.md](./ALL_VMIDS_ENDPOINTS.md)).
|
||||
- **Secrets hygiene:** [GITEA_CD_OPERATOR_CHECKLIST.md](../00-meta/GITEA_CD_OPERATOR_CHECKLIST.md) expanded (token table, Gitea-only, no tokens in `git remote` URLs).
|
||||
|
||||
## Why this exists
|
||||
|
||||
@@ -46,38 +53,21 @@ Besu-only hosts per the exclusion list above. For those, the matrix may omit row
|
||||
|
||||
## Objectives (work packages)
|
||||
|
||||
1. **Machine-readable matrix**
|
||||
Add `config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.schema.json` (JSON Schema) and `config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json` (or generated `reports/status/…` with a committed snapshot) listing, for each **in-scope VMID**: `vmid`, `hostname`, `primary_ip`, `category`, `gitea_repos[]`, `deploy_target`, `workflow_glob`, `health_url`, `notes`.
|
||||
|
||||
2. **Validator / gate script**
|
||||
`scripts/verify/validate-non-blockchain-vm-routing-matrix.sh` (or Python under `scripts/lib/`):
|
||||
- Load latest `live_inventory.json`.
|
||||
- Compute **in-scope VMIDs** = all running guests minus **exclusion list** (config-driven, e.g. `config/gitea-phoenix/besu-vmid-exclusions.v1.json`).
|
||||
- Fail CI if any in-scope VMID is **missing** from the matrix file unless explicitly listed in an **`allowed_missing`** section with reason (e.g. “ephemeral lab CT”).
|
||||
- Warn (or fail, policy TBD) if matrix references a VMID **not** in inventory.
|
||||
|
||||
3. **`deploy-targets.json` parity**
|
||||
Every **Pattern A** app that should redeploy from Gitea must have a target consistent with the matrix; health URLs must match ALL_VMIDS / E2E lists where applicable.
|
||||
|
||||
4. **Workflow deduplication**
|
||||
Portal templates under `config/gitea-workflow-templates/repos/` vs copies in each `Gov_Web_Portals/*` repo: reduce drift (shared snippet, documented bump process, or generator — pick in implementation).
|
||||
|
||||
5. **Optional `gov-portals-runtime.json`**
|
||||
Single file mapping **7804** unit names → ports → public FQDNs for operators and Phoenix (only if it reduces duplication with `deploy-targets` healthchecks).
|
||||
|
||||
6. **Secrets hygiene**
|
||||
Document per-repo **least-privilege** tokens (read monorepo vs deploy vs NPM API); no long-lived tokens in `.git/config` URLs (Gitea-only policy).
|
||||
|
||||
7. **Docs**
|
||||
Update [GITEA_REPO_VM_CD_CI_MATRIX.md](./GITEA_REPO_VM_CD_CI_MATRIX.md) from the generated matrix (or link “generated from …” to avoid double maintenance).
|
||||
1. **Machine-readable matrix** — Done (`non-blockchain-vm-routing-matrix.v1.json` + schema).
|
||||
2. **Validator / gate script** — Done (`validate` + `validate-config-files.sh` + `validate-vm-routing-parity.sh`).
|
||||
3. **`deploy-targets.json` parity** — Done (`parity-deploy-targets`; single-repo rows also check `health_url`).
|
||||
4. **Workflow deduplication** — Done as **process + CI**: [PORTAL_WORKFLOW_PARITY.md](../../config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md) + `check-gov-portal-workflow-canonical-strings.sh` + template header comments pointing at Pattern A/B.
|
||||
5. **`gov-portals-runtime.json`** — Done (`gov-portals-runtime.v1.json` + schema + jq gate in `validate-config-files.sh`).
|
||||
6. **Secrets hygiene** — Done (operator checklist section + parity doc).
|
||||
7. **Docs** — Done (this file, [GITEA_REPO_VM_CD_CI_MATRIX.md](./GITEA_REPO_VM_CD_CI_MATRIX.md), [GOV_PORTALS_XOM_DEV_DEPLOYMENT.md](./GOV_PORTALS_XOM_DEV_DEPLOYMENT.md), [config/gitea-phoenix/README.md](../../config/gitea-phoenix/README.md)).
|
||||
|
||||
## Acceptance criteria (task complete when)
|
||||
|
||||
- **Closure:** Every **running** guest VMID in `live_inventory.json` that is **not** in the **Besu exclusion** config has a matrix entry **or** an approved `allowed_missing` record with owner sign-off in JSON.
|
||||
- **Scripts:** `bash scripts/validation/validate-config-files.sh` (or `run-all-validation.sh`) invokes the new validator once the matrix is committed.
|
||||
- **Phoenix:** `deploy-targets.json` passes `bash scripts/validation/validate-phoenix-deploy-targets.sh` and matches matrix targets for all **Phoenix-backed** non-Besu apps.
|
||||
- **Docs:** ALL_VMIDS and matrix show **no contradictions** for in-scope VMIDs (IP, FQDN, VMID).
|
||||
- **Gitea-only:** No canonical repo uses GitHub as `origin` for app code paths documented in the matrix (mirrors optional, clearly labeled).
|
||||
- **Docs:** ALL_VMIDS / operational template vs matrix: **IPv4** enforced; hostname differences **WARN** until template or inventory naming is reconciled (see `parity-operational-template` output).
|
||||
- **Gitea-only:** Policy unchanged; matrix does not embed GitHub `origin` rules (see [GOV_PORTALS_REPO_DIRECTORY_VM_FQDN_TABLE.md](./GOV_PORTALS_REPO_DIRECTORY_VM_FQDN_TABLE.md)).
|
||||
|
||||
## Suggested implementation order
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Each **application repo** should carry **its own** `.gitea/workflows/*.yml` so p
|
||||
|
||||
**Canonical integration:** [Phoenix deploy API](../../phoenix-deploy-api/server.js) + [`deploy-targets.json`](../../phoenix-deploy-api/deploy-targets.json). Gov portals two-path model: [GITEA_GOV_PORTALS_LIVE_SOURCE_OF_TRUTH.md](./GITEA_GOV_PORTALS_LIVE_SOURCE_OF_TRUTH.md).
|
||||
|
||||
**Planned full-cluster alignment (non-Besu VMIDs):** [GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md](./GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md) — machine-readable matrix + CI gate so every **non-blockchain** guest in `live_inventory.json` is mapped or explicitly exempt. **Committed matrix:** [`config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json`](../../config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json) (regenerate after inventory export per [`config/gitea-phoenix/README.md`](../../config/gitea-phoenix/README.md)).
|
||||
**Planned full-cluster alignment (non-Besu VMIDs):** [GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md](./GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md) — machine-readable matrix + CI gates. **Committed data:** [`config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json`](../../config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json), [`config/gitea-phoenix/gov-portals-runtime.v1.json`](../../config/gitea-phoenix/gov-portals-runtime.v1.json). **Workflow patterns:** [`config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md`](../../config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md).
|
||||
|
||||
**Postgres / Prisma in Actions (self-hosted runners):** use **`...@postgres:5432`** (service hostname) and keep **`container.network`** empty on **`act_runner`** — [GITEA_ACT_RUNNER_SETUP.md](GITEA_ACT_RUNNER_SETUP.md) (troubleshooting **P1001**).
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ Or use a wildcard:
|
||||
| omnl.xom-dev.phoenix.sankofa.nexus | 3003 | OMNL portal |
|
||||
| xom.xom-dev.phoenix.sankofa.nexus | 3004 | XOM portal |
|
||||
|
||||
Machine-readable copy of this table (Gitea repos, `pnpm` filters, Phoenix `target` names): [`config/gitea-phoenix/gov-portals-runtime.v1.json`](../../config/gitea-phoenix/gov-portals-runtime.v1.json) (validated in `scripts/validation/validate-config-files.sh`).
|
||||
|
||||
## NPMplus proxy hosts (manual fallback)
|
||||
|
||||
If the add script cannot reach NPMplus, add these in NPMplus UI → Hosts → Proxy Hosts:
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
| **Gitea TLS expiry cron** | `bash scripts/maintenance/schedule-gitea-cert-check-cron.sh --install` — installs a daily warning check with `WARN_DAYS=30` |
|
||||
| **Gitea repo ↔ VM CI/CD matrix** | [04-configuration/GITEA_REPO_VM_CD_CI_MATRIX.md](04-configuration/GITEA_REPO_VM_CD_CI_MATRIX.md) — per-repo workflows, Phoenix deploy targets, templates under `config/gitea-workflow-templates/`; gov portals live paths: [GITEA_GOV_PORTALS_LIVE_SOURCE_OF_TRUTH.md](04-configuration/GITEA_GOV_PORTALS_LIVE_SOURCE_OF_TRUTH.md) |
|
||||
| **Gov portals: directory, Gitea/GitHub, VMID, FQDN** | [04-configuration/GOV_PORTALS_REPO_DIRECTORY_VM_FQDN_TABLE.md](04-configuration/GOV_PORTALS_REPO_DIRECTORY_VM_FQDN_TABLE.md) — one table for proxmox, `gov-portals-monorepo`, and DBIS/ICCC/OMNL/XOM submodules |
|
||||
| **Gitea / Phoenix routing matrix (all non-Besu VMIDs)** | [04-configuration/GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md](04-configuration/GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md) — closure vs `live_inventory.json`; committed data: `config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json`, `scripts/lib/non_blockchain_vm_routing_matrix.py` |
|
||||
| **Gitea / Phoenix routing matrix (all non-Besu VMIDs)** | [04-configuration/GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md](04-configuration/GITEA_PHOENIX_NON_BLOCKCHAIN_VM_ROUTING_CLEANUP_TASK.md) — matrix + deploy-target + operational parity; `config/gitea-phoenix/gov-portals-runtime.v1.json`; [PORTAL_WORKFLOW_PARITY.md](../config/gitea-workflow-templates/PORTAL_WORKFLOW_PARITY.md) |
|
||||
| **Gitea CD operator checklist** | [00-meta/GITEA_CD_OPERATOR_CHECKLIST.md](00-meta/GITEA_CD_OPERATOR_CHECKLIST.md) — secrets, Phoenix host sync, `report-gitea-cd-parity.sh` |
|
||||
| **TsunamiSwap DEX plan** | [00-meta/AAVE_CHAIN138_AND_MARIONETTE_TSUNAMISWAP_PLAN.md](00-meta/AAVE_CHAIN138_AND_MARIONETTE_TSUNAMISWAP_PLAN.md) — canonical TsunamiSwap VM `5010` plan, current DEX link, and publish checklist |
|
||||
| **Required / optional / recommended (full plan)** | [00-meta/COMPLETE_REQUIRED_OPTIONAL_RECOMMENDED_INDEX.md](00-meta/COMPLETE_REQUIRED_OPTIONAL_RECOMMENDED_INDEX.md) |
|
||||
|
||||
@@ -247,6 +247,132 @@ def cmd_validate(args: argparse.Namespace) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_parity_deploy_targets(args: argparse.Namespace) -> int:
|
||||
"""Each deploy-target with a resolved VMID must list its repo on the matrix row; optional health URL match."""
|
||||
repo_root = Path(args.repo_root).resolve()
|
||||
matrix = load_json(Path(args.matrix))
|
||||
targets_path = repo_root / "phoenix-deploy-api" / "deploy-targets.json"
|
||||
if not targets_path.is_file():
|
||||
print("ERROR: deploy-targets.json missing", file=sys.stderr)
|
||||
return 1
|
||||
data = load_json(targets_path)
|
||||
by_vmid: dict[str, dict[str, Any]] = {str(e["vmid"]): e for e in matrix.get("entries", [])}
|
||||
errs = 0
|
||||
for t in data.get("targets", []):
|
||||
repo = t.get("repo")
|
||||
desc = t.get("description") or ""
|
||||
if not repo or "/" not in str(repo):
|
||||
continue
|
||||
vmid = _vmid_from_target_description(desc)
|
||||
hc = t.get("healthcheck") or {}
|
||||
url = (hc.get("url") or "").strip()
|
||||
if vmid is None and url:
|
||||
if "192.168.11.51:3000" in url:
|
||||
vmid = "7801"
|
||||
elif "blockscout.defi-oracle.io" in url or "/api/config/capabilities" in url:
|
||||
vmid = "5000"
|
||||
if vmid is None:
|
||||
continue
|
||||
row = by_vmid.get(vmid)
|
||||
if not row:
|
||||
print(f"WARN parity-deploy-targets: vmid {vmid} has no matrix row (repo {repo})", file=sys.stderr)
|
||||
continue
|
||||
grepos = row.get("gitea_repos") or []
|
||||
if repo not in grepos:
|
||||
print(
|
||||
f"ERROR parity-deploy-targets: repo {repo} for vmid {vmid} not in matrix gitea_repos {grepos}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
errs += 1
|
||||
# Multi-repo CT (7804): health URL differs per portal — skip URL equality.
|
||||
if url and row.get("health_url") and len(grepos) <= 1 and row["health_url"] != url:
|
||||
print(
|
||||
f"ERROR parity-deploy-targets: vmid {vmid} health_url matrix={row['health_url']!r} "
|
||||
f"target={url!r} repo={repo}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
errs += 1
|
||||
if errs:
|
||||
return 1
|
||||
print("OK: parity-deploy-targets (repo ⊆ matrix; health match where single-repo row)", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_parity_operational_template(args: argparse.Namespace) -> int:
|
||||
"""Matrix hostname + IP must match config/proxmox-operational-template.json when a service row exists."""
|
||||
matrix = load_json(Path(args.matrix))
|
||||
tmpl = load_json(Path(args.template))
|
||||
services = tmpl.get("services") or []
|
||||
by_vmid: dict[str, dict[str, Any]] = {}
|
||||
for s in services:
|
||||
vid = s.get("vmid")
|
||||
if vid is None:
|
||||
continue
|
||||
by_vmid[str(int(vid))] = s
|
||||
errs = 0
|
||||
warns = 0
|
||||
for row in matrix.get("entries", []):
|
||||
vid = str(row["vmid"])
|
||||
s = by_vmid.get(vid)
|
||||
if not s:
|
||||
continue
|
||||
h_t = (s.get("hostname") or "").strip()
|
||||
ip_t = (s.get("ipv4") or "").strip()
|
||||
h_m = (row.get("hostname") or "").strip()
|
||||
ip_m = (row.get("primary_ip") or "").strip()
|
||||
if h_t and h_m and h_t != h_m:
|
||||
print(
|
||||
f"WARN parity-operational: vmid {vid} hostname inventory/matrix={h_m!r} "
|
||||
f"operational_template={h_t!r} (template may use design names)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
warns += 1
|
||||
if not ip_t or not ip_m:
|
||||
continue
|
||||
if ip_t == ip_m:
|
||||
continue
|
||||
# NPMplus primary: live inventory often lists first net (.166); template uses ingress .167.
|
||||
if vid == "10233" and ip_m == "192.168.11.166" and ip_t == "192.168.11.167":
|
||||
print(
|
||||
"WARN parity-operational: vmid 10233 matrix IP .166 vs template .167 (dual-homed; see ALL_VMIDS)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
warns += 1
|
||||
continue
|
||||
print(
|
||||
f"ERROR parity-operational: vmid {vid} ipv4 matrix={ip_m!r} template={ip_t!r}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
errs += 1
|
||||
if warns:
|
||||
print(f"WARN: parity-operational-template: {warns} hostname/IP note(s)", file=sys.stderr)
|
||||
if errs:
|
||||
return 1
|
||||
print("OK: parity-operational-template (hostname + ipv4 vs matrix)", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_parity_gov_portals_runtime(args: argparse.Namespace) -> int:
|
||||
"""Matrix row 7804 gitea_repos must match gov-portals-runtime.v1.json portal list."""
|
||||
matrix = load_json(Path(args.matrix))
|
||||
runtime = load_json(Path(args.runtime))
|
||||
portals = runtime.get("portals") or []
|
||||
expected = sorted(p["gitea_repo"] for p in portals if p.get("gitea_repo"))
|
||||
row7804 = next((e for e in matrix.get("entries", []) if str(e.get("vmid")) == "7804"), None)
|
||||
if not row7804:
|
||||
print("ERROR parity-gov-runtime: no matrix row for vmid 7804", file=sys.stderr)
|
||||
return 1
|
||||
got = sorted(row7804.get("gitea_repos") or [])
|
||||
if got != expected:
|
||||
print(
|
||||
f"ERROR parity-gov-runtime: matrix 7804 gitea_repos {got} != runtime {expected}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
print("OK: parity-gov-portals-runtime (7804 repos vs runtime file)", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
sub = ap.add_subparsers(dest="cmd", required=True)
|
||||
@@ -264,6 +390,21 @@ def main() -> int:
|
||||
v.add_argument("--matrix", required=True, type=Path)
|
||||
v.set_defaults(func=cmd_validate)
|
||||
|
||||
pdt = sub.add_parser("parity-deploy-targets", help="Matrix rows cover deploy-target repos (and health for single-repo VMIDs)")
|
||||
pdt.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[2])
|
||||
pdt.add_argument("--matrix", required=True, type=Path)
|
||||
pdt.set_defaults(func=cmd_parity_deploy_targets)
|
||||
|
||||
pot = sub.add_parser("parity-operational-template", help="Matrix hostname/IP vs proxmox-operational-template services")
|
||||
pot.add_argument("--matrix", required=True, type=Path)
|
||||
pot.add_argument("--template", required=True, type=Path)
|
||||
pot.set_defaults(func=cmd_parity_operational_template)
|
||||
|
||||
pgr = sub.add_parser("parity-gov-portals-runtime", help="Matrix vmid 7804 gitea_repos match gov-portals-runtime.v1.json")
|
||||
pgr.add_argument("--matrix", required=True, type=Path)
|
||||
pgr.add_argument("--runtime", required=True, type=Path)
|
||||
pgr.set_defaults(func=cmd_parity_gov_portals_runtime)
|
||||
|
||||
args = ap.parse_args()
|
||||
return int(args.func(args))
|
||||
|
||||
|
||||
@@ -307,14 +307,41 @@ else
|
||||
# Non-blockchain VM routing matrix (closure vs reports/status/live_inventory.json)
|
||||
if [[ -x "$PROJECT_ROOT/scripts/verify/validate-non-blockchain-vm-routing-matrix.sh" ]]; then
|
||||
if "$PROJECT_ROOT/scripts/verify/validate-non-blockchain-vm-routing-matrix.sh" "$PROJECT_ROOT"; then
|
||||
log_ok "non-blockchain-vm-routing-matrix: inventory closure vs matrix"
|
||||
log_ok "non-blockchain-vm-routing: inventory + deploy-target + operational + gov-runtime parity"
|
||||
else
|
||||
log_err "non-blockchain-vm-routing-matrix: validation failed (regenerate: python3 scripts/lib/non_blockchain_vm_routing_matrix.py generate …)"
|
||||
log_err "non-blockchain-vm-routing: validation failed (regenerate: python3 scripts/lib/non_blockchain_vm_routing_matrix.py generate …)"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
else
|
||||
log_warn "validate-non-blockchain-vm-routing-matrix.sh missing or not executable; skipping"
|
||||
fi
|
||||
if [[ -f "$PROJECT_ROOT/config/gitea-phoenix/gov-portals-runtime.v1.json" ]] && command -v jq &>/dev/null; then
|
||||
if jq -e '
|
||||
(.schemaVersion == "1")
|
||||
and (.lxc_vmid == 7804)
|
||||
and (.lan_ipv4 | type == "string")
|
||||
and (.portals | type == "array")
|
||||
and (.portals | length == 4)
|
||||
and ((.portals | map(.id) | sort) == ["DBIS","ICCC","OMNL","XOM"])
|
||||
' "$PROJECT_ROOT/config/gitea-phoenix/gov-portals-runtime.v1.json" &>/dev/null; then
|
||||
log_ok "gov-portals-runtime.v1.json: schemaVersion, vmid, four portals"
|
||||
else
|
||||
log_err "gov-portals-runtime.v1.json: invalid structure or portal set"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
else
|
||||
log_warn "gov-portals-runtime.v1.json missing or jq not installed; skipping"
|
||||
fi
|
||||
if [[ -x "$PROJECT_ROOT/scripts/verify/check-gov-portal-workflow-canonical-strings.sh" ]]; then
|
||||
if "$PROJECT_ROOT/scripts/verify/check-gov-portal-workflow-canonical-strings.sh"; then
|
||||
log_ok "gov-portal monorepo workflow strings (optional path)"
|
||||
else
|
||||
log_err "gov-portal monorepo workflow canonical string check failed"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
else
|
||||
log_warn "check-gov-portal-workflow-canonical-strings.sh missing or not executable; skipping"
|
||||
fi
|
||||
# Proxmox operational template (VMID/IP/FQDN mirror; see docs/03-deployment/PROXMOX_VE_OPERATIONAL_DEPLOYMENT_TEMPLATE.md)
|
||||
if [[ -f "$PROJECT_ROOT/config/proxmox-operational-template.json" ]]; then
|
||||
log_ok "Found: config/proxmox-operational-template.json"
|
||||
|
||||
31
scripts/verify/check-gov-portal-workflow-canonical-strings.sh
Executable file
31
scripts/verify/check-gov-portal-workflow-canonical-strings.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Ensure monorepo portal workflows still reference Phoenix targets and monorepo clone.
|
||||
# Set GOV_PORTALS_MONOREPO_ROOT to override (default: ~/projects/gov-portals-monorepo).
|
||||
set -euo pipefail
|
||||
ROOT="${GOV_PORTALS_MONOREPO_ROOT:-$HOME/projects/gov-portals-monorepo}"
|
||||
if [[ ! -d "$ROOT/DBIS/.gitea/workflows" ]]; then
|
||||
echo "[INFO] check-gov-portal-workflow-canonical-strings: no monorepo at $ROOT — skip"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
fail() { echo "[ERROR] $*" >&2; exit 1; }
|
||||
|
||||
check_portal() {
|
||||
local portal="$1" target="$2" filter="$3"
|
||||
local d="$ROOT/$portal/.gitea/workflows/deploy-live.yml"
|
||||
local c="$ROOT/$portal/.gitea/workflows/ci.yml"
|
||||
[[ -f "$d" ]] || fail "missing $d"
|
||||
[[ -f "$c" ]] || fail "missing $c"
|
||||
grep -q "PHOENIX_DEPLOY_URL" "$d" || fail "$portal deploy-live: PHOENIX_DEPLOY_URL"
|
||||
grep -q "PHOENIX_DEPLOY_TOKEN" "$d" || fail "$portal deploy-live: PHOENIX_DEPLOY_TOKEN"
|
||||
grep -qF "${target}" "$d" || fail "$portal deploy-live: Phoenix target ${target}"
|
||||
grep -q "Gov_Web_Portals/gov-portals-monorepo" "$d" || fail "$portal deploy-live: monorepo URL"
|
||||
grep -q "pnpm --filter ${filter}" "$d" "$c" || fail "$portal: pnpm --filter ${filter} in ci or deploy"
|
||||
}
|
||||
|
||||
check_portal DBIS dbis-portal-live portal-dbis
|
||||
check_portal ICCC iccc-portal-live portal-iccc
|
||||
check_portal OMNL omnl-portal-live portal-omnl
|
||||
check_portal XOM xom-portal-live portal-xom
|
||||
|
||||
echo "[OK] gov-portal workflow canonical strings (monorepo under $ROOT)"
|
||||
@@ -32,3 +32,10 @@ for f in "$ROOT/config/gitea-workflow-templates/repos/"*.yml; do
|
||||
basename "$f"
|
||||
done
|
||||
shopt -u nullglob
|
||||
echo ""
|
||||
echo "== Non-blockchain VM matrix + parity (inventory, deploy-targets, template, gov runtime) =="
|
||||
if [[ -x "$ROOT/scripts/verify/validate-vm-routing-parity.sh" ]]; then
|
||||
"$ROOT/scripts/verify/validate-vm-routing-parity.sh" "$ROOT"
|
||||
else
|
||||
echo "(validate-vm-routing-parity.sh not executable)"
|
||||
fi
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Validate non-blockchain VM routing matrix vs committed live_inventory snapshot.
|
||||
# Validate non-blockchain VM routing matrix + deploy-target / template / gov-runtime parity.
|
||||
# Usage: scripts/verify/validate-non-blockchain-vm-routing-matrix.sh [PROJECT_ROOT]
|
||||
set -euo pipefail
|
||||
ROOT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
||||
INV="${NON_BLOCKCHAIN_MATRIX_INVENTORY:-$ROOT/reports/status/live_inventory.json}"
|
||||
EXC="$ROOT/config/gitea-phoenix/besu-vmid-exclusions.v1.json"
|
||||
MTX="$ROOT/config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json"
|
||||
PY="$ROOT/scripts/lib/non_blockchain_vm_routing_matrix.py"
|
||||
|
||||
if [[ ! -f "$INV" ]]; then
|
||||
echo "[WARN] validate-non-blockchain-vm-routing-matrix: missing inventory $INV — skip"
|
||||
exit 0
|
||||
fi
|
||||
if [[ ! -f "$MTX" ]] || [[ ! -f "$EXC" ]] || [[ ! -f "$PY" ]]; then
|
||||
echo "[ERROR] validate-non-blockchain-vm-routing-matrix: missing matrix, exclusions, or script" >&2
|
||||
exit 1
|
||||
fi
|
||||
exec python3 "$PY" validate --inventory "$INV" --exclusions "$EXC" --matrix "$MTX"
|
||||
exec bash "$ROOT/scripts/verify/validate-vm-routing-parity.sh" "$ROOT"
|
||||
|
||||
18
scripts/verify/validate-vm-routing-parity.sh
Executable file
18
scripts/verify/validate-vm-routing-parity.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Matrix ↔ deploy-targets ↔ operational template ↔ gov-portals runtime (optional).
|
||||
set -euo pipefail
|
||||
R="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
||||
PY="$R/scripts/lib/non_blockchain_vm_routing_matrix.py"
|
||||
INV="${NON_BLOCKCHAIN_MATRIX_INVENTORY:-$R/reports/status/live_inventory.json}"
|
||||
EXC="$R/config/gitea-phoenix/besu-vmid-exclusions.v1.json"
|
||||
MTX="$R/config/gitea-phoenix/non-blockchain-vm-routing-matrix.v1.json"
|
||||
TPL="$R/config/proxmox-operational-template.json"
|
||||
RUN="$R/config/gitea-phoenix/gov-portals-runtime.v1.json"
|
||||
|
||||
python3 "$PY" validate --inventory "$INV" --exclusions "$EXC" --matrix "$MTX"
|
||||
python3 "$PY" parity-deploy-targets --repo-root "$R" --matrix "$MTX"
|
||||
python3 "$PY" parity-operational-template --matrix "$MTX" --template "$TPL"
|
||||
if [[ -f "$RUN" ]]; then
|
||||
python3 "$PY" parity-gov-portals-runtime --matrix "$MTX" --runtime "$RUN"
|
||||
fi
|
||||
echo "[OK] validate-vm-routing-parity: inventory + deploy-targets + operational template + gov runtime"
|
||||
Reference in New Issue
Block a user