Skip to content

Commit 1241e4c

Browse files
committed
Merge remote-tracking branch 'origin/main' into users/priyanshuag/actions-hub-clone-site
2 parents e0816d4 + c8b3c6e commit 1241e4c

3 files changed

Lines changed: 304 additions & 11 deletions

File tree

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
#
4+
# Dependabot Auto-fix
5+
# ------------------------------------------------------------------------
6+
# Runs the `fix-dependabot-alerts` skill via GitHub Copilot CLI on a weekly
7+
# schedule (and on-demand). Copilot enumerates open Dependabot alerts,
8+
# applies fixes following `.claude/skills/fix-dependabot-alerts/SKILL.md`,
9+
# runs the build + tests, and opens a single consolidated PR.
10+
#
11+
# Required secrets
12+
# ------------------------------------------------------------------------
13+
# POWER_PAGES_PUBLIC_GITHUB_APP_PRIVATE_KEY
14+
# Private key of the existing GitHub App (app-id 2740120) that is
15+
# already used by loc-update.yml / translations-export.yml. The App
16+
# installation on this repo must have:
17+
# - Contents: Read/Write
18+
# - Pull requests: Read/Write
19+
# Commits and the PR are authored as github-actions[bot] via this App.
20+
#
21+
# COPILOT_CLI_PAT
22+
# Fine-grained PAT from a user with a Copilot license. Needed because
23+
# GitHub App tokens cannot authenticate Copilot CLI (Copilot licenses
24+
# are per-user). Required permissions:
25+
# - Account: Copilot Requests: Read
26+
# - Repository: Dependabot alerts: Read (so `gh api .../dependabot/alerts` works)
27+
# The org-level "Copilot CLI" policy must be enabled for this user.
28+
# ------------------------------------------------------------------------
29+
30+
name: Dependabot Auto-fix
31+
32+
on:
33+
schedule:
34+
# Weekly, Mondays 06:00 UTC
35+
- cron: '0 6 * * 1'
36+
workflow_dispatch:
37+
38+
permissions:
39+
contents: read
40+
41+
concurrency:
42+
group: dependabot-autofix
43+
cancel-in-progress: false
44+
45+
jobs:
46+
autofix:
47+
name: Copilot CLI Dependabot Auto-fix
48+
runs-on: ubuntu-latest
49+
timeout-minutes: 45
50+
permissions:
51+
contents: write
52+
pull-requests: write
53+
54+
steps:
55+
- name: Generate GitHub App Token
56+
id: app-token
57+
uses: actions/create-github-app-token@v1
58+
with:
59+
app-id: 2740120
60+
private-key: ${{ secrets.POWER_PAGES_PUBLIC_GITHUB_APP_PRIVATE_KEY }}
61+
62+
- name: Checkout Repository
63+
uses: actions/checkout@v4
64+
with:
65+
fetch-depth: 0
66+
token: ${{ steps.app-token.outputs.token }}
67+
68+
- name: Setup Node.js
69+
uses: actions/setup-node@v4
70+
with:
71+
node-version: '20'
72+
cache: 'npm'
73+
74+
- name: Install dependencies
75+
run: npm ci
76+
77+
- name: Install GitHub Copilot CLI
78+
run: npm install -g @github/copilot
79+
80+
- name: Configure git identity
81+
run: |
82+
git config --local user.name "github-actions[bot]"
83+
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
84+
85+
- name: Create working branch
86+
id: branch
87+
run: |
88+
BRANCH="copilot/dependabot-autofix-${{ github.run_id }}"
89+
git checkout -b "$BRANCH"
90+
echo "name=$BRANCH" >> "$GITHUB_OUTPUT"
91+
92+
- name: Run Copilot CLI (fix-dependabot-alerts)
93+
id: copilot
94+
timeout-minutes: 30
95+
env:
96+
# Copilot CLI auth + Dependabot alerts read. Redacted from logs.
97+
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_CLI_PAT }}
98+
# App token used by `gh pr create` and `git push` so the PR
99+
# and commits are authored by github-actions[bot].
100+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
101+
REPO: ${{ github.repository }}
102+
BRANCH: ${{ steps.branch.outputs.name }}
103+
run: |
104+
set -euo pipefail
105+
106+
# Inline the skill so behavior is identical even if Copilot CLI
107+
# on the runner does not auto-load .claude/skills/.
108+
SKILL_BODY="$(cat .claude/skills/fix-dependabot-alerts/SKILL.md)"
109+
110+
PROMPT=$(cat <<PROMPT_EOF
111+
You are running inside a GitHub Actions job. Follow the skill
112+
below to fix all currently open Dependabot alerts for the
113+
repository \`${REPO}\` in a SINGLE consolidated pull request.
114+
115+
Environment already set up for you:
116+
- Repository is checked out at the current working directory.
117+
- A working branch named \`${BRANCH}\` is already created and checked out.
118+
- \`npm ci\` has already installed dependencies.
119+
- \`git\` is configured as github-actions[bot].
120+
- \`COPILOT_GITHUB_TOKEN\` is available for \`gh api\` calls that read
121+
Dependabot alerts (e.g. \`gh api repos/${REPO}/dependabot/alerts\`).
122+
- \`GH_TOKEN\` is a GitHub App token with Contents and Pull requests
123+
write access. Use it (it is already in env) for \`git push\` and
124+
\`gh pr create\`.
125+
126+
Mandatory rules:
127+
128+
1. ALERT ENUMERATION — source of truth.
129+
Run exactly:
130+
GH_TOKEN=\$COPILOT_GITHUB_TOKEN gh api \\\\
131+
"repos/${REPO}/dependabot/alerts?state=open&per_page=100" \\\\
132+
--paginate \\\\
133+
--jq '.[] | {number, ghsa: .security_advisory.ghsa_id, pkg: .dependency.package.name, ecosystem: .dependency.package.ecosystem, severity: .security_vulnerability.severity, scope: .dependency.scope, manifest: .dependency.manifest_path, summary: .security_advisory.summary, vulnerable: .security_vulnerability.vulnerable_version_range, patched: .security_vulnerability.first_patched_version.identifier}'
134+
Save the raw output to \`alerts.json\`. The PR description
135+
and the count of "alerts fixed" MUST be built one-to-one
136+
from this list. Do NOT count transitive-path occurrences
137+
of the same alert number as separate alerts. Do NOT
138+
inflate counts based on how many \`node_modules/**\`
139+
entries appear in \`package-lock.json\`.
140+
141+
2. ZERO ALERTS — exit cleanly.
142+
If step 1 returns an empty list, do not commit, do not
143+
push, do not open a PR. Print "NO_OPEN_ALERTS" and exit.
144+
145+
3. MINIMUM VIABLE FIX — prefer the smallest blast radius.
146+
For each alert, pick the least-invasive strategy in this
147+
strict preference order and record your choice in the PR
148+
body:
149+
a. Transitive dependency → add/extend an entry in the
150+
\`overrides\` block of \`package.json\` pinning the
151+
vulnerable package to the first patched version.
152+
This is the preferred fix.
153+
b. Direct dependency → bump that specific dependency in
154+
\`package.json\` to the first patched version.
155+
c. Only if (a) and (b) are infeasible (e.g. override
156+
breaks peer-dep resolution, or a parent package
157+
pins the vulnerable version), escalate to bumping a
158+
parent package. In that case, justify the escalation
159+
in the PR body and keep the parent bump as narrow
160+
as possible (patch > minor > major).
161+
Never run \`npm audit fix\` or \`npm audit fix --force\` as
162+
a shortcut — they produce sprawling diffs with unrelated
163+
upgrades. Use \`npm install\` / \`npm update\` targeted at
164+
the specific package(s) you are fixing.
165+
166+
4. DIFF DISCIPLINE.
167+
After the lockfile is regenerated, run:
168+
git diff --stat origin/main
169+
If any of the following are true, STOP, revert with
170+
\`git checkout -- package.json package-lock.json\`, and
171+
try a narrower strategy from rule 3:
172+
- package.json changed a dependency that is NOT on the
173+
alert list (except for adding entries to \`overrides\`).
174+
- Any dependency bumped a MAJOR version that is not
175+
strictly required to reach the first patched version.
176+
177+
5. VERIFY.
178+
Run \`npm run build\` AND \`npm test\`. If either fails,
179+
do NOT push and do NOT open a PR. Print
180+
"BUILD_OR_TEST_FAILED" and exit non-zero.
181+
182+
6. OPEN THE PR (verification passed).
183+
- \`git push -u origin ${BRANCH}\` (uses \$GH_TOKEN).
184+
- Build the PR title and body strictly from \`alerts.json\`:
185+
* Title: \`chore(deps): fix N open Dependabot alert(s)\`
186+
where N = number of distinct entries in \`alerts.json\`.
187+
* Body format:
188+
## Summary
189+
Fixes N open Dependabot alert(s) as enumerated by
190+
\`gh api repos/${REPO}/dependabot/alerts?state=open\`.
191+
## Alerts addressed
192+
For each entry in \`alerts.json\`, one bullet:
193+
- \`<pkg>\` (#<number>, <severity>, <ghsa>) —
194+
vulnerable \`<vulnerable>\` → patched \`<patched>\`.
195+
Strategy: override | direct-bump | parent-bump.
196+
Rationale if parent-bump: <one line>.
197+
## Collateral changes
198+
List any other dep bumps that \`npm install\` cascaded
199+
(e.g. peer updates) and explain why they were
200+
necessary. If there are none, say "None".
201+
## Verification
202+
- \`npm run build\`: PASS
203+
- \`npm test\`: PASS
204+
- Open the PR with \`gh pr create --base main --head ${BRANCH}\`
205+
using that title and body.
206+
- Print the PR URL.
207+
208+
7. COMMIT / AUTHORSHIP HYGIENE.
209+
Never manually edit integrity hashes in package-lock.json
210+
(see skill). Use \`npm install\`, \`npm update\`, or a clean
211+
reinstall to let npm compute them. Do not add any
212+
\`Co-authored-by:\` trailer.
213+
214+
8. PERMISSIONS.
215+
Never use \`--allow-all\` semantics; stick to the tools you
216+
already have permission to use.
217+
218+
----- SKILL START -----
219+
${SKILL_BODY}
220+
----- SKILL END -----
221+
PROMPT_EOF
222+
)
223+
224+
copilot \
225+
-p "$PROMPT" \
226+
--model claude-sonnet-4.6 \
227+
-s \
228+
--no-ask-user \
229+
--allow-tool 'shell(npm:*), shell(npx:*), shell(gh:*), shell(git:*), shell(node:*), write, read' \
230+
--secret-env-vars 'COPILOT_CLI_PAT' \
231+
--share ./copilot-session.md \
232+
| tee copilot-output.txt
233+
234+
- name: Summarize run
235+
if: always()
236+
run: |
237+
{
238+
echo "## Dependabot Auto-fix"
239+
echo ""
240+
echo "- Branch: \`${{ steps.branch.outputs.name }}\`"
241+
if [ -f copilot-output.txt ]; then
242+
if grep -q "NO_OPEN_ALERTS" copilot-output.txt; then
243+
echo "- Result: no open Dependabot alerts; no PR opened."
244+
elif grep -q "BUILD_OR_TEST_FAILED" copilot-output.txt; then
245+
echo "- Result: build or tests failed after fixes; no PR opened."
246+
else
247+
PR_URL=$(grep -Eo 'https://github.com/[^ ]+/pull/[0-9]+' copilot-output.txt | head -n1 || true)
248+
if [ -n "$PR_URL" ]; then
249+
echo "- PR: $PR_URL"
250+
else
251+
echo "- Result: see Copilot session transcript artifact."
252+
fi
253+
fi
254+
else
255+
echo "- Result: Copilot step did not produce output."
256+
fi
257+
} >> "$GITHUB_STEP_SUMMARY"
258+
259+
- name: Upload Copilot session transcript
260+
if: always()
261+
uses: actions/upload-artifact@v4
262+
with:
263+
name: copilot-session-${{ github.run_id }}
264+
path: |
265+
copilot-session.md
266+
copilot-output.txt
267+
retention-days: 14
268+
if-no-files-found: ignore

package-lock.json

Lines changed: 34 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,7 @@
18361836
"@types/jwt-decode": "2.2.0",
18371837
"@types/node-fetch": "^2.6.2",
18381838
"@vscode/extension-telemetry": "^0.6.2",
1839-
"@xmldom/xmldom": "^0.8.12",
1839+
"@xmldom/xmldom": "^0.8.13",
18401840
"cockatiel": "^3.1.1",
18411841
"command-exists": "^1.2.9",
18421842
"find-process": "^1.4.7",
@@ -1852,7 +1852,7 @@
18521852
"stream-http": "^3.2.0",
18531853
"tty-browserify": "^0.0.1",
18541854
"unzip-stream": "^0.3.2",
1855-
"uuid": "^8.3.2",
1855+
"uuid": "^14.0.0",
18561856
"vscode-languageclient": "^7.0.0",
18571857
"vscode-languageserver": "^7.0.0",
18581858
"vscode-languageserver-textdocument": "^1.0.1",

0 commit comments

Comments
 (0)