Repository navigation
103 lines (91 loc) · 4.32 KB
/
Copy pathretest.yaml
File metadata and controls
103 lines (91 loc) · 4.32 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
# Hardened /retest workflow for stacklok/toolhive
#
# Comment "/retest" on a PR to re-run its failed GitHub Actions workflow runs.
#
# Security notes (see also the inline comments below):
# - issue_comment workflows ALWAYS execute the copy of this file on the
# default branch, never the version in the PR. A malicious PR cannot alter
# this workflow to steal the token. Review/protect this file on `main`.
# - The job uses the ephemeral, auto-revoked GITHUB_TOKEN (NOT a PAT/App key).
# Its only powers here are: re-run workflow runs in THIS repo, and
# react to the triggering comment. It cannot read secrets, push code, or
# change settings.
# - Triggering is gated to org members/collaborators so arbitrary public
# users cannot replay CI, and the comment body must contain "/retest".
# - No third-party action holds the token: the re-run is a few lines of
# `gh api` calls owned in this repo. (We previously used
# envoyproxy/toolshed retest, but that action assumes check runs carry a
# populated output.title/text — true for its AZP/App checks but null for
# plain GitHub Actions checks — so it crashed on a null dereference.)
#
# BEFORE enabling, confirm there is NO privileged/side-effecting workflow
# (pull_request_target, deploy, release, publish, etc.) on this repo's PRs that
# a /retest could replay with secrets. We re-run existing failed runs on the PR
# head; for normal fork pull_request runs that is sandboxed and safe.
name: Retest Action on PR Comment
on:
# Required for /retest; trusted authors can only rerun pull_request workflows.
# No PR checkout or execution; event values are passed through quoted env vars.
issue_comment: # zizmor: ignore[dangerous-triggers]
types: [created]
# Default everything to read-only; the job below opts into the minimum it needs.
permissions:
contents: read
jobs:
retest:
name: Retest
runs-on: ubuntu-26.04
# Only run for PR comments containing "/retest", in this repo, from a
# trusted author, and not bots.
if: >-
${{
github.event.issue.pull_request
&& github.repository == 'stacklok/toolhive'
&& contains(github.event.comment.body, '/retest')
&& contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'),
github.event.comment.author_association)
&& github.actor != 'dependabot[bot]'
&& github.actor != 'github-actions[bot]'
}}
permissions:
actions: write # re-run failed workflow runs
pull-requests: write # react to the triggering comment
steps:
- name: Re-run failed workflow runs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.issue.pull_request.url }}
COMMENT_ID: ${{ github.event.comment.id }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
react() { gh api -X POST "repos/$REPO/issues/comments/$COMMENT_ID/reactions" -f content="$1" >/dev/null; }
# Acknowledge immediately so the commenter gets feedback.
react eyes
head_sha=$(gh api "$PR_URL" --jq '.head.sha')
# Capture the query separately so a transient API failure surfaces as
# an error (set -e) rather than being mistaken for "nothing to retry".
# Only replay pull_request CI, never push, release, or other privileged runs.
runs_json=$(gh api "repos/$REPO/actions/runs?event=pull_request&head_sha=$head_sha&per_page=100")
mapfile -t run_ids < <(jq -r \
'.workflow_runs[] | select(.conclusion=="failure" or .conclusion=="cancelled" or .conclusion=="timed_out") | .id' \
<<<"$runs_json")
if [ ${#run_ids[@]} -eq 0 ]; then
echo "No failed runs to retry"
react confused
exit 0
fi
failures=0
for id in "${run_ids[@]}"; do
echo "Re-running failed jobs for run $id"
if ! gh api -X POST "repos/$REPO/actions/runs/$id/rerun-failed-jobs" >/dev/null; then
echo "::warning::Could not re-run $id (too old or not retryable)"
failures=$((failures + 1))
fi
done
if [ "$failures" -eq "${#run_ids[@]}" ]; then
echo "All re-run attempts failed"
react confused
exit 1
fi
react rocket