Repository navigation
146 lines (143 loc) · 5.82 KB
/
Copy pathintegration-test.yml
File metadata and controls
146 lines (143 loc) · 5.82 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
name: Secure Integration test
on:
pull_request_target:
branches: main
# workflow_call entry — TRUST INVARIANT.
#
# Lets another workflow in this repo reuse the integ tests against an
# arbitrary `ref` while keeping AWS_*. The collaborator check below is
# short-circuited on this path because the only caller (release.yml) is
# workflow_dispatch-gated, which already requires repo write access.
#
# Before adding another caller, check all of:
# 1. Cannot be triggered by an unauthenticated user or a fork
# (no pull_request; no pull_request_target without an auth gate;
# no push from non-main branches).
# 2. Cannot be coerced into a fork-PR ref. validate-call-ref below is
# the runtime guard, but condition 1 should make that unnecessary.
# 3. STRANDS_INTEG_TEST_ROLE is scoped to least privilege.
workflow_call:
inputs:
ref:
required: true
type: string
jobs:
validate-call-ref:
name: Validate workflow_call ref
if: inputs.ref != ''
runs-on: ubuntu-latest
permissions:
contents: read
# Reject ref shapes that could check out untrusted code:
# `refs/pull/*` (fork-PR merge refs) and `owner:branch` (cross-repo
# refs) fail; plain branches and SHAs pass.
steps:
- name: Reject untrusted-shaped refs
env:
REF: ${{ inputs.ref }}
run: |
set -euo pipefail
case "$REF" in
refs/pull/*|*:*)
echo "::error::workflow_call ref '$REF' looks like a fork PR or cross-repo ref."
exit 1
;;
esac
echo "ref '$REF' passed shape check."
authorization-check:
name: Check access
needs: [validate-call-ref]
# `needs` only runs after non-skipped predecessors. validate-call-ref is
# skipped on pull_request_target (inputs.ref is empty), so use
# `if: always()` to ensure this still runs there. On workflow_call,
# validate-call-ref must have succeeded.
if: |
always() &&
(needs.validate-call-ref.result == 'success' || needs.validate-call-ref.result == 'skipped')
# Kept within what the workflow_call caller (release.yml's `integ` job)
# grants — a called workflow's job cannot request more than the caller.
# The collaborator lookup only needs repo read.
permissions:
contents: read
pull-requests: read
runs-on: ubuntu-latest
outputs:
approval-env: ${{ steps.collab-check.outputs.result }}
steps:
- name: Collaborator Check
uses: actions/github-script@v9
id: collab-check
env:
# Only a workflow_call caller (release.yml) sets this; empty on
# pull_request_target. When set, skip the collaborator lookup — the
# caller is workflow_dispatch-gated and already requires write access.
CALL_REF: ${{ inputs.ref }}
with:
result-encoding: string
script: |
if (process.env.CALL_REF) {
console.log("workflow_call path (release); skipping collaborator check.")
return "auto-approve"
}
try {
const permissionResponse = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.payload.pull_request.user.login,
});
const permission = permissionResponse.data.permission;
const hasWriteAccess = ['write', 'admin'].includes(permission);
if (!hasWriteAccess) {
console.log(`User ${context.payload.pull_request.user.login} does not have write access to the repository (permission: ${permission})`);
return "manual-approval"
} else {
console.log(`Verifed ${context.payload.pull_request.user.login} has write access. Auto Approving PR Checks.`)
return "auto-approve"
}
} catch (error) {
console.log(`${context.payload.pull_request.user.login} does not have write access. Requiring Manual Approval to run PR Checks.`)
return "manual-approval"
}
check-access-and-checkout:
name: Run integration tests
runs-on: ubuntu-latest
needs: authorization-check
if: always() && needs.authorization-check.result == 'success'
environment: ${{ needs.authorization-check.outputs.approval-env }}
permissions:
id-token: write
pull-requests: read
contents: read
steps:
- name: Configure Credentials
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }}
aws-region: us-east-1
mask-aws-account-id: true
- name: Checkout head commit
uses: actions/checkout@v7
with:
# On workflow_call (release) use the pinned ref; on
# pull_request_target pull the PR head from the forked repo.
ref: ${{ inputs.ref || github.event.pull_request.head.sha }}
persist-credentials: false # Don't persist credentials for subsequent actions
# Opt back into fork-PR checkout, blocked by default in checkout@v7.
# Safe here: the authorization-check job gates external contributors
# behind the manual-approval environment before this job runs.
allow-unsafe-pr-checkout: true
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install --no-cache-dir hatch
- name: Run integration tests
env:
AWS_REGION: us-east-1
AWS_REGION_NAME: us-east-1
STRANDS_TEST_API_KEYS_SECRET_NAME: ${{ secrets.STRANDS_TEST_API_KEYS_SECRET_NAME }}
id: tests
run: |
hatch test tests_integ