fix(cli): grant s3 encryption actions in lambda policies user output (#2289)

`hyperframes lambda deploy` runs `sam deploy --resolve-s3`, and SAM's
managed artifacts bucket (aws-sam-cli-managed-default) is created with
default SSE encryption. Setting that requires s3:PutEncryptionConfiguration,
which the generated deploy policy did not grant, so a first deploy by a
user provisioned exactly per `lambda policies user` 403s on the bucket and
the managed stack rolls back.

Add s3:GetEncryptionConfiguration and s3:PutEncryptionConfiguration to the
s3Bucket action set (Get pairs with Put for CloudFormation update/drift
reads, matching the existing Get/Put pairs in the list). Also add a hint to
the sam-deploy failure path pointing at the ROLLBACK_COMPLETE recovery step,
since first-time users hit the stuck-rollback error on their retry.

Fixes #2137

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
James Russo
2026-07-11 21:36:17 -07:00
committed by GitHub
co-authored by Claude Opus 4.8
parent ebbd1eb2c2
commit f1f317a20c
3 changed files with 18 additions and 1 deletions
@@ -32,6 +32,10 @@ describe("policies — required actions", () => {
"lambda:CreateFunction",
"states:StartExecution",
"s3:PutObject",
// SAM's --resolve-s3 managed bucket is encrypted; the deploy user must
// be able to set/read that encryption or the first deploy rolls back.
"s3:PutEncryptionConfiguration",
"s3:GetEncryptionConfiguration",
"iam:CreateRole",
"logs:CreateLogGroup",
"cloudwatch:PutMetricAlarm",
@@ -123,12 +123,18 @@ const REQUIRED_ACTIONS = {
"s3:GetBucketPolicy",
"s3:GetBucketTagging",
"s3:GetBucketVersioning",
// SAM's `--resolve-s3` managed bucket (aws-sam-cli-managed-default) sets
// default SSE encryption; CloudFormation reads it on update/drift. Without
// Get/PutEncryptionConfiguration the first `lambda deploy` 403s creating
// that bucket and the managed stack rolls back.
"s3:GetEncryptionConfiguration",
"s3:GetLifecycleConfiguration",
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:PutBucketPolicy",
"s3:PutBucketTagging",
"s3:PutBucketVersioning",
"s3:PutEncryptionConfiguration",
"s3:PutLifecycleConfiguration",
"s3:PutPublicAccessBlock",
],
+8 -1
View File
@@ -106,7 +106,14 @@ export function samDeploy(opts: DeployOptions): void {
const samDir = join(opts.repoRoot, "examples", "aws-lambda");
const result = spawnSync("sam", args, { cwd: samDir, stdio: opts.stdio ?? "inherit" });
if (result.status !== 0) {
throw new Error(`[lambda] sam deploy exited with code ${result.status ?? "unknown"}`);
throw new Error(
`[lambda] sam deploy exited with code ${result.status ?? "unknown"}\n` +
`If a prior attempt left a stack in ROLLBACK_COMPLETE, CloudFormation can't reuse it. ` +
`Delete it before retrying:\n` +
` aws cloudformation delete-stack --stack-name aws-sam-cli-managed-default --region ${opts.region}\n` +
` aws cloudformation delete-stack --stack-name ${opts.stackName} --region ${opts.region}\n` +
`(the first is SAM's managed artifacts stack from --resolve-s3; the second is the render stack).`,
);
}
}