fix(claude-apps-gateway): make deploy.sh safe to re-run — status-aware pass 1 + destructive-change gate - #288
Conversation
…e pass 1 + destructive-change gate Re-running deploy.sh against an existing stack executed CDK pass 1 (-c imageReady=false) unconditionally. Pass 1 synthesizes a template containing only the ECR repository, so CloudFormation treats the update as 'remove everything else' and tears down the VPC, RDS, ALB, and ECS service of a live deployment. Changes: - Step 1 now switches on the stack STATUS rather than running pass 1 blindly: healthy states skip pass 1, a missing stack runs it, ROLLBACK_COMPLETE fails early with delete-stack recovery commands (CloudFormation cannot update that state), and in-progress states fail with a wait-and-retry message. - Step 2 validates the EcrRepositoryUri output; a partial/rolled-back stack yields '' or 'None', which previously flowed into the CodeBuild IAM policy and failed far from the cause. - The CodeBuild poll now treats FAULT and TIMED_OUT as terminal (previously an infinite loop). - Pass 2 is gated on 'cdk diff': the deploy aborts if the change set would remove or replace any resource, with FORCE_DESTRUCTIVE=1 as the explicit override for intentional changes. diff synth errors are printed before exiting instead of dying silently under set -e. Verified: bash -n; cdk npm test (17/17); branch logic exercised for all stack states; live re-run against an UPDATE_COMPLETE stack lands on the skip path; cdk 2.1133.0 confirmed to exit 0 on diffs without --fail, so the capture is safe under set -e.
|
Thanks for working on this. This is a bug i'd identfied previously and raise a PR to resolve so this overlaps directly with #266 in the same In terms of this PR, I found two blocking issues. The status query fails openSTACK_STATUS=$(... 2>/dev/null || echo "NONE")This maps every The catch-all status branch also gives incorrect recovery advice. The safest shape is to put the narrow allowlist on the destructive branch: run pass 1 only when the stack is absent or known to contain no deployed resources, and skip pass 1 for every other state. That avoids having to maintain a list of every safe and future CloudFormation status. The pass-2 gate rejects routine task-definition replacements
This local repro needs cd claude-apps-gateway/cdk
CTX="-c region=us-east-1 -c gatewayName=claude-gateway -c publicUrl=https://gw.example.com \
-c zoneName=example.com -c zoneId=Z123456789ABCDEFGHIJK -c ingressCidr=10.0.0.0/8 \
-c certArn=arn:aws:acm:us-east-1:111122223333:certificate/abc"
npx cdk synth --quiet -c imageReady=true $CTX -c imageTag=latest -o /tmp/p2
NO_COLOR=1 npx cdk diff --template /tmp/p2/ClaudeGatewayStack.template.json \
-c imageReady=true $CTX -c imageTag=v2 2>&1 |
grep -Ec '^\[-\]|requires replacement|may be replaced'The results were: I also synthesized the admin API edit from root README section 5. Adding CPU, memory, environment, and other legitimate task-definition edits have the same result. The current script avoids the image-tag case only because it pins the mutable The gate also runs after pass 1, while the destructive failure in #287 happens during pass 1. The status decision is the mechanism that fixes #287; the gate cannot protect its own fail-open path. I would drop the gate from this PR. If replacement protection is retained, it needs to distinguish routine task-definition revisions from replacement of stateful resources. Matching only Other changesThe Please add a committed regression test for the status decision. The sample already keeps dependency-free shell tests under Finally, please document the new rerun behavior and any retained override in the script's |
There was a problem hiding this comment.
Withdrawing this review. Deferring to @bluedoors' review above.
Withdrawn — premature approval; deferring to @bluedoors' blocking review.
… states deploy.sh's CodeBuild wait loop only broke out on SUCCEEDED, FAILED and STOPPED. buildStatus is one of SUCCEEDED | FAILED | FAULT | TIMED_OUT | IN_PROGRESS | STOPPED, so a build that faulted or hit the project's timeout left the loop polling a finished build every 10s forever — the deploy never returns and never reports why. Found by Sawit M. in aws-samples#288, which is otherwise superseded by this branch. Co-authored-by: Sawit M. <6754219+peepeepopapapeepeepo@users.noreply.github.com>
|
Thanks for the careful write-up on this. The Taking #266 for the rest, for three reasons:
#266 resolves the pass-1 destruction with a fail-closed status query, a narrow allowlist on the destructive branch, the same Superseded by #266 — I don't have triage rights on this repo to close it here, so a maintainer or you can close it. #287 stays open until #266 merges. |
Fixes #287.
Problem
cdk/scripts/deploy.shran CDK pass 1 (-c imageReady=false) unconditionally. Pass 1 synthesizes a template containing only the ECR repository, so re-running the script against a live stack updates it to that template — CloudFormation removes the VPC, RDS, ALB, ECS service, secrets, and DNS record. Details and repro in #287.Changes (all in
claude-apps-gateway/cdk/scripts/deploy.sh)describe-stacksnow feeds acaseonStackStatusinstead of running pass 1 blindly:CREATE_COMPLETE/UPDATE_COMPLETE/UPDATE_ROLLBACK_COMPLETE→ skip pass 1, go straight to build + pass 2ROLLBACK_COMPLETE(failed first deploy — not updatable) → fail early with the exactdelete-stack+waitrecovery commandsEcrRepositoryUrioutput guard. A partial/rolled-back stack returns""/None; previously that flowed into the CodeBuild IAM policy (repository/None) and failed far from the cause. Now it fails immediately with a pointer to the console.FAULTandTIMED_OUTas failures; previously they spun the loop forever.cdk diffruns first; the deploy aborts if the change set would remove (^\[-\]) or replace (requires replacement/may be replaced) any resource.FORCE_DESTRUCTIVE=1overrides for intentional changes (e.g. dropping VPC endpoints afterCREATE_VPC_ENDPOINTS=false). The match is deliberately narrow — a barereplacegrep would trip on cdk's own boilerplate line on every run. Synth errors are echoed before exiting instead of dying silently underset -e(cdk diffexits 0 on mere differences unless--fail; verified on 2.1133.0).Testing
bash -nclean.cdksuite:npm test— 17/17 pass (no template changes; script-only).NONE, all three healthy states,ROLLBACK_COMPLETE, and in-progress states.UPDATE_COMPLETEdeployment (ap-southeast-7) lands on the skip path and proceeds to build + pass 2.By submitting this pull request, I confirm that my contribution is made under the terms of the repository's license.