diff --git a/.github/workflows/node-security-dependency-scan.yml b/.github/workflows/node-security-dependency-scan.yml index 3459e1c..121bedf 100644 --- a/.github/workflows/node-security-dependency-scan.yml +++ b/.github/workflows/node-security-dependency-scan.yml @@ -63,93 +63,11 @@ jobs: run: npm ci - name: Run npm audit - run: npm audit --audit-level=${{ inputs.audit_level }} + run: ./scripts/node-security-dependency-scan/run-npm-audit.sh ${{ inputs.audit_level }} ${{ inputs.continue_on_error }} continue-on-error: ${{ inputs.continue_on_error }} - name: Run npm outdated check - run: | - echo "๐Ÿ” Checking for outdated dependencies..." - - # Get the list of allowed outdated libraries - ALLOWED_LIBS='${{ inputs.allowed_outdated_libraries }}' - - if [ -n "$ALLOWED_LIBS" ]; then - echo "๐Ÿ“‹ Libraries allowed to be outdated: $ALLOWED_LIBS" - - # Clean up the allowed libraries string (remove spaces, normalize) - ALLOWED_CLEAN=$(echo "$ALLOWED_LIBS" | tr -d ' ' | tr ',' '\n' | grep -v '^$' | tr '\n' ',' | sed 's/,$//') - echo "๐Ÿ“‹ Cleaned allowed libraries: $ALLOWED_CLEAN" - - if [ -n "$ALLOWED_CLEAN" ]; then - # Run npm outdated and filter out allowed libraries - npm outdated --json 2>/dev/null | jq -r --arg allowed "$ALLOWED_CLEAN" ' - if . then - to_entries[] | - select(.key | IN($allowed | split(","))) | - "ALLOWED: \(.key) - Current: \(.value.current) -> Latest: \(.value.latest)" - else - empty - end - ' || echo "โœ… No outdated dependencies found" - - # Check for non-allowed outdated libraries using a simpler approach - UNAUTHORIZED_OUTDATED="" - - # Use a simpler bash-based approach to filter out allowed libraries - UNAUTHORIZED_OUTDATED="" - - # Get all outdated packages - npm outdated --json 2>/dev/null > /tmp/all_outdated.json || true - - if [ -s /tmp/all_outdated.json ]; then - # Convert allowed libraries to a format we can use with grep - ALLOWED_PATTERN=$(echo "$ALLOWED_CLEAN" | tr ',' '|') - - # Extract package names that are NOT in the allowed list - jq -r 'to_entries[] | .key' /tmp/all_outdated.json | grep -vE "^($ALLOWED_PATTERN)$" > /tmp/unauthorized_names.txt || true - - if [ -s /tmp/unauthorized_names.txt ]; then - # Get full details for unauthorized packages - while IFS= read -r pkg; do - if [ -n "$pkg" ]; then - pkg_info=$(jq -r --arg pkg "$pkg" '.[$pkg] | "\($pkg) - Current: \(.current) -> Latest: \(.latest)"' /tmp/all_outdated.json 2>/dev/null || echo "") - if [ -n "$pkg_info" ]; then - UNAUTHORIZED_OUTDATED="${UNAUTHORIZED_OUTDATED}${pkg_info}"$'\n' - fi - fi - done < /tmp/unauthorized_names.txt - - # Remove trailing newline - UNAUTHORIZED_OUTDATED=$(echo "$UNAUTHORIZED_OUTDATED" | sed 's/^$//') - fi - fi - - if [ -n "$UNAUTHORIZED_OUTDATED" ]; then - echo "โŒ UNAUTHORIZED OUTDATED DEPENDENCIES DETECTED:" - echo "$UNAUTHORIZED_OUTDATED" - echo "" - echo "๐Ÿšจ BUILD FAILED: These dependencies must be updated" - - # Clean up temporary files - rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt - exit 1 - else - echo "โœ… All outdated dependencies are in the allowed list" - - # Clean up temporary files - rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt - fi - else - echo "๐Ÿ“‹ No valid library names found in the allowed list" - npm outdated - fi - else - echo "๐Ÿ“‹ No libraries are allowed to be outdated - checking all dependencies" - npm outdated - fi - - # Clean up any temporary files that might have been left behind - rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt /tmp/unauthorized_outdated.txt + run: ./scripts/node-security-dependency-scan/check-outdated-dependencies.sh '${{ inputs.allowed_outdated_libraries }}' ${{ inputs.continue_on_error }} continue-on-error: ${{ inputs.continue_on_error }} - name: Run OWASP Dependency Check @@ -166,38 +84,7 @@ jobs: - name: Check for High Severity Vulnerabilities if: ${{ !inputs.continue_on_error }} - run: | - echo "๐Ÿ” Checking for high severity vulnerabilities..." - - # Check npm audit for high/critical vulnerabilities - if npm audit --audit-level=high --json | jq -e '.vulnerabilities | length > 0' > /dev/null 2>&1; then - echo "โŒ HIGH SEVERITY VULNERABILITIES DETECTED!" - echo "npm audit found high or critical vulnerabilities that must be fixed." - echo "" - echo "Vulnerability details:" - npm audit --audit-level=high - echo "" - echo "๐Ÿšจ BUILD FAILED: High severity vulnerabilities detected" - echo "Please fix these vulnerabilities before proceeding." - exit 1 - fi - - # Check OWASP report for high CVSS scores - if [ -f "reports/dependency-check-report.xml" ]; then - echo "๐Ÿ” Checking OWASP report for high CVSS vulnerabilities..." - - # Check if there are any vulnerabilities with CVSS >= 7 (high) - if grep -q 'severity="High"' reports/dependency-check-report.xml 2>/dev/null; then - echo "โŒ HIGH CVSS VULNERABILITIES DETECTED IN OWASP REPORT!" - echo "OWASP Dependency Check found high severity vulnerabilities." - echo "" - echo "๐Ÿšจ BUILD FAILED: High CVSS vulnerabilities detected" - echo "Please review the OWASP report and fix high severity issues." - exit 1 - fi - fi - - echo "โœ… No high severity vulnerabilities detected" + run: ./scripts/node-security-dependency-scan/check-high-severity-vulnerabilities.sh ${{ inputs.continue_on_error }} - name: Upload OWASP report uses: actions/upload-artifact@v4 @@ -207,77 +94,10 @@ jobs: path: reports/ retention-days: 30 - - name: Comment PR with security findings - if: github.event_name == 'pull_request' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const path = require('path'); - - // Check if npm audit found vulnerabilities - try { - const auditResult = await $exec('npm audit --json --audit-level=${{ inputs.audit_level }}'); - const auditData = JSON.parse(auditResult.stdout); - - if (auditData.vulnerabilities && Object.keys(auditData.vulnerabilities).length > 0) { - let comment = '## ๐Ÿ”’ Node.js Security Scan Results\n\n'; - comment += 'โš ๏ธ **Vulnerabilities found in dependencies:**\n\n'; - - for (const [pkg, vuln] of Object.entries(auditData.vulnerabilities)) { - comment += `- **${pkg}**: ${vuln.title} (Severity: ${vuln.severity})\n`; - comment += ` - Fixed in: ${vuln.fixedIn || 'Not available'}\n`; - comment += ` - More info: ${vuln.url}\n\n`; - } - - comment += 'Please review and update vulnerable dependencies.'; - - await github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); - } else { - let comment = '## ๐Ÿ”’ Node.js Security Scan Results\n\nโœ… **No vulnerabilities found at the configured audit level.**\n\n'; - - // Add information about allowed outdated libraries if configured - const allowedLibs = '${{ inputs.allowed_outdated_libraries }}'; - if (allowedLibs && allowedLibs.trim() !== '') { - comment += `๐Ÿ“‹ **Libraries allowed to be outdated:** ${allowedLibs}\n\n`; - } - - comment += 'Note: High severity vulnerabilities will always fail the build regardless of the audit level setting.'; - - await github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); - } - } catch (error) { - console.log('Error processing npm audit results:', error); - } - - name: Security Gate Check if: ${{ !inputs.continue_on_error }} - run: | - echo "๐Ÿ”’ Final security gate check..." + run: ./scripts/node-security-dependency-scan/security-gate-check.sh ${{ inputs.audit_level }} ${{ inputs.continue_on_error }} - # Check if npm audit found vulnerabilities at the configured level - if npm audit --audit-level=${{ inputs.audit_level }} --json | jq -e '.vulnerabilities | length > 0' > /dev/null 2>&1; then - echo "โŒ Security vulnerabilities detected at level '${{ inputs.audit_level }}' - build blocked" - echo "Please fix the vulnerabilities before proceeding" - exit 1 - fi - - # Double-check for high severity vulnerabilities (should have been caught earlier, but safety check) - if npm audit --audit-level=high --json | jq -e '.vulnerabilities | length > 0' > /dev/null 2>&1; then - echo "โŒ CRITICAL: High severity vulnerabilities still detected - build blocked" - echo "This should not happen if previous checks passed. Please investigate." - exit 1 - fi - - echo "โœ… Security gate passed - no vulnerabilities detected" - echo "โœ… Build can proceed safely" + - name: Cleanup + if: always() + run: ./scripts/node-security-dependency-scan/cleanup.sh diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..1ce441a --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,100 @@ +# Scripts Directory + +This directory contains shell scripts organized by workflow to improve maintainability and testability. + +## Structure + +``` +scripts/ +โ”œโ”€โ”€ README.md +โ””โ”€โ”€ node-security-dependency-scan/ + โ”œโ”€โ”€ run-npm-audit.sh + โ”œโ”€โ”€ check-outdated-dependencies.sh + โ”œโ”€โ”€ check-high-severity-vulnerabilities.sh + โ”œโ”€โ”€ security-gate-check.sh + โ””โ”€โ”€ cleanup.sh +``` + +## Node.js Security Dependency Scan Scripts + +### `run-npm-audit.sh` + +Runs npm audit with configurable audit level and continue-on-error behavior. + +**Usage:** `./run-npm-audit.sh ` + +**Parameters:** + +- `audit_level`: npm audit level (low, moderate, high, critical) +- `continue_on_error`: whether to continue on audit failure (true/false) + +### `check-outdated-dependencies.sh` + +Checks for outdated dependencies with filtering for allowed libraries. + +**Usage:** `./check-outdated-dependencies.sh ` + +**Parameters:** + +- `allowed_libraries`: comma-separated list of libraries allowed to be outdated +- `continue_on_error`: whether to continue on failure (true/false) + +### `check-high-severity-vulnerabilities.sh` + +Checks for high severity vulnerabilities in npm audit and OWASP reports. + +**Usage:** `./check-high-severity-vulnerabilities.sh ` + +**Parameters:** + +- `continue_on_error`: whether to continue on failure (true/false) + +### `security-gate-check.sh` + +Performs final security gate check before allowing build to proceed. + +**Usage:** `./security-gate-check.sh ` + +**Parameters:** + +- `audit_level`: npm audit level threshold +- `continue_on_error`: whether to continue on failure (true/false) + +### `cleanup.sh` + +Cleans up temporary files created during the workflow execution. + +**Usage:** `./cleanup.sh` + +## Benefits of This Structure + +1. **Maintainability**: Each script has a single responsibility and can be easily modified +2. **Testability**: Individual scripts can be tested independently +3. **Reusability**: Scripts can be reused in other workflows or run locally +4. **Debugging**: Easier to debug issues by running specific scripts +5. **Version Control**: Better tracking of changes to specific functionality +6. **Documentation**: Each script can have its own documentation and examples + +## Adding New Scripts + +When adding new scripts: + +1. Create the script in the appropriate workflow folder +2. Make it executable: `chmod +x scripts/workflow-name/script-name.sh` +3. Update this README with usage information +4. Consider adding tests for the script functionality + +## Testing Scripts Locally + +You can test individual scripts locally by: + +1. Setting up the required environment (Node.js, npm, etc.) +2. Running the script with appropriate parameters +3. Checking the output and exit codes + +Example: + +```bash +cd scripts/node-security-dependency-scan +./run-npm-audit.sh moderate false +``` diff --git a/scripts/node-security-dependency-scan/check-high-severity-vulnerabilities.sh b/scripts/node-security-dependency-scan/check-high-severity-vulnerabilities.sh new file mode 100755 index 0000000..4ea4226 --- /dev/null +++ b/scripts/node-security-dependency-scan/check-high-severity-vulnerabilities.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Script to check for high severity vulnerabilities +# Usage: ./check-high-severity-vulnerabilities.sh + +set -e + +CONTINUE_ON_ERROR=${1:-"false"} + +echo "๐Ÿ” Checking for high severity vulnerabilities..." + +# Check npm audit for high/critical vulnerabilities +if npm audit --audit-level=high --json | jq -e '.vulnerabilities | length > 0' > /dev/null 2>&1; then + echo "โŒ HIGH SEVERITY VULNERABILITIES DETECTED!" + echo "npm audit found high or critical vulnerabilities that must be fixed." + echo "" + echo "Vulnerability details:" + npm audit --audit-level=high + echo "" + echo "๐Ÿšจ BUILD FAILED: High severity vulnerabilities detected" + echo "Please fix these vulnerabilities before proceeding." + exit 1 +fi + +# Check OWASP report for high CVSS scores +if [ -f "reports/dependency-check-report.xml" ]; then + echo "๐Ÿ” Checking OWASP report for high CVSS vulnerabilities..." + + # Check if there are any vulnerabilities with CVSS >= 7 (high) + if grep -q 'severity="High"' reports/dependency-check-report.xml 2>/dev/null; then + echo "โŒ HIGH CVSS VULNERABILITIES DETECTED IN OWASP REPORT!" + echo "OWASP Dependency Check found high severity vulnerabilities." + echo "" + echo "๐Ÿšจ BUILD FAILED: High CVSS vulnerabilities detected" + echo "Please review the OWASP report and fix high severity issues." + exit 1 + fi +fi + +echo "โœ… No high severity vulnerabilities detected" diff --git a/scripts/node-security-dependency-scan/check-outdated-dependencies.sh b/scripts/node-security-dependency-scan/check-outdated-dependencies.sh new file mode 100755 index 0000000..6afe3dd --- /dev/null +++ b/scripts/node-security-dependency-scan/check-outdated-dependencies.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Script to check for outdated dependencies with allowed libraries filtering +# Usage: ./check-outdated-dependencies.sh + +set -e + +ALLOWED_LIBS=${1:-""} +CONTINUE_ON_ERROR=${2:-"false"} + +echo "๐Ÿ” Checking for outdated dependencies..." + +if [ -n "$ALLOWED_LIBS" ]; then + echo "๐Ÿ“‹ Libraries allowed to be outdated: $ALLOWED_LIBS" + + # Clean up the allowed libraries string (remove spaces, normalize) + ALLOWED_CLEAN=$(echo "$ALLOWED_LIBS" | tr -d ' ' | tr ',' '\n' | grep -v '^$' | tr '\n' ',' | sed 's/,$//') + echo "๐Ÿ“‹ Cleaned allowed libraries: $ALLOWED_CLEAN" + + if [ -n "$ALLOWED_CLEAN" ]; then + # Run npm outdated and filter out allowed libraries + npm outdated --json 2>/dev/null | jq -r --arg allowed "$ALLOWED_CLEAN" ' + if . then + to_entries[] | + select(.key | IN($allowed | split(","))) | + "ALLOWED: \(.key) - Current: \(.value.current) -> Latest: \(.value.latest)" + else + empty + end + ' || echo "โœ… No outdated dependencies found" + + # Check for non-allowed outdated libraries using a simpler approach + UNAUTHORIZED_OUTDATED="" + + # Get all outdated packages + npm outdated --json 2>/dev/null > /tmp/all_outdated.json || true + + if [ -s /tmp/all_outdated.json ]; then + # Convert allowed libraries to a format we can use with grep + ALLOWED_PATTERN=$(echo "$ALLOWED_CLEAN" | tr ',' '|') + + # Extract package names that are NOT in the allowed list + jq -r 'to_entries[] | .key' /tmp/all_outdated.json | grep -vE "^($ALLOWED_PATTERN)$" > /tmp/unauthorized_names.txt || true + + if [ -s /tmp/unauthorized_names.txt ]; then + # Get full details for unauthorized packages + while IFS= read -r pkg; do + if [ -n "$pkg" ]; then + pkg_info=$(jq -r --arg pkg "$pkg" '.[$pkg] | "\($pkg) - Current: \(.current) -> Latest: \(.latest)"' /tmp/all_outdated.json 2>/dev/null || echo "") + if [ -n "$pkg_info" ]; then + UNAUTHORIZED_OUTDATED="${UNAUTHORIZED_OUTDATED}${pkg_info}"$'\n' + fi + fi + done < /tmp/unauthorized_names.txt + + # Remove trailing newline + UNAUTHORIZED_OUTDATED=$(echo "$UNAUTHORIZED_OUTDATED" | sed 's/^$//') + fi + fi + + if [ -n "$UNAUTHORIZED_OUTDATED" ]; then + echo "โŒ UNAUTHORIZED OUTDATED DEPENDENCIES DETECTED:" + echo "$UNAUTHORIZED_OUTDATED" + echo "" + echo "๐Ÿšจ BUILD FAILED: These dependencies must be updated" + + # Clean up temporary files + rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt + exit 1 + else + echo "โœ… All outdated dependencies are in the allowed list" + + # Clean up temporary files + rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt + fi + else + echo "๐Ÿ“‹ No valid library names found in the allowed list" + npm outdated + fi +else + echo "๐Ÿ“‹ No libraries are allowed to be outdated - checking all dependencies" + npm outdated +fi + +# Clean up any temporary files that might have been left behind +rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt /tmp/unauthorized_outdated.txt diff --git a/scripts/node-security-dependency-scan/cleanup.sh b/scripts/node-security-dependency-scan/cleanup.sh new file mode 100755 index 0000000..fb2c51a --- /dev/null +++ b/scripts/node-security-dependency-scan/cleanup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Script to cleanup temporary files +# Usage: ./cleanup.sh + +echo "๐Ÿงน Cleaning up temporary files..." + +# Remove temporary files that might have been left behind +rm -f /tmp/all_outdated.json /tmp/unauthorized_names.txt /tmp/unauthorized_outdated.txt + +echo "โœ… Cleanup completed" diff --git a/scripts/node-security-dependency-scan/run-npm-audit.sh b/scripts/node-security-dependency-scan/run-npm-audit.sh new file mode 100755 index 0000000..a420cb2 --- /dev/null +++ b/scripts/node-security-dependency-scan/run-npm-audit.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Script to run npm audit with configurable audit level +# Usage: ./run-npm-audit.sh + +set -e + +AUDIT_LEVEL=${1:-"moderate"} +CONTINUE_ON_ERROR=${2:-"false"} + +echo "๐Ÿ” Running npm audit with level: $AUDIT_LEVEL" + +# Run npm audit with the specified level +if npm audit --audit-level="$AUDIT_LEVEL"; then + echo "โœ… npm audit passed at level: $AUDIT_LEVEL" + exit 0 +else + echo "โŒ npm audit failed at level: $AUDIT_LEVEL" + + if [ "$CONTINUE_ON_ERROR" = "true" ]; then + echo "โš ๏ธ Continuing despite audit failure (continue_on_error=true)" + exit 0 + else + echo "๐Ÿšจ Build failed due to npm audit issues" + exit 1 + fi +fi diff --git a/scripts/node-security-dependency-scan/security-gate-check.sh b/scripts/node-security-dependency-scan/security-gate-check.sh new file mode 100755 index 0000000..28e5768 --- /dev/null +++ b/scripts/node-security-dependency-scan/security-gate-check.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Script to perform final security gate check +# Usage: ./security-gate-check.sh + +set -e + +AUDIT_LEVEL=${1:-"moderate"} +CONTINUE_ON_ERROR=${2:-"false"} + +echo "๐Ÿ”’ Final security gate check..." + +# Check if npm audit found vulnerabilities at the configured level +if npm audit --audit-level="$AUDIT_LEVEL" --json | jq -e '.vulnerabilities | length > 0' > /dev/null 2>&1; then + echo "โŒ Security vulnerabilities detected at level '$AUDIT_LEVEL' - build blocked" + echo "Please fix the vulnerabilities before proceeding" + exit 1 +fi + +# Double-check for high severity vulnerabilities (should have been caught earlier, but safety check) +if npm audit --audit-level=high --json | jq -e '.vulnerabilities | length > 0' > /dev/null 2>&1; then + echo "โŒ CRITICAL: High severity vulnerabilities still detected - build blocked" + echo "This should not happen if previous checks passed. Please investigate." + exit 1 +fi + +echo "โœ… Security gate passed - no vulnerabilities detected" +echo "โœ… Build can proceed safely"