-
Notifications
You must be signed in to change notification settings - Fork 61
187 lines (172 loc) · 8.15 KB
/
Copy pathe2e.yml
File metadata and controls
187 lines (172 loc) · 8.15 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
name: E2E Tests
# PR-triggered e2e uses pull_request_target so fork PRs receive secrets.
# Authorization runs in a separate gate job (base checkout only) before the e2e
# job checks out the PR head — see gate/e2e job comments for why this is split.
permissions: {}
on:
push:
branches: [main]
# SYNC-WITH: grep regex in "Check for e2e-relevant changes" step in the e2e job
paths:
- '**/*.go'
- 'go.mod'
- 'go.sum'
- 'e2e/**'
- 'internal/scaffold/fullsend-repo/**'
- 'internal/security/hooks/**'
- 'internal/dispatch/gcf/mintsrc/**'
- 'internal/sentencetoken/english.json'
- 'Makefile'
- '.github/workflows/e2e.yml'
- '.github/actions/check-e2e-authorization/**'
- 'scripts/check-e2e-authorization.sh'
pull_request_target:
types: [opened, synchronize, reopened, labeled]
merge_group:
workflow_dispatch:
concurrency:
group: >-
${{ github.event_name == 'pull_request_target'
&& format('e2e-{0}', github.event.pull_request.number)
|| format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: >-
${{ github.event_name == 'pull_request_target'
|| github.ref != 'refs/heads/main' }}
jobs:
gate:
# Separate job (not steps in e2e) so pull-requests: write stays out of the
# job that checks out fork head and runs make e2e-test with secrets.
# Never checkout github.event.pull_request.head.sha here.
if: >-
github.event_name == 'pull_request_target' &&
(github.event.action != 'labeled' || github.event.label.name == 'ok-to-test')
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
pull-requests: write
outputs:
authorized: ${{ steps.auth.outputs.authorized }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.sha }} # Base branch only — never checkout PR head in gate
- name: Check PR authorization
id: auth
uses: ./.github/actions/check-e2e-authorization
with:
pr_number: ${{ github.event.pull_request.number }}
repository: ${{ github.repository }}
pr_updated_at: ${{ github.event.pull_request.updated_at }}
event_action: ${{ github.event.action }}
pr_author_association: ${{ github.event.pull_request.author_association }}
pr_author_login: ${{ github.event.pull_request.user.login }}
e2e:
# For pull_request_target, runs only when gate sets authorized=true.
# Do not treat a skipped gate as authorized (e.g. labeled events for non-ok-to-test labels).
# This job checks out untrusted PR head code — no pull-requests: write here.
needs: gate
if: >-
!cancelled() &&
(github.event_name != 'pull_request_target' || needs.gate.outputs.authorized == 'true')
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
id-token: write
steps:
- name: Check for e2e-relevant changes
id: changes
if: github.event_name == 'pull_request_target' || github.event_name == 'merge_group'
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
MERGE_GROUP_BASE: ${{ github.event.merge_group.base_sha }}
MERGE_GROUP_HEAD: ${{ github.event.merge_group.head_sha }}
# SYNC-WITH: push.paths filter above
run: |
if [ "$EVENT_NAME" = "merge_group" ]; then
FILES=$(gh api "repos/${REPO}/compare/${MERGE_GROUP_BASE}...${MERGE_GROUP_HEAD}" --jq '.files[].filename') || {
echo "::warning::Failed to fetch merge group files — running e2e tests as a precaution"
echo "relevant=true" >> "$GITHUB_OUTPUT"
exit 0
}
FILE_COUNT=$(echo "$FILES" | wc -l)
if [ "$FILE_COUNT" -ge 300 ]; then
echo "::warning::Compare API returned $FILE_COUNT files (possible truncation at 300) — running e2e tests as a precaution"
echo "relevant=true" >> "$GITHUB_OUTPUT"
exit 0
fi
else
FILES=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/files" --paginate --jq '.[].filename') || {
echo "::warning::Failed to fetch PR files — running e2e tests as a precaution"
echo "relevant=true" >> "$GITHUB_OUTPUT"
exit 0
}
fi
if echo "$FILES" | grep -qE '\.go$|^go\.(mod|sum)$|^e2e/|^internal/scaffold/fullsend-repo/|^internal/security/hooks/|^internal/dispatch/gcf/mintsrc/|^internal/sentencetoken/english\.json$|^Makefile$|^\.github/workflows/e2e\.yml$|^\.github/actions/check-e2e-authorization/|^scripts/check-e2e-authorization\.sh$'; then
echo "relevant=true" >> "$GITHUB_OUTPUT"
else
echo "::notice::No e2e-relevant files changed — skipping tests"
echo "relevant=false" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
if: steps.changes.outputs.relevant != 'false'
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
# checkout@v7 blocks fork PR head checkouts on pull_request_target by default.
# Safe here: gate job authorizes before this job runs; no pull-requests: write.
allow-unsafe-pr-checkout: ${{ github.event_name == 'pull_request_target' }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
if: steps.changes.outputs.relevant != 'false'
with:
go-version-file: go.mod
- name: Install Playwright system dependencies
if: steps.changes.outputs.relevant != 'false'
run: npx playwright install-deps chromium
- name: Check for secrets
if: steps.changes.outputs.relevant != 'false'
id: secrets-check
run: |
if [ -z "$E2E_GITHUB_SESSION_B64" ]; then
echo "::warning::E2E secrets are not configured. Skipping e2e tests."
echo "available=false" >> "$GITHUB_OUTPUT"
else
echo "available=true" >> "$GITHUB_OUTPUT"
fi
env:
E2E_GITHUB_SESSION_B64: ${{ secrets.E2E_GITHUB_SESSION }}
- name: Decode session
if: steps.changes.outputs.relevant != 'false' && steps.secrets-check.outputs.available == 'true'
run: |
SESSION_FILE="${RUNNER_TEMP}/github-session.json"
printf '%s' "$E2E_GITHUB_SESSION_B64" | base64 -d > "$SESSION_FILE"
echo "E2E_GITHUB_SESSION_FILE=${SESSION_FILE}" >> "$GITHUB_ENV"
env:
E2E_GITHUB_SESSION_B64: ${{ secrets.E2E_GITHUB_SESSION }}
- name: Authenticate to GCP
if: steps.changes.outputs.relevant != 'false' && steps.secrets-check.outputs.available == 'true'
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
workload_identity_provider: ${{ secrets.E2E_GCP_WIF_PROVIDER }}
service_account: ${{ secrets.E2E_GCP_SERVICE_ACCOUNT }}
- name: Run e2e tests
if: steps.changes.outputs.relevant != 'false' && steps.secrets-check.outputs.available == 'true'
run: make e2e-test
env:
E2E_SCREENSHOT_DIR: ${{ runner.temp }}/e2e-screenshots
E2E_GITHUB_PASSWORD: ${{ secrets.E2E_GITHUB_PASSWORD }}
E2E_GITHUB_TOTP_SECRET: ${{ secrets.E2E_GITHUB_TOTP_SECRET }}
E2E_MINT_URL: ${{ secrets.E2E_MINT_URL }}
E2E_GCP_PROJECT_ID: ${{ secrets.E2E_GCP_PROJECT_ID }}
- name: Upload debug screenshots
if: always() && steps.changes.outputs.relevant != 'false' && steps.secrets-check.outputs.available == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-screenshots-${{ github.event_name == 'pull_request_target' && github.event.pull_request.number || github.run_id }}
path: ${{ runner.temp }}/e2e-screenshots/
if-no-files-found: ignore
retention-days: 5