Repository navigation
chore: add Dependabot security-only update config #1
Changes from all commits
ee86714
c304a56
763a4a8
14f99d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: "cargo" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| open-pull-requests-limit: 0 | ||
| labels: | ||
| - "security" | ||
| - "dependencies" | ||
|
|
||
| - package-ecosystem: "github-actions" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| open-pull-requests-limit: 10 | ||
| labels: | ||
| - "security" | ||
| - "dependencies" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| # Dependabot auto-merge workflow | ||
| # | ||
| # Requires repository secrets: | ||
| # APP_ID — GitHub App ID with contents:write and pull-requests:write | ||
| # APP_PRIVATE_KEY — GitHub App private key | ||
| # | ||
| # Auto-approves and enables auto-merge for Dependabot PRs that are: | ||
| # - GitHub Actions updates (patch or minor version bumps) | ||
| # - Security updates for any ecosystem (patch or minor) | ||
| # - Indirect (transitive) dependency updates | ||
| # Major version updates are always left for human review. | ||
| # Uses --auto so the merge waits for all required CI checks to pass. | ||
| # | ||
| # Safety model: application ecosystems use open-pull-requests-limit: 0 in | ||
| # dependabot.yml, so the only app-ecosystem PRs Dependabot can create are | ||
| # security updates. This workflow adds defense-in-depth by also checking | ||
| # the package ecosystem. | ||
| name: Dependabot auto-merge | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| branches: | ||
| - main | ||
|
|
||
| permissions: {} | ||
|
|
||
| jobs: | ||
| dependabot: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| pull-requests: read | ||
| if: github.event.pull_request.user.login == 'dependabot[bot]' | ||
| steps: | ||
| - name: Dependabot metadata | ||
| id: metadata | ||
| uses: dependabot/fetch-metadata@ffa630c65fa7e0ecfa0625b5ceda64399aea1b36 # v2 | ||
| with: | ||
| github-token: "${{ secrets.GITHUB_TOKEN }}" | ||
|
|
||
| - name: Determine if auto-merge eligible | ||
| id: eligible | ||
| run: | | ||
| UPDATE_TYPE="${{ steps.metadata.outputs.update-type }}" | ||
| DEP_TYPE="${{ steps.metadata.outputs.dependency-type }}" | ||
| ECOSYSTEM="${{ steps.metadata.outputs.package-ecosystem }}" | ||
|
|
||
| # Must be patch, minor, or indirect | ||
| if [[ "$UPDATE_TYPE" != "version-update:semver-patch" && \ | ||
| "$UPDATE_TYPE" != "version-update:semver-minor" && \ | ||
| "$DEP_TYPE" != "indirect" ]]; then | ||
| echo "eligible=false" >> "$GITHUB_OUTPUT" | ||
| echo "Skipping: major update requires human review" | ||
|
don-petry marked this conversation as resolved.
|
||
| exit 0 | ||
| fi | ||
|
|
||
| # GitHub Actions version updates are always eligible | ||
| # App ecosystem PRs can only exist as security updates (limit: 0) | ||
| echo "eligible=true" >> "$GITHUB_OUTPUT" | ||
| echo "Auto-merge eligible: ecosystem=$ECOSYSTEM update=$UPDATE_TYPE" | ||
|
|
||
| - name: Generate app token | ||
| if: steps.eligible.outputs.eligible == 'true' | ||
| id: app-token | ||
| uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3 | ||
| with: | ||
| app-id: ${{ secrets.APP_ID }} | ||
| private-key: ${{ secrets.APP_PRIVATE_KEY }} | ||
|
|
||
| - name: Approve and enable auto-merge | ||
| if: steps.eligible.outputs.eligible == 'true' | ||
| run: | | ||
| gh pr review --approve "$PR_URL" | ||
| gh pr merge --auto --squash "$PR_URL" | ||
| env: | ||
| PR_URL: ${{ github.event.pull_request.html_url }} | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,217 @@ | ||
| # Dependency vulnerability audit | ||
| # | ||
| # Auto-detects ecosystems present in the repository and runs the appropriate | ||
| # audit tool. Fails the build if any dependency has a known security advisory. | ||
|
don-petry marked this conversation as resolved.
|
||
| # | ||
| # Add "dependency-audit" as a required status check in branch protection. | ||
|
don-petry marked this conversation as resolved.
|
||
| # | ||
| # Pinned tool versions (update deliberately): | ||
| # govulncheck v1.1.4 | cargo-audit 0.22.1 | pip-audit 2.9.0 | ||
| name: Dependency audit | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [main] | ||
| push: | ||
| branches: [main] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| detect: | ||
|
Comment on lines
+19
to
+22
|
||
| name: Detect ecosystems | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| npm: ${{ steps.check.outputs.npm }} | ||
| pnpm: ${{ steps.check.outputs.pnpm }} | ||
| gomod: ${{ steps.check.outputs.gomod }} | ||
| cargo: ${{ steps.check.outputs.cargo }} | ||
| pip: ${{ steps.check.outputs.pip }} | ||
| steps: | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
|
|
||
| - name: Detect package ecosystems | ||
| id: check | ||
| run: | | ||
| # npm — look for package-lock.json anywhere (excluding node_modules) | ||
| if find . -name 'package-lock.json' -not -path '*/node_modules/*' | grep -q .; then | ||
| echo "npm=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "npm=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| # pnpm — look for pnpm-lock.yaml anywhere | ||
| if find . -name 'pnpm-lock.yaml' -not -path '*/node_modules/*' | grep -q .; then | ||
| echo "pnpm=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "pnpm=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| # Go modules — detect via go.mod (not go.sum, which may not exist) | ||
| if find . -name 'go.mod' -not -path '*/vendor/*' | grep -q .; then | ||
|
Comment on lines
+41
to
+52
|
||
| echo "gomod=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "gomod=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| # Cargo — detect via Cargo.toml anywhere (lockfile may not exist for libraries) | ||
| if find . -name 'Cargo.toml' -not -path '*/target/*' | grep -q .; then | ||
| echo "cargo=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "cargo=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| # Python — detect pyproject.toml or requirements.txt anywhere | ||
| if find . -name 'pyproject.toml' -not -path '*/.venv/*' -not -path '*/venv/*' | grep -q . || \ | ||
| find . -name 'requirements.txt' -not -path '*/.venv/*' -not -path '*/venv/*' | grep -q .; then | ||
| echo "pip=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "pip=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| audit-npm: | ||
| name: npm audit | ||
| needs: detect | ||
| if: needs.detect.outputs.npm == 'true' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
|
|
||
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | ||
| with: | ||
| node-version: "lts/*" | ||
|
|
||
| - name: Audit npm dependencies | ||
| run: | | ||
| # Audit each package-lock.json found in the repo | ||
| status=0 | ||
| while IFS= read -r dir; do | ||
| echo "::group::npm audit $dir" | ||
| if ! (cd "$dir" && npm audit --audit-level=low); then | ||
| status=1 | ||
| fi | ||
| echo "::endgroup::" | ||
| done < <(find . -name 'package-lock.json' -not -path '*/node_modules/*' -exec dirname {} \;) | ||
| exit $status | ||
|
|
||
| audit-pnpm: | ||
| name: pnpm audit | ||
| needs: detect | ||
| if: needs.detect.outputs.pnpm == 'true' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
|
|
||
| - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 | ||
|
|
||
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | ||
| with: | ||
| node-version: "lts/*" | ||
| cache: "pnpm" | ||
|
|
||
| - name: Audit pnpm dependencies | ||
| run: | | ||
| # Audit each pnpm-lock.yaml found in the repo | ||
| status=0 | ||
| while IFS= read -r dir; do | ||
| echo "::group::pnpm audit $dir" | ||
| if ! (cd "$dir" && pnpm audit --audit-level low); then | ||
| status=1 | ||
| fi | ||
| echo "::endgroup::" | ||
| done < <(find . -name 'pnpm-lock.yaml' -not -path '*/node_modules/*' -exec dirname {} \;) | ||
| exit $status | ||
|
|
||
| audit-go: | ||
| name: govulncheck | ||
| needs: detect | ||
| if: needs.detect.outputs.gomod == 'true' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
|
|
||
| - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 | ||
| with: | ||
| go-version: "stable" | ||
|
|
||
| - name: Install govulncheck | ||
| run: go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 | ||
|
|
||
| - name: Audit Go dependencies | ||
| run: | | ||
| status=0 | ||
| while IFS= read -r dir; do | ||
| echo "::group::govulncheck $dir" | ||
| if ! (cd "$dir" && govulncheck ./...); then | ||
|
Comment on lines
+142
to
+146
|
||
| status=1 | ||
| fi | ||
|
Comment on lines
+144
to
+148
|
||
| echo "::endgroup::" | ||
| done < <(find . -name 'go.mod' -not -path '*/vendor/*' -exec dirname {} \;) | ||
| exit $status | ||
|
|
||
| audit-cargo: | ||
| name: cargo audit | ||
| needs: detect | ||
| if: needs.detect.outputs.cargo == 'true' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
|
|
||
| - uses: dtolnay/rust-toolchain@stable | ||
|
|
||
| - name: Install cargo-audit | ||
| run: cargo install cargo-audit@0.22.1 --locked | ||
|
|
||
| - name: Audit Cargo dependencies | ||
| run: | | ||
| # cargo audit operates on Cargo.lock at workspace root | ||
| # For workspaces, a single audit at root covers all crates | ||
| status=0 | ||
| while IFS= read -r dir; do | ||
| echo "::group::cargo audit $dir" | ||
| if ! (cd "$dir" && cargo generate-lockfile 2>/dev/null; cargo audit); then | ||
| status=1 | ||
| fi | ||
| echo "::endgroup::" | ||
| done < <(find . -name 'Cargo.toml' -not -path '*/target/*' -exec dirname {} \; | sort -u) | ||
| exit $status | ||
|
|
||
| audit-pip: | ||
| name: pip-audit | ||
| needs: detect | ||
| if: needs.detect.outputs.pip == 'true' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
|
|
||
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | ||
| with: | ||
| python-version: "3.x" | ||
|
|
||
| - name: Install pip-audit | ||
| run: pip install pip-audit==2.9.0 | ||
|
|
||
| - name: Audit Python dependencies | ||
| run: | | ||
| status=0 | ||
| # Audit each Python project found in the repo | ||
| while IFS= read -r dir; do | ||
| echo "::group::pip-audit $dir" | ||
| if [ -f "$dir/pyproject.toml" ]; then | ||
| if ! pip-audit "$dir"; then | ||
| status=1 | ||
| fi | ||
| elif [ -f "$dir/requirements.txt" ]; then | ||
| if ! pip-audit -r "$dir/requirements.txt"; then | ||
| status=1 | ||
| fi | ||
| fi | ||
| echo "::endgroup::" | ||
| done < <( | ||
| { | ||
| find . -name 'pyproject.toml' -not -path '*/.venv/*' -not -path '*/venv/*' -exec dirname {} \; | ||
| find . -name 'requirements.txt' -not -path '*/.venv/*' -not -path '*/venv/*' -exec dirname {} \; | ||
| } | sort -u | ||
| ) | ||
| exit $status | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR description says Cargo updates should be security-only (open-pull-requests-limit 0), but this entry is configured to allow up to 10 version-update PRs. If the intent is security-only for Cargo, set open-pull-requests-limit to 0 so Dependabot doesn’t open routine version bump PRs.