-
Notifications
You must be signed in to change notification settings - Fork 79
191 lines (175 loc) · 8.6 KB
/
Copy pathupdate.yml
File metadata and controls
191 lines (175 loc) · 8.6 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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Keeps the allowlist trio in sync: `actions.yml` (source of truth),
# `.github/actions/for-dependabot-triggered-reviews/action.yml` (the
# composite Dependabot watches), and `approved_patterns.yml` (the
# org-wide allow list). A single concurrency group serialises edits so
# neither direction's change is lost when both files move in overlapping
# pushes (see #866 for the race this prevents).
#
# Also enforces the 800/1000-entry cap on `approved_patterns.yml` inline
# (see the "Check approved actions count" step) — running after
# regeneration and before commit/push, so an over-cap state never lands
# on `main`. The commit-and-push step uses the `ALLOWLIST_WORKFLOW_TOKEN`
# PAT because `main` is a protected branch; see the comment on the
# `token:` input below for the full rationale.
name: Update Allowlist and Composite Action
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "actions.yml"
- ".github/actions/for-dependabot-triggered-reviews/action.yml"
pull_request:
paths:
- ".github/workflows/update.yml"
- ".github/actions/for-dependabot-triggered-reviews/action.yml"
- "actions.yml"
- "gateway/*"
permissions:
contents: read
# Single group across both inputs so no two updates touch the allowlist
# files in parallel. Don't cancel — every queued run must finish so we
# don't drop a dependabot bump or a manual actions.yml edit.
concurrency:
group: "${{ github.ref }}-update"
cancel-in-progress: false
jobs:
update:
runs-on: ubuntu-latest
# `contents: write` is required on push/dispatch so the commit step
# can push the regenerated files back to `main`. The workflow also
# runs on `pull_request`, where GitHub automatically downgrades the
# GITHUB_TOKEN to read-only regardless of what's declared here, so
# PRs from forks can't acquire write access via this workflow.
permissions:
contents: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: true
# The PAT is required because `main` is a protected branch and
# the default `GITHUB_TOKEN` cannot push to it — every push from
# a `GITHUB_TOKEN`-authenticated commit step fails with
# `GH006: Protected branch update failed`. The
# `ALLOWLIST_WORKFLOW_TOKEN` secret is configured with bypass
# rights for this workflow's commit so the regenerated
# `actions.yml`, composite, and `approved_patterns.yml` can
# land. Fallback to `github.token` is only useful for PR/fork
# runs, where the commit step is skipped anyway.
token: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN || github.token }} # zizmor: ignore[secrets-outside-env]
# On push/dispatch, check out the current tip of main rather
# than the trigger SHA. A queued run that started on an older
# SHA would otherwise regenerate from stale inputs and either
# undo the prior run's commit or fail to push.
ref: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && 'main' || '' }}
- run: pipx install uv
- name: Sync composite action, actions.yml, and approved_patterns.yml
run: |
uv run python << 'PYEOF'
import sys
sys.path.append("./gateway/")
import gateway as g
composite = ".github/actions/for-dependabot-triggered-reviews/action.yml"
actions = "actions.yml"
patterns = "approved_patterns.yml"
# Run both directions every time, regardless of which file
# triggered us — the outcome is the same either way.
#
# 1. Pull any new refs from the composite (e.g. dependabot
# bumps) into actions.yml. Additive: existing entries stay
# and get their expiry refreshed.
g.update_actions(composite, actions)
# 2. Regenerate the composite from the (now-merged)
# actions.yml so a manual actions.yml edit is reflected.
g.update_workflow(composite, actions)
# 3. Regenerate the approved patterns from actions.yml.
g.update_patterns(patterns, actions)
PYEOF
- name: Check approved actions count
# The org-wide approved_patterns list has a hard limit of 1000
# entries; we fail at 800 to give maintainers room to act before
# hitting the wall. Runs after regeneration and before
# commit/push, so an over-cap state never lands on main. See
# https://github.com/apache/infrastructure-actions/issues/602
run: |
LIMIT=800
COUNT=$(grep -c '^- ' approved_patterns.yml)
echo "Approved actions count: $COUNT / 1000 (warning threshold: $LIMIT)"
if [ "$COUNT" -ge "$LIMIT" ]; then
echo "::error::Approved actions count ($COUNT) has reached the warning threshold of $LIMIT. The org-wide limit is 1000. Time to clean up unused actions or explore workarounds. See https://github.com/apache/infrastructure-actions/issues/602"
exit 1
fi
- name: Commit and push changes
if: ${{ github.event_name != 'pull_request' }}
env:
# Same PAT as the checkout step above — `main` is a protected
# branch and only the `ALLOWLIST_WORKFLOW_TOKEN` PAT has bypass
# rights for this workflow's automated push. Without it, the
# push fails with `GH006: Protected branch update failed` and
# the regenerated files never land.
GH_TOKEN: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN || github.token }} # zizmor: ignore[secrets-outside-env]
run: |
AUTHOR_NAME=$(gh api /user --jq '.login' 2>/dev/null || echo "asfgit")
AUTHOR_EMAIL=$(gh api /user --jq '.email // "\(.login)@users.noreply.github.com"' 2>/dev/null || echo "asfgit@users.noreply.github.com")
git config --local user.name "${AUTHOR_NAME}"
git config --local user.email "${AUTHOR_EMAIL}"
composite=".github/actions/for-dependabot-triggered-reviews/action.yml"
if git diff --quiet -- actions.yml approved_patterns.yml "${composite}"; then
echo "No changes"
exit 0
fi
git add -f actions.yml approved_patterns.yml "${composite}"
git commit \
-m "Sync actions.yml, composite action, and approved_patterns.yml" \
-m "Generated by .github/workflows/update.yml"
# If a concurrent push (e.g. remove_expired.yml) advanced main
# while we were computing, rebase and retry. The sync script is
# idempotent so re-running on the rebased tree is safe.
for attempt in 1 2 3; do
if git push origin HEAD:main; then
exit 0
fi
echo "Push rejected on attempt ${attempt}; rebasing and re-running sync"
git fetch origin main
git reset --hard origin/main
uv run python << 'PYEOF'
import sys
sys.path.append("./gateway/")
import gateway as g
composite = ".github/actions/for-dependabot-triggered-reviews/action.yml"
actions = "actions.yml"
patterns = "approved_patterns.yml"
g.update_actions(composite, actions)
g.update_workflow(composite, actions)
g.update_patterns(patterns, actions)
PYEOF
if git diff --quiet -- actions.yml approved_patterns.yml "${composite}"; then
echo "Already in sync after rebase; nothing to push"
exit 0
fi
git add -f actions.yml approved_patterns.yml "${composite}"
git commit \
-m "Sync actions.yml, composite action, and approved_patterns.yml" \
-m "Generated by .github/workflows/update.yml"
done
echo "Failed to push after 3 attempts"
exit 1