forked from apache/cloudstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpost-compile.sh
More file actions
executable file
·148 lines (134 loc) · 7.03 KB
/
Copy pathpost-compile.sh
File metadata and controls
executable file
·148 lines (134 loc) · 7.03 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
#!/usr/bin/env bash
# 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.
# Re-applies the token round-robin wiring to the gh-aw generated .lock.yml files,
# which `gh aw compile` doesn't know about. Run after every compile:
#
# gh aw compile && bash .github/scripts/post-compile.sh
#
# Three edits per lock file (see .github/COPILOT_TOKENS.md for the design):
# - point the agent execute step's COPILOT_GITHUB_TOKEN at the pick_copilot_token
# job's output, falling back to the base secret
# - point the agent job's "Redact secrets in logs" step at the same rotated token,
# so a volunteer token is scrubbed from uploaded artifacts, not just the base one
# - make the agent job depend on pick_copilot_token, and strip the self-reference
# gh-aw sometimes adds to pick_copilot_token's own needs (that would be a cycle)
#
# Safe to re-run; a second run is a no-op.
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
# Kept in an env var so perl doesn't try to interpolate the ${{ }} bits.
export NEWVAL='${{ needs.pick_copilot_token.outputs.name != '"'"''"'"' && secrets[format('"'"'COPILOT_GITHUB_TOKEN_{0}'"'"', needs.pick_copilot_token.outputs.name)] || secrets.COPILOT_GITHUB_TOKEN }}'
FILES=(
".github/workflows/weekly-repo-status.lock.yml"
".github/workflows/daily-issue-triage.lock.yml"
)
fail() { echo "ERROR: $1" >&2; exit 1; }
# Fixes up `needs:` for the agent and pick_copilot_token jobs only; gh-aw adds
# pick_copilot_token to several other jobs' needs and those must stay as-is.
# Reads stdin, writes stdout. gh-aw emits inline needs (needs: foo) for single
# dependencies and block form for lists; inline is fine unless it needs editing,
# in which case "INLINE_NEEDS:<job>" is printed to stderr and the caller bails.
normalise_needs() {
awk '
function isjob(l){ return (l ~ /^ [A-Za-z0-9_-]+:[ \t]*$/) }
BEGIN { job=""; inneeds=0; agentpick=0 }
{
line=$0
if (isjob(line)) {
if (inneeds && job=="agent" && !agentpick) print " - pick_copilot_token"
inneeds=0; agentpick=0
name=line; sub(/^ /,"",name); sub(/:[ \t]*$/,"",name); job=name
print line; next
}
if (line ~ /^ needs:[ \t]*[^ \t]/) {
if (job=="agent" && line !~ /pick_copilot_token/) print "INLINE_NEEDS:" job > "/dev/stderr"
if (job=="pick_copilot_token" && line ~ /pick_copilot_token/) print "INLINE_NEEDS:" job > "/dev/stderr"
print line; next
}
if (line ~ /^ needs:[ \t]*$/) { inneeds=1; agentpick=0; print line; next }
if (inneeds) {
if (line ~ /^ - /) {
item=line; sub(/^ - /,"",item); gsub(/[ \t\r]/,"",item)
if (job=="pick_copilot_token" && item=="pick_copilot_token") next
if (job=="agent" && item=="pick_copilot_token") agentpick=1
print line; next
} else {
if (job=="agent" && !agentpick) print " - pick_copilot_token"
inneeds=0
print line; next
}
}
print line
}
END { if (inneeds && job=="agent" && !agentpick) print " - pick_copilot_token" }
'
}
for f in "${FILES[@]}"; do
if [ ! -f "$f" ]; then
echo "WARN: $f not found, run 'gh aw compile' first? Skipping" >&2
continue
fi
# Repoint the agent execute step's token. The anchor is the GH_AW_PHASE: agent env
# var further down the same env block; the detection job's block has
# GH_AW_PHASE: detection so it doesn't match and keeps the base token.
before=$(grep -cF 'COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}' "$f" || true)
perl -0pi -e \
's/^([ \t]*)COPILOT_GITHUB_TOKEN:[ \t]*\$\{\{[ \t]*secrets\.COPILOT_GITHUB_TOKEN[ \t]*\}\}[ \t]*\n(?=(?:[ \t]+[A-Z][A-Za-z0-9_]*:[^\n]*\n)*?[ \t]+GH_AW_PHASE:[ \t]*agent[ \t]*\n)/$1."COPILOT_GITHUB_TOKEN: ".$ENV{NEWVAL}."\n"/me' \
"$f"
after=$(grep -cF 'COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}' "$f" || true)
removed=$(( before - after ))
if [ "$removed" -eq 1 ]; then token_edit="applied"
elif [ "$removed" -eq 0 ] && grep -qE '^[ \t]+COPILOT_GITHUB_TOKEN: \$\{\{ needs\.pick_copilot_token' "$f"; then token_edit="already"
else fail "$f: execute-step token line not patched as expected (removed=$removed), anchor drifted?"
fi
# Repoint the redact step's SECRET_COPILOT_GITHUB_TOKEN the same way; the line is
# unique to the agent job's "Redact secrets in logs" step.
before=$(grep -cF 'SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}' "$f" || true)
if [ "$before" -gt 1 ]; then
fail "$f: expected at most one redact-step SECRET_COPILOT_GITHUB_TOKEN line, found $before"
fi
perl -0pi -e \
's/^([ \t]*)SECRET_COPILOT_GITHUB_TOKEN:[ \t]*\$\{\{[ \t]*secrets\.COPILOT_GITHUB_TOKEN[ \t]*\}\}[ \t]*$/$1."SECRET_COPILOT_GITHUB_TOKEN: ".$ENV{NEWVAL}/me' \
"$f"
after=$(grep -cF 'SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}' "$f" || true)
if [ "$before" -eq 1 ] && [ "$after" -eq 0 ]; then redact_edit="applied"
elif [ "$before" -eq 0 ] && grep -qF 'SECRET_COPILOT_GITHUB_TOKEN: ${{ needs.pick_copilot_token.outputs.name' "$f"; then redact_edit="already"
else fail "$f: redact-step SECRET_COPILOT_GITHUB_TOKEN line not patched (before=$before after=$after)"
fi
errf="$(mktemp)"
normalise_needs < "$f" > "$f.tmp" 2>"$errf"
if grep -q '^INLINE_NEEDS:' "$errf"; then
rm -f "$f.tmp"; rm -f "$errf"
fail "$f: agent/pick_copilot_token have inline 'needs:' that would need editing, update normalise_needs"
fi
rm -f "$errf"
mv "$f.tmp" "$f"
# sanity checks
self_refs=$(awk '
/^ pick_copilot_token:[ \t]*$/{p=1;next}
/^ [A-Za-z0-9_-]+:[ \t]*$/{p=0}
p && /^ - pick_copilot_token[ \t]*$/{c++}
END{print c+0}' "$f")
[ "$self_refs" -eq 0 ] || fail "$f: pick_copilot_token still self-references (cycle)"
awk '/^ agent:[ \t]*$/{a=1} /^ [A-Za-z0-9_-]+:[ \t]*$/ && !/agent/{if(a&&!seen)exit 3} a && /^ - pick_copilot_token/{seen=1} END{exit (seen?0:3)}' "$f" \
|| fail "$f: agent job does not depend on pick_copilot_token"
grep -qF 'Validate COPILOT_GITHUB_TOKEN secret' "$f" || echo "WARN: validate-secret step missing in $f" >&2
grep -qE '^ pick_copilot_token:$' "$f" || echo "WARN: pick_copilot_token job missing in $f, did compile include the .md jobs: block?" >&2
echo "$f: token-ref=$token_edit, redact-ref=$redact_edit, needs=normalised (self-refs=0, agent->pick ok)"
done
echo "Done."