diff --git a/.github/workflows/dependency-vulnerability-scan.yml b/.github/workflows/dependency-vulnerability-scan.yml new file mode 100644 index 00000000..dfea9efa --- /dev/null +++ b/.github/workflows/dependency-vulnerability-scan.yml @@ -0,0 +1,59 @@ +name: Dependency Vulnerability Scanning + +on: + pull_request: + paths: + - "**/package.json" + - "**/package-lock.json" + - "**/Cargo.toml" + - "**/Cargo.lock" + - "scripts/audit-vulnerabilities.sh" + schedule: + - cron: "0 0 * * 1" # Weekly Monday scan + workflow_dispatch: + +concurrency: + group: vuln-scan-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + security-events: write + +jobs: + npm-audit: + name: npm-vulnerability-audit + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Audit Listener Dependencies + run: | + cd listener + npm audit --audit-level=high + + - name: Audit Dashboard Dependencies + run: | + cd dashboard + npm audit --audit-level=high + + cargo-audit: + name: cargo-vulnerability-audit + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Rust & cargo-audit + uses: rustsec/audit-check@v2.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + manifest-path: contract/Cargo.toml diff --git a/docs/DEPENDENCY_VULNERABILITY_SCANNING.md b/docs/DEPENDENCY_VULNERABILITY_SCANNING.md new file mode 100644 index 00000000..b6d897f9 --- /dev/null +++ b/docs/DEPENDENCY_VULNERABILITY_SCANNING.md @@ -0,0 +1,35 @@ +# 🛡️ Automated Dependency Vulnerability Scanning Policy + +This document details NotifyChain's automated vulnerability scanning architecture across JavaScript, TypeScript, and Rust toolchains (Issue #718). + +--- + +## 1. Tooling Architecture + +| Ecosystem | Scanner Tool | Target Files | Severity Gate | +|---|---|---|---| +| **Node.js (Listener & Dashboard)** | `npm audit` | `package.json`, `package-lock.json` | High / Critical (Blocking) | +| **Rust (Smart Contracts)** | `cargo-audit` (RustSec) | `Cargo.toml`, `Cargo.lock` | Warnings / Vulnerabilities (Blocking) | + +--- + +## 2. Severity Classification Policy + +1. **Informational (Low / Moderate)**: Logged during local and CI audits to provide developers visibility into non-critical advisory notices without failing builds. +2. **Blocking (High / Critical)**: PRs introducing known exploitable vulnerabilities or critical security advisories fail CI automatically. + +--- + +## 3. Local Audit Execution + +Run the consolidated vulnerability scanner locally: + +```bash +chmod +x scripts/audit-vulnerabilities.sh + +# Standard blocking audit +./scripts/audit-vulnerabilities.sh + +# Non-blocking advisory mode +./scripts/audit-vulnerabilities.sh --warn-only +``` diff --git a/scripts/audit-vulnerabilities.sh b/scripts/audit-vulnerabilities.sh new file mode 100755 index 00000000..aae7ae06 --- /dev/null +++ b/scripts/audit-vulnerabilities.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +# ============================================================================== +# NotifyChain Automated Dependency Vulnerability Scanner (Issue #718) +# ============================================================================== +# Scans Node.js and Rust dependencies for known security vulnerabilities (CVEs) +# Distinguishes informational (Low/Moderate) from blocking (High/Critical) findings. +# ============================================================================== +set -u + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" + +WARN_ONLY=false +if [[ "${1:-}" == "--warn-only" ]]; then + WARN_ONLY=true +fi + +BLOCKING_FAILURES=0 + +echo -e "${BLUE}==================================================================${NC}" +echo -e "${BLUE} 🛡️ NotifyChain Automated Dependency Vulnerability Scanner ${NC}" +echo -e "${BLUE}==================================================================${NC}\n" + +audit_npm_package() { + local dir_name="$1" + local full_path="${ROOT_DIR}/${dir_name}" + + echo -e "${BLUE}--- Scanning Node.js [${dir_name}] ---${NC}" + if [ ! -f "${full_path}/package.json" ]; then + echo -e "${YELLOW}Skipped: No package.json in ${dir_name}/${NC}\n" + return + fi + + if ! command -v npm >/dev/null 2>&1; then + echo -e "${YELLOW}npm CLI not found locally; skipping live npm audit.${NC}\n" + return + fi + + cd "${full_path}" + + # 1. Informational scan (Low/Moderate) + echo -n " • Informational check (Low/Moderate): " + npm audit --audit-level=low >/dev/null 2>&1 && echo -e "${GREEN}Clean${NC}" || echo -e "${YELLOW}Findings present (non-blocking)${NC}" + + # 2. Blocking scan (High/Critical) + echo -n " • Blocking check (High/Critical): " + if npm audit --audit-level=high >/dev/null 2>&1; then + echo -e "${GREEN}✓ Passed (No High/Critical CVEs)${NC}\n" + else + echo -e "${RED}✗ HIGH/CRITICAL Vulnerabilities Found!${NC}" + npm audit --audit-level=high || true + BLOCKING_FAILURES=$((BLOCKING_FAILURES + 1)) + echo "" + fi +} + +audit_cargo_package() { + local dir_name="$1" + local full_path="${ROOT_DIR}/${dir_name}" + + echo -e "${BLUE}--- Scanning Rust [${dir_name}] ---${NC}" + if [ ! -f "${full_path}/Cargo.toml" ]; then + echo -e "${YELLOW}Skipped: No Cargo.toml in ${dir_name}/${NC}\n" + return + fi + + if ! command -v cargo-audit >/dev/null 2>&1; then + echo -e "${YELLOW}cargo-audit not installed locally; skipping live cargo scan.${NC}\n" + return + fi + + cd "${full_path}" + if cargo audit --deny warnings; then + echo -e "${GREEN}✓ Passed (No Rust CVE advisories)${NC}\n" + else + echo -e "${RED}✗ Rust Security Advisories Detected!${NC}\n" + BLOCKING_FAILURES=$((BLOCKING_FAILURES + 1)) + fi +} + +audit_npm_package "listener" +audit_npm_package "dashboard" +audit_cargo_package "contract" + +echo -e "${BLUE}==================================================================${NC}" +if [ $BLOCKING_FAILURES -eq 0 ]; then + echo -e "${GREEN}✅ All components passed high-severity vulnerability checks!${NC}" + exit 0 +else + if [ "$WARN_ONLY" = true ]; then + echo -e "${YELLOW}⚠️ Found ${BLOCKING_FAILURES} blocking vulnerability finding(s), but exiting 0 due to --warn-only.${NC}" + exit 0 + else + echo -e "${RED}❌ Found ${BLOCKING_FAILURES} blocking vulnerability finding(s). Remediation required.${NC}" + exit 1 + fi +fi