-
Notifications
You must be signed in to change notification settings - Fork 39.3k
Expand file tree
/
Copy pathno-engineering-system-changes.yml
More file actions
149 lines (139 loc) · 9.17 KB
/
no-engineering-system-changes.yml
File metadata and controls
149 lines (139 loc) · 9.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
name: Prevent engineering system changes in PRs
on: pull_request
permissions: {}
jobs:
main:
name: Prevent engineering system changes in PRs
runs-on: ubuntu-latest
steps:
- name: Get file changes
uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b # v1.2.4
id: file_changes
- name: Check if engineering systems were modified
id: engineering_systems_check
run: |
if cat $HOME/files.json | jq -e 'any(test("^\\.github\\/workflows\\/|^build\\/|package\\.json$"))' > /dev/null; then
echo "engineering_systems_modified=true" >> $GITHUB_OUTPUT
echo "Engineering systems were modified in this PR"
else
echo "engineering_systems_modified=false" >> $GITHUB_OUTPUT
echo "No engineering systems were modified in this PR"
fi
- name: Allow automated distro or version field updates
id: bot_field_exception
if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && github.event.pull_request.user.login == 'vs-code-engineering[bot]' }}
run: |
# Allow the vs-code-engineering bot ONLY when:
# 1. package.json is the sole changed file and the diff exclusively
# touches the "distro" or "version" field, OR
# 2. package.json + package-lock.json are the only changed files and
# the package.json diff exclusively touches the "version" field
# (lock file updates are expected from npm install after version bump), OR
# 3. Same as (2) but also including extensions/copilot/package.json
# and extensions/copilot/package-lock.json, where the copilot
# package.json diff only touches "version" and "vscode" fields.
SORTED_FILES=$(jq -e '. | sort' "$HOME/files.json")
ONLY_PKG=$(echo "$SORTED_FILES" | jq -e '. == ["package.json"]' > /dev/null 2>&1 && echo true || echo false)
PKG_AND_LOCK=$(echo "$SORTED_FILES" | jq -e '. == ["package-lock.json", "package.json"]' > /dev/null 2>&1 && echo true || echo false)
PKG_LOCK_AND_COPILOT=$(echo "$SORTED_FILES" | jq -e '. == ["extensions/copilot/package-lock.json", "extensions/copilot/package.json", "package-lock.json", "package.json"]' > /dev/null 2>&1 && echo true || echo false)
if [[ "$ONLY_PKG" != "true" && "$PKG_AND_LOCK" != "true" && "$PKG_LOCK_AND_COPILOT" != "true" ]]; then
echo "Bot modified files beyond package.json (+ package-lock.json + extensions/copilot) — not allowed"
echo "allowed=false" >> $GITHUB_OUTPUT
exit 0
fi
DIFF=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }}) || {
echo "Failed to fetch PR diff — not allowed"
echo "allowed=false" >> $GITHUB_OUTPUT
exit 0
}
# Extract only the root package.json diff section (ignore lock file changes)
PKG_DIFF=$(echo "$DIFF" | awk '/^diff --git a\/package\.json b\/package\.json/{p=1} p && /^diff --git / && !/^diff --git a\/package\.json/{exit} p{print}')
CHANGED_LINES=$(echo "$PKG_DIFF" | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | wc -l)
DISTRO_LINES=$(echo "$PKG_DIFF" | grep -cE '^[+-][[:space:]]*"distro"[[:space:]]*:' || true)
VERSION_LINES=$(echo "$PKG_DIFF" | grep -cE '^[+-][[:space:]]*"version"[[:space:]]*:' || true)
if [[ "$ONLY_PKG" == "true" && "$CHANGED_LINES" -eq 2 && ("$DISTRO_LINES" -eq 2 || "$VERSION_LINES" -eq 2) ]]; then
echo "Distro-only or version-only update by bot — allowing"
echo "allowed=true" >> $GITHUB_OUTPUT
elif [[ ("$PKG_AND_LOCK" == "true" || "$PKG_LOCK_AND_COPILOT" == "true") && "$CHANGED_LINES" -eq 2 && "$VERSION_LINES" -eq 2 ]]; then
# Validate extensions/copilot/package.json when present
if [[ "$PKG_LOCK_AND_COPILOT" == "true" ]]; then
COPILOT_PKG_DIFF=$(echo "$DIFF" | awk '/^diff --git a\/extensions\/copilot\/package\.json b\/extensions\/copilot\/package\.json/{p=1} p && /^diff --git / && !/^diff --git a\/extensions\/copilot\/package\.json/{exit} p{print}')
COPILOT_CHANGED=$(echo "$COPILOT_PKG_DIFF" | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | wc -l)
COPILOT_VERSION=$(echo "$COPILOT_PKG_DIFF" | grep -cE '^[+-][[:space:]]*"version"[[:space:]]*:' || true)
COPILOT_VSCODE=$(echo "$COPILOT_PKG_DIFF" | grep -cE '^[+-][[:space:]]*"vscode"[[:space:]]*:' || true)
if [[ "$COPILOT_CHANGED" -eq 4 && "$COPILOT_VERSION" -eq 2 && "$COPILOT_VSCODE" -eq 2 ]]; then
echo "Version bump with lock file and copilot extension update by bot — allowing"
echo "allowed=true" >> $GITHUB_OUTPUT
else
echo "Copilot package.json changed more than version + vscode fields — not allowed"
echo "allowed=false" >> $GITHUB_OUTPUT
fi
else
echo "Version bump with lock file update by bot — allowing"
echo "allowed=true" >> $GITHUB_OUTPUT
fi
else
echo "Bot changed more than a single allowed field (distro or version) — not allowed"
echo "allowed=false" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Allow cherry-pick bot PRs
id: cherry_pick_exception
if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && steps.bot_field_exception.outputs.allowed != 'true' && github.event.pull_request.user.login == 'vs-code-engineering[bot]' && startsWith(github.event.pull_request.title, '[cherry-pick]') }}
run: |
# The label is applied ~2s after PR creation, so the webhook payload
# may not include it yet. Fetch current labels from the API with retries.
for attempt in 1 2 3; do
if gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels --jq '.[].name' | grep -qx 'cherry-pick-artifact'; then
echo "Cherry-pick PR by vs-code-engineering bot with cherry-pick-artifact label — allowing"
echo "allowed=true" >> $GITHUB_OUTPUT
exit 0
fi
if [ "$attempt" -lt 3 ]; then
echo "cherry-pick-artifact label not present yet (attempt $attempt/3); retrying in 2s"
sleep 2
fi
done
echo "Cherry-pick PR by bot but missing cherry-pick-artifact label after retries — not allowed"
echo "allowed=false" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Determine if engineering system changes are allowed
id: allowed
if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' }}
run: |
if [[ "${{ steps.bot_field_exception.outputs.allowed }}" == "true" || "${{ steps.cherry_pick_exception.outputs.allowed }}" == "true" ]]; then
echo "Engineering system changes are allowed by an exception"
echo "blocked=false" >> $GITHUB_OUTPUT
else
echo "No exception applies — enforcing restrictions"
echo "blocked=true" >> $GITHUB_OUTPUT
fi
- name: Prevent Copilot from modifying engineering systems
if: ${{ steps.allowed.outputs.blocked == 'true' && github.event.pull_request.user.login == 'Copilot' }}
run: |
echo "Copilot is not allowed to modify .github/workflows, build folder files, or package.json files."
echo "If you need to update engineering systems, please do so manually or through authorized means."
exit 1
- uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0
id: get_permissions
if: ${{ steps.allowed.outputs.blocked == 'true' && github.event.pull_request.user.login != 'Copilot' }}
with:
route: GET /repos/microsoft/vscode/collaborators/${{ github.event.pull_request.user.login }}/permission
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set control output variable
id: control
if: ${{ steps.allowed.outputs.blocked == 'true' && github.event.pull_request.user.login != 'Copilot' }}
run: |
echo "user: ${{ github.event.pull_request.user.login }}"
echo "role: ${{ fromJson(steps.get_permissions.outputs.data).permission }}"
echo "is dependabot: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}"
echo "should_run: ${{ !contains(fromJson('["admin", "maintain", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}"
echo "should_run=${{ !contains(fromJson('["admin", "maintain", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) && github.event.pull_request.user.login != 'dependabot[bot]' }}" >> $GITHUB_OUTPUT
- name: Check for engineering system changes
if: ${{ steps.allowed.outputs.blocked == 'true' && steps.control.outputs.should_run == 'true' }}
run: |
echo "Changes to .github/workflows/, build/ folder files, or package.json files aren't allowed in PRs."
exit 1