diff --git a/.github/workflows/build-verify.yml b/.github/workflows/build-verify.yml new file mode 100644 index 0000000..7944a62 --- /dev/null +++ b/.github/workflows/build-verify.yml @@ -0,0 +1,65 @@ +name: build-verify + +# Catches the exact class of failure that broke two consecutive PeerCortex +# deploys on 2026-07-16: server.js requiring a local file that was never +# actually committed/uploaded (MODULE_NOT_FOUND crash-loop on Erik), and a +# runtime dependency (pg) missing from package.json/node_modules. Runs on +# every push and PR; does NOT deploy anything -- see deploy.sh / the manual +# Erik deploy process for that. +# +# No untrusted event data (PR titles/bodies/commit messages) is interpolated +# into any run: step below -- nothing here is exposed to injection. + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + build-verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: npm ci + run: npm ci + + - name: server.js / local-db-client.js / bio-rd-client.js syntax + run: | + for f in server.js local-db-client.js bio-rd-client.js bgp-hijack-monitor.js magatama-s2ten-bgp-enrichment.js; do + [ -f "$f" ] && node --check "$f" + done + + - name: every local require() target actually exists + run: | + MISSING=0 + for f in server.js local-db-client.js bio-rd-client.js; do + [ -f "$f" ] || continue + for req in $(grep -oE "require\(['\"]\./[^'\"]+['\"]\)" "$f" | sed -E "s/require\(['\"]\.\/([^'\"]+)['\"]\)/\1/"); do + target="$req" + if [ ! -f "$target" ] && [ ! -f "$target.js" ] && [ ! -d "$target" ]; then + echo "::error file=$f::require('./$req') has no matching file (checked $target, $target.js)" + MISSING=1 + fi + done + done + exit $MISSING + + - name: TypeScript typecheck + run: npx tsc --noEmit --pretty false || true + # Non-blocking for now: src/mcp-server/* and src/sources/* have pre-existing + # errors unrelated to the deployed server.js path (see project memory, + # 2026-07-16 audit). Flip to a hard failure once those are cleaned up -- + # until then this step is informational only, visible in the job log. + + - name: build (dist/) + run: npm run build + + - name: vitest + run: npm test diff --git a/deploy-from-git.sh b/deploy-from-git.sh new file mode 100755 index 0000000..cb75b18 --- /dev/null +++ b/deploy-from-git.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# Git-pull-based deploy for Erik. Replaces the ad-hoc per-file `cat file | ssh` +# uploads used on 2026-07-16, which twice missed files that server.js actually +# requires (src/backend/config.js, src/backend/services/smtp.js) because +# uploading was a manual, easy-to-forget step instead of a single `git pull`. +# +# Run this ON Erik, from /opt/peercortex-app. Deliberately manual (not wired +# to a Gitea Action) -- Erik hosts many unrelated production services and +# main can contain code that hasn't been live-tested yet (see project memory). +# +# Usage: ./deploy-from-git.sh [branch] (default: main) + +set -euo pipefail +cd "$(dirname "$0")" + +BRANCH="${1:-main}" +BACKUP_DIR=/opt/_rollbacks/peercortex-app +TS=$(date -u +%Y%m%dT%H%M%SZ) +mkdir -p "$BACKUP_DIR" + +echo "[1/7] Backing up current server.js + public/index.html..." +cp -p server.js "$BACKUP_DIR/server.js.$TS" +cp -p public/index.html "$BACKUP_DIR/index.html.$TS" + +echo "[2/7] Fetching + checking out $BRANCH..." +git fetch origin +git checkout "$BRANCH" +git pull origin "$BRANCH" + +echo "[3/7] npm ci..." +npm ci + +echo "[4/7] Verifying every local require() target actually exists..." +MISSING=0 +for f in server.js local-db-client.js bio-rd-client.js; do + [ -f "$f" ] || continue + for req in $(grep -oE "require\(['\"]\./[^'\"]+['\"]\)" "$f" | sed -E "s/require\(['\"]\.\/([^'\"]+)['\"]\)/\1/"); do + if [ ! -f "$req" ] && [ ! -f "$req.js" ] && [ ! -d "$req" ]; then + echo " MISSING: $f requires ./$req -- not found" >&2 + MISSING=1 + fi + done +done +if [ "$MISSING" = "1" ]; then + echo "Aborting: fix the missing file(s) above before deploying." >&2 + exit 1 +fi + +echo "[5/7] Syntax check..." +node --check server.js +node --check local-db-client.js + +echo "[6/7] Building dist/ (TypeScript API server)..." +npm run build + +echo "[7/7] Restarting peercortex (and peercortex-api if configured)..." +pm2 restart peercortex --update-env +pm2 restart peercortex-api --update-env 2>/dev/null || echo " (peercortex-api not running yet, skipped)" + +echo "" +echo "Done. Rollback: cp $BACKUP_DIR/server.js.$TS server.js && cp $BACKUP_DIR/index.html.$TS public/index.html && pm2 restart peercortex"