erpnext/scripts/ci/ci-readiness.sh
epistemophiliac 0c8d593d40 Add production ERPNext Coolify stack with CI gates
Single compose file for Coolify: MariaDB, Redis, idempotent site creation,
migrations on redeploy, SERVICE_URL_FRONTEND_8080 routing, and Forgejo Actions
readiness validation vendored from production-ci-readiness skill.
2026-06-16 17:52:02 -04:00

127 lines
4 KiB
Bash
Executable file

#!/usr/bin/env bash
# Production readiness scanner — run from repo root or pass path as $1
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
REPO="${1:-.}"
REPO="$(cd "$REPO" && pwd)"
STRICT="${STRICT:-0}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ERR=0
WARN=0
INFO=0
err() { echo "ERROR $*"; ERR=$((ERR + 1)); }
warn() { echo "WARN $*"; WARN=$((WARN + 1)); }
info() { echo "INFO $*"; }
pass() { echo "OK $*"; }
echo "=== Production readiness: $REPO ==="
echo "strict=$STRICT"
echo
# --- Secrets in tracked files ---
if command -v git >/dev/null 2>&1 && git -C "$REPO" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
if git -C "$REPO" ls-files | grep -qE '^\.env$|credentials\.json|\.pem$'; then
err "[SEC-01] Tracked sensitive files (.env, credentials, pem)"
else
pass "[SEC-01] No obvious secret filenames tracked"
fi
while IFS= read -r f; do
[ -f "$REPO/$f" ] || continue
if grep -qE 'BEGIN (RSA |EC )?PRIVATE KEY|api[_-]?key\s*=\s*["\x27][a-zA-Z0-9]{20,}' "$REPO/$f" 2>/dev/null; then
err "[SEC-01] Possible secret in tracked file: $f"
fi
done < <(git -C "$REPO" ls-files '*.yml' '*.yaml' '*.json' '*.md' '*.sh' '*.js' '*.go' '*.env*' 2>/dev/null | head -500)
else
warn "[SEC-01] Not a git repo — skip secret scan"
fi
# --- node_modules in git ---
if command -v git >/dev/null 2>&1 && git -C "$REPO" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
NM_COUNT=$(git -C "$REPO" ls-files '**/node_modules/**' 2>/dev/null | wc -l | tr -d ' ')
if [ "${NM_COUNT:-0}" -gt 0 ]; then
err "[DC-06] node_modules tracked ($NM_COUNT files) — git rm -r --cached and .gitignore"
else
pass "[DC-06] node_modules not tracked"
fi
fi
# --- Node Dockerfiles: lockfile + npm ci ---
while IFS= read -r df; do
[ -f "$df" ] || continue
dir="$(dirname "$df")"
if grep -qE 'npm install' "$df" && ! grep -qE 'npm ci' "$df"; then
warn "[DC-07] $df uses npm install without npm ci"
fi
if grep -qE 'npm ci|npm install' "$df"; then
if [ ! -f "$dir/package-lock.json" ] && [ ! -f "$dir/yarn.lock" ] && [ ! -f "$dir/pnpm-lock.yaml" ]; then
warn "[DC-07] $df has no lockfile in $dir"
else
pass "[DC-07] $df has lockfile"
fi
fi
done < <(find "$REPO" -name Dockerfile \
-not -path '*/node_modules/*' \
-not -path '*/fabric-samples-upstream/*' \
-not -path '*/.git/*' \
2>/dev/null)
# --- Gateway patterns (if present) ---
GW="$REPO/gateway/server.js"
if [ -f "$GW" ]; then
if grep -q 'withChainLock' "$GW" && grep -q 'evaluateChaincodeRaw' "$GW"; then
if grep -A2 'evaluateChaincodeRaw' "$GW" | grep -q 'withChainLock'; then
warn "[GW-02] gateway evaluates may be serialized behind withChainLock"
else
pass "[GW-02] evaluates not behind global chain lock"
fi
fi
if grep -qE "app\.get\(['\"]/health" "$GW"; then
pass "[GW-01] /health route present"
else
warn "[GW-01] no /health in gateway/server.js"
fi
fi
# --- Deploy docs ---
for doc in README.md docs/COOLIFY_DEPLOY.md docs/GATEWAY.md AGENTS.md; do
if [ -f "$REPO/$doc" ]; then
pass "[HY-01] found $doc"
break
fi
done
# --- Compose (delegate) ---
if [ -f "$REPO/docker-compose.yml" ] || [ -f "$REPO/docker-compose.yaml" ]; then
echo
echo "--- docker-compose validation ---"
COMPOSE_ERR=0
bash "$SCRIPT_DIR/validate-docker-compose.sh" "$REPO" || COMPOSE_ERR=$?
if [ "$COMPOSE_ERR" -ne 0 ]; then
ERR=$((ERR + COMPOSE_ERR))
fi
fi
# --- Go tests hint ---
if [ -f "$REPO/Makefile" ] && grep -q 'test' "$REPO/Makefile"; then
info "[HY-03] Makefile has test target — run in CI"
fi
if [ -d "$REPO/chaincode" ] || find "$REPO" -name go.mod -print -quit 2>/dev/null | grep -q .; then
info "Consider: cd chaincode && go test ./..."
fi
echo
echo "=== Summary ==="
echo "errors=$ERR warnings=$WARN"
if [ "$ERR" -gt 0 ]; then
echo "VERDICT: FAIL"
exit 1
fi
if [ "$STRICT" = "1" ] && [ "$WARN" -gt 0 ]; then
echo "VERDICT: FAIL (strict mode, warnings treated as errors)"
exit 1
fi
echo "VERDICT: PASS"
exit 0