in src/backend/transliterator/index.ts [93:203]
public constructor(scope: Construct, id: string, props: TransliteratorProps) {
super(scope, id);
const repository = props.vpcEndpoints?.codeArtifact && props.vpcEndpoints.codeArtifactApi
? props.codeArtifact?.throughVpcEndpoint(props.vpcEndpoints.codeArtifactApi, props.vpcEndpoints.codeArtifact)
: props.codeArtifact;
const bucket = props.vpcEndpoints
? s3.throughVpcEndpoint(props.bucket, props.vpcEndpoints.s3)
: props.bucket;
const environment: Record<string, string> = {
// temporaty hack to generate construct-hub compliant markdown.
// see https://github.com/cdklabs/jsii-docgen/blob/master/src/docgen/render/markdown.ts#L172
HEADER_SPAN: 'true',
// Set embedded metrics format environment to "Local", to have a consistent experience.
AWS_EMF_ENVIRONMENT: 'Local',
};
if (props.vpcEndpoints?.codeArtifactApi) {
// Those are returned as an array of HOSTED_ZONE_ID:DNS_NAME... We care
// only about the DNS_NAME of the first entry in that array (which is
// the AZ-agnostic DNS name).
environment.CODE_ARTIFACT_API_ENDPOINT = Fn.select(1,
Fn.split(':',
Fn.select(0, props.vpcEndpoints.codeArtifactApi.vpcEndpointDnsEntries),
),
);
}
if (props.codeArtifact) {
environment.CODE_ARTIFACT_DOMAIN_NAME = props.codeArtifact.repositoryDomainName;
environment.CODE_ARTIFACT_DOMAIN_OWNER = props.codeArtifact.repositoryDomainOwner;
environment.CODE_ARTIFACT_REPOSITORY_ENDPOINT = props.codeArtifact.repositoryNpmEndpoint;
}
this.logGroup = new LogGroup(this, 'LogGroup', { retention: props.logRetention });
this.containerDefinition = new Container(this, 'Resource', {
environment,
logging: LogDrivers.awsLogs({ logGroup: this.logGroup, streamPrefix: 'transliterator' }),
taskDefinition: new FargateTaskDefinition(this, 'TaskDefinition', {
cpu: 4_096,
memoryLimitMiB: 8_192,
}),
});
repository?.grantReadFromRepository(this.taskDefinition.taskRole);
// The task handler reads & writes to this bucket.
bucket.grantRead(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.ASSEMBLY_KEY_SUFFIX}`);
bucket.grantRead(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.PACKAGE_KEY_SUFFIX}`);
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.UNINSTALLABLE_PACKAGE_SUFFIX}`);
bucket.grantDelete(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.UNINSTALLABLE_PACKAGE_SUFFIX}`);
for (const language of DocumentationLanguage.ALL) {
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language)}`);
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language, '*')}`);
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language)}${constants.NOT_SUPPORTED_SUFFIX}`);
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language, '*')}${constants.NOT_SUPPORTED_SUFFIX}`);
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language)}${constants.CORRUPT_ASSEMBLY_SUFFIX}`);
bucket.grantWrite(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language, '*')}${constants.CORRUPT_ASSEMBLY_SUFFIX}`);
bucket.grantDelete(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language)}${constants.CORRUPT_ASSEMBLY_SUFFIX}`);
bucket.grantDelete(this.taskDefinition.taskRole, `${constants.STORAGE_KEY_PREFIX}*${constants.docsKeySuffix(language, '*')}${constants.CORRUPT_ASSEMBLY_SUFFIX}`);
}
const executionRole = this.taskDefinition.obtainExecutionRole();
props.vpcEndpoints?.ecrApi.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
actions: [
'ecr:GetAuthorizationToken',
],
resources: ['*'], // Action does not support resource scoping
principals: [executionRole],
sid: 'Allow-ECR-ReadOnly',
}));
props.vpcEndpoints?.ecr.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
actions: [
'ecr:BatchCheckLayerAvailability',
'ecr:GetDownloadUrlForLayer',
'ecr:BatchGetImage',
],
// We cannot get the ECR repository info from an asset... So scoping down to same-account repositories instead...
resources: [Stack.of(this).formatArn({ service: 'ecr', resource: 'repository', arnFormat: ArnFormat.SLASH_RESOURCE_NAME, resourceName: '*' })],
principals: [executionRole],
sid: 'Allow-ECR-ReadOnly',
}));
props.vpcEndpoints?.cloudWatchLogs.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
actions: [
'logs:CreateLogStream',
'logs:PutLogEvents',
],
resources: [
Stack.of(this).formatArn({ service: 'logs', resource: 'log-group', arnFormat: ArnFormat.COLON_RESOURCE_NAME, resourceName: this.logGroup.logGroupName }),
Stack.of(this).formatArn({ service: 'logs', resource: 'log-group', arnFormat: ArnFormat.COLON_RESOURCE_NAME, resourceName: `${this.logGroup.logGroupName}:log-stream:*` }),
],
principals: [executionRole],
sid: 'Allow-Logging',
}));
props.vpcEndpoints?.stepFunctions.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
actions: [
'states:SendTaskFailure',
'states:SendTaskHeartbeat',
'states:SendTaskSuccess',
],
resources: ['*'], // Actions don't support resource scoping
principals: [this.taskDefinition.taskRole],
sid: 'Allow-StepFunctions-Callbacks',
}));
}