Skip to content
78 changes: 78 additions & 0 deletions .github/actions/npm-audit-list/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright 2025 Digital Bazaar, Inc.
# SPDX-License-Identifier: BSD-3-Clause

name: Output npm audit and list results as Markdown
description: >
A reusable action to output `npm audit` and a filtered `npm list` (based on
the audit results) in Markdown.
outputs:
result:
description: Combined npm audit/list reports
value: ${{ steps.combined_report.outputs.result }}
runs:
using: composite
steps:
# Run `npm audit` and collect as JSON
- name: npm audit
id: npm_audit
shell: bash
run: |
echo 'result=$(npm audit --json)' >> $GITHUB_OUTPUT
continue-on-error: true
# Use `jq` to create a Markdown table of the findings
- name: npm audit
id: audit_report
shell: bash
run: |
AUDIT=$(echo "${{ toJson(steps.npm_audit.outputs.result) }}" | jq -r '
"| Severity | Name | Version | Fix Available |",
"| --- | --- | --- | --- |",
(.vulnerabilities | to_entries | .[] |
"| \(.value.severity) | \(.key) | \(.value.range) | \(.value.fixAvailable.version) |"
)')
# Use a random delimiter to capture the multi-line output
delimiter=$(openssl rand -hex 8)
echo "result<<$delimiter" >> $GITHUB_OUTPUT
echo "$AUDIT" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
continue-on-error: true
# Generate a tree/list based on the vulnerable package names
- name: npm list vulnerable dependencies
id: list_report
shell: bash
run: |
DEPS=$(echo "${{ toJSON(steps.npm_audit.outputs.result) }}" | jq -r '[.vulnerabilities | to_entries[] | .key] | join(" ")')
LIST=$(npm list $DEPS --json --package-lock-only | jq -r '
def walk_tree(prefix):
to_entries | map(
"\(prefix)\(.key)@\(.value.version)\n" +
if .value.dependencies then
(.value.dependencies | walk_tree(" " + prefix))
else
""
end
) | join("");
.dependencies | walk_tree("* ")')
# Use a random delimiter to capture the multi-line output
delimiter=$(openssl rand -hex 8)
echo "result<<$delimiter" >> $GITHUB_OUTPUT
echo "$LIST" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
continue-on-error: true
# Combine the two Markdown reports into one for use elsewhere
- name: combine npm audit/list reports
id: combined_report
shell: bash
run: |
# Use a random delimiter to capture the multi-line output
delimiter=$(openssl rand -hex 8)
echo "result<<$delimiter" >> $GITHUB_OUTPUT
echo "### npm audit

${{ steps.audit_report.outputs.result }}

### npm list

${{ steps.list_report.outputs.result }}
" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
21 changes: 20 additions & 1 deletion .github/workflows/osv-scanner-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ jobs:
uses: juliangruber/read-file-action@b549046febe0fe86f8cb4f93c24e284433f9ab58 # v1.1.7
with:
path: old-results.md
# Run npm audit and npm list to build up additional report explanations
- name: Generate npm audit and list report
id: old_audit_list_report
uses: ./.github/actions/npm-audit-list
continue-on-error: true # this action may not exist in the repo yet...

# --- run the same on the current branch ---
- name: "Checkout current branch"
# Use -f in case any changes were made by osv-scanner (there should be no changes)
run: |
Expand Down Expand Up @@ -100,12 +107,24 @@ jobs:
uses: juliangruber/read-file-action@b549046febe0fe86f8cb4f93c24e284433f9ab58 # v1.1.7
with:
path: new-results.md
- name: Add OSV comment

# Run npm audit and npm list to build up additional report explanations
- name: Generate npm audit and list report
id: new_audit_list_report
uses: ./.github/actions/npm-audit-list

# Combine OSV, npm audit, and npm list output into a single comment
- name: Add a comment containing OSV, npm audit, and npm list output
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
with:
message: |
## Vulnerability results from base branch
${{ steps.old.outputs.content }}

${{ steps.old_audit_list_report.outputs.result }}
---

## Vulnerability results from current PR branch
${{ steps.new.outputs.content }}

${{ steps.new_audit_list_report.outputs.result }}