-
Notifications
You must be signed in to change notification settings - Fork 99
320 lines (281 loc) · 10.2 KB
/
ci-integration.yml
File metadata and controls
320 lines (281 loc) · 10.2 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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# Integration tests for PRs (including forks).
# Uses workflow_run to safely access secrets without checking out untrusted PR code.
# Security model:
# - ci.yml builds the PR's code in an unprivileged context and uploads binary artifacts
# - This workflow downloads those artifacts and runs tests from the DEFAULT BRANCH (main)
# - PR code is never checked out in a privileged context
# - Fork PRs require manual environment approval before tests run (security gate)
# - Internal PRs (same repo) skip the approval gate — contributors already have write access
name: Integration Tests (PR)
env:
PYTHON_VERSION: '3.12'
on:
workflow_run:
workflows: ["CI"]
types: [completed]
permissions:
contents: read
actions: read
statuses: write
jobs:
# Fork PRs: require manual approval via environment protection rules.
# A maintainer must review the fork's code before secrets are exposed to its artifacts.
approve-fork:
if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.head_repository.full_name != github.repository
runs-on: ubuntu-latest
environment: integration-tests
steps:
- run: echo "Fork PR approved for ${{ github.event.workflow_run.head_branch }} from ${{ github.event.workflow_run.head_repository.full_name }}"
# Internal PRs: skip approval gate — contributors already have write access to the repo.
approve-internal:
if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.head_repository.full_name == github.repository
runs-on: ubuntu-latest
steps:
- run: echo "Internal PR auto-approved for ${{ github.event.workflow_run.head_branch }}"
smoke-test:
needs: [approve-fork, approve-internal]
# Run if either approval job succeeded (the other will be skipped)
if: always() && (needs.approve-fork.result == 'success' || needs.approve-internal.result == 'success')
runs-on: ${{ matrix.os }}
permissions:
contents: read
actions: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
arch: x86_64
platform: linux
- os: ubuntu-24.04-arm
arch: arm64
platform: linux
- os: macos-15-intel
arch: x86_64
platform: darwin
- os: macos-latest
arch: arm64
platform: darwin
steps:
# Checkout default branch (main) — never PR code
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup build environment (macOS-15 Intel)
if: matrix.os == 'macos-15-intel'
run: |
# Install Xcode Command Line Tools
sudo xcode-select --install 2>/dev/null || true
# Wait for installation to complete
until xcode-select -p >/dev/null 2>&1; do sleep 5; done
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Cache uv environments
uses: actions/cache@v3
with:
path: |
~/.cache/uv
~/.local/share/uv
key: ${{ runner.os }}-uv-${{ hashFiles('**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-uv-
- name: Install dependencies
run: uv sync --extra dev
- name: Run smoke tests
env:
GITHUB_TOKEN: ${{ secrets.GH_MODELS_PAT }}
GITHUB_APM_PAT: ${{ secrets.GH_CLI_PAT }}
run: uv run pytest tests/integration/test_runtime_smoke.py -v
integration-tests:
name: Integration Tests
needs: [smoke-test]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
arch: x86_64
platform: linux
binary_name: apm-linux-x86_64
- os: ubuntu-24.04-arm
arch: arm64
platform: linux
binary_name: apm-linux-arm64
- os: macos-15-intel
arch: x86_64
platform: darwin
binary_name: apm-darwin-x86_64
- os: macos-latest
arch: arm64
platform: darwin
binary_name: apm-darwin-arm64
runs-on: ${{ matrix.os }}
permissions:
contents: read
actions: read
models: read
steps:
# Checkout default branch (main) for test scripts — never PR code
- name: Checkout code
uses: actions/checkout@v4
# Download binary artifact built from PR code by ci.yml
- name: Download APM binary from CI workflow
uses: actions/download-artifact@v4
with:
name: ${{ matrix.binary_name }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup build environment (macOS-15-intel)
if: matrix.os == 'macos-15-intel'
run: |
# Install Xcode Command Line Tools
sudo xcode-select --install 2>/dev/null || true
# Wait for installation to complete
until xcode-select -p >/dev/null 2>&1; do sleep 5; done
- name: Install uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install test dependencies
run: uv sync --extra dev
- name: Run integration tests
env:
APM_E2E_TESTS: "1"
GITHUB_TOKEN: ${{ secrets.GH_MODELS_PAT }}
GITHUB_APM_PAT: ${{ secrets.GH_CLI_PAT }}
ADO_APM_PAT: ${{ secrets.ADO_APM_PAT }}
run: |
chmod +x scripts/test-integration.sh
uv run ./scripts/test-integration.sh
timeout-minutes: 20
release-validation:
name: Release Validation
needs: [integration-tests]
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
arch: x86_64
platform: linux
binary_name: apm-linux-x86_64
- os: ubuntu-24.04-arm
arch: arm64
platform: linux
binary_name: apm-linux-arm64
- os: macos-15-intel
arch: x86_64
platform: darwin
binary_name: apm-darwin-x86_64
- os: macos-latest
arch: arm64
platform: darwin
binary_name: apm-darwin-arm64
runs-on: ${{ matrix.os }}
permissions:
contents: read
actions: read
models: read
steps:
# Checkout default branch for test scripts — never PR code
- name: Checkout test scripts
uses: actions/checkout@v4
with:
sparse-checkout: scripts
path: repo
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup build environment (macOS-15-intel)
if: matrix.os == 'macos-15-intel'
run: |
# Install Xcode Command Line Tools
sudo xcode-select --install 2>/dev/null || true
# Wait for installation to complete
until xcode-select -p >/dev/null 2>&1; do sleep 5; done
# Download binary artifact to isolated test directory
- name: Download APM binary from CI workflow
uses: actions/download-artifact@v4
with:
name: ${{ matrix.binary_name }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: /tmp/apm-isolated-test/
- name: Make binary executable and verify isolation
run: |
cd /tmp/apm-isolated-test
echo "Downloaded structure:"
find . -name "apm" -type f
ls -la ./dist/
chmod +x ./dist/${{ matrix.binary_name }}/apm
- name: Create APM symlink for testing
run: |
cd /tmp/apm-isolated-test
ln -s "$(pwd)/dist/${{ matrix.binary_name }}/apm" "$(pwd)/apm"
echo "/tmp/apm-isolated-test" >> $GITHUB_PATH
- name: Prepare test scripts from default branch
run: |
# Copy test scripts from main branch checkout into isolated test dir
cp -r repo/scripts /tmp/apm-isolated-test/scripts
- name: Run release validation tests
env:
APM_E2E_TESTS: "1"
GITHUB_TOKEN: ${{ secrets.GH_MODELS_PAT }}
GITHUB_APM_PAT: ${{ secrets.GH_CLI_PAT }}
ADO_APM_PAT: ${{ secrets.ADO_APM_PAT }}
run: |
cd /tmp/apm-isolated-test
chmod +x scripts/test-release-validation.sh
./scripts/test-release-validation.sh
timeout-minutes: 20
# Report integration test results back to the PR as a commit status
report-status:
needs: [smoke-test, integration-tests, release-validation]
if: always()
runs-on: ubuntu-latest
permissions:
statuses: write
steps:
- name: Report status to PR
uses: actions/github-script@v7
with:
script: |
const success = '${{ needs.release-validation.result }}' === 'success'
&& '${{ needs.integration-tests.result }}' === 'success'
&& '${{ needs.smoke-test.result }}' === 'success';
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.workflow_run.head_sha,
state: success ? 'success' : 'failure',
target_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
context: 'Integration Tests (PR)',
description: success ? 'All integration tests passed' : 'Integration tests failed'
});