#!/usr/bin/env bash set -euo pipefail # Master test/security runner. # - npm audit (high+) # - lint / type-check / format check / tests # - Trivy file-system scan (HIGH/CRITICAL) # - OWASP ZAP baseline (unauthenticated) # # Outputs are written under reports/runs// and summarized in summary.html. # # Env vars: # TARGET - URL to scan with ZAP (default: https://test.lomavuokraus.fi) # TRIVY_TARGET - Path or image to scan (default: current directory) # TRIVY_MODE - "fs" (default) or "image" # ZAP_IMAGE - Override ZAP image (default in zap-baseline.sh) # TIMEOUT_MINUTES - ZAP timeout minutes (default in zap-baseline.sh) RUN_TS=$(date +"%Y%m%d-%H%M%S") RUN_DIR="reports/runs/${RUN_TS}" mkdir -p "$RUN_DIR" SUMMARY_ROWS=() SUMMARY_TEXT_ROWS=() log() { echo "[$(date +"%H:%M:%S")] $*" } record_result() { local name="$1"; shift local status="$1"; shift local detail="$1"; shift local detail_text="$1"; shift SUMMARY_ROWS+=("${name}${status}${detail}") SUMMARY_TEXT_ROWS+=("${name}: ${status}${detail_text:+ - ${detail_text}}") } # 1) npm audit if command -v npm >/dev/null 2>&1; then log "Running npm audit (high)..." AUDIT_JSON="$RUN_DIR/npm-audit.json" AUDIT_TXT="$RUN_DIR/npm-audit.txt" if npm audit --audit-level=high --json >"$AUDIT_JSON" 2>"$AUDIT_TXT"; then record_result "npm audit" "PASS" "text | json" "reports: ${AUDIT_TXT}, ${AUDIT_JSON}" else record_result "npm audit" "FAIL" "text | json" "reports: ${AUDIT_TXT}, ${AUDIT_JSON}" fi else log "npm not found; skipping npm audit" record_result "npm audit" "SKIP" "npm not available" "npm not available" fi # 2) Lint / type-check / format / tests run_npm_check() { local name="$1"; shift local outfile="$RUN_DIR/${name}.txt" if ! command -v npm >/dev/null 2>&1; then log "npm not found; skipping ${name}" record_result "${name}" "SKIP" "npm not available" "npm not available" return fi if npm run 2>/dev/null | grep -qE "^ ${name}$"; then log "Running ${name}..." if npm run "${name}" >"$outfile" 2>&1; then record_result "${name}" "PASS" "log" "log: ${outfile}" else record_result "${name}" "FAIL" "log" "log: ${outfile}" fi else log "npm script '${name}' not defined; skipping" record_result "${name}" "SKIP" "script not defined" "script not defined" fi } run_npm_check "lint" run_npm_check "type-check" run_npm_check "format:check" run_npm_check "test" # 3) Trivy (fs by default) TRIVY_TARGET="${TRIVY_TARGET:-.}" TRIVY_MODE="${TRIVY_MODE:-fs}" if command -v trivy >/dev/null 2>&1; then log "Running Trivy (${TRIVY_MODE}) on ${TRIVY_TARGET}..." TRIVY_TXT="$RUN_DIR/trivy.txt" if trivy "${TRIVY_MODE}" --severity HIGH,CRITICAL --timeout 5m "$TRIVY_TARGET" >"$TRIVY_TXT"; then record_result "Trivy (${TRIVY_MODE})" "PASS" "report" "report: ${TRIVY_TXT}" else record_result "Trivy (${TRIVY_MODE})" "FAIL" "report" "report: ${TRIVY_TXT}" fi else log "Trivy not found; skipping" record_result "Trivy" "SKIP" "trivy not available" "trivy not available" fi # 4) OWASP ZAP baseline TARGET="${TARGET:-https://test.lomavuokraus.fi}" ZAP_DIR="$RUN_DIR/zap" mkdir -p "$ZAP_DIR" log "Running ZAP baseline against ${TARGET}..." if TARGET="$TARGET" REPORT_DIR="$ZAP_DIR" "${BASH_SOURCE%/*}/zap-baseline.sh"; then record_result "OWASP ZAP baseline" "PASS" "HTML | JSON" "reports: ${ZAP_DIR}/zap-report.html, ${ZAP_DIR}/zap-report.json" else record_result "OWASP ZAP baseline" "FAIL" "HTML | JSON" "reports: ${ZAP_DIR}/zap-report.html, ${ZAP_DIR}/zap-report.json" fi # Summary HTML SUMMARY_FILE="$RUN_DIR/summary.html" cat >"$SUMMARY_FILE" < Test Suite Summary - ${RUN_TS}

Test Suite Summary

Run: ${RUN_TS}
Target: ${TARGET}
${SUMMARY_ROWS[*]}
CheckStatusDetails
EOF log "Summary:" for row in "${SUMMARY_TEXT_ROWS[@]}"; do echo " - ${row}" done log "Done. Reports in ${RUN_DIR}" echo "Open ${SUMMARY_FILE} in a browser for the summary."