fix(npm): IT API TLS helper + treat certificate_id string 0 as missing
All checks were successful
Deploy to Phoenix / deploy (push) Successful in 6s
All checks were successful
Deploy to Phoenix / deploy (push) Successful in 6s
- jq select includes certificate_id == "0" for NPM JSON quirks - request-it-api-tls-npm.sh wraps CERT_DOMAINS_FILTER for it-api.sankofa.nexus - Docs: TLS command, Cloudflare redirect-loop note; spec remaining items Made-with: Cursor
This commit is contained in:
@@ -54,7 +54,7 @@ Orchestration for Proxmox VE, Chain 138 (`smom-dbis-138/`), explorers, NPMplus,
|
||||
| The Order portal (`https://the-order.sankofa.nexus`) | OSJ management UI (secure auth); source repo **the_order** at `~/projects/the_order`. NPM upstream defaults to **order-haproxy** CT **10210** (`IP_ORDER_HAPROXY:80`); use `THE_ORDER_UPSTREAM_*` to point at the Sankofa portal if 10210 is down. Provision HAProxy: `scripts/deployment/provision-order-haproxy-10210.sh`. **`www.the-order.sankofa.nexus`** → **301** apex (same as www.sankofa / www.phoenix). |
|
||||
| Portal login + Keycloak systemd + `.env` (prints password once) | `./scripts/deployment/enable-sankofa-portal-login-7801.sh` (`--dry-run` first); preserves `KEYCLOAK_*` from repo `.env` and runs merge script when `KEYCLOAK_CLIENT_SECRET` is set |
|
||||
| Keycloak redirect URIs (portal + admin) | `./scripts/deployment/keycloak-sankofa-ensure-client-redirects-via-proxmox-pct.sh` (or `keycloak-sankofa-ensure-client-redirects.sh` for LAN URL) — needs `KEYCLOAK_ADMIN_PASSWORD` in `.env` |
|
||||
| NPM TLS for hosts missing certs | `./scripts/request-npmplus-certificates.sh` — optional `CERT_DOMAINS_FILTER='portal\\.sankofa|admin\\.sankofa'` |
|
||||
| NPM TLS for hosts missing certs | `./scripts/request-npmplus-certificates.sh` — optional `CERT_DOMAINS_FILTER='portal\\.sankofa|admin\\.sankofa'`; IT API: `./scripts/deployment/request-it-api-tls-npm.sh` (same as filter `it-api\\.sankofa\\.nexus`) |
|
||||
| Token-aggregation API (Chain 138) | `pnpm run verify:token-aggregation-api` — tokens, pools, quote (prints `quoteEngine` when `jq` installed), `bridge/routes`, networks. Build + env: `scripts/deploy-token-aggregation-for-publication.sh` (sets `RPC_URL_138`, `TOKEN_AGGREGATION_CHAIN138_RPC_URL`, optional `TOKEN_AGGREGATION_PMM_*`). LAN push + restart: `scripts/deployment/push-token-aggregation-bundle-to-explorer.sh`. Nginx gaps: `scripts/fix-explorer-http-api-v1-proxy.sh` (apex `/api/v1/`), `scripts/fix-explorer-token-aggregation-api-v2-proxy.sh` (planner POST). Runbook: `docs/04-configuration/TOKEN_AGGREGATION_REPORT_API_RUNBOOK.md`. |
|
||||
| **Chain 138 Open Snap** (MetaMask, open Snap permissions only; stable MetaMask requires MetaMask install allowlist for npm Snaps) | Source repo: [Defi-Oracle-Tooling/chain138-snap-minimal](https://github.com/Defi-Oracle-Tooling/chain138-snap-minimal). Vendored in this workspace: `metamask-integration/chain138-snap-minimal/`. Snap ID `npm:chain138-open-snap`; **`npm run verify`** = `npm audit --omit=dev` + build. **Publish:** token in `chain138-snap/.env` or `npm login`, then `./scripts/deployment/publish-chain138-open-snap.sh`. **Full-feature Snap** (API quotes, allowlist): `metamask-integration/chain138-snap/`. Explorer `/wallet` install works on stable MetaMask only after allowlisting; use Flask or local serve for dev. |
|
||||
| Completable (no LAN) | `./scripts/run-completable-tasks-from-anywhere.sh` |
|
||||
|
||||
@@ -171,7 +171,7 @@ The HTML controller should show a **joined view**: *public hostname → NPM →
|
||||
|
||||
1. **Full BFF** with OIDC (Keycloak) and Postgres — **`dbis_core` vs dedicated CT** — decide once.
|
||||
2. **Keycloak** — assign **`sankofa-it-admin`** to real IT users (role creation is scripted; mapping is manual policy).
|
||||
3. **TLS for `it-api.sankofa.nexus`** — NPM certificate after DNS propagation; duplicate guest IP remediation (export exit **2**) on the cluster.
|
||||
3. **TLS for `it-api.sankofa.nexus`** — `scripts/deployment/request-it-api-tls-npm.sh` (or `CERT_DOMAINS_FILTER='it-api\.sankofa\.nexus'` + `request-npmplus-certificates.sh`). If public HTTPS redirect-loops, align Cloudflare proxy/SSL mode with NPM. **Duplicate guest IPs** (export exit **2**) — remediate on cluster.
|
||||
4. **UniFi / NPM** live collectors — Phase 2 of this spec.
|
||||
|
||||
This spec does **not** replace change control; it gives you a **single product vision** so IP, VLAN, ports, hosts, licenses, and billing support evolve together instead of in silos.
|
||||
|
||||
@@ -11,7 +11,7 @@ One command after `.env` has `NPM_PASSWORD`, Cloudflare vars (for DNS), and SSH
|
||||
1. **`bash scripts/deployment/bootstrap-sankofa-it-read-api-lan.sh`** — Refreshes inventory JSON, rsyncs a minimal tree to **`/opt/proxmox`** on **`PROXMOX_HOST`** (default r630-01), installs **`sankofa-it-read-api`** (bind **`0.0.0.0:8787`**, secrets in **`/etc/sankofa-it-read-api.env`**), upserts **`IT_READ_API_URL`** / **`IT_READ_API_KEY`** in repo **`.env`**, enables weekly **`sankofa-it-inventory-export.timer`** on the same host, runs **`sankofa-portal-merge-it-read-api-env-from-repo.sh`** for CT **7801**. Export exit code **2** (duplicate guest IPs) does **not** abort the bootstrap.
|
||||
2. **NPM:** `bash scripts/nginx-proxy-manager/upsert-it-read-api-proxy-host.sh` — proxy **`it-api.sankofa.nexus`** → **`http://<r630-01>:8787`** (override with **`IT_READ_API_PUBLIC_HOST`**).
|
||||
3. **DNS:** `bash scripts/cloudflare/add-it-api-sankofa-dns.sh` — **`it-api.sankofa.nexus`** A → **`PUBLIC_IP`** (proxied).
|
||||
4. **TLS:** In NPM UI, request a certificate for **`it-api.sankofa.nexus`** after DNS propagates (or widen **`CERT_DOMAINS_FILTER`** in `scripts/request-npmplus-certificates.sh`).
|
||||
4. **TLS:** `CERT_DOMAINS_FILTER='it-api\.sankofa\.nexus' bash scripts/request-npmplus-certificates.sh` (or NPM UI → SSL). If the public URL redirect-loops (e.g. Cloudflare **Proxied** + NPM **SSL forced**), set the record to **DNS only** temporarily or align Cloudflare SSL mode with your origin.
|
||||
|
||||
**Note:** Operator workstations outside VLAN 11 may be firewalled from **`192.168.11.11:8787`**; portal CT **7801** and NPM on LAN should still reach it.
|
||||
|
||||
|
||||
9
scripts/deployment/request-it-api-tls-npm.sh
Executable file
9
scripts/deployment/request-it-api-tls-npm.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Request Let's Encrypt via NPMplus for it-api.sankofa.nexus and assign to proxy host.
|
||||
# Requires NPM_* in repo .env. Same as:
|
||||
# CERT_DOMAINS_FILTER='it-api\.sankofa\.nexus' bash scripts/request-npmplus-certificates.sh
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
export CERT_DOMAINS_FILTER='it-api\.sankofa\.nexus'
|
||||
exec bash "${PROJECT_ROOT}/scripts/request-npmplus-certificates.sh" "$@"
|
||||
@@ -67,7 +67,7 @@ echo ""
|
||||
# Authenticate (use jq to build JSON so password is safely escaped)
|
||||
log_info "Authenticating to NPMplus API..."
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
TOKEN_RESPONSE=$(curl -s -k -L --http1.1 --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-180}" -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
|
||||
@@ -87,7 +87,7 @@ echo ""
|
||||
|
||||
# Get all proxy hosts
|
||||
log_info "Fetching proxy hosts..."
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -L --http1.1 --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-300}" -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
@@ -101,7 +101,7 @@ if [ "$PROXY_COUNT" = "0" ]; then
|
||||
fi
|
||||
|
||||
# Build list of hosts that need a certificate (id|domain, one per line)
|
||||
NEED_CERT_LIST=$(echo "$PROXY_HOSTS_JSON" | jq -r '.[] | select(.certificate_id == null or .certificate_id == 0) | "\(.id)|\(.domain_names[0] // "")"' 2>/dev/null | while IFS='|' read -r id domain; do
|
||||
NEED_CERT_LIST=$(echo "$PROXY_HOSTS_JSON" | jq -r '.[] | select(.certificate_id == null or .certificate_id == 0 or .certificate_id == "0") | "\(.id)|\(.domain_names[0] // "")"' 2>/dev/null | while IFS='|' read -r id domain; do
|
||||
[ -z "$domain" ] || [ "$domain" = "null" ] && continue
|
||||
echo "$domain" | grep -q "test.*example.com" && continue
|
||||
echo "${id}|${domain}"
|
||||
@@ -133,7 +133,7 @@ fi
|
||||
# Try to get DNS (Cloudflare) credential_id so we use same method as UI (DNS challenge)
|
||||
CREDENTIAL_ID=""
|
||||
for path in "/api/nginx/letsencrypt-credentials" "/api/letsencrypt-credentials"; do
|
||||
CRED_JSON=$(curl -s -k -X GET "$NPM_URL$path" -H "Authorization: Bearer $TOKEN" 2>/dev/null || echo "[]")
|
||||
CRED_JSON=$(curl -s -k -L --http1.1 --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-180}" -X GET "$NPM_URL$path" -H "Authorization: Bearer $TOKEN" 2>/dev/null || echo "[]")
|
||||
if echo "$CRED_JSON" | jq -e 'type == "array" and length > 0' >/dev/null 2>&1; then
|
||||
CREDENTIAL_ID=$(echo "$CRED_JSON" | jq -r '.[0].id // .[0].credential_id // empty' 2>/dev/null)
|
||||
[ -n "$CREDENTIAL_ID" ] && [ "$CREDENTIAL_ID" != "null" ] && break
|
||||
@@ -158,7 +158,7 @@ while IFS='|' read -r host_id domain; do
|
||||
# Request certificate. NPM API accepts only domain_names + provider (extra keys cause "must NOT have additional properties").
|
||||
# For DNS (Cloudflare) and correct expiry, request certs in NPM UI: Hosts → host → SSL → Request new SSL Certificate → DNS Challenge, Cloudflare.
|
||||
log_info " Requesting SSL certificate..."
|
||||
CERT_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/certificates" \
|
||||
CERT_RESPONSE=$(curl -s -k -L --http1.1 --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-180}" -X POST "$NPM_URL/api/nginx/certificates" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(jq -n --arg domain "$domain" '{ domain_names: [$domain], provider: "letsencrypt" }')")
|
||||
@@ -175,7 +175,7 @@ while IFS='|' read -r host_id domain; do
|
||||
|
||||
# Update proxy host to use certificate
|
||||
log_info " Assigning certificate to proxy host..."
|
||||
UPDATE_RESPONSE=$(curl -s -k -X PUT "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
|
||||
UPDATE_RESPONSE=$(curl -s -k -L --http1.1 --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-180}" -X PUT "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
|
||||
Reference in New Issue
Block a user