Skip to content

Commit feccf16

Browse files
feat(ci): add deploy.yml workflow triggered by build completion
Adds a deploy workflow that: - Fires on workflow_run after build.yml succeeds - Resolves deploy targets from PR labels (deploy=all, deploy:<type>=one) or defaults to all registered types on push to main - Skips entirely (no approval prompt) when no deploy labels are present - Downloads the exact cdk-<compute_type>-out artifact from the build run - Uses OIDC to assume the CDK bootstrap deploy role - Deploys via `cdk deploy --app cdk/cdk.out --all --require-approval never` - Protected by the `deploy` GitHub environment (manual approval required) - Concurrency: non-cancellable once started, max-parallel 3 Part of #73 Phase 3. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 822a79d commit feccf16

1 file changed

Lines changed: 116 additions & 0 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
name: deploy
2+
on:
3+
# zizmor: ignore[dangerous-triggers] — intentional; workflow_run is required
4+
# for OIDC id-token on PR builds. Mitigations: env-var-only untrusted input,
5+
# least-privilege permissions per job, deploy environment approval gate.
6+
workflow_run:
7+
workflows: [build]
8+
types: [completed]
9+
permissions: {}
10+
jobs:
11+
resolve-targets:
12+
if: github.event.workflow_run.conclusion == 'success'
13+
runs-on: ubuntu-latest
14+
permissions:
15+
actions: read
16+
pull-requests: read
17+
outputs:
18+
matrix: ${{ steps.targets.outputs.matrix }}
19+
has_targets: ${{ steps.targets.outputs.has_targets }}
20+
run_id: ${{ github.event.workflow_run.id }}
21+
steps:
22+
- name: Resolve deploy targets from labels
23+
id: targets
24+
env:
25+
GH_TOKEN: ${{ github.token }}
26+
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
27+
EVENT_TYPE: ${{ github.event.workflow_run.event }}
28+
REPO: ${{ github.repository }}
29+
PR_NUMBER_FROM_EVENT: ${{ github.event.workflow_run.pull_requests[0].number }}
30+
run: |
31+
ALL_TYPES='["agentcore"]'
32+
33+
# Push to main always deploys all registered types
34+
if [[ "$HEAD_BRANCH" == "main" && "$EVENT_TYPE" == "push" ]]; then
35+
echo "matrix=$ALL_TYPES" >> "$GITHUB_OUTPUT"
36+
echo "has_targets=true" >> "$GITHUB_OUTPUT"
37+
exit 0
38+
fi
39+
40+
# For PRs, look up labels via API
41+
if [[ -z "$PR_NUMBER_FROM_EVENT" ]]; then
42+
echo "matrix=[]" >> "$GITHUB_OUTPUT"
43+
echo "has_targets=false" >> "$GITHUB_OUTPUT"
44+
exit 0
45+
fi
46+
47+
LABELS=$(gh api "repos/$REPO/pulls/$PR_NUMBER_FROM_EVENT" --jq '[.labels[].name]')
48+
49+
if echo "$LABELS" | jq -e 'index("deploy:*")' > /dev/null 2>&1; then
50+
echo "matrix=$ALL_TYPES" >> "$GITHUB_OUTPUT"
51+
echo "has_targets=true" >> "$GITHUB_OUTPUT"
52+
elif echo "$LABELS" | jq -e '[.[] | select(startswith("deploy:"))] | length > 0' > /dev/null 2>&1; then
53+
TYPES=$(echo "$LABELS" | jq -c '[.[] | select(startswith("deploy:")) | ltrimstr("deploy:")]')
54+
echo "matrix=$TYPES" >> "$GITHUB_OUTPUT"
55+
echo "has_targets=true" >> "$GITHUB_OUTPUT"
56+
elif echo "$LABELS" | jq -e 'index("deploy")' > /dev/null 2>&1; then
57+
echo "matrix=$ALL_TYPES" >> "$GITHUB_OUTPUT"
58+
echo "has_targets=true" >> "$GITHUB_OUTPUT"
59+
else
60+
echo "matrix=[]" >> "$GITHUB_OUTPUT"
61+
echo "has_targets=false" >> "$GITHUB_OUTPUT"
62+
fi
63+
64+
deploy:
65+
needs: resolve-targets
66+
if: needs.resolve-targets.outputs.has_targets == 'true'
67+
runs-on: ubuntu-latest
68+
environment: deploy
69+
concurrency:
70+
group: deploy-${{ matrix.compute_type }}
71+
cancel-in-progress: false
72+
strategy:
73+
matrix:
74+
compute_type: ${{ fromJson(needs.resolve-targets.outputs.matrix) }}
75+
max-parallel: 3
76+
permissions:
77+
id-token: write
78+
contents: read
79+
actions: read
80+
steps:
81+
- name: Checkout
82+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
83+
with:
84+
persist-credentials: false
85+
86+
- name: Download CDK artifact (${{ matrix.compute_type }})
87+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
88+
with:
89+
name: cdk-${{ matrix.compute_type }}-out
90+
path: cdk/
91+
run-id: ${{ needs.resolve-targets.outputs.run_id }}
92+
github-token: ${{ github.token }}
93+
94+
- name: Configure AWS credentials
95+
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1
96+
with:
97+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
98+
aws-region: ${{ vars.AWS_REGION }}
99+
100+
- name: Install mise
101+
uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1
102+
with:
103+
cache: true
104+
105+
- name: Setup Node.js
106+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
107+
with:
108+
node-version: 22.x
109+
110+
- name: Install dependencies
111+
run: yarn install --immutable
112+
113+
- name: Deploy
114+
env:
115+
COMPUTE_TYPE: ${{ matrix.compute_type }}
116+
run: npx cdk deploy --app cdk/cdk.out --all --require-approval never

0 commit comments

Comments
 (0)