Created
May 26, 2026 18:38
-
-
Save breiter/d77b5ecbe93efb43ff9d2eafc1239c58 to your computer and use it in GitHub Desktop.
export aws inspector code repo findings to markdown
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 | |
| set -euo pipefail | |
| PROFILE="${1:-default}" | |
| OUTDIR="$(PROFILE)_inspector_reports" | |
| mkdir -p "$OUTDIR" | |
| fetch_all_findings() { | |
| local filter="$1" | |
| local outfile="$2" | |
| aws inspector2 list-findings \ | |
| --profile "$PROFILE" \ | |
| --filter "$filter" \ | |
| --output json > "$outfile" | |
| while token=$(jq -r '.nextToken // empty' "$outfile" 2>/dev/null) && [ -n "$token" ]; do | |
| aws inspector2 list-findings \ | |
| --profile "$PROFILE" \ | |
| --filter "$filter" \ | |
| --next-token "$token" \ | |
| --output json > "${outfile}.next" | |
| jq -s ' | |
| .[0].findings += .[1].findings | |
| | .[0].nextToken = .[1].nextToken | |
| | .[0] | |
| ' "$outfile" "${outfile}.next" > "${outfile}.merged" | |
| mv "${outfile}.merged" "$outfile" | |
| rm -f "${outfile}.next" | |
| echo " Fetched $(grep -v '"nextToken"' "$outfile" | jq '.findings | length') findings so far..." | |
| done | |
| local count | |
| count=$(grep -v '"nextToken"' "$outfile" | jq '.findings | length') | |
| echo " Total: $count findings" | |
| } | |
| split_by_repo() { | |
| local rawfile="$1" | |
| local suffix="$2" | |
| local count | |
| count=$(grep -v '"nextToken"' "$rawfile" | jq '.findings | length') | |
| if [ "$count" -eq 0 ]; then | |
| echo " No findings to split." | |
| return 0 | |
| fi | |
| for repo in $(grep -v '"nextToken"' "$rawfile" \ | |
| | jq -r '[.findings[].resources[0].details.codeRepository.projectName] | unique[]'); do | |
| local filename | |
| filename="$OUTDIR/$(echo "$repo" | tr '/' '_' | sed 's/:.*//').$suffix.json" | |
| grep -v '"nextToken"' "$rawfile" \ | |
| | jq --arg repo "$repo" \ | |
| '[.findings[] | select(.resources[0].details.codeRepository.projectName == $repo)]' \ | |
| > "$filename" | |
| echo " Wrote $filename" | |
| done | |
| } | |
| generate_pkg_reports() { | |
| local found=0 | |
| for f in "$OUTDIR"/*.pkg.json; do | |
| [ -f "$f" ] || continue | |
| found=1 | |
| local outfile="${f%.json}_report.md" | |
| jq -r ' | |
| [.[] | { | |
| severity: .severity, | |
| cve: .packageVulnerabilityDetails.vulnerabilityId, | |
| package: .packageVulnerabilityDetails.vulnerablePackages[0].name, | |
| version: .packageVulnerabilityDetails.vulnerablePackages[0].version, | |
| fixedIn: (.packageVulnerabilityDetails.vulnerablePackages[0].fixedInVersion // "N/A"), | |
| filePath: .packageVulnerabilityDetails.vulnerablePackages[0].filePath, | |
| sourceUrl: .packageVulnerabilityDetails.sourceUrl | |
| }] | |
| | sort_by( | |
| (if .severity == "CRITICAL" then 0 | |
| elif .severity == "HIGH" then 1 | |
| elif .severity == "MEDIUM" then 2 | |
| elif .severity == "LOW" then 3 | |
| else 4 end), | |
| .filePath | |
| ) | |
| | "| SEVERITY | CVE | PACKAGE | VERSION | FIXED IN | FILE | URL |", | |
| "| --- | --- | --- | --- | --- | --- | --- |", | |
| (.[] | "| \(.severity) | \(.cve) | \(.package) | \(.version) | \(.fixedIn) | \(.filePath) | \(.sourceUrl) |") | |
| ' "$f" > "$outfile" | |
| echo " Wrote $outfile" | |
| done | |
| if [ "$found" -eq 0 ]; then | |
| echo " No package vulnerability files to report." | |
| fi | |
| } | |
| generate_code_reports() { | |
| local found=0 | |
| for f in "$OUTDIR"/*.code.json; do | |
| [ -f "$f" ] || continue | |
| found=1 | |
| local outfile="${f%.json}_report.md" | |
| jq -r ' | |
| [.[] | { | |
| severity: .severity, | |
| title: .title, | |
| filePath: .codeVulnerabilityDetails.filePath.fileName, | |
| startLine: .codeVulnerabilityDetails.filePath.startLine, | |
| endLine: .codeVulnerabilityDetails.filePath.endLine, | |
| url: .remediation.recommendation.Url | |
| }] | |
| | sort_by( | |
| (if .severity == "CRITICAL" then 0 | |
| elif .severity == "HIGH" then 1 | |
| elif .severity == "MEDIUM" then 2 | |
| elif .severity == "LOW" then 3 | |
| else 4 end), | |
| .filePath | |
| ) | |
| | "| SEVERITY | TITLE | FILE | START | END | URL |", | |
| "| --- | --- | --- | --- | --- | --- |", | |
| (.[] | "| \(.severity) | \(.title) | \(.filePath) | \(.startLine) | \(.endLine) | \(.url) |") | |
| ' "$f" > "$outfile" | |
| echo " Wrote $outfile" | |
| done | |
| if [ "$found" -eq 0 ]; then | |
| echo " No code vulnerability files to report." | |
| fi | |
| } | |
| echo "Using profile: $PROFILE" | |
| echo "" | |
| echo "Fetching package vulnerabilities (CODE_REPOSITORY)..." | |
| PKG_FILTER='{"findingStatus":[{"comparison":"EQUALS","value":"ACTIVE"}],"findingType":[{"comparison":"EQUALS","value":"PACKAGE_VULNERABILITY"}],"resourceType":[{"comparison":"EQUALS","value":"CODE_REPOSITORY"}]}' | |
| fetch_all_findings "$PKG_FILTER" pkg_findings_raw.json | |
| echo "" | |
| echo "Fetching code vulnerabilities..." | |
| CODE_FILTER='{"findingStatus":[{"comparison":"EQUALS","value":"ACTIVE"}],"findingType":[{"comparison":"EQUALS","value":"CODE_VULNERABILITY"}]}' | |
| fetch_all_findings "$CODE_FILTER" code_findings_raw.json | |
| echo "" | |
| echo "Splitting package findings by repository..." | |
| split_by_repo pkg_findings_raw.json pkg | |
| echo "" | |
| echo "Splitting code findings by repository..." | |
| split_by_repo code_findings_raw.json code | |
| echo "" | |
| echo "Generating package vulnerability reports..." | |
| generate_pkg_reports | |
| echo "" | |
| echo "Generating code vulnerability reports..." | |
| generate_code_reports | |
| echo "" | |
| echo "Done. Reports are in $OUTDIR/" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment