@@ -122,10 +122,85 @@ jobs:
122122 ;;
123123 esac
124124
125- deploy :
125+ # Surfaces CloudFormation changes in the step summary BEFORE the deploy
126+ # approval gate. Uses a read-only IAM role (no deploy/mutate permissions).
127+ # Configure the 'diff' environment with no required reviewers so it auto-runs;
128+ # gate it later if read-access to stack templates needs approval.
129+ diff :
126130 needs : resolve-targets
127131 if : needs.resolve-targets.outputs.has_targets == 'true'
128132 runs-on : ubuntu-latest
133+ environment : diff
134+ strategy :
135+ matrix :
136+ compute_type : ${{ fromJson(needs.resolve-targets.outputs.matrix) }}
137+ permissions :
138+ id-token : write
139+ contents : read
140+ actions : read
141+ steps :
142+ - name : Checkout
143+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
144+ with :
145+ persist-credentials : false
146+
147+ - name : Download CDK artifact (${{ matrix.compute_type }})
148+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
149+ with :
150+ name : cdk-${{ matrix.compute_type }}-out
151+ path : cdk/
152+ run-id : ${{ needs.resolve-targets.outputs.run_id }}
153+ github-token : ${{ github.token }}
154+
155+ - name : Configure AWS credentials
156+ uses : aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1
157+ with :
158+ role-to-assume : ${{ secrets.AWS_ROLE_TO_ASSUME }}
159+ aws-region : ${{ vars.AWS_REGION }}
160+
161+ - name : Setup Node.js
162+ uses : actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
163+ with :
164+ node-version : 22.x
165+
166+ - name : Install dependencies
167+ run : yarn install --immutable
168+
169+ - name : CDK Diff (full)
170+ env :
171+ COMPUTE_TYPE : ${{ matrix.compute_type }}
172+ run : |
173+ # --method=template: read-only comparison against deployed template;
174+ # no change-set creation, no S3 asset publishing, no deploy role needed.
175+ npx cdk diff --app cdk/cdk.out --all --method=template --no-color 2>&1 | tee cdk-diff-full.txt || true
176+
177+ - name : CDK Diff (security only)
178+ env :
179+ COMPUTE_TYPE : ${{ matrix.compute_type }}
180+ run : |
181+ echo "## Security Changes (\`$COMPUTE_TYPE\`)" >> "$GITHUB_STEP_SUMMARY"
182+ echo "" >> "$GITHUB_STEP_SUMMARY"
183+ npx cdk diff --app cdk/cdk.out --all --method=template --security-only --no-color 2>&1 | tee cdk-diff-security.txt
184+ if [ -s cdk-diff-security.txt ]; then
185+ echo '```' >> "$GITHUB_STEP_SUMMARY"
186+ cat cdk-diff-security.txt >> "$GITHUB_STEP_SUMMARY"
187+ echo '```' >> "$GITHUB_STEP_SUMMARY"
188+ else
189+ echo "No security-relevant changes detected." >> "$GITHUB_STEP_SUMMARY"
190+ fi
191+
192+ - name : Upload diff artifacts
193+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
194+ with :
195+ name : cdk-diff-${{ matrix.compute_type }}
196+ path : |
197+ cdk-diff-full.txt
198+ cdk-diff-security.txt
199+
200+ deploy :
201+ needs : [resolve-targets, diff]
202+ if : needs.resolve-targets.outputs.has_targets == 'true'
203+ runs-on : ubuntu-latest
129204 environment : deploy
130205 concurrency :
131206 group : deploy-${{ matrix.compute_type }}
@@ -174,4 +249,14 @@ jobs:
174249 - name : Deploy
175250 env :
176251 COMPUTE_TYPE : ${{ matrix.compute_type }}
252+ # --require-approval never: CDK hard-fails in non-TTY CI without this
253+ # (throws "terminal (TTY) is not attached"). The approval mechanism is the
254+ # GitHub 'deploy' environment gate above — a human must approve before this
255+ # job starts. The 'diff' job surfaces all CloudFormation and security changes
256+ # in the step summary (visible before approval), and the full diff is
257+ # downloadable as an artifact. Defense in depth:
258+ # 1. diff environment (read-only role) → surfaces changes pre-approval
259+ # 2. deploy environment (required reviewers) → human gate
260+ # 3. fork guard (line 14) → blocks untrusted repositories
261+ # 4. OIDC federation → no stored credentials, request-scoped tokens
177262 run : npx cdk deploy --app cdk/cdk.out --all --require-approval never
0 commit comments