dependency-audit.sh 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/usr/bin/env bash
  2. # Audit project dependencies with available ecosystem vulnerability scanners.
  3. #
  4. # Usage: dependency-audit.sh
  5. # Input: Project manifests in the current directory; no stdin input.
  6. # Output: Raw vulnerability scanner findings on stdout.
  7. # Stderr: Progress banners, missing-tool guidance, summaries, and usage errors.
  8. # Exit: 0 clean, 2 usage error, 10 findings present.
  9. #
  10. # Examples:
  11. # dependency-audit.sh
  12. # dependency-audit.sh > dependency-findings.txt
  13. set -uo pipefail
  14. usage() {
  15. cat <<'EOF'
  16. Usage: dependency-audit.sh
  17. Run available ecosystem vulnerability scanners for manifests in the current
  18. directory. Findings are written to stdout; progress is written to stderr.
  19. Exit codes:
  20. 0 audits completed with no findings
  21. 2 usage error
  22. 10 one or more scanners reported findings
  23. EXAMPLES
  24. dependency-audit.sh
  25. dependency-audit.sh > dependency-findings.txt
  26. EOF
  27. }
  28. case "${1:-}" in
  29. --help|-h) usage; exit 0 ;;
  30. '') ;;
  31. *) printf 'dependency-audit.sh: unknown argument: %s\n' "$1" >&2; usage >&2; exit 2 ;;
  32. esac
  33. if [[ $# -gt 1 ]]; then
  34. printf 'dependency-audit.sh: expected no arguments\n' >&2
  35. usage >&2
  36. exit 2
  37. fi
  38. RED='\033[0;31m'
  39. YELLOW='\033[1;33m'
  40. NC='\033[0m'
  41. ISSUES=0
  42. run_audit() {
  43. if "$@"; then
  44. return 0
  45. fi
  46. ISSUES=$((ISSUES + 1))
  47. return 0
  48. }
  49. printf '%s\n\n' '=== Dependency Security Audit ===' >&2
  50. if [[ -f requirements.txt || -f pyproject.toml ]]; then
  51. printf '%s\n' '--- Python Dependencies ---' >&2
  52. if command -v pip-audit >/dev/null 2>&1; then
  53. printf '%s\n' 'Running pip-audit...' >&2
  54. run_audit pip-audit
  55. elif command -v safety >/dev/null 2>&1; then
  56. printf '%s\n' 'Running safety check...' >&2
  57. run_audit safety check
  58. else
  59. printf '%bInstall pip-audit or safety for Python vulnerability scanning%b\n' "$YELLOW" "$NC" >&2
  60. printf '%s\n' ' pip install pip-audit' >&2
  61. fi
  62. fi
  63. if [[ -f package.json ]]; then
  64. printf '%s\n' '--- Node.js Dependencies ---' >&2
  65. if command -v npm >/dev/null 2>&1; then
  66. printf '%s\n' 'Running npm audit...' >&2
  67. run_audit npm audit --audit-level=moderate
  68. fi
  69. fi
  70. if [[ -f go.mod ]]; then
  71. printf '%s\n' '--- Go Dependencies ---' >&2
  72. if command -v govulncheck >/dev/null 2>&1; then
  73. printf '%s\n' 'Running govulncheck...' >&2
  74. run_audit govulncheck ./...
  75. else
  76. printf '%bInstall govulncheck for Go vulnerability scanning%b\n' "$YELLOW" "$NC" >&2
  77. printf '%s\n' ' go install golang.org/x/vuln/cmd/govulncheck@latest' >&2
  78. fi
  79. fi
  80. if [[ -f Cargo.toml ]]; then
  81. printf '%s\n' '--- Rust Dependencies ---' >&2
  82. if command -v cargo-audit >/dev/null 2>&1; then
  83. printf '%s\n' 'Running cargo audit...' >&2
  84. run_audit cargo audit
  85. else
  86. printf '%bInstall cargo-audit for Rust vulnerability scanning%b\n' "$YELLOW" "$NC" >&2
  87. printf '%s\n' ' cargo install cargo-audit' >&2
  88. fi
  89. fi
  90. if [[ -f Dockerfile ]]; then
  91. printf '%s\n' '--- Docker Image ---' >&2
  92. if command -v trivy >/dev/null 2>&1; then
  93. printf '%s\n' 'Running trivy on Dockerfile...' >&2
  94. run_audit trivy config Dockerfile
  95. else
  96. printf '%bInstall trivy for container vulnerability scanning%b\n' "$YELLOW" "$NC" >&2
  97. printf '%s\n' ' brew install trivy' >&2
  98. fi
  99. fi
  100. printf '%s\n' '=== Audit Complete ===' >&2
  101. if [[ $ISSUES -gt 0 ]]; then
  102. printf '%bOne or more dependency scanners reported findings%b\n' "$RED" "$NC" >&2
  103. exit 10
  104. fi
  105. exit 0