From a9696c1f69a0b7e6959a4abafd770f1e119648cd Mon Sep 17 00:00:00 2001 From: aRustyDev <36318507+aRustyDev@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:17:08 -0500 Subject: [PATCH 1/5] Add auto-assign.yml from gist --- .github/workflows/auto-assign.yml | 95 +++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 .github/workflows/auto-assign.yml diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..0fde858 --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,95 @@ +name: Auto Assign Owner + +on: + issues: + types: [opened] + pull_request_target: + types: [opened] + +permissions: + issues: write + pull-requests: write + contents: read + +jobs: + check-and-assign: + runs-on: ubuntu-latest + steps: + - name: Check collaborator count and assign owner + uses: actions/github-script@v7 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + + // Get collaborators with push or admin access + const { data: collaborators } = await github.rest.repos.listCollaborators({ + owner, + repo, + permission: 'push' + }); + + // Filter to only users with push or admin (not just read) + const pushCollaborators = collaborators.filter(c => + c.permissions?.push || c.permissions?.admin + ); + + console.log(`Found ${pushCollaborators.length} collaborators with push access`); + + // Only auto-assign if there's 1 or fewer collaborators with push access + if (pushCollaborators.length > 1) { + console.log('Multiple collaborators found, skipping auto-assign'); + return; + } + + // Determine the assignee (repo owner) + const assignee = owner; + + if (context.eventName === 'issues') { + const issue = context.payload.issue; + + // Skip if already assigned + if (issue.assignees && issue.assignees.length > 0) { + console.log('Issue already has assignees, skipping'); + return; + } + + // Skip if author is a bot + if (issue.user.type === 'Bot') { + console.log('Issue author is a bot, skipping'); + return; + } + + await github.rest.issues.addAssignees({ + owner, + repo, + issue_number: issue.number, + assignees: [assignee] + }); + + console.log(`Assigned issue #${issue.number} to ${assignee}`); + + } else if (context.eventName === 'pull_request_target') { + const pr = context.payload.pull_request; + + // Skip if already assigned + if (pr.assignees && pr.assignees.length > 0) { + console.log('PR already has assignees, skipping'); + return; + } + + // Skip if author is a bot + if (pr.user.type === 'Bot') { + console.log('PR author is a bot, skipping'); + return; + } + + await github.rest.issues.addAssignees({ + owner, + repo, + issue_number: pr.number, + assignees: [assignee] + }); + + console.log(`Assigned PR #${pr.number} to ${assignee}`); + } From 45e4bd439f0a9edc36ba2bfda3db968fc73472d6 Mon Sep 17 00:00:00 2001 From: aRustyDev <36318507+aRustyDev@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:17:08 -0500 Subject: [PATCH 2/5] Add dependabot-issue.yml from gist --- .github/workflows/dependabot-issue.yml | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/dependabot-issue.yml diff --git a/.github/workflows/dependabot-issue.yml b/.github/workflows/dependabot-issue.yml new file mode 100644 index 0000000..4b07207 --- /dev/null +++ b/.github/workflows/dependabot-issue.yml @@ -0,0 +1,63 @@ +name: Create Issue for Dependabot PRs + +on: + pull_request_target: + types: [opened] + +permissions: + issues: write + pull-requests: read + +jobs: + create-tracking-issue: + if: github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - name: Create tracking issue for Dependabot PR + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const owner = context.repo.owner; + const repo = context.repo.repo; + + // Extract version info from PR title + // Typical format: "Bump actions/checkout from 3 to 4" + const title = pr.title; + + const issueTitle = `deps: ${title}`; + const issueBody = `## Dependabot Update + + ${pr.body || 'Automated dependency update.'} + + ## Pull Request + + - PR: #${pr.number} + - Author: @${pr.user.login} + - URL: ${pr.html_url} + + --- + This issue was automatically created to track the Dependabot update. + `; + + const { data: issue } = await github.rest.issues.create({ + owner, + repo, + title: issueTitle, + body: issueBody, + labels: ['dependencies', 'github-actions'] + }); + + console.log(`Created tracking issue #${issue.number} for PR #${pr.number}`); + + // Update PR body to reference the issue + const updatedBody = `${pr.body || ''}\n\n---\nCloses #${issue.number}`; + + await github.rest.pulls.update({ + owner, + repo, + pull_number: pr.number, + body: updatedBody + }); + + console.log(`Updated PR #${pr.number} to close issue #${issue.number}`); From b72a29dd1e9745d974b907fe437cbbd0b88f5add Mon Sep 17 00:00:00 2001 From: aRustyDev <36318507+aRustyDev@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:17:09 -0500 Subject: [PATCH 3/5] Add dependabot.yml from gist --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9818577 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + commit-message: + prefix: "ci" + labels: + - "dependencies" + - "github-actions" + open-pull-requests-limit: 5 From 0df0d8797361453f4130f52ca24e78d69ad07d39 Mon Sep 17 00:00:00 2001 From: aRustyDev <36318507+aRustyDev@users.noreply.github.com> Date: Tue, 23 Dec 2025 16:49:07 -0500 Subject: [PATCH 4/5] fix(ci): remove PR body update from dependabot-issue workflow Dependabot PRs have restricted permissions that prevent modifying the PR body. --- .github/workflows/dependabot-issue.yml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/dependabot-issue.yml b/.github/workflows/dependabot-issue.yml index 4b07207..5c7d27f 100644 --- a/.github/workflows/dependabot-issue.yml +++ b/.github/workflows/dependabot-issue.yml @@ -50,14 +50,5 @@ jobs: console.log(`Created tracking issue #${issue.number} for PR #${pr.number}`); - // Update PR body to reference the issue - const updatedBody = `${pr.body || ''}\n\n---\nCloses #${issue.number}`; - - await github.rest.pulls.update({ - owner, - repo, - pull_number: pr.number, - body: updatedBody - }); - - console.log(`Updated PR #${pr.number} to close issue #${issue.number}`); + // Note: We don't update the PR body because Dependabot PRs have + // restricted permissions. The issue references the PR instead. From be69bb48486867c2c52cffb451c6c202623b94df Mon Sep 17 00:00:00 2001 From: aRustyDev <36318507+aRustyDev@users.noreply.github.com> Date: Wed, 24 Dec 2025 01:41:56 -0500 Subject: [PATCH 5/5] feat(ci): add dependabot auto-merge workflow --- .github/workflows/dependabot-auto-merge.yml | 71 +++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/dependabot-auto-merge.yml diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..ef3542f --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,71 @@ +# Dependabot Auto-Merge +# +# Automatically approves and merges Dependabot PRs for patch/minor updates. +# Major updates require human review. +# +# Prerequisites: +# 1. Enable auto-merge in repo settings (Settings → General → Allow auto-merge) +# 2. Branch protection on main requiring: +# - Status checks to pass +# - At least 1 approval +# +# Security: +# - Only auto-merges patch/minor updates +# - Blocks PRs with high-severity vulnerabilities +# - Major updates always require human review + +name: Dependabot Auto-Merge + +on: pull_request + +permissions: + contents: write + pull-requests: write + +jobs: + auto-merge: + runs-on: ubuntu-latest + if: github.actor == 'dependabot[bot]' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v4 + with: + fail-on-severity: high + + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Auto-approve patch/minor updates + if: steps.metadata.outputs.update-type != 'version-update:semver-major' + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable auto-merge for patch/minor + if: steps.metadata.outputs.update-type != 'version-update:semver-major' + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Comment on major updates + if: steps.metadata.outputs.update-type == 'version-update:semver-major' + run: | + gh pr comment "$PR_URL" --body "⚠️ **Major version update** - requires manual review. + + **Update type:** ${{ steps.metadata.outputs.update-type }} + **Dependency:** ${{ steps.metadata.outputs.dependency-names }} + **From:** ${{ steps.metadata.outputs.previous-version }} + **To:** ${{ steps.metadata.outputs.new-version }} + + Please review the changelog for breaking changes before approving." + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}