Skip to content

Commit 1ea4caa

Browse files
fix(workflows): automate weekly SHA staleness check with issue creation (#975)
## Description This PR automates the weekly SHA staleness security check in the GitHub workflow. Previously, the sha-staleness-check workflow only executed the Test-SHAStaleness.ps1 script but did not create any actionable follow-up when stale dependencies were detected. This update improves the workflow by: Running the Test-SHAStaleness.ps1 script automatically during the weekly security maintenance workflow. Parsing the generated sha-staleness-results.json file to detect stale GitHub Actions or tools. Automatically creating or updating a tracking GitHub issue when stale dependencies exceed the defined threshold. Preventing duplicate issues by updating an existing open issue if one already exists. Automatically closing the issue when no stale dependencies are detected in future runs. 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 ### Code & Documentation * [x] Bug fix (non-breaking change fixing an issue) * [ ] New feature (non-breaking change adding functionality) * [ ] Breaking change (fix or feature causing existing functionality to change) * [ ] Documentation update ### Infrastructure & Configuration * [x] GitHub Actions workflow * [ ] Linting configuration (markdown, PowerShell, etc.) * [x] Security configuration * [ ] DevContainer configuration * [ ] Dependency update ### AI Artifacts * [ ] Reviewed contribution with prompt-builder agent and addressed all feedback * [ ] Copilot instructions (.github/instructions/*.instructions.md) * [ ] Copilot prompt (.github/prompts/*.prompt.md) * [ ] Copilot agent (.github/agents/*.agent.md) * [ ] Copilot skill (.github/skills/*/SKILL.md) ### Other * [x] Script/automation (.ps1, .sh, .py) * [ ] Other (please describe): --- ## Testing Checklist ### Required Checks * [ ] Documentation is updated (if applicable) * [x] Files follow existing naming conventions * [x] Changes are backwards compatible * [ ] Tests added for new functionality (if applicable) ### Required Automated Checks The following validation commands must pass before merging: * Markdown linting: `npm run lint:md` * Spell checking: `npm run spell-check` * Frontmatter validation: `npm run lint:frontmatter` * Skill structure validation: `npm run validate:skills` * Link validation: `npm run lint:md-links` * PowerShell analysis: `npm run lint:ps` * Plugin freshness: `npm run plugin:generate` --- ## Security Considerations * [x] This PR does not contain any sensitive or NDA information * [ ] Any new dependencies have been reviewed for security issues * [x] Security-related scripts follow the principle of least privilege --- ## Additional Notes This workflow improves long-term repository security maintenance by automatically detecting stale SHA pins and guiding maintainers to update them when necessary. --------- Co-authored-by: Bill Berry <WilliamBerryiii@users.noreply.github.com> Co-authored-by: Bill Berry <wberry@microsoft.com>
1 parent b273a4b commit 1ea4caa

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

.github/workflows/weekly-security-maintenance.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ jobs:
5757
runs-on: ubuntu-latest
5858
permissions:
5959
contents: read
60+
issues: write
6061
steps:
6162
- name: Generate summary
6263
shell: pwsh
@@ -196,3 +197,101 @@ jobs:
196197
if ($unpinnedCount -eq '0' -and $staleCount -eq '0') {
197198
Write-Output "::notice::All dependencies are properly pinned and up-to-date!"
198199
}
200+
- name: Download staleness report
201+
if: ${{ !cancelled() && needs.check-staleness.result == 'success' }}
202+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
203+
with:
204+
name: sha-staleness-results
205+
path: logs
206+
continue-on-error: true
207+
208+
- name: Create or Update Staleness Issue
209+
if: ${{ !cancelled() && needs.check-staleness.result == 'success' }}
210+
shell: pwsh
211+
env:
212+
GH_TOKEN: ${{ github.token }}
213+
STALE_COUNT: ${{ needs.check-staleness.outputs.stale-count }}
214+
THRESHOLD_DAYS: ${{ inputs.max-age-days || 30 }}
215+
REPO: ${{ github.repository }}
216+
SERVER_URL: ${{ github.server_url }}
217+
RUN_ID: ${{ github.run_id }}
218+
run: |
219+
$staleCount = [int]$env:STALE_COUNT
220+
$thresholdDays = $env:THRESHOLD_DAYS
221+
$automationMarker = '<!-- automation:sha-staleness -->'
222+
223+
$searchQuery = "repo:$env:REPO is:issue is:open in:body `"automation:sha-staleness`""
224+
$existingIssue = gh issue list `
225+
--repo $env:REPO `
226+
--search $searchQuery `
227+
--limit 1 `
228+
--json number `
229+
--jq '.[0].number // empty'
230+
231+
$existingIssue = if ($existingIssue) { $existingIssue.Trim() } else { $null }
232+
233+
# Build stale dependency details from the report artifact
234+
$staleDetails = ''
235+
$resultsPath = 'logs/sha-staleness-results.json'
236+
if (Test-Path $resultsPath) {
237+
$report = Get-Content $resultsPath | ConvertFrom-Json
238+
foreach ($dep in $report.Dependencies) {
239+
if ($dep.DaysOld -gt [int]$thresholdDays) {
240+
$staleDetails += "- **$($dep.File):** ``$($dep.Action)@$($dep.CurrentVersion)`` — $($dep.DaysOld) days old (latest: ``$($dep.LatestVersion)``)`n"
241+
}
242+
}
243+
}
244+
245+
$issueTitle = 'Security: Stale dependency SHAs detected'
246+
$issueBody = @"
247+
## Stale GitHub Action SHAs Detected
248+
249+
**$staleCount** dependencies have SHA pins older than **$thresholdDays** days.
250+
251+
### Stale Dependencies
252+
253+
$staleDetails
254+
255+
---
256+
257+
**Workflow Run:** $env:SERVER_URL/$env:REPO/actions/runs/$env:RUN_ID
258+
**Detection Date:** $(Get-Date -Format 'yyyy-MM-dd' -AsUTC)
259+
260+
### Action Required
261+
262+
- [ ] Run ``npm run sha-staleness`` to review current state
263+
- [ ] Update outdated SHAs: ``scripts/security/Update-ActionSHAPinning.ps1 -Path .github/workflows -UpdateStale``
264+
- [ ] Close this issue manually after fixes are merged
265+
266+
$automationMarker
267+
"@
268+
269+
if ($staleCount -gt 0) {
270+
if ($existingIssue) {
271+
Write-Host "Updating existing issue #$existingIssue"
272+
gh issue edit $existingIssue `
273+
--repo $env:REPO `
274+
--body $issueBody
275+
276+
$updateDate = Get-Date -Format 'yyyy-MM-dd' -AsUTC
277+
gh issue comment $existingIssue `
278+
--repo $env:REPO `
279+
--body "🔄 **Weekly staleness update:** $staleCount stale SHAs detected as of $updateDate"
280+
} else {
281+
Write-Host "Creating new staleness issue"
282+
gh issue create `
283+
--repo $env:REPO `
284+
--title $issueTitle `
285+
--body $issueBody `
286+
--label "security,staleness,automated,needs-triage"
287+
}
288+
} elseif ($existingIssue) {
289+
gh issue comment $existingIssue `
290+
--repo $env:REPO `
291+
--body "✅ All action SHAs are now within the $thresholdDays-day freshness threshold. Closing automatically."
292+
293+
gh issue close $existingIssue `
294+
--repo $env:REPO
295+
} else {
296+
Write-Host "No stale SHAs and no existing issue — nothing to do"
297+
}

0 commit comments

Comments
 (0)