Created
April 1, 2026 13:10
-
-
Save millancore/fb149033192e223ff0bb1adbcb251bae to your computer and use it in GitHub Desktop.
NPM Audit Table format with jq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # npm-audit: Run npm audit and display results in a table view using jq + column | |
| # Usage: npm-audit [--severity critical|high|moderate|low|info] | |
| set -euo pipefail | |
| FILTER="" | |
| usage() { | |
| echo "Usage: npm-audit [--severity critical|high|moderate|low|info]" | |
| echo " --severity Show only vulnerabilities at or above the given level" | |
| exit 0 | |
| } | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --severity|-s) | |
| FILTER="${2:-}" | |
| shift 2 | |
| ;; | |
| --help|-h) usage ;; | |
| *) echo "Unknown option: $1"; usage ;; | |
| esac | |
| done | |
| if [[ -n "$FILTER" ]]; then | |
| case "$FILTER" in | |
| critical|high|moderate|low|info) ;; | |
| *) echo "Invalid severity: $FILTER. Must be one of: critical high moderate low info"; exit 1 ;; | |
| esac | |
| fi | |
| severity_color() { | |
| case "$1" in | |
| critical) printf '\033[0;31m' ;; | |
| high) printf '\033[0;31m' ;; | |
| moderate) printf '\033[1;33m' ;; | |
| low) printf '\033[0;36m' ;; | |
| info) printf '\033[0;37m' ;; | |
| *) printf '' ;; | |
| esac | |
| } | |
| # Run audit and capture JSON | |
| AUDIT_JSON=$(npm audit --json 2>/dev/null || true) | |
| if [ -z "$AUDIT_JSON" ]; then | |
| echo "Error: npm audit returned no output. Are you in a Node.js project directory?" >&2 | |
| exit 1 | |
| fi | |
| # Check for vulnerabilities count | |
| VULN_COUNT=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities | .total // (.critical + .high + .moderate + .low + .info)' 2>/dev/null || echo 0) | |
| if [ "$VULN_COUNT" -eq 0 ] 2>/dev/null; then | |
| echo -e "\033[1mNo vulnerabilities found.\033[0m" | |
| exit 0 | |
| fi | |
| # Print summary header | |
| echo "" | |
| echo -e "\033[1mNPM Audit Report\033[0m" | |
| [[ -n "$FILTER" ]] && echo -e "Filter: \033[1m$FILTER\033[0m and above" | |
| # Print summary counts | |
| echo "" | |
| echo -e "\033[1mSummary:\033[0m" | |
| echo "$AUDIT_JSON" | jq -r ' | |
| .metadata.vulnerabilities | | |
| (if .critical > 0 then " \u001b[0;31mCritical : \(.critical)\u001b[0m" else empty end), | |
| (if .high > 0 then " \u001b[0;31mHigh : \(.high)\u001b[0m" else empty end), | |
| (if .moderate > 0 then " \u001b[1;33mModerate : \(.moderate)\u001b[0m" else empty end), | |
| (if .low > 0 then " \u001b[0;36mLow : \(.low)\u001b[0m" else empty end), | |
| (if .info > 0 then " \u001b[0;37mInfo : \(.info)\u001b[0m" else empty end) | |
| ' | |
| echo "" | |
| echo "================================================================================" | |
| printf "\033[1m%-10s %-25s %-15s %s\033[0m\n" "SEVERITY" "PACKAGE" "VERSION" "URL" | |
| echo "--------------------------------------------------------------------------------" | |
| # Severity order map: critical=0, high=1, moderate=2, low=3, info=4 | |
| # Filter thresholds (show this level and above, i.e. lower or equal numeric order) | |
| FILTER_LEVEL=4 | |
| case "$FILTER" in | |
| critical) FILTER_LEVEL=0 ;; | |
| high) FILTER_LEVEL=1 ;; | |
| moderate) FILTER_LEVEL=2 ;; | |
| low) FILTER_LEVEL=3 ;; | |
| info) FILTER_LEVEL=4 ;; | |
| esac | |
| # Extract, sort by severity order, apply filter, print rows | |
| echo "$AUDIT_JSON" | jq -r ' | |
| def sev_order: {"critical":0,"high":1,"moderate":2,"low":3,"info":4}; | |
| [ | |
| .vulnerabilities // {} | | |
| to_entries[] | | |
| .value as $v | | |
| { | |
| order: ($v.severity | sev_order[.] // 99), | |
| sev: $v.severity, | |
| pkg: $v.name, | |
| ver: ($v.range // "unknown"), | |
| url: ($v.via | if type == "array" then | |
| map(if type == "object" then .url // "" else "" end) | map(select(. != "")) | first // "n/a" | |
| else "" end) | |
| } | |
| ] | sort_by(.order)[] | | |
| "\(.order)|\(.sev)|\(.pkg)|\(.ver)|\(.url)" | |
| ' | while IFS='|' read -r order sev pkg ver url; do | |
| if [[ "$order" -le "$FILTER_LEVEL" ]]; then | |
| color=$(severity_color "$sev") | |
| [[ ${#pkg} -gt 25 ]] && pkg="${pkg:0:24}…" | |
| [[ ${#ver} -gt 15 ]] && ver="${ver:0:14}…" | |
| printf "${color}%-10s\033[0m %-25s %-15s \033[0;34m%s\033[0m\n" "$sev" "$pkg" "$ver" "$url" | |
| fi | |
| done | |
| echo "================================================================================" | |
| echo "" | |
| echo -e "Total vulnerabilities: \033[1m${VULN_COUNT}\033[0m" | |
| echo "" | |
| echo "Run 'npm audit fix' to fix automatically, or 'npm audit fix --force' to force." | |
| echo "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment