fix(workflows): automate weekly SHA staleness check with issue creation#916
fix(workflows): automate weekly SHA staleness check with issue creation#916PratikWayase wants to merge 9 commits intomicrosoft:mainfrom
Conversation
|
Thank you for this contribution, @PratikWayase! Your work on automating the weekly SHA staleness check improves our security validation workflow. We appreciate the time and care you put into this. We've made a couple of updates to align with project conventions:
No action needed on your end. If you have questions about any of the changes, feel free to comment here. |
@microsoft-github-policy-service agree |
WilliamBerryiii
left a comment
There was a problem hiding this comment.
Thanks for adding automated issue tracking for SHA staleness — this is a great addition to the security maintenance workflow.
Two items are blockers (the unpinned action SHA and the missing issues: write permission) and will need to be fixed before merge. The remaining comments are suggestions to improve reliability and output quality.
One additional suggestion: when the script closes a resolved staleness issue (the else branch around line 250), consider adding a comment to the issue before closing it — something like "All action SHAs are now within the freshness threshold. Closing automatically." This provides an audit trail so readers understand why the issue was closed without having to trace back to the workflow run.
| } | ||
| - name: Create or Update Staleness Issue | ||
| if: always() | ||
| uses: actions/github-script@v7 |
There was a problem hiding this comment.
actions/github-script@v7 is not SHA-pinned. Per repository policy (.github/instructions/workflows.instructions.md), all actions must use full SHA references. This will also fail the validate-action-pinning CI check.
| uses: actions/github-script@v7 | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 |
| if ($unpinnedCount -eq '0' -and $staleCount -eq '0') { | ||
| Write-Output "::notice::All dependencies are properly pinned and up-to-date!" | ||
| } | ||
| - name: Create or Update Staleness Issue |
There was a problem hiding this comment.
The summary job currently only has contents: read permission, but this step calls github.rest.issues.create(), .update(), and .listForRepo() which require issues: write. These API calls will return 403 without the additional permission.
Add to the summary job's permissions block:
permissions:
contents: read
issues: write| const threshold = Number('${{ inputs.max-age-days || 30 }}'); | ||
|
|
||
| const issueTitle = "Security: Stale dependency SHAs detected"; | ||
|
|
There was a problem hiding this comment.
listForRepo defaults to 30 results per page. If there are many open issues, the target tracking issue could fall outside the first page, causing the script to create a duplicate instead of updating the existing one.
Consider using per_page: 100 or paginating with github.paginate() to ensure the existing issue is found:
const issues = await github.paginate(github.rest.issues.listForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'security,staleness',
per_page: 100
});| Write-Output "::notice::All dependencies are properly pinned and up-to-date!" | ||
| } | ||
| - name: Create or Update Staleness Issue | ||
| if: always() |
There was a problem hiding this comment.
if: always() runs even when the workflow is cancelled or upstream jobs fail for infrastructure reasons. In those cases, needs.check-staleness.outputs.stale-count will be empty, causing parseInt to return NaN, and the step will attempt to create/close an issue based on bad data.
Consider narrowing the condition:
| if: always() | |
| if: ${{ !cancelled() && needs.check-staleness.result == 'success' }} |
|
|
||
| const body = ` | ||
| ## Stale GitHub Action SHAs Detected | ||
|
|
There was a problem hiding this comment.
The template literal indentation here produces leading whitespace in the rendered markdown body. GitHub will interpret the indented lines as code blocks rather than normal markdown.
Either dedent the template content or use a helper variable:
const body = [
`## 🔒 SHA Staleness Report`,
``,
`**${staleCount}** action reference(s) exceed the **${maxAgeDays}-day** freshness threshold.`,
``,
`Run the staleness check locally or review the [latest workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`,
``,
`> This issue is automatically managed by the weekly security maintenance workflow.`,
].join('\n');|
closing this in favor of #975 |
Pull Request
Description
This PR automates the weekly SHA staleness security check in the GitHub workflow.
Previously, the
sha-staleness-checkworkflow only executed theTest-SHAStaleness.ps1script but did not create any actionable follow-up when stale dependencies were detected.This update improves the workflow by:
Test-SHAStaleness.ps1script automatically during the weekly security maintenance workflow.sha-staleness-results.jsonfile to detect stale GitHub Actions or tools.This ensures that outdated GitHub Action SHAs and security tools are continuously monitored and tracked without requiring manual checks.
Related Issue(s)
Fixes #268
Type of Change
Select all that apply:
Code & Documentation:
Infrastructure & Configuration:
AI Artifacts:
prompt-builderagent and addressed all feedback.github/instructions/*.instructions.md).github/prompts/*.prompt.md).github/agents/*.agent.md).github/skills/*/SKILL.md)Other:
.ps1,.sh,.py)Testing
Checklist
Required Checks
Required Automated Checks
The following validation commands must pass before merging:
npm run lint:mdnpm run spell-checknpm run lint:frontmatternpm run validate:skillsnpm run lint:md-linksnpm run lint:psnpm run plugin:generateSecurity Considerations
Additional Notes