diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 30b6f3b..5200490 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,9 @@ updates: directory: "/" schedule: interval: "weekly" + # The test/ tree holds throwaway fixture packages (npm, yarn, pnpm, pip, + # docker, Pipfile, ...) that are intentionally pinned, out of date, or + # deliberately broken. Never open version-update PRs for their manifests. + # `**` matches recursively, so this covers every nested fixture manifest. exclude-paths: - "test/**" - - "ossprey/test_*.py" diff --git a/.github/scripts/dismiss-test-fixture-alerts.sh b/.github/scripts/dismiss-test-fixture-alerts.sh new file mode 100755 index 0000000..c0a7481 --- /dev/null +++ b/.github/scripts/dismiss-test-fixture-alerts.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# +# Dismiss all OPEN Dependabot alerts whose manifest lives under a given path +# prefix (default: test/). Every other alert is left untouched, so real +# (root) dependencies keep alerting normally and the "Dependabot alerts +# enabled" compliance control (e.g. Vanta) stays satisfied. Dismissing an +# alert also stops Dependabot from opening security-update PRs for it. +# +# The test/ tree holds intentionally vulnerable / pinned / broken fixture +# packages used by the scanner's own test suite; they are never shipped or +# executed, so their alerts are dismissed as "not_used". +# +# Requires: gh CLI, authenticated (GH_TOKEN) with a token that has +# "Dependabot alerts: read and write" (fine-grained PAT) or the classic +# `repo` + `security_events` scope. The default Actions GITHUB_TOKEN +# CANNOT write Dependabot alerts, so a dedicated secret is required. +# +# Env vars: +# REPO owner/repo (default: ossprey/ossprey-python-client) +# PATH_PREFIX manifest path prefix (default: test/) +# APPLY 1 to dismiss, else dry-run (default: dry-run) +# +set -euo pipefail + +REPO="${REPO:-ossprey/ossprey-python-client}" +PATH_PREFIX="${PATH_PREFIX:-test/}" +REASON="not_used" # one of: fix_started inaccurate no_bandwidth not_used tolerable_risk +COMMENT="Intentional vulnerable test fixture under ${PATH_PREFIX}; not shipped or executed in production." + +echo ">> Repo: ${REPO} | prefix: ${PATH_PREFIX} | apply: ${APPLY:-0}" +echo ">> Fetching open Dependabot alerts ..." + +mapfile -t nums < <( + gh api --paginate "/repos/${REPO}/dependabot/alerts?state=open&per_page=100" \ + --jq ".[] | select(.dependency.manifest_path | startswith(\"${PATH_PREFIX}\")) | .number" +) + +if [ "${#nums[@]}" -eq 0 ]; then + echo ">> No open alerts under ${PATH_PREFIX}. Nothing to do." + exit 0 +fi + +echo ">> ${#nums[@]} open alert(s) under ${PATH_PREFIX}: ${nums[*]}" + +if [ "${APPLY:-0}" != "1" ]; then + echo ">> DRY RUN. Set APPLY=1 to dismiss the alerts above." + exit 0 +fi + +for num in "${nums[@]}"; do + echo ">> Dismissing alert #${num} ..." + gh api -X PATCH "/repos/${REPO}/dependabot/alerts/${num}" \ + -f state="dismissed" \ + -f dismissed_reason="${REASON}" \ + -f dismissed_comment="${COMMENT}" \ + --jq '" -> now: \(.state) (\(.dismissed_reason))"' +done + +echo ">> Done. Dismissed ${#nums[@]} alert(s)." diff --git a/.github/workflows/dismiss-test-fixture-alerts.yml b/.github/workflows/dismiss-test-fixture-alerts.yml new file mode 100644 index 0000000..595c01d --- /dev/null +++ b/.github/workflows/dismiss-test-fixture-alerts.yml @@ -0,0 +1,56 @@ +name: Dismiss test-fixture Dependabot alerts + +# The test/ tree holds intentionally vulnerable / pinned / broken fixture +# packages used by the scanner's own test suite. They must stay in the repo +# for the tests to work, but they should never count as open Dependabot +# alerts. This job dismisses (as "not_used") any open alert whose manifest +# lives under test/, leaving alerts for real dependencies untouched so the +# repo-wide Dependabot alerting (and the Vanta control that monitors it) +# stays intact. +# +# Requires a repository secret DEPENDABOT_ALERTS_TOKEN: a fine-grained PAT +# scoped to this repo with "Dependabot alerts: Read and write" permission. +# The built-in GITHUB_TOKEN cannot write Dependabot alerts, so this secret +# is mandatory. + +on: + schedule: + - cron: "0 6 * * 1" # every Monday 06:00 UTC + workflow_dispatch: + inputs: + dry_run: + description: "Only list what would be dismissed (do not dismiss)" + type: boolean + default: false + +permissions: {} + +concurrency: + group: dismiss-test-fixture-alerts + cancel-in-progress: false + +jobs: + dismiss: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Verify token secret is configured + env: + GH_TOKEN: ${{ secrets.DEPENDABOT_ALERTS_TOKEN }} + run: | + if [ -z "${GH_TOKEN}" ]; then + echo "::error::Secret DEPENDABOT_ALERTS_TOKEN is not set. Create a fine-grained PAT" \ + "with 'Dependabot alerts: Read and write' on this repo and add it as a repo secret." + exit 1 + fi + + - name: Dismiss test-fixture alerts + env: + GH_TOKEN: ${{ secrets.DEPENDABOT_ALERTS_TOKEN }} + REPO: ${{ github.repository }} + PATH_PREFIX: "test/" + # Scheduled runs apply; manual runs honor the dry_run toggle. + APPLY: ${{ (github.event_name == 'workflow_dispatch' && inputs.dry_run) && '0' || '1' }} + run: bash .github/scripts/dismiss-test-fixture-alerts.sh