Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci-scan-community-node.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: 'CI: Scan Community Node'

# Exercises the scan-community-node reusable workflow on pull requests that
# touch it: once against a published package and once against this repository.

on:
pull_request:
paths:
- '.github/workflows/scan-community-node*.yml'
- '.github/workflows/ci-scan-community-node.yml'
- 'scan-community-node/**'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
# A consumer that only scans packages needs nothing beyond contents: read.
package:
uses: $/.github/workflows/scan-community-node.yml
with:
package: n8n-nodes-evolution-api
version: 1.0.4

# Scans this repository. The upload stays off: Semgrep and Scorecard do not
# know `$/` and would report every self-reference here as an unpinned action.
workspace:
uses: $/.github/workflows/scan-community-node.yml
24 changes: 20 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,30 @@ jobs:

- run: pnpm typecheck

- name: Release dropdown covers every action
- name: Release dropdown covers every action and reusable workflow
run: |
set -euo pipefail
missing=0
check() {
grep -qE "^ +- $1$" .github/workflows/release.yml || {
echo "::error::'$1' is missing from the package options in .github/workflows/release.yml"
missing=1
}
}
for path in */action.yml; do
name="${path%/action.yml}"
grep -qE "^ +- ${name}$" .github/workflows/release.yml || {
echo "::error::'${name}' is missing from the package options in .github/workflows/release.yml"
check "${path%/action.yml}"
done
# A reusable workflow is released under its file name. Sub-workflows
# named <package>-<part>.yml belong to <package> and are not listed.
for path in $(grep -lE '^ +workflow_call:' .github/workflows/*.yml); do
name="$(basename "$path" .yml)"
pkg="$name"
while [ -n "$pkg" ] && ! grep -qE "^ +- ${pkg}$" .github/workflows/release.yml; do
[ "${pkg%-*}" = "$pkg" ] && pkg="" || pkg="${pkg%-*}"
done
[ -n "$pkg" ] || check "$name"
[ -z "$pkg" ] || [ -f "$pkg/README.md" ] || {
echo "::error::reusable workflow package '$pkg' has no $pkg/README.md"
missing=1
}
done
Expand Down
36 changes: 28 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ run-name: "Release: ${{ inputs.package }} (${{ inputs.bump }})${{ inputs.dry-run
# Tags one action at a time. Tags are `<action>/vMAJOR.MINOR.PATCH`, so actions
# version independently and a bump to one doesn't churn the others.
#
# Adding a new action means adding it to the `package` options below — CI fails
# if a directory with an action.yml is missing from that list.
# Adding a new action or reusable workflow means adding it to the `package`
# options below — CI fails if a directory with an action.yml, or a workflow
# with a `workflow_call` trigger, is missing from that list.

on:
workflow_dispatch:
Expand All @@ -16,6 +17,7 @@ on:
type: choice
options:
- cla-check
- scan-community-node

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The package input description still reads 'Action to release', but the new scan-community-node option is a reusable workflow (no scan-community-node/action.yml exists; it is released via .github/workflows/scan-community-node.yml). Update the description to something like 'Package to release' so the dispatch form matches the available options.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/release.yml, line 20:

<comment>The `package` input description still reads 'Action to release', but the new `scan-community-node` option is a reusable workflow (no `scan-community-node/action.yml` exists; it is released via `.github/workflows/scan-community-node.yml`). Update the description to something like 'Package to release' so the dispatch form matches the available options.</comment>

<file context>
@@ -16,6 +17,7 @@ on:
         type: choice
         options:
           - cla-check
+          - scan-community-node
       bump:
         description: 'Version bump (first release of an action is always v1.0.0)'
</file context>

bump:
description: 'Version bump (first release of an action is always v1.0.0)'
required: true
Expand Down Expand Up @@ -78,8 +80,17 @@ jobs:
run: |
set -euo pipefail

if [ ! -f "$PACKAGE/action.yml" ]; then
echo "::error::$PACKAGE/action.yml not found"
# An action lives in <package>/action.yml. A reusable workflow lives
# in .github/workflows/<package>.yml, with any sub-workflows named
# <package>-*.yml and docs plus helpers under <package>/.
if [ -f "$PACKAGE/action.yml" ]; then
uses_path="$PACKAGE"
paths="$PACKAGE"
elif [ -f ".github/workflows/$PACKAGE.yml" ]; then
uses_path=".github/workflows/$PACKAGE.yml"
paths=".github/workflows/$PACKAGE.yml .github/workflows/$PACKAGE-*.yml $PACKAGE"
else
echo "::error::neither $PACKAGE/action.yml nor .github/workflows/$PACKAGE.yml found"
exit 1
fi

Expand Down Expand Up @@ -112,6 +123,8 @@ jobs:
echo "tag=$tag"
echo "version=$next"
echo "prev_tag=${prev_version:+$PACKAGE/v$prev_version}"
echo "uses_path=$uses_path"
echo "paths=$paths"
} >> "$GITHUB_OUTPUT"

- name: Render release notes
Expand All @@ -120,26 +133,33 @@ jobs:
PACKAGE: ${{ inputs.package }}
VERSION: ${{ steps.version.outputs.version }}
PREV_TAG: ${{ steps.version.outputs.prev_tag }}
USES_PATH: ${{ steps.version.outputs.uses_path }}
PATHS: ${{ steps.version.outputs.paths }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail

# PATHS is a space-separated list of pathspecs. Globbing is turned off
# so the shell only splits the words and git matches any glob against
# every tree in the range, including files renamed or removed since.
set -f
# shellcheck disable=SC2086
{
echo '```yaml'
echo "- uses: ${{ github.repository }}/$PACKAGE@$SHA # v$VERSION"
echo "- uses: ${{ github.repository }}/$USES_PATH@$SHA # v$VERSION"
echo '```'
echo
echo "### Changes"
echo
if [ -n "$PREV_TAG" ]; then
git log "$PREV_TAG..HEAD" --no-merges --pretty='- %s (%h)' -- "$PACKAGE" > /tmp/commits
git log "$PREV_TAG..HEAD" --no-merges --pretty='- %s (%h)' -- $PATHS > /tmp/commits
else
git log --no-merges --pretty='- %s (%h)' -- "$PACKAGE" > /tmp/commits
git log --no-merges --pretty='- %s (%h)' -- $PATHS > /tmp/commits
fi
if [ -s /tmp/commits ]; then
cat /tmp/commits
else
echo "- No commits touched \`$PACKAGE/\` since ${PREV_TAG:-the start of the repo}."
echo "- No commits touched \`$PACKAGE\` since ${PREV_TAG:-the start of the repo}."
fi
if [ -n "$PREV_TAG" ]; then
echo
Expand Down
77 changes: 77 additions & 0 deletions .github/workflows/scan-community-node-cve-lite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: 'Scan Community Node (CVE Lite CLI)'

on:
workflow_call:
inputs:
package:
description: 'npm package name to scan (e.g. express or @scope/pkg). Leave empty to verify the local package.json.'
required: false
type: string
version:
description: 'Optional package version to scan (e.g. 4.18.2).'
required: false
default: 'latest'
type: string
upload-sarif:
description: 'Whether to upload SARIF reports to GitHub code scanning.'
required: false
default: false
type: boolean

env:
PACKAGE_SPEC: ${{ inputs.package }}@${{ inputs.version }}

jobs:
cve-lite:
name: CVE Lite CLI
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: $/scan-community-node/actions/setup
with:
node: 'true'

- name: Prepare scan target
id: prep
env:
PACKAGE: ${{ inputs.package }}
run: |
# With a package name, scan the published npm tarball; otherwise scan this checkout.
if [ -n "$PACKAGE" ]; then
# Unpack outside the workspace so the caller's own files are never scanned.
DIR="$RUNNER_TEMP/cve-lite-target"
rm -rf "$DIR" && mkdir -p "$DIR"
# npm pack downloads <name>-<version>.tgz and prints that file name.
ARCHIVE="$(npm pack --silent "$PACKAGE_SPEC")"
# The tarball wraps everything in a package/ folder; strip that level.
tar -xzf "$ARCHIVE" -C "$DIR" --strip-components=1
# Tarballs ship no lockfile; without one only pinned direct deps are scanned.
# --package-lock-only resolves the tree without downloading or running anything.
(cd "$DIR" && npm install --package-lock-only --ignore-scripts)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Running npm inside the extracted, untrusted package tree lets the scanned (possibly malicious) package influence the scan: npm reads project-level .npmrc first, so a tarball that ships one can redirect the registry/proxy or inject token config into the resolution of the very tree this scanner distrusts. --ignore-scripts and --package-lock-only limit the blast radius (no code runs, tarballs aren't downloaded), but the resolved tree then comes from an attacker-chosen endpoint. Point npm at an empty config so the resolution cannot be steered by the scanned package.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/scan-community-node-cve-lite.yml, line 52:

<comment>Running npm inside the extracted, untrusted package tree lets the scanned (possibly malicious) package influence the scan: npm reads project-level `.npmrc` first, so a tarball that ships one can redirect the registry/proxy or inject token config into the resolution of the very tree this scanner distrusts. `--ignore-scripts` and `--package-lock-only` limit the blast radius (no code runs, tarballs aren't downloaded), but the resolved tree then comes from an attacker-chosen endpoint. Point npm at an empty config so the resolution cannot be steered by the scanned package.</comment>

<file context>
@@ -0,0 +1,77 @@
+            tar -xzf "$ARCHIVE" -C "$DIR" --strip-components=1
+            # Tarballs ship no lockfile; without one only pinned direct deps are scanned.
+            # --package-lock-only resolves the tree without downloading or running anything.
+            (cd "$DIR" && npm install --package-lock-only --ignore-scripts)
+            # Hand the directory to the scan step as steps.prep.outputs.path.
+            echo "path=$DIR" >> "$GITHUB_OUTPUT"
</file context>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: npm install --package-lock-only is treated as a hard requirement, but it is only best-effort context: the comment itself notes that without a lockfile only pinned direct deps are scanned, and CVE Lite can still scan the package.json. Broken, incomplete, or deliberately malformed packages — exactly what this scanner exists to find — commonly fail npm resolution (invalid package.json, git:/file: protocols, opaque registry errors). When it fails, Prepare scan target fails, steps.prep.outputs.path is never set, and Run CVE Lite CLI runs with an empty path and fails, so the CVE scan silently misses the very packages that need it. Make the lockfile generation best-effort so the scan still runs when no lockfile can be produced.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/scan-community-node-cve-lite.yml, line 52:

<comment>`npm install --package-lock-only` is treated as a hard requirement, but it is only best-effort context: the comment itself notes that without a lockfile only pinned direct deps are scanned, and CVE Lite can still scan the package.json. Broken, incomplete, or deliberately malformed packages — exactly what this scanner exists to find — commonly fail npm resolution (invalid package.json, git:/file: protocols, opaque registry errors). When it fails, `Prepare scan target` fails, `steps.prep.outputs.path` is never set, and `Run CVE Lite CLI` runs with an empty `path` and fails, so the CVE scan silently misses the very packages that need it. Make the lockfile generation best-effort so the scan still runs when no lockfile can be produced.</comment>

<file context>
@@ -0,0 +1,77 @@
+            tar -xzf "$ARCHIVE" -C "$DIR" --strip-components=1
+            # Tarballs ship no lockfile; without one only pinned direct deps are scanned.
+            # --package-lock-only resolves the tree without downloading or running anything.
+            (cd "$DIR" && npm install --package-lock-only --ignore-scripts)
+            # Hand the directory to the scan step as steps.prep.outputs.path.
+            echo "path=$DIR" >> "$GITHUB_OUTPUT"
</file context>

# Hand the directory to the scan step as steps.prep.outputs.path.
echo "path=$DIR" >> "$GITHUB_OUTPUT"
else
echo "path=." >> "$GITHUB_OUTPUT"
fi

- name: Run CVE Lite CLI
uses: OWASP/cve-lite-cli@e444d847f67d5f2b07f38d66a8e61b9eeba8b18d # v1.37.0
with:
path: ${{ steps.prep.outputs.path }}
version: 1.37.0
sarif: true
output: security-report

- name: Write CVE Lite CLI summary
if: always()
uses: $/scan-community-node/actions/security-summary

- name: Upload CVE Lite CLI SARIF file to GitHub
if: always()
uses: $/scan-community-node/actions/upload-security-sarif
with:
category: cve-lite
package: ${{ inputs.package }}
upload: ${{ inputs.upload-sarif }}
72 changes: 72 additions & 0 deletions .github/workflows/scan-community-node-gitleaks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: 'Scan Community Node (Gitleaks)'

on:
workflow_call:
inputs:
package:
description: 'npm package name to scan (e.g. express or @scope/pkg). Leave empty to verify the local package.json.'
required: false
type: string
version:
description: 'Optional package version to scan (e.g. 4.18.2).'
required: false
default: 'latest'
type: string
upload-sarif:
description: 'Whether to upload SARIF reports to GitHub code scanning.'
required: false
default: false
type: boolean

env:
PACKAGE_SPEC: ${{ inputs.package }}@${{ inputs.version }}
GITLEAKS_VERSION: 8.30.1
# SHA-256 of gitleaks_<version>_linux_x64.tar.gz; update when bumping the version.
GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb

jobs:
gitleaks:
name: Gitleaks
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: $/scan-community-node/actions/setup
with:
node: 'true'

- name: Install Gitleaks
run: |
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
echo "${GITLEAKS_SHA256} gitleaks.tar.gz" | sha256sum -c -
tar -xzf gitleaks.tar.gz gitleaks
sudo install -m 0755 gitleaks /usr/local/bin/gitleaks
rm -f gitleaks gitleaks.tar.gz

- name: Run Gitleaks
continue-on-error: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: continue-on-error: true on the combined pack/extract/scan step swallows genuine "scanner cannot run" failures, contradicting the package README contract ("A job fails only when a scanner cannot run"). Gitleaks exits 1 when leaks are found, which is why the suppression exists, but a bad package/version (npm pack failure), an extraction failure, or a gitleaks crash also passes the job and the summary then reports "No findings." for a scan that never ran. Keep finding-suppression but fail on run failures: remove continue-on-error and let the script exit non-zero unless gitleaks itself finishes with the findings exit code (e.g. set +e; gitleaks dir ...; status=$?; [ "$status" -le 1 ] || exit "$status"), or split the pack/extract commands into their own step without continue-on-error.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/scan-community-node-gitleaks.yml, line 48:

<comment>`continue-on-error: true` on the combined pack/extract/scan step swallows genuine "scanner cannot run" failures, contradicting the package README contract ("A job fails only when a scanner cannot run"). Gitleaks exits 1 when leaks are found, which is why the suppression exists, but a bad `package`/`version` (npm pack failure), an extraction failure, or a gitleaks crash also passes the job and the summary then reports "No findings." for a scan that never ran. Keep finding-suppression but fail on run failures: remove `continue-on-error` and let the script exit non-zero unless gitleaks itself finishes with the findings exit code (e.g. `set +e; gitleaks dir ...; status=$?; [ "$status" -le 1 ] || exit "$status"`), or split the pack/extract commands into their own step without `continue-on-error`.</comment>

<file context>
@@ -0,0 +1,72 @@
+          rm -f gitleaks gitleaks.tar.gz
+
+      - name: Run Gitleaks
+        continue-on-error: true
+        env:
+          PACKAGE: ${{ inputs.package }}
</file context>

env:
PACKAGE: ${{ inputs.package }}
run: |
if [ -n "$PACKAGE" ]; then
DIR="$RUNNER_TEMP/gitleaks-target"
rm -rf "$DIR" && mkdir -p "$DIR"
npm pack "$PACKAGE_SPEC"
tar -xzf ./*.tgz -C "$DIR" --strip-components=1
TARGET="$DIR"
else
TARGET="."
fi
gitleaks dir "$TARGET" --report-format sarif --report-path security-report/gitleaks.sarif

- name: Write Gitleaks summary
if: always()
uses: $/scan-community-node/actions/security-summary

- name: Upload Gitleaks SARIF file to GitHub
uses: $/scan-community-node/actions/upload-security-sarif
with:
category: gitleaks
package: ${{ inputs.package }}
upload: ${{ inputs.upload-sarif }}
68 changes: 68 additions & 0 deletions .github/workflows/scan-community-node-guarddog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: 'Scan Community Node (GuardDog)'

on:
workflow_call:
inputs:
package:
description: 'npm package name to scan (e.g. express or @scope/pkg). Leave empty to verify the local package.json.'
required: false
type: string
version:
description: 'Optional package version to scan (e.g. 4.18.2).'
required: false
default: 'latest'
type: string
sandbox:
description: 'Whether GuardDog should run inside its kernel-level sandbox.'
required: false
default: true
type: boolean
upload-sarif:
description: 'Whether to upload SARIF reports to GitHub code scanning.'
required: false
default: false
type: boolean

jobs:
guarddog:
name: GuardDog
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: $/scan-community-node/actions/setup

- name: Run GuardDog

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This step has no continue-on-error: true, unlike the Gitleaks scan step. GuardDog exits non-zero when its scanners flag a package at or above the severity threshold, so a finding fails the job — contradicting the README contract in this PR that "none of them fails its job on findings. A job fails only when a scanner cannot run." Add continue-on-error: true if findings should not turn the check red.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/scan-community-node-guarddog.yml, line 36:

<comment>This step has no `continue-on-error: true`, unlike the Gitleaks scan step. GuardDog exits non-zero when its scanners flag a package at or above the severity threshold, so a finding fails the job — contradicting the README contract in this PR that "none of them fails its job on findings. A job fails only when a scanner cannot run." Add `continue-on-error: true` if findings should not turn the check red.</comment>

<file context>
@@ -0,0 +1,68 @@
+
+      - uses: $/scan-community-node/actions/setup
+
+      - name: Run GuardDog
+        env:
+          PACKAGE: ${{ inputs.package }}
</file context>

env:
PACKAGE: ${{ inputs.package }}
VERSION: ${{ inputs.version }}
SANDBOX: ${{ inputs.sandbox }}
run: |
# pipefail so a GuardDog failure isn't masked by tee's exit code.
set -o pipefail
SANDBOX_FLAG=""
if [ "$SANDBOX" = "false" ]; then
SANDBOX_FLAG="--no-sandbox"
fi
if [ -n "$PACKAGE" ]; then
# GuardDog scan can't emit SARIF, so keep its native report.
if [ -n "$VERSION" ] && [ "$VERSION" != "latest" ]; then
uvx guarddog npm scan $SANDBOX_FLAG "$PACKAGE" --version "$VERSION" | tee security-report/guarddog.txt
else
uvx guarddog npm scan $SANDBOX_FLAG "$PACKAGE" | tee security-report/guarddog.txt

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: uvx guarddog installs the latest guarddog release from PyPI on every run, so scanner behavior and report content are not reproducible. This contradicts the pinning policy exercised everywhere else in this package (Gitleaks pins version + SHA-256, Scorecard pins the image digest) and means a newly released, or compromised, guarddog version silently changes results for all callers. Pin the version, e.g. uvx --from 'guarddog==<version>' guarddog ....

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/scan-community-node-guarddog.yml, line 53:

<comment>`uvx guarddog` installs the latest guarddog release from PyPI on every run, so scanner behavior and report content are not reproducible. This contradicts the pinning policy exercised everywhere else in this package (Gitleaks pins version + SHA-256, Scorecard pins the image digest) and means a newly released, or compromised, guarddog version silently changes results for all callers. Pin the version, e.g. `uvx --from 'guarddog==<version>' guarddog ...`.</comment>

<file context>
@@ -0,0 +1,68 @@
+            if [ -n "$VERSION" ] && [ "$VERSION" != "latest" ]; then
+              uvx guarddog npm scan $SANDBOX_FLAG "$PACKAGE" --version "$VERSION" | tee security-report/guarddog.txt
+            else
+              uvx guarddog npm scan $SANDBOX_FLAG "$PACKAGE" | tee security-report/guarddog.txt
+            fi
+          else
</file context>

fi
else
uvx guarddog npm verify $SANDBOX_FLAG --output-format sarif package.json > security-report/guarddog.sarif
fi

- name: Write GuardDog summary
if: always()
uses: $/scan-community-node/actions/security-summary

- name: Upload SARIF file to GitHub
uses: $/scan-community-node/actions/upload-security-sarif
Comment on lines +63 to +64

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This upload step has no if: always(), so when the GuardDog step fails (e.g. it exits non-zero on a finding in local-verify mode, the only mode that produces guarddog.sarif), the opted-in SARIF upload is skipped exactly when there is a report to upload. The cve-lite workflow in this same PR sets if: always() on its upload step, and the composite action's own guard is always() && .... Add if: always() here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/scan-community-node-guarddog.yml, line 63:

<comment>This upload step has no `if: always()`, so when the GuardDog step fails (e.g. it exits non-zero on a finding in local-verify mode, the only mode that produces `guarddog.sarif`), the opted-in SARIF upload is skipped exactly when there is a report to upload. The cve-lite workflow in this same PR sets `if: always()` on its upload step, and the composite action's own guard is `always() && ...`. Add `if: always()` here.</comment>

<file context>
@@ -0,0 +1,68 @@
+        if: always()
+        uses: $/scan-community-node/actions/security-summary
+
+      - name: Upload SARIF file to GitHub
+        uses: $/scan-community-node/actions/upload-security-sarif
+        with:
</file context>
Suggested change
- name: Upload SARIF file to GitHub
uses: $/scan-community-node/actions/upload-security-sarif
- name: Upload SARIF file to GitHub
if: always()
uses: $/scan-community-node/actions/upload-security-sarif

with:
category: guarddog-builtin
package: ${{ inputs.package }}
upload: ${{ inputs.upload-sarif }}
Loading
Loading