Repository navigation
Auto-create QA tickets for Dependabot PRs #48008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
8df31ab
Auto-create QA tickets for Dependabot PRs (#48007)
sharon-fdm 92980ba
Fix zizmor: use PR author check, add gate waivers
sharon-fdm 23e6ecb
Merge branch 'main' into dependabot-qa-ticket
sharon-fdm fc04971
Fix dependabot-qa-ticket workflow: branch matching and status label
sharon-fdm d4e1b1f
Drop unnecessary pull-requests: write permission
sharon-fdm b891f7a
Make QA-ticket creation idempotent
sharon-fdm 4103850
Address review feedback from Lucas
sharon-fdm 3f101a3
Switch project board status from Awaiting QA to Inbox
sharon-fdm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| name: Create QA ticket for Dependabot PRs | ||
|
|
||
| # When Dependabot opens a code-dependency PR, create a QA issue on the | ||
| # #g-orchestration board so the team can verify that the bump introduces no | ||
| # behavioral regressions (see postmortem for #45763). | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| create-qa-ticket: | ||
| if: > | ||
| github.event.repository.owner.login == 'fleetdm' && | ||
| github.event.pull_request.user.login == 'dependabot[bot]' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
| steps: | ||
| - name: Harden Runner | ||
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: Create QA issue and add to project board | ||
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | ||
| env: | ||
| PROJECT_TOKEN: ${{ secrets.FLEET_GITHUB_TOKEN_PROJECTS }} | ||
| with: | ||
| script: | | ||
| const pr = context.payload.pull_request; | ||
| const branch = pr.head.ref; | ||
|
|
||
| // Only process code dependency updates (Go modules, npm root). | ||
| // Skip: github-actions, docker, website npm, slackbot npm. | ||
| // Dependabot uses slashes for single-package updates and dashes for grouped updates: | ||
| // single: dependabot/go_modules/golang.org/x/crypto-0.35.0 | ||
| // grouped: dependabot-go_modules-google.golang.org-grpc-1.82.1 | ||
| const isGomod = branch.startsWith('dependabot/go_modules/') | ||
| || branch.startsWith('dependabot-go_modules-'); | ||
| const isNpm = (branch.startsWith('dependabot/npm_and_yarn/') | ||
| || branch.startsWith('dependabot-npm_and_yarn-')) | ||
| && !branch.includes('/website/') | ||
| && !branch.includes('/fleet-slackbot/') | ||
| && !branch.includes('-website-') | ||
| && !branch.includes('-fleet-slackbot-'); | ||
|
|
||
| if (!isGomod && !isNpm) { | ||
| console.log(`Skipping non-code dependency PR (branch: ${branch})`); | ||
| return; | ||
| } | ||
|
|
||
| const ecosystem = branch.includes('go_modules') ? 'Go' : 'npm'; | ||
| const issueTitle = `QA: ${pr.title}`; | ||
|
|
||
| // Idempotency: check if a QA issue already exists for this PR | ||
| // (guards against duplicate tickets on workflow re-runs). | ||
| const existing = await github.rest.issues.listForRepo({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| labels: 'dependabot', | ||
| state: 'open', | ||
| per_page: 100, | ||
| }); | ||
| const duplicate = existing.data.find(i => i.title === issueTitle); | ||
| if (duplicate) { | ||
| console.log(`QA issue already exists: #${duplicate.number} — skipping.`); | ||
| return; | ||
| } | ||
|
|
||
| // Create the QA tracking issue. | ||
| const issue = await github.rest.issues.create({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| title: issueTitle, | ||
| body: [ | ||
| `## Dependabot dependency update — QA review needed`, | ||
| ``, | ||
| `| Field | Value |`, | ||
| `|-------|-------|`, | ||
| `| **PR** | #${pr.number} |`, | ||
| `| **Ecosystem** | ${ecosystem} |`, | ||
| `| **Branch** | \`${branch}\` |`, | ||
| ``, | ||
| `### Why this needs QA`, | ||
| ``, | ||
| `Dependabot PRs update third-party dependencies. Even minor/patch bumps can`, | ||
| `change runtime behavior (see #45763 for a real example where a dependency`, | ||
| `bump silently broke SCEP certificate issuance). Please verify that the`, | ||
| `updated dependency does not cause regressions in related functionality.`, | ||
| ``, | ||
| `### What to check`, | ||
| ``, | ||
| `1. Review the PR diff and the dependency's changelog/release notes`, | ||
| `2. Identify which Fleet features use this dependency`, | ||
| `3. Test those features for behavioral changes`, | ||
| ``, | ||
| `---`, | ||
| `*This issue was automatically created by the dependabot-qa-ticket workflow.*`, | ||
| ].join('\n'), | ||
| labels: ['dependabot'], | ||
| assignees: ['AndreyKizimenko'], | ||
| }); | ||
|
sharon-fdm marked this conversation as resolved.
|
||
|
|
||
| console.log(`Created issue #${issue.data.number}`); | ||
|
|
||
| // Comment on the PR linking to the QA issue. | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: pr.number, | ||
| body: `QA ticket created: #${issue.data.number}`, | ||
| }); | ||
|
|
||
| // --- Project board: add to #g-orchestration and set status to "Inbox" --- | ||
| // Requires a PAT stored as FLEET_GITHUB_TOKEN_PROJECTS with | ||
| // read/write access to organization projects. | ||
| const projectToken = process.env.PROJECT_TOKEN; | ||
| if (!projectToken) { | ||
| core.warning( | ||
| 'FLEET_GITHUB_TOKEN_PROJECTS secret is not configured — ' + | ||
| 'issue was created but not added to the project board. ' + | ||
| 'Create a fine-grained PAT with Organization Projects read/write scope.' | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const { getOctokit } = require('@actions/github'); | ||
| const projectOctokit = getOctokit(projectToken); | ||
|
|
||
| const PROJECT_ID = 'PVT_kwDOBDAnic4A4BEx'; // #g-orchestration (#71) | ||
| const STATUS_FIELD = 'PVTSSF_lADOBDAnic4A4BExzgtDlHw'; | ||
| const INBOX = 'f33a1ec5'; | ||
|
|
||
| // Add the issue to the project. | ||
| const addResult = await projectOctokit.graphql(` | ||
| mutation($projectId: ID!, $contentId: ID!) { | ||
| addProjectV2ItemById(input: {projectId: $projectId, contentId: $contentId}) { | ||
| item { id } | ||
| } | ||
| } | ||
| `, { | ||
| projectId: PROJECT_ID, | ||
| contentId: issue.data.node_id, | ||
| }); | ||
|
|
||
| const itemId = addResult.addProjectV2ItemById.item.id; | ||
| console.log(`Added to #g-orchestration board (item ${itemId})`); | ||
|
|
||
| // Set status to "Inbox". | ||
| await projectOctokit.graphql(` | ||
| mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) { | ||
| updateProjectV2ItemFieldValue(input: { | ||
| projectId: $projectId | ||
| itemId: $itemId | ||
| fieldId: $fieldId | ||
| value: {singleSelectOptionId: $optionId} | ||
| }) { | ||
| projectV2Item { id } | ||
| } | ||
| } | ||
| `, { | ||
| projectId: PROJECT_ID, | ||
| itemId: itemId, | ||
| fieldId: STATUS_FIELD, | ||
| optionId: INBOX, | ||
| }); | ||
|
|
||
| console.log('Status set to "Inbox"'); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.