Skip to content

Conversation

@pahud
Copy link
Contributor

@pahud pahud commented Jan 21, 2026

Issue # (if applicable)

Closes #7090.

Reason for this change

Users serving pre-compressed static websites from S3+CloudFront need to set different Content-Encoding headers based on file extension. Currently, the contentEncoding property applies a single encoding to ALL files in the deployment, which breaks browser decompression when serving mixed content (e.g., .br files with Brotli, .gz files with Gzip, and uncompressed files).

The current workaround requires creating multiple BucketDeployment constructs with prune: false and complex exclude/include filters, resulting in:

  • Multiple Lambda invocations (increased cost and deployment time)
  • Inability to use the pruning feature
  • Complex, error-prone configuration

This feature has strong community interest with 19 👍 reactions on the issue (open since March 2020).

Description of changes

Added a new contentEncodingByExtension property to BucketDeploymentProps that accepts an array of file pattern to encoding mappings. The Lambda handler executes multiple aws s3 sync commands with appropriate --include/--exclude filters and --content-encoding values.

Key changes:

  • Added ContentEncodingMapping interface with include (file pattern) and encoding (Content-Encoding value) properties
  • Added contentEncodingByExtension optional property to BucketDeploymentProps
  • Modified Lambda handler to run multiple sync commands:
    1. First sync excludes files matching encoding patterns (with prune if enabled)
    2. Subsequent syncs handle each encoding pattern with its specific Content-Encoding header
  • Added comprehensive unit tests (5 new tests)
  • Updated README.md with documentation and usage examples

Usage example:

new s3deploy.BucketDeployment(this, 'DeployWebsite', {
  sources: [s3deploy.Source.asset('./website')],
  destinationBucket: bucket,
  contentEncodingByExtension: [
    { include: '*.br', encoding: 'br' },
    { include: '*.gz', encoding: 'gzip' },
  ],
});

Files modified:

File Changes
packages/aws-cdk-lib/aws-s3-deployment/lib/bucket-deployment.ts Added ContentEncodingMapping interface and contentEncodingByExtension property
packages/@aws-cdk/custom-resource-handlers/lib/aws-s3-deployment/bucket-deployment-handler/index.py Added multi-sync logic for per-extension encoding
packages/aws-cdk-lib/aws-s3-deployment/test/bucket-deployment.test.ts Added 5 new unit tests
packages/aws-cdk-lib/aws-s3-deployment/README.md Added documentation section

Describe any new or updated permissions being added

N/A - No IAM permission changes. The Lambda handler continues to use the same S3 permissions it already has for the s3 sync operation.

Description of how you validated changes

  • Unit tests: Added 5 new unit tests covering:
    • contentEncodingByExtension property is passed to custom resource
    • contentEncodingByExtension with single mapping
    • contentEncodingByExtension is not set when not specified
    • contentEncodingByExtension can be used with other system metadata
    • contentEncodingByExtension with directory pattern
  • Build validation: TypeScript compilation successful, no linting errors
  • Test results: All 85 tests passed (including 5 new tests)

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@github-actions github-actions bot added effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2 labels Jan 21, 2026
@aws-cdk-automation aws-cdk-automation requested a review from a team January 21, 2026 21:17
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Jan 21, 2026
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pull request linter fails with the following errors:

❌ Features must contain a change to an integration test file and the resulting snapshot.

If you believe this pull request should receive an exemption, please comment and provide a justification. A comment requesting an exemption should contain the text Exemption Request. Additionally, if clarification is needed, add Clarification Request to a comment.

@pahud
Copy link
Contributor Author

pahud commented Jan 23, 2026

This PR is going to have impact on existing deployment. I think we should consider #36790 before we are able to continue this PR to minimize the risk on existing deployments.

pahud added 3 commits January 24, 2026 10:08
- Add ContentEncodingByExtension property to enable file-specific Content-Encoding headers based on extension patterns
- Implement s3_deploy_with_encoding_by_extension function to handle multiple sync commands with different encodings
- Update bucket deployment handler to parse and pass content encoding configuration
- Modify sync logic to exclude encoded files from main sync and apply per-extension encoding in separate syncs
- Add comprehensive documentation and examples for the new content encoding feature
- Include test coverage for content encoding by extension scenarios
- Allows users to apply different Content-Encoding headers (e.g., gzip, brotli) to files matching specific patterns during deployment
…puts

- Add validateContentEncodingByExtension() method to validate encoding values and patterns
- Validate encoding values against standard HTTP Content-Encoding values (br, gzip, compress, deflate, identity, zstd)
- Validate include patterns contain only safe glob characters and reject path traversal sequences
- Add comprehensive test coverage for invalid encoding values, invalid pattern characters, and path traversal attempts
- Add tests verifying valid patterns with glob characters and case-insensitive encoding values
- Improve security by preventing injection attacks through pattern validation
- Switch from allowlist to blocklist for pattern validation (allows glob patterns like brackets/braces)
- Add comprehensive path traversal detection with normalized path segments
- Non-standard encodings now warn instead of error, vendor extensions (x-*) accepted
- Add array-level and object-level token checks for better CDK Token handling
- Add warning when catch-all patterns used with contentEncoding property
- Add runtime validation in Python handler as defense-in-depth
- Update binary asset snapshots for bucket deployment integration tests
- Reorganize asset file paths to consolidate common dependencies
- Refresh CloudFormation templates and manifests across all test suites
- Update tree.json and assets.json files to reflect latest deployment configurations
- Consolidate Python and JavaScript handler assets across multiple test scenarios
@github-actions
Copy link
Contributor

github-actions bot commented Jan 24, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results480 ran480 passed
TestResult
No test annotations available

@github-actions
Copy link
Contributor

github-actions bot commented Jan 24, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ☑️SkippedFailed ❌️
Security Guardian Results with resolved templates480 ran477 passed3 failed
TestResult
Security Guardian Results with resolved templates
packages/@aws-cdk-testing/framework-integ/test/aws-codepipeline-actions/test/integ.pipeline-commands.js.snapshot/aws-cdk-codepipeline-commands.template.json
iam-role-root-principal-needs-conditions.guard❌ failure
packages/@aws-cdk-testing/framework-integ/test/aws-codepipeline-actions/test/integ.pipeline-ecr-image-scan-action.js.snapshot/codepipeline-ecr-image-scan-action.template.json
iam-role-root-principal-needs-conditions.guard❌ failure
packages/@aws-cdk-testing/framework-integ/test/aws-codepipeline-actions/test/integ.pipeline-elastic-beanstalk-deploy.js.snapshot/aws-cdk-codepipeline-elastic-beanstalk-deploy.template.json
iam-role-root-principal-needs-conditions.guard❌ failure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution/core This is a PR that came from AWS. effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

S3 Bucket Deployments with content encoding based on file extension.

2 participants