agent-claw: automated task changes

This commit is contained in:
daniel
2026-05-06 18:55:16 -05:00
parent 38905bb1e9
commit 732b00fb66
8494 changed files with 2018127 additions and 4 deletions

View File

@@ -0,0 +1,13 @@
{
"targets": {
"java": {
"package": "software.amazon.awscdk.services.s3.deployment"
},
"dotnet": {
"namespace": "Amazon.CDK.AWS.S3.Deployment"
},
"python": {
"module": "aws_cdk.aws_s3_deployment"
}
}
}

View File

@@ -0,0 +1,627 @@
# AWS S3 Deployment Construct Library
This library allows populating an S3 bucket with the contents of .zip files
from other S3 buckets or from local disk.
The following example defines a publicly accessible S3 bucket with web hosting
enabled and populates it from a local directory on disk.
```ts
const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', {
websiteIndexDocument: 'index.html',
publicReadAccess: true,
});
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket: websiteBucket,
destinationKeyPrefix: 'web/static', // optional prefix in destination bucket
});
```
This is what happens under the hood:
1. When this stack is deployed (either via `cdk deploy` or via CI/CD), the
contents of the local `website-dist` directory will be archived and uploaded
to an intermediary assets bucket (the `StagingBucket` of the CDK bootstrap stack).
If there is more than one source, they will be individually uploaded.
2. The `BucketDeployment` construct synthesizes a Lambda-backed custom CloudFormation resource
of type `Custom::CDKBucketDeployment` into the template. The source bucket/key
is set to point to the assets bucket.
3. The custom resource invokes its associated Lambda function, which downloads the .zip archive,
extracts it and issues `aws s3 sync --delete` against the destination bucket (in this case
`websiteBucket`). If there is more than one source, the sources will be
downloaded and merged pre-deployment at this step.
If you are referencing the filled bucket in another construct that depends on
the files already be there, be sure to use `deployment.deployedBucket`. This
will ensure the bucket deployment has finished before the resource that uses
the bucket is created:
```ts
declare const websiteBucket: s3.Bucket;
const deployment = new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))],
destinationBucket: websiteBucket,
});
new ConstructThatReadsFromTheBucket(this, 'Consumer', {
// Use 'deployment.deployedBucket' instead of 'websiteBucket' here
bucket: deployment.deployedBucket,
});
```
It is also possible to add additional sources using the `addSource` method.
```ts
declare const websiteBucket: s3.IBucket;
const deployment = new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket: websiteBucket,
destinationKeyPrefix: 'web/static', // optional prefix in destination bucket
});
deployment.addSource(s3deploy.Source.asset('./another-asset'));
```
For the Lambda function to download object(s) from the source bucket, besides the obvious
`s3:GetObject*` permissions, the Lambda's execution role needs the `kms:Decrypt` and `kms:DescribeKey`
permissions on the KMS key that is used to encrypt the bucket. By default, when the source bucket is
encrypted with the S3 managed key of the account, these permissions are granted by the key's
resource-based policy, so they do not need to be on the Lambda's execution role policy explicitly.
However, if the encryption key is not the s3 managed one, its resource-based policy is quite likely
to NOT grant such KMS permissions. In this situation, the Lambda execution will fail with an error
message like below:
```txt
download failed: ...
An error occurred (AccessDenied) when calling the GetObject operation:
User: *** is not authorized to perform: kms:Decrypt on the resource associated with this ciphertext
because no identity-based policy allows the kms:Decrypt action
```
When this happens, users can use the public `handlerRole` property of `BucketDeployment` to manually
add the KMS permissions:
```ts
declare const destinationBucket: s3.Bucket;
const deployment = new s3deploy.BucketDeployment(this, 'DeployFiles', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'source-files'))],
destinationBucket,
});
deployment.handlerRole.addToPolicy(
new iam.PolicyStatement({
actions: ['kms:Decrypt', 'kms:DescribeKey'],
effect: iam.Effect.ALLOW,
resources: ['<encryption key ARN>'],
}),
);
```
The situation above could arise from the following scenarios:
- User created a customer managed KMS key and passed its ID to the `cdk bootstrap` command via
the `--bootstrap-kms-key-id` CLI option.
The [default key policy](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-root-enable-iam)
alone is not sufficient to grant the Lambda KMS permissions.
- A corporation uses its own custom CDK bootstrap process, which encrypts the CDK `StagingBucket`
by a KMS key from a management account of the corporation's AWS Organization. In this cross-account
access scenario, the KMS permissions must be explicitly present in the Lambda's execution role policy.
- One of the sources for the `BucketDeployment` comes from the `Source.bucket` static method, which
points to a bucket whose encryption key is not the S3 managed one, and the resource-based policy
of the encryption key is not sufficient to grant the Lambda `kms:Decrypt` and `kms:DescribeKey`
permissions.
## Supported sources
The following source types are supported for bucket deployments:
- Local .zip file: `s3deploy.Source.asset('/path/to/local/file.zip')`
- Local directory: `s3deploy.Source.asset('/path/to/local/directory')`
- Another bucket: `s3deploy.Source.bucket(bucket, zipObjectKey)`
- String data: `s3deploy.Source.data('object-key.txt', 'hello, world!')`
(supports [deploy-time values](#data-with-deploy-time-values))
- JSON data: `s3deploy.Source.jsonData('object-key.json', { json: 'object' })`
(supports [deploy-time values](#data-with-deploy-time-values))
- YAML data: `s3deploy.Source.yamlData('object-key.yaml', { yaml: 'object' })`
(supports [deploy-time values](#data-with-deploy-time-values))
To create a source from a single file, you can pass `AssetOptions` to exclude
all but a single file:
- Single file: `s3deploy.Source.asset('/path/to/local/directory', { exclude: ['**', '!onlyThisFile.txt'] })`
**IMPORTANT** The `aws-s3-deployment` module is only intended to be used with
zip files from trusted sources. Directories bundled by the CDK CLI (by using
`Source.asset()` on a directory) are safe. If you are using `Source.asset()` or
`Source.bucket()` to reference an existing zip file, make sure you trust the
file you are referencing. Zips from untrusted sources might be able to execute
arbitrary code in the Lambda Function used by this module, and use its permissions
to read or write unexpected files in the S3 bucket.
## Retain on Delete
By default, the contents of the destination bucket will **not** be deleted when the
`BucketDeployment` resource is removed from the stack or when the destination is
changed. You can use the option `retainOnDelete: false` to disable this behavior,
in which case the contents will be deleted.
Configuring this has a few implications you should be aware of:
- **Logical ID Changes**
Changing the logical ID of the `BucketDeployment` construct, without changing the destination
(for example due to refactoring, or intentional ID change) **will result in the deletion of the objects**.
This is because CloudFormation will first create the new resource, which will have no affect,
followed by a deletion of the old resource, which will cause a deletion of the objects,
since the destination hasn't changed, and `retainOnDelete` is `false`.
- **Destination Changes**
When the destination bucket or prefix is changed, all files in the previous destination will **first** be
deleted and then uploaded to the new destination location. This could have availability implications
on your users.
### General Recommendations
#### Shared Bucket
If the destination bucket **is not** dedicated to the specific `BucketDeployment` construct (i.e shared by other entities),
we recommend to always configure the `destinationKeyPrefix` property. This will prevent the deployment from
accidentally deleting data that wasn't uploaded by it.
#### Dedicated Bucket
If the destination bucket **is** dedicated, it might be reasonable to skip the prefix configuration,
in which case, we recommend to remove `retainOnDelete: false`, and instead, configure the
[`autoDeleteObjects`](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-s3-readme.html#bucket-deletion)
property on the destination bucket. This will avoid the logical ID problem mentioned above.
## Prune
By default, files in the destination bucket that don't exist in the source will be deleted
when the `BucketDeployment` resource is created or updated. You can use the option `prune: false` to disable
this behavior, in which case the files will not be deleted.
```ts
declare const destinationBucket: s3.Bucket;
new s3deploy.BucketDeployment(this, 'DeployMeWithoutDeletingFilesOnDestination', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))],
destinationBucket,
prune: false,
});
```
This option also enables you to
multiple bucket deployments for the same destination bucket & prefix,
each with its own characteristics. For example, you can set different cache-control headers
based on file extensions:
```ts
declare const destinationBucket: s3.Bucket;
new s3deploy.BucketDeployment(this, 'BucketDeployment', {
sources: [s3deploy.Source.asset('./website', { exclude: ['index.html'] })],
destinationBucket,
cacheControl: [
s3deploy.CacheControl.maxAge(Duration.days(365)),
s3deploy.CacheControl.immutable(),
],
prune: false,
});
new s3deploy.BucketDeployment(this, 'HTMLBucketDeployment', {
sources: [s3deploy.Source.asset('./website', { exclude: ['*', '!index.html'] })],
destinationBucket,
cacheControl: [
s3deploy.CacheControl.maxAge(Duration.seconds(0)),
],
prune: false,
});
```
## Exclude and Include Filters
There are two points at which filters are evaluated in a deployment: asset bundling and the actual deployment. If you simply want to exclude files in the asset bundling process, you should leverage the `exclude` property of `AssetOptions` when defining your source:
```ts
declare const destinationBucket: s3.Bucket;
new s3deploy.BucketDeployment(this, 'HTMLBucketDeployment', {
sources: [s3deploy.Source.asset('./website', { exclude: ['*', '!index.html'] })],
destinationBucket,
});
```
If you want to specify filters to be used in the deployment process, you can use the `exclude` and `include` filters on `BucketDeployment`. If excluded, these files will not be deployed to the destination bucket. In addition, if the file already exists in the destination bucket, it will not be deleted if you are using the `prune` option:
```ts
declare const destinationBucket: s3.Bucket;
new s3deploy.BucketDeployment(this, 'DeployButExcludeSpecificFiles', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))],
destinationBucket,
exclude: ['*.txt'],
});
```
These filters follow the same format that is used for the AWS CLI. See the CLI documentation for information on [Using Include and Exclude Filters](https://docs.aws.amazon.com/cli/latest/reference/s3/index.html#use-of-exclude-and-include-filters).
## Objects metadata
You can specify metadata to be set on all the objects in your deployment.
There are 2 types of metadata in S3: system-defined metadata and user-defined metadata.
System-defined metadata have a special purpose, for example cache-control defines how long to keep an object cached.
User-defined metadata are not used by S3 and keys always begin with `x-amz-meta-` (this prefix is added automatically).
System defined metadata keys include the following:
- cache-control (`--cache-control` in `aws s3 sync`)
- content-disposition (`--content-disposition` in `aws s3 sync`)
- content-encoding (`--content-encoding` in `aws s3 sync`)
- content-language (`--content-language` in `aws s3 sync`)
- content-type (`--content-type` in `aws s3 sync`)
- expires (`--expires` in `aws s3 sync`)
- x-amz-storage-class (`--storage-class` in `aws s3 sync`)
- x-amz-website-redirect-location (`--website-redirect` in `aws s3 sync`)
- x-amz-server-side-encryption (`--sse` in `aws s3 sync`)
- x-amz-server-side-encryption-aws-kms-key-id (`--sse-kms-key-id` in `aws s3 sync`)
- x-amz-server-side-encryption-customer-algorithm (`--sse-c-copy-source` in `aws s3 sync`)
- x-amz-acl (`--acl` in `aws s3 sync`)
You can find more information about system defined metadata keys in
[S3 PutObject documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)
and [`aws s3 sync` documentation](https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html).
```ts
const websiteBucket = new s3.Bucket(this, 'WebsiteBucket', {
websiteIndexDocument: 'index.html',
publicReadAccess: true,
});
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket: websiteBucket,
destinationKeyPrefix: 'web/static', // optional prefix in destination bucket
metadata: { A: "1", b: "2" }, // user-defined metadata
// system-defined metadata
contentType: "text/html",
contentLanguage: "en",
storageClass: s3deploy.StorageClass.INTELLIGENT_TIERING,
serverSideEncryption: s3deploy.ServerSideEncryption.AES_256,
cacheControl: [
s3deploy.CacheControl.setPublic(),
s3deploy.CacheControl.maxAge(Duration.hours(1)),
],
accessControl: s3.BucketAccessControl.BUCKET_OWNER_FULL_CONTROL,
});
```
## CloudFront Invalidation
You can provide a CloudFront distribution and optional paths to invalidate after the bucket deployment finishes.
```ts
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
const bucket = new s3.Bucket(this, 'Destination');
// Handles buckets whether or not they are configured for website hosting.
const distribution = new cloudfront.Distribution(this, 'Distribution', {
defaultBehavior: { origin: new origins.S3Origin(bucket) },
});
new s3deploy.BucketDeployment(this, 'DeployWithInvalidation', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket: bucket,
distribution,
distributionPaths: ['/images/*.png'],
});
```
By default, the deployment will wait for invalidation to succeed to complete. This will poll Cloudfront for a maximum of 13 minutes to check for a successful invalidation. The drawback to this is that the deployment will fail if invalidation fails or if it takes longer than 13 minutes. As a workaround, there is the option `waitForDistributionInvalidation`, which can be set to false to skip waiting for the invalidation, but this can be risky as invalidation errors will not be reported.
```ts
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
declare const bucket: s3.IBucket;
declare const distribution: cloudfront.IDistribution;
new s3deploy.BucketDeployment(this, 'DeployWithInvalidation', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket: bucket,
distribution,
distributionPaths: ['/images/*.png'],
// Invalidate cache but don't wait or verify that invalidation has completed successfully.
waitForDistributionInvalidation: false
});
```
## Signed Content Payloads
By default, deployment uses streaming uploads which set the `x-amz-content-sha256`
request header to `UNSIGNED-PAYLOAD` (matching default behavior of the AWS CLI tool).
In cases where bucket policy restrictions require signed content payloads, you can enable
generation of a signed `x-amz-content-sha256` request header with `signContent: true`.
```ts
declare const bucket: s3.IBucket;
new s3deploy.BucketDeployment(this, 'DeployWithSignedPayloads', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket: bucket,
signContent: true,
});
```
## Size Limits
The default memory limit for the deployment resource is 128MiB. If you need to
copy larger files, you can use the `memoryLimit` configuration to increase the
size of the AWS Lambda resource handler.
The default ephemeral storage size for the deployment resource is 512MiB. If you
need to upload larger files, you may hit this limit. You can use the
`ephemeralStorageSize` configuration to increase the storage size of the AWS Lambda
resource handler.
> NOTE: a new AWS Lambda handler will be created in your stack for each combination
> of memory and storage size.
## JSON-Aware Source Processing
When using `Source.jsonData` with CDK Tokens (references to construct properties), you may need to enable the escaping option. This is particularly important when the referenced properties might contain special characters that require proper JSON escaping (like double quotes, line breaks, etc.).
```ts
declare const bucket: s3.Bucket;
declare const param: ssm.StringParameter;
// Example with a secret value that contains double quotes
const deployment = new s3deploy.BucketDeployment(this, 'JsonDeployment', {
sources: [
s3deploy.Source.jsonData('config.json', {
api_endpoint: 'https://api.example.com',
secretValue: param.stringValue, // value with double quotes
config: {
enabled: true,
features: ['feature1', 'feature2']
}
},
// Enable escaping at deployment time
{ escape: true },
)
],
destinationBucket: bucket,
});
```
## EFS Support
If your workflow needs more disk space than default (512 MB) disk space, you may attach an EFS storage to underlying
lambda function. To Enable EFS support set `efs` and `vpc` props for BucketDeployment.
Check sample usage below.
Please note that creating VPC inline may cause stack deletion failures. It is shown as below for simplicity.
To avoid such condition, keep your network infra (VPC) in a separate stack and pass as props.
```ts
declare const destinationBucket: s3.Bucket;
declare const vpc: ec2.Vpc;
new s3deploy.BucketDeployment(this, 'DeployMeWithEfsStorage', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))],
destinationBucket,
destinationKeyPrefix: 'efs/',
useEfs: true,
vpc,
retainOnDelete: false,
});
```
## Data with deploy-time values
The content passed to `Source.data()`, `Source.jsonData()`, or `Source.yamlData()` can include
references that will get resolved only during deployment. Only a subset of CloudFormation functions
are supported however, namely: Ref, Fn::GetAtt, Fn::Join, and Fn::Select (Fn::Split may be nested under Fn::Select).
For example:
```ts
import * as sns from 'aws-cdk-lib/aws-sns';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
declare const destinationBucket: s3.Bucket;
declare const topic: sns.Topic;
declare const tg: elbv2.ApplicationTargetGroup;
const appConfig = {
topic_arn: topic.topicArn,
base_url: 'https://my-endpoint',
lb_name: tg.firstLoadBalancerFullName,
};
new s3deploy.BucketDeployment(this, 'BucketDeployment', {
sources: [s3deploy.Source.jsonData('config.json', appConfig)],
destinationBucket,
});
```
The value in `topic.topicArn` is a deploy-time value. It only gets resolved
during deployment by placing a marker in the generated source file and
substituting it when its deployed to the destination with the actual value.
### Substitutions from Templated Files
The `DeployTimeSubstitutedFile` construct allows you to specify substitutions
to make from placeholders in a local file which will be resolved during deployment. This
is especially useful in situations like creating an API from a spec file, where users might
want to reference other CDK resources they have created.
The syntax for template variables is `{{ variableName }}` in your local file. Then, you would
specify the substitutions in CDK like this:
```ts
import * as lambda from 'aws-cdk-lib/aws-lambda';
declare const myLambdaFunction: lambda.Function;
declare const destinationBucket: s3.Bucket;
//(Optional) if provided, the resulting processed file would be uploaded to the destinationBucket under the destinationKey name.
declare const destinationKey: string;
declare const role: iam.Role;
new s3deploy.DeployTimeSubstitutedFile(this, 'MyFile', {
source: 'my-file.yaml',
destinationKey: destinationKey,
destinationBucket: destinationBucket,
substitutions: {
variableName: myLambdaFunction.functionName,
},
role: role,
});
```
Nested variables, like `{{ {{ foo }} }}` or `{{ foo {{ bar }} }}`, are not supported by this
construct. In the first case of a single variable being is double nested `{{ {{ foo }} }}`, only
the `{{ foo }}` would be replaced by the substitution, and the extra brackets would remain in the file.
In the second case of two nexted variables `{{ foo {{ bar }} }}`, only the `{{ bar }}` would be replaced
in the file.
## Keep Files Zipped
By default, files are zipped, then extracted into the destination bucket.
You can use the option `extract: false` to disable this behavior, in which case, files will remain in a zip file when deployed to S3. To reference the object keys, or filenames, which will be deployed to the bucket, you can use the `objectKeys` getter on the bucket deployment.
```ts
import * as cdk from 'aws-cdk-lib';
declare const destinationBucket: s3.Bucket;
const myBucketDeployment = new s3deploy.BucketDeployment(this, 'DeployMeWithoutExtractingFilesOnDestination', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))],
destinationBucket,
extract: false,
});
new cdk.CfnOutput(this, 'ObjectKey', {
value: cdk.Fn.select(0, myBucketDeployment.objectKeys),
});
```
## Controlling the Output of Source Object Keys
By default, the keys of the source objects copied to the destination bucket are returned in the Data property of the custom resource. However, you can disable this behavior by setting the outputObjectKeys property to false. This is particularly useful when the number of objects is too large and might exceed the size limit of the responseData property.
```ts
import * as cdk from 'aws-cdk-lib';
declare const destinationBucket: s3.Bucket;
const myBucketDeployment = new s3deploy.BucketDeployment(this, 'DeployMeWithoutExtractingFilesOnDestination', {
sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))],
destinationBucket,
outputObjectKeys: false,
});
new cdk.CfnOutput(this, 'ObjectKey', {
value: cdk.Fn.select(0, myBucketDeployment.objectKeys),
});
```
## Specifying a Custom VPC, Subnets, and Security Groups in BucketDeployment
By default, the AWS CDK BucketDeployment construct runs in a publicly accessible environment. However, for enhanced security and compliance, you may need to deploy your assets from within a VPC while restricting network access through custom subnets and security groups.
### Using a Custom VPC
To deploy assets within a private network, specify the vpc property in BucketDeploymentProps. This ensures that the deployment Lambda function executes within your specified VPC.
```ts
const vpc = ec2.Vpc.fromLookup(this, 'ExistingVPC', { vpcId: 'vpc-12345678' });
const bucket = new s3.Bucket(this, 'MyBucket');
new s3deploy.BucketDeployment(this, 'DeployToS3', {
destinationBucket: bucket,
vpc: vpc,
sources: [s3deploy.Source.asset('./website')],
});
```
### Specifying Subnets for Deployment
By default, when you specify a VPC, the BucketDeployment function is deployed in the private subnets of that VPC.
However, you can customize the subnet selection using the vpcSubnets property.
```ts
const vpc = ec2.Vpc.fromLookup(this, 'ExistingVPC', { vpcId: 'vpc-12345678' });
const bucket = new s3.Bucket(this, 'MyBucket');
new s3deploy.BucketDeployment(this, 'DeployToS3', {
destinationBucket: bucket,
vpc: vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
sources: [s3deploy.Source.asset('./website')],
});
```
### Defining Custom Security Groups
For enhanced network security, you can now specify custom security groups in BucketDeploymentProps.
This allows fine-grained control over ingress and egress rules for the deployment Lambda function.
```ts
const vpc = ec2.Vpc.fromLookup(this, 'ExistingVPC', { vpcId: 'vpc-12345678' });
const bucket = new s3.Bucket(this, 'MyBucket');
const securityGroup = new ec2.SecurityGroup(this, 'CustomSG', {
vpc: vpc,
description: 'Allow HTTPS outbound access',
allowAllOutbound: false,
});
securityGroup.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'Allow HTTPS traffic');
new s3deploy.BucketDeployment(this, 'DeployWithSecurityGroup', {
destinationBucket: bucket,
vpc: vpc,
securityGroups: [securityGroup],
sources: [s3deploy.Source.asset('./website')],
});
```
## Notes
- This library uses an AWS CloudFormation custom resource which is about 10MiB in
size. The code of this resource is bundled with this library.
- AWS Lambda execution time is limited to 15min. This limits the amount of data
which can be deployed into the bucket by this timeout.
- When the `BucketDeployment` is removed from the stack, the contents are retained
in the destination bucket ([#952](https://github.com/aws/aws-cdk/issues/952)).
- If you are using `s3deploy.Source.bucket()` to take the file source from
another bucket: the deployed files will only be updated if the key (file name)
of the file in the source bucket changes. Mutating the file in place will not
be good enough: the custom resource will simply not run if the properties don't
change.
- If you use assets (`s3deploy.Source.asset()`) you don't need to worry
about this: the asset system will make sure that if the files have changed,
the file name is unique and the deployment will run.
## Development
The custom resource is implemented in Python 3.9 in order to be able to leverage
the AWS CLI for "aws s3 sync".
The code is now in the `@aws-cdk/custom-resource-handlers` package under [`lib/aws-s3-deployment/bucket-deployment-handler`](https://github.com/aws/aws-cdk/tree/main/packages/@aws-cdk/custom-resource-handlers/lib/aws-s3-deployment/bucket-deployment-handler/) and
unit tests are under [`test/aws-s3-deployment/bucket-deployment-handler`](https://github.com/aws/aws-cdk/tree/main/packages/@aws-cdk/custom-resource-handlers/test/aws-s3-deployment/bucket-deployment-handler/).
This package requires Python 3.9 during build time in order to create the custom
resource Lambda bundle and test it. It also relies on a few bash scripts, so
might be tricky to build on Windows.
## Roadmap
- [ ] Support "blue/green" deployments ([#954](https://github.com/aws/aws-cdk/issues/954))

View File

@@ -0,0 +1 @@
export * from './lib';

View File

@@ -0,0 +1 @@
"use strict";var __createBinding=exports&&exports.__createBinding||(Object.create?(function(o,m,k,k2){k2===void 0&&(k2=k);var desc=Object.getOwnPropertyDescriptor(m,k);(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable))&&(desc={enumerable:!0,get:function(){return m[k]}}),Object.defineProperty(o,k2,desc)}):(function(o,m,k,k2){k2===void 0&&(k2=k),o[k2]=m[k]})),__exportStar=exports&&exports.__exportStar||function(m,exports2){for(var p in m)p!=="default"&&!Object.prototype.hasOwnProperty.call(exports2,p)&&__createBinding(exports2,m,p)};Object.defineProperty(exports,"__esModule",{value:!0});var _noFold;exports.BucketDeployment=void 0,Object.defineProperty(exports,_noFold="BucketDeployment",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").BucketDeployment;return Object.defineProperty(exports,_noFold="BucketDeployment",{enumerable:!0,configurable:!0,value}),value}}),exports.DeployTimeSubstitutedFile=void 0,Object.defineProperty(exports,_noFold="DeployTimeSubstitutedFile",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").DeployTimeSubstitutedFile;return Object.defineProperty(exports,_noFold="DeployTimeSubstitutedFile",{enumerable:!0,configurable:!0,value}),value}}),exports.CacheControl=void 0,Object.defineProperty(exports,_noFold="CacheControl",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").CacheControl;return Object.defineProperty(exports,_noFold="CacheControl",{enumerable:!0,configurable:!0,value}),value}}),exports.ServerSideEncryption=void 0,Object.defineProperty(exports,_noFold="ServerSideEncryption",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").ServerSideEncryption;return Object.defineProperty(exports,_noFold="ServerSideEncryption",{enumerable:!0,configurable:!0,value}),value}}),exports.StorageClass=void 0,Object.defineProperty(exports,_noFold="StorageClass",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").StorageClass;return Object.defineProperty(exports,_noFold="StorageClass",{enumerable:!0,configurable:!0,value}),value}}),exports.Expires=void 0,Object.defineProperty(exports,_noFold="Expires",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").Expires;return Object.defineProperty(exports,_noFold="Expires",{enumerable:!0,configurable:!0,value}),value}}),exports.Source=void 0,Object.defineProperty(exports,_noFold="Source",{enumerable:!0,configurable:!0,get:()=>{var value=require("./lib").Source;return Object.defineProperty(exports,_noFold="Source",{enumerable:!0,configurable:!0,value}),value}});

View File

@@ -0,0 +1,519 @@
import { Construct } from 'constructs';
import type { ISource } from './source';
import type * as cloudfront from '../../aws-cloudfront';
import type * as ec2 from '../../aws-ec2';
import * as iam from '../../aws-iam';
import type * as logs from '../../aws-logs';
import * as s3 from '../../aws-s3';
import * as cdk from '../../core';
/**
* Properties for `BucketDeployment`.
*/
export interface BucketDeploymentProps {
/**
* The sources from which to deploy the contents of this bucket.
*/
readonly sources: ISource[];
/**
* The S3 bucket to sync the contents of the zip file to.
*/
readonly destinationBucket: s3.IBucket;
/**
* Key prefix in the destination bucket. Must be <=104 characters
*
* If it's set with prune: true, it will only prune files with the prefix.
*
* We recommend to always configure the `destinationKeyPrefix` property. This will prevent the deployment
* from accidentally deleting data that wasn't uploaded by it.
*
* @default "/" (unzip to root of the destination bucket)
*/
readonly destinationKeyPrefix?: string;
/**
* If this is set, the zip file will be synced to the destination S3 bucket and extracted.
* If false, the file will remain zipped in the destination bucket.
* @default true
*/
readonly extract?: boolean;
/**
* If this is set, matching files or objects will be excluded from the deployment's sync
* command. This can be used to exclude a file from being pruned in the destination bucket.
*
* If you want to just exclude files from the deployment package (which excludes these files
* evaluated when invalidating the asset), you should leverage the `exclude` property of
* `AssetOptions` when defining your source.
*
* @default - No exclude filters are used
* @see https://docs.aws.amazon.com/cli/latest/reference/s3/index.html#use-of-exclude-and-include-filters
*/
readonly exclude?: string[];
/**
* If this is set, matching files or objects will be included with the deployment's sync
* command. Since all files from the deployment package are included by default, this property
* is usually leveraged alongside an `exclude` filter.
*
* @default - No include filters are used and all files are included with the sync command
* @see https://docs.aws.amazon.com/cli/latest/reference/s3/index.html#use-of-exclude-and-include-filters
*/
readonly include?: string[];
/**
* By default, files in the destination bucket that don't exist in the source will be deleted
* when the BucketDeployment resource is created or updated.
*
* If this is set to false, files in the destination bucket that
* do not exist in the asset, will NOT be deleted during deployment (create/update).
*
* @see https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html
*
* @default true
*/
readonly prune?: boolean;
/**
* If this is set to "false", the destination files will be deleted when the
* resource is deleted or the destination is updated.
*
* NOTICE: Configuring this to "false" might have operational implications. Please
* visit to the package documentation referred below to make sure you fully understand those implications.
*
* @see https://github.com/aws/aws-cdk/tree/main/packages/aws-cdk-lib/aws-s3-deployment#retain-on-delete
* @default true - when resource is deleted/updated, files are retained
*/
readonly retainOnDelete?: boolean;
/**
* The CloudFront distribution using the destination bucket as an origin.
* Files in the distribution's edge caches will be invalidated after
* files are uploaded to the destination bucket.
*
* @default - No invalidation occurs
*/
readonly distribution?: cloudfront.IDistributionRef;
/**
* The file paths to invalidate in the CloudFront distribution.
*
* @default - All files under the destination bucket key prefix will be invalidated.
*/
readonly distributionPaths?: string[];
/**
* In case of using a cloudfront distribution, if this property is set to false then the custom resource
* will not wait and verify for Cloudfront invalidation to complete. This may speed up deployment and avoid
* intermittent Cloudfront issues. However, this is risky and not recommended as cache invalidation
* can silently fail.
*
* @see https://github.com/aws/aws-cdk/issues/15891
* @default true
*/
readonly waitForDistributionInvalidation?: boolean;
/**
* The number of days that the lambda function's log events are kept in CloudWatch Logs.
*
* This is a legacy API and we strongly recommend you migrate to `logGroup` if you can.
* `logGroup` allows you to create a fully customizable log group and instruct the Lambda function to send logs to it.
*
* @default logs.RetentionDays.INFINITE
*/
readonly logRetention?: logs.RetentionDays;
/**
* The Log Group used for logging of events emitted by the custom resource's lambda function.
*
* Providing a user-controlled log group was rolled out to commercial regions on 2023-11-16.
* If you are deploying to another type of region, please check regional availability first.
*
* @default - a default log group created by AWS Lambda
*/
readonly logGroup?: logs.ILogGroupRef;
/**
* The amount of memory (in MiB) to allocate to the AWS Lambda function which
* replicates the files from the CDK bucket to the destination bucket.
*
* If you are deploying large files, you will need to increase this number
* accordingly.
*
* @default 128
*/
readonly memoryLimit?: number;
/**
* The size of the AWS Lambda functions /tmp directory in MiB.
*
* @default 512 MiB
*/
readonly ephemeralStorageSize?: cdk.Size;
/**
* Mount an EFS file system. Enable this if your assets are large and you encounter disk space errors.
* Enabling this option will require a VPC to be specified.
*
* @default - No EFS. Lambda has access only to 512MB of disk space.
*/
readonly useEfs?: boolean;
/**
* Execution role associated with this function
*
* @default - A role is automatically created
*/
readonly role?: iam.IRole;
/**
* User-defined object metadata to be set on all objects in the deployment
* @default - No user metadata is set
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#UserMetadata
*/
readonly metadata?: {
[key: string]: string;
};
/**
* System-defined cache-control metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly cacheControl?: CacheControl[];
/**
* System-defined cache-disposition metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly contentDisposition?: string;
/**
* System-defined content-encoding metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly contentEncoding?: string;
/**
* System-defined content-language metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly contentLanguage?: string;
/**
* System-defined content-type metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly contentType?: string;
/**
* System-defined expires metadata to be set on all objects in the deployment.
* @default - The objects in the distribution will not expire.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly expires?: cdk.Expiration;
/**
* System-defined x-amz-server-side-encryption metadata to be set on all objects in the deployment.
* @default - Server side encryption is not used.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly serverSideEncryption?: ServerSideEncryption;
/**
* System-defined x-amz-storage-class metadata to be set on all objects in the deployment.
* @default - Default storage-class for the bucket is used.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly storageClass?: StorageClass;
/**
* System-defined x-amz-website-redirect-location metadata to be set on all objects in the deployment.
* @default - No website redirection.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly websiteRedirectLocation?: string;
/**
* System-defined x-amz-server-side-encryption-aws-kms-key-id metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
readonly serverSideEncryptionAwsKmsKeyId?: string;
/**
* System-defined x-amz-server-side-encryption-customer-algorithm metadata to be set on all objects in the deployment.
* Warning: This is not a useful parameter until this bug is fixed: https://github.com/aws/aws-cdk/issues/6080
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html#sse-c-how-to-programmatically-intro
*/
readonly serverSideEncryptionCustomerAlgorithm?: string;
/**
* System-defined x-amz-acl metadata to be set on all objects in the deployment.
* @default - Not set.
* @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl
*/
readonly accessControl?: s3.BucketAccessControl;
/**
* The VPC network to place the deployment lambda handler in.
* This is required if `useEfs` is set.
*
* @default None
*/
readonly vpc?: ec2.IVpc;
/**
* Where in the VPC to place the deployment lambda handler.
* Only used if 'vpc' is supplied.
*
* @default - the Vpc default strategy if not specified
*/
readonly vpcSubnets?: ec2.SubnetSelection;
/**
* If set to true, uploads will precompute the value of `x-amz-content-sha256`
* and include it in the signed S3 request headers.
*
* @default - `x-amz-content-sha256` will not be computed
*/
readonly signContent?: boolean;
/**
* If set to false, the custom resource will not send back the SourceObjectKeys.
* This is useful when you are facing the error `Response object is too long`
*
* See https://github.com/aws/aws-cdk/issues/28579
*
* @default true
*/
readonly outputObjectKeys?: boolean;
/**
* The list of security groups to associate with the lambda handlers network interfaces.
*
* Only used if 'vpc' is supplied.
*
* @default undefined - If the function is placed within a VPC and a security group is
* not specified a dedicated security group will be created for this function.
*/
readonly securityGroups?: ec2.ISecurityGroup[];
}
/**
* `BucketDeployment` populates an S3 bucket with the contents of .zip files from
* other S3 buckets or from local disk
*/
export declare class BucketDeployment extends Construct {
/**
* Uniquely identifies this class.
*/
static readonly PROPERTY_INJECTION_ID: string;
private readonly cr;
private _deployedBucket?;
private requestDestinationArn;
private readonly destinationBucket;
private readonly sources;
/**
* Execution role of the Lambda function behind the custom CloudFormation resource of type `Custom::CDKBucketDeployment`.
*/
readonly handlerRole: iam.IRole;
constructor(scope: Construct, id: string, props: BucketDeploymentProps);
/**
* The bucket after the deployment
*
* If you want to reference the destination bucket in another construct and make sure the
* bucket deployment has happened before the next operation is started, pass the other construct
* a reference to `deployment.deployedBucket`.
*
* Note that this only returns an immutable reference to the destination bucket.
* If sequenced access to the original destination bucket is required, you may add a dependency
* on the bucket deployment instead: `otherResource.node.addDependency(deployment)`
*/
get deployedBucket(): s3.IBucket;
/**
* The object keys for the sources deployed to the S3 bucket.
*
* This returns a list of tokenized object keys for source files that are deployed to the bucket.
*
* This can be useful when using `BucketDeployment` with `extract` set to `false` and you need to reference
* the object key that resides in the bucket for that zip source file somewhere else in your CDK
* application, such as in a CFN output.
*
* For example, use `Fn.select(0, myBucketDeployment.objectKeys)` to reference the object key of the
* first source file in your bucket deployment.
*/
get objectKeys(): string[];
/**
* Add an additional source to the bucket deployment
*
* @example
* declare const websiteBucket: s3.IBucket;
* const deployment = new s3deploy.BucketDeployment(this, 'Deployment', {
* sources: [s3deploy.Source.asset('./website-dist')],
* destinationBucket: websiteBucket,
* });
*
* deployment.addSource(s3deploy.Source.asset('./another-asset'));
*/
addSource(source: ISource): void;
private renderUniqueId;
private renderSingletonUuid;
/**
* Function to get/create a stack singleton instance of EFS FileSystem per vpc.
*
* @param scope Construct
* @param fileSystemProps EFS FileSystemProps
*/
private getOrCreateEfsFileSystem;
}
export interface DeployTimeSubstitutedFileProps {
/**
* Path to the user's local file.
*/
readonly source: string;
/**
* The object key in the destination bucket where the processed
* file would be written to.
* @default - Fingerprint of the file content would be used as object key
*/
readonly destinationKey?: string;
/**
* The S3 bucket to sync the contents of the zip file to.
*/
readonly destinationBucket: s3.IBucket;
/**
* User-defined substitutions to make in the file.
* Placeholders in the user's local file must be specified with double curly
* brackets and spaces. For example, if you use the key 'xxxx' in the file,
* it must be written as: {{ xxxx }} to be recognized by the construct as a
* substitution.
*/
readonly substitutions: {
[key: string]: string;
};
/**
* Execution role associated with this function
*
* @default - A role is automatically created
*/
readonly role?: iam.IRole;
}
/**
* `DeployTimeSubstitutedFile` is an extension of `BucketDeployment` that allows users to
* upload individual files and specify to make substitutions in the file.
*/
export declare class DeployTimeSubstitutedFile extends BucketDeployment {
readonly objectKey: string;
constructor(scope: Construct, id: string, props: DeployTimeSubstitutedFileProps);
get bucket(): s3.IBucket;
}
/**
* Used for HTTP cache-control header, which influences downstream caches.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
export declare class CacheControl {
/**
* The raw cache control setting.
*/
readonly value: any;
/**
* Sets 'must-revalidate'.
*/
static mustRevalidate(): CacheControl;
/**
* Sets 'no-cache'.
*/
static noCache(): CacheControl;
/**
* Sets 'no-transform'.
*/
static noTransform(): CacheControl;
/**
* Sets 'no-store'.
*/
static noStore(): CacheControl;
/**
* Sets 'must-understand'.
*/
static mustUnderstand(): CacheControl;
/**
* Sets 'public'.
*/
static setPublic(): CacheControl;
/**
* Sets 'private'.
*/
static setPrivate(): CacheControl;
/**
* Sets 'immutable'.
*/
static immutable(): CacheControl;
/**
* Sets 'proxy-revalidate'.
*/
static proxyRevalidate(): CacheControl;
/**
* Sets 'max-age=<duration-in-seconds>'.
*/
static maxAge(t: cdk.Duration): CacheControl;
/**
* Sets 's-maxage=<duration-in-seconds>'.
*/
static sMaxAge(t: cdk.Duration): CacheControl;
/**
* Sets 'stale-while-revalidate=<duration-in-seconds>'.
*/
static staleWhileRevalidate(t: cdk.Duration): CacheControl;
/**
* Sets 'stale-if-error=<duration-in-seconds>'.
*/
static staleIfError(t: cdk.Duration): CacheControl;
/**
* Constructs a custom cache control key from the literal value.
*/
static fromString(s: string): CacheControl;
private constructor();
}
/**
* Indicates whether server-side encryption is enabled for the object, and whether that encryption is
* from the AWS Key Management Service (AWS KMS) or from Amazon S3 managed encryption (SSE-S3).
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
export declare enum ServerSideEncryption {
/**
* 'AES256'
*/
AES_256 = "AES256",
/**
* 'aws:kms'
*/
AWS_KMS = "aws:kms",
/**
* 'aws:kms:dsse'
*/
AWS_KMS_DSSE = "aws:kms:dsse"
}
/**
* Storage class used for storing the object.
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#SysMetadata
*/
export declare enum StorageClass {
/**
* 'STANDARD'
*/
STANDARD = "STANDARD",
/**
* 'REDUCED_REDUNDANCY'
*/
REDUCED_REDUNDANCY = "REDUCED_REDUNDANCY",
/**
* 'STANDARD_IA'
*/
STANDARD_IA = "STANDARD_IA",
/**
* 'ONEZONE_IA'
*/
ONEZONE_IA = "ONEZONE_IA",
/**
* 'INTELLIGENT_TIERING'
*/
INTELLIGENT_TIERING = "INTELLIGENT_TIERING",
/**
* 'GLACIER'
*/
GLACIER = "GLACIER",
/**
* 'DEEP_ARCHIVE'
*/
DEEP_ARCHIVE = "DEEP_ARCHIVE"
}
/**
* Custom user defined metadata.
*
* @deprecated Use raw property bags instead (object literals, `Map<String,Object>`, etc... )
*/
export interface UserDefinedObjectMetadata {
/**
* Arbitrary metadata key-values
* The `x-amz-meta-` prefix will automatically be added to keys.
*
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#UserMetadata
*
* This index signature is not usable in non-TypeScript/JavaScript languages.
*
* @jsii ignore
*/
readonly [key: string]: string;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export * from './bucket-deployment';
export * from './source';

View File

@@ -0,0 +1 @@
"use strict";var __createBinding=exports&&exports.__createBinding||(Object.create?(function(o,m,k,k2){k2===void 0&&(k2=k);var desc=Object.getOwnPropertyDescriptor(m,k);(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable))&&(desc={enumerable:!0,get:function(){return m[k]}}),Object.defineProperty(o,k2,desc)}):(function(o,m,k,k2){k2===void 0&&(k2=k),o[k2]=m[k]})),__exportStar=exports&&exports.__exportStar||function(m,exports2){for(var p in m)p!=="default"&&!Object.prototype.hasOwnProperty.call(exports2,p)&&__createBinding(exports2,m,p)};Object.defineProperty(exports,"__esModule",{value:!0});var _noFold;exports.BucketDeployment=void 0,Object.defineProperty(exports,_noFold="BucketDeployment",{enumerable:!0,configurable:!0,get:()=>{var value=require("./bucket-deployment").BucketDeployment;return Object.defineProperty(exports,_noFold="BucketDeployment",{enumerable:!0,configurable:!0,value}),value}}),exports.DeployTimeSubstitutedFile=void 0,Object.defineProperty(exports,_noFold="DeployTimeSubstitutedFile",{enumerable:!0,configurable:!0,get:()=>{var value=require("./bucket-deployment").DeployTimeSubstitutedFile;return Object.defineProperty(exports,_noFold="DeployTimeSubstitutedFile",{enumerable:!0,configurable:!0,value}),value}}),exports.CacheControl=void 0,Object.defineProperty(exports,_noFold="CacheControl",{enumerable:!0,configurable:!0,get:()=>{var value=require("./bucket-deployment").CacheControl;return Object.defineProperty(exports,_noFold="CacheControl",{enumerable:!0,configurable:!0,value}),value}}),exports.ServerSideEncryption=void 0,Object.defineProperty(exports,_noFold="ServerSideEncryption",{enumerable:!0,configurable:!0,get:()=>{var value=require("./bucket-deployment").ServerSideEncryption;return Object.defineProperty(exports,_noFold="ServerSideEncryption",{enumerable:!0,configurable:!0,value}),value}}),exports.StorageClass=void 0,Object.defineProperty(exports,_noFold="StorageClass",{enumerable:!0,configurable:!0,get:()=>{var value=require("./bucket-deployment").StorageClass;return Object.defineProperty(exports,_noFold="StorageClass",{enumerable:!0,configurable:!0,value}),value}}),exports.Expires=void 0,Object.defineProperty(exports,_noFold="Expires",{enumerable:!0,configurable:!0,get:()=>{var value=require("./bucket-deployment").Expires;return Object.defineProperty(exports,_noFold="Expires",{enumerable:!0,configurable:!0,value}),value}}),exports.Source=void 0,Object.defineProperty(exports,_noFold="Source",{enumerable:!0,configurable:!0,get:()=>{var value=require("./source").Source;return Object.defineProperty(exports,_noFold="Source",{enumerable:!0,configurable:!0,value}),value}});

View File

@@ -0,0 +1,13 @@
export interface Content {
readonly text: string;
readonly markers: Record<string, any>;
}
/**
* Renders the given string data as deployable content with markers substituted
* for all tokens.
*
* @param data The input data
* @returns The markered text (`text`) and a map that maps marker names to their
* values (`markers`).
*/
export declare function renderData(data: string): Content;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.renderData=renderData;var core_1=()=>{var tmp=require("../../core");return core_1=()=>tmp,tmp};class TokenToMarkerMapper{markers;constructor(){this.markers={}}mapToken(token){const newMarker=`<<marker:0xbaba:${Object.keys(this.markers).length}>>`;return this.markers[newMarker]=token.toString(),newMarker}}function renderData(data){const tokenMapper=new TokenToMarkerMapper;return data===""?{text:"",markers:{}}:{text:core_1().Tokenization.reverseString(data).mapTokens(tokenMapper).join(new(core_1()).StringConcat),markers:tokenMapper.markers}}

View File

@@ -0,0 +1,168 @@
import type { Construct } from 'constructs';
import type * as iam from '../../aws-iam';
import type * as s3 from '../../aws-s3';
import * as s3_assets from '../../aws-s3-assets';
/**
* Source information.
*/
export interface SourceConfig {
/**
* The source bucket to deploy from.
*/
readonly bucket: s3.IBucket;
/**
* An S3 object key in the source bucket that points to a zip file.
*/
readonly zipObjectKey: string;
/**
* A set of markers to substitute in the source content.
* @default - no markers
*/
readonly markers?: Record<string, any>;
/**
* A configuration for markers substitution strategy.
* @default - no configuration
*/
readonly markersConfig?: MarkersConfig;
}
/**
* A configuration for markers substitution strategy.
*/
export interface MarkersConfig {
/**
* If set to `true`, the marker substitution will make ure the value inserted in the file
* will be a valid JSON string.
* @default - false
*/
readonly jsonEscape?: boolean;
}
/**
* Define options which can be passed using the method `Source.jsonData()`.
*/
export interface JsonProcessingOptions {
/**
* If set to `true`, the marker substitution will make sure the value inserted in the file
* will be a valid JSON string.
* @default - false
*/
readonly escape?: boolean;
}
/**
* Bind context for ISources
*/
export interface DeploymentSourceContext {
/**
* The role for the handler
*/
readonly handlerRole: iam.IRole;
}
/**
* Represents a source for bucket deployments.
*/
export interface ISource {
/**
* Binds the source to a bucket deployment.
* @param scope The construct tree context.
*/
bind(scope: Construct, context?: DeploymentSourceContext): SourceConfig;
}
/**
* Specifies bucket deployment source.
*
* Usage:
*
* Source.bucket(bucket, key)
* Source.asset('/local/path/to/directory')
* Source.asset('/local/path/to/a/file.zip')
* Source.data('hello/world/file.txt', 'Hello, world!')
* Source.jsonData('config.json', { baz: topic.topicArn })
* Source.yamlData('config.yaml', { baz: topic.topicArn })
*
*/
export declare class Source {
/**
* Uses a .zip file stored in an S3 bucket as the source for the destination bucket contents.
*
* Make sure you trust the producer of the archive.
*
* If the `bucket` parameter is an "out-of-app" reference "imported" via static methods such
* as `s3.Bucket.fromBucketName`, be cautious about the bucket's encryption key. In general,
* CDK does not query for additional properties of imported constructs at synthesis time.
* For example, for a bucket created from `s3.Bucket.fromBucketName`, CDK does not know
* its `IBucket.encryptionKey` property, and therefore will NOT give KMS permissions to the
* Lambda execution role of the `BucketDeployment` construct. If you want the
* `kms:Decrypt` and `kms:DescribeKey` permissions on the bucket's encryption key
* to be added automatically, reference the imported bucket via `s3.Bucket.fromBucketAttributes`
* and pass in the `encryptionKey` attribute explicitly.
*
* @example
* declare const destinationBucket: s3.Bucket;
* const sourceBucket = s3.Bucket.fromBucketAttributes(this, 'SourceBucket', {
* bucketArn: 'arn:aws:s3:::my-source-bucket-name',
* encryptionKey: kms.Key.fromKeyArn(
* this,
* 'SourceBucketEncryptionKey',
* 'arn:aws:kms:us-east-1:123456789012:key/<key-id>'
* ),
* });
* const deployment = new s3deploy.BucketDeployment(this, 'DeployFiles', {
* sources: [s3deploy.Source.bucket(sourceBucket, 'source.zip')],
* destinationBucket,
* });
*
* @param bucket The S3 Bucket
* @param zipObjectKey The S3 object key of the zip file with contents
*/
static bucket(bucket: s3.IBucket, zipObjectKey: string): ISource;
/**
* Uses a local asset as the deployment source.
*
* If the local asset is a .zip archive, make sure you trust the
* producer of the archive.
*
* @param path The path to a local .zip file or a directory
*/
static asset(path: string, options?: s3_assets.AssetOptions): ISource;
/**
* Deploys an object with the specified string contents into the bucket. The
* content can include deploy-time values (such as `snsTopic.topicArn`) that
* will get resolved only during deployment.
*
* To store a JSON object use `Source.jsonData()`.
* To store YAML content use `Source.yamlData()`.
*
* @param objectKey The destination S3 object key (relative to the root of the
* S3 deployment).
* @param data The data to be stored in the object.
*/
static data(objectKey: string, data: string, markersConfig?: MarkersConfig): ISource;
/**
* Deploys an object with the specified JSON object into the bucket. The
* object can include deploy-time values (such as `snsTopic.topicArn`) that
* will get resolved only during deployment.
*
* @param objectKey The destination S3 object key (relative to the root of the
* S3 deployment).
* @param obj A JSON object.
* @param jsonProcessingOptions Options for how to process the JSON object.
*/
static jsonData(objectKey: string, obj: any, jsonProcessingOptions?: JsonProcessingOptions): ISource;
/**
* Deploys an object with the specified JSON object formatted as YAML into the bucket.
* The object can include deploy-time values (such as `snsTopic.topicArn`) that
* will get resolved only during deployment.
*
* @param objectKey The destination S3 object key (relative to the root of the
* S3 deployment).
* @param obj A JSON object.
*/
static yamlData(objectKey: string, obj: any): ISource;
/**
* Process objects such that it escapes token output suitable for JSON output.
*
* @param scope Parent construct scope
* @returns Object with with tokens escaped for JSON output.
*/
private static escapeTokens;
private constructor();
}

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Source=void 0;var jsiiDeprecationWarnings=()=>{var tmp=require("../../.warnings.jsii.js");return jsiiDeprecationWarnings=()=>tmp,tmp};const JSII_RTTI_SYMBOL_1=Symbol.for("jsii.rtti");var fs=()=>{var tmp=require("fs");return fs=()=>tmp,tmp},path_1=()=>{var tmp=require("path");return path_1=()=>tmp,tmp},render_data_1=()=>{var tmp=require("./render-data");return render_data_1=()=>tmp,tmp},s3_assets=()=>{var tmp=require("../../aws-s3-assets");return s3_assets=()=>tmp,tmp},core_1=()=>{var tmp=require("../../core");return core_1=()=>tmp,tmp},errors_1=()=>{var tmp=require("../../core/lib/errors");return errors_1=()=>tmp,tmp},literal_string_1=()=>{var tmp=require("../../core/lib/private/literal-string");return literal_string_1=()=>tmp,tmp},yaml_cfn=()=>{var tmp=require("../../core/lib/private/yaml-cfn");return yaml_cfn=()=>tmp,tmp};class Source{static[JSII_RTTI_SYMBOL_1]={fqn:"aws-cdk-lib.aws_s3_deployment.Source",version:"2.252.0"};static bucket(bucket,zipObjectKey){try{jsiiDeprecationWarnings().aws_cdk_lib_aws_s3_IBucket(bucket)}catch(error){throw process.env.JSII_DEBUG!=="1"&&error.name==="DeprecationError"&&Error.captureStackTrace(error,this.bucket),error}return{bind:(scope,context)=>{if(!context)throw new(errors_1()).ValidationError((0,literal_string_1().lit)`Source`,"To use a Source.bucket(), context must be provided",scope);return bucket.grantRead(context.handlerRole),{bucket,zipObjectKey}}}}static asset(path,options){try{jsiiDeprecationWarnings().aws_cdk_lib_aws_s3_assets_AssetOptions(options)}catch(error){throw process.env.JSII_DEBUG!=="1"&&error.name==="DeprecationError"&&Error.captureStackTrace(error,this.asset),error}return{bind(scope,context){if(!context)throw new(errors_1()).ValidationError((0,literal_string_1().lit)`Source`,"To use a Source.asset(), context must be provided",scope);let id=1;for(;scope.node.tryFindChild(`Asset${id}`);)id++;const asset=new(s3_assets()).Asset(scope,`Asset${id}`,{path,...options});if(!asset.isZipArchive)throw new(errors_1()).ValidationError((0,literal_string_1().lit)`AssetPathZipFileDirectory`,"Asset path must be either a .zip file or a directory",scope);return asset.grantRead(context.handlerRole),{bucket:asset.bucket,zipObjectKey:asset.s3ObjectKey}}}}static data(objectKey,data,markersConfig){try{jsiiDeprecationWarnings().aws_cdk_lib_aws_s3_deployment_MarkersConfig(markersConfig)}catch(error){throw process.env.JSII_DEBUG!=="1"&&error.name==="DeprecationError"&&Error.captureStackTrace(error,this.data),error}return{bind:(scope,context)=>{const workdir=core_1().FileSystem.mkdtemp("s3-deployment");try{const outputPath=(0,path_1().join)(workdir,objectKey),rendered=(0,render_data_1().renderData)(data);fs().mkdirSync((0,path_1().dirname)(outputPath),{recursive:!0}),fs().writeFileSync(outputPath,rendered.text);const asset=this.asset(workdir).bind(scope,context);return{bucket:asset.bucket,zipObjectKey:asset.zipObjectKey,markers:rendered.markers,markersConfig}}finally{core_1().FileSystem.rmrf(workdir)}}}}static jsonData(objectKey,obj,jsonProcessingOptions){try{jsiiDeprecationWarnings().aws_cdk_lib_aws_s3_deployment_JsonProcessingOptions(jsonProcessingOptions)}catch(error){throw process.env.JSII_DEBUG!=="1"&&error.name==="DeprecationError"&&Error.captureStackTrace(error,this.jsonData),error}let markersConfig={};return jsonProcessingOptions?.escape&&(markersConfig={jsonEscape:!0}),{bind:(scope,context)=>{const serializedObj=JSON.stringify(Source.escapeTokens(scope,obj));return Source.data(objectKey,serializedObj,markersConfig).bind(scope,context)}}}static yamlData(objectKey,obj){return{bind:(scope,context)=>{const serializedObj=yaml_cfn().serialize(Source.escapeTokens(scope,obj));return Source.data(objectKey,serializedObj).bind(scope,context)}}}static escapeTokens(scope,obj){return core_1().Token.isUnresolved(obj)?core_1().Token.asNumber(core_1().Stack.of(scope).toJsonString(obj)):Array.isArray(obj)?obj.map(v=>Source.escapeTokens(scope,v)):obj!==null&&typeof obj=="object"?Object.fromEntries(Object.entries(obj).map(([key,value])=>[key,Source.escapeTokens(scope,value)])):obj}constructor(){}}exports.Source=Source;