@go-to-k/cdkd 0.62.0 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1098 -238
- package/dist/cli.js.map +4 -4
- package/dist/go-to-k-cdkd-0.64.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.62.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -42217,6 +42217,42 @@ var EC2Provider = class {
|
|
|
42217
42217
|
throw err;
|
|
42218
42218
|
}
|
|
42219
42219
|
}
|
|
42220
|
+
/**
|
|
42221
|
+
* Drift-unknown paths per resource type.
|
|
42222
|
+
*
|
|
42223
|
+
* The 6 EC2 sub-resource types (`AWS::EC2::Route` /
|
|
42224
|
+
* `VPCGatewayAttachment` / `SubnetRouteTableAssociation` /
|
|
42225
|
+
* `SecurityGroupIngress` / `NetworkAclEntry` /
|
|
42226
|
+
* `SubnetNetworkAclAssociation`) have NO AWS-side `Tags` API — the
|
|
42227
|
+
* underlying AWS objects (route entries, NACL entries, route-table
|
|
42228
|
+
* associations, NACL associations, IGW attachments) are not
|
|
42229
|
+
* tag-bearing on AWS, and the corresponding CFn schemas do not model
|
|
42230
|
+
* `Tags` either. Declaring `'Tags'` here is defense-in-depth: if a
|
|
42231
|
+
* future CFn schema revision adds `Tags` to one of these types, or
|
|
42232
|
+
* cdkd state somehow carries `Tags` for one of them via a custom
|
|
42233
|
+
* property override, the drift comparator will skip the path
|
|
42234
|
+
* instead of firing guaranteed false-positive drift on every clean
|
|
42235
|
+
* run.
|
|
42236
|
+
*
|
|
42237
|
+
* Other EC2 types (`VPC` / `Subnet` / `InternetGateway` /
|
|
42238
|
+
* `NatGateway` / `RouteTable` / `SecurityGroup` / `Instance` /
|
|
42239
|
+
* `NetworkAcl`) have first-class Tags support via
|
|
42240
|
+
* `DescribeTags` — they surface `Tags` directly in
|
|
42241
|
+
* `readCurrentState` and don't need this declaration.
|
|
42242
|
+
*/
|
|
42243
|
+
getDriftUnknownPaths(resourceType) {
|
|
42244
|
+
switch (resourceType) {
|
|
42245
|
+
case "AWS::EC2::Route":
|
|
42246
|
+
case "AWS::EC2::VPCGatewayAttachment":
|
|
42247
|
+
case "AWS::EC2::SubnetRouteTableAssociation":
|
|
42248
|
+
case "AWS::EC2::SecurityGroupIngress":
|
|
42249
|
+
case "AWS::EC2::NetworkAclEntry":
|
|
42250
|
+
case "AWS::EC2::SubnetNetworkAclAssociation":
|
|
42251
|
+
return ["Tags"];
|
|
42252
|
+
default:
|
|
42253
|
+
return [];
|
|
42254
|
+
}
|
|
42255
|
+
}
|
|
42220
42256
|
async readVpcCurrentState(physicalId) {
|
|
42221
42257
|
const resp = await this.ec2Client.send(new DescribeVpcsCommand2({ VpcIds: [physicalId] }));
|
|
42222
42258
|
const vpc = resp.Vpcs?.[0];
|
|
@@ -56144,6 +56180,15 @@ import {
|
|
|
56144
56180
|
GetTableCommand,
|
|
56145
56181
|
GetTablesCommand,
|
|
56146
56182
|
GetTagsCommand,
|
|
56183
|
+
CreateWorkflowCommand,
|
|
56184
|
+
UpdateWorkflowCommand,
|
|
56185
|
+
DeleteWorkflowCommand,
|
|
56186
|
+
GetWorkflowCommand,
|
|
56187
|
+
ListWorkflowsCommand,
|
|
56188
|
+
CreateSecurityConfigurationCommand,
|
|
56189
|
+
DeleteSecurityConfigurationCommand,
|
|
56190
|
+
GetSecurityConfigurationCommand,
|
|
56191
|
+
GetSecurityConfigurationsCommand,
|
|
56147
56192
|
EntityNotFoundException
|
|
56148
56193
|
} from "@aws-sdk/client-glue";
|
|
56149
56194
|
import { STSClient as STSClient8, GetCallerIdentityCommand as GetCallerIdentityCommand8 } from "@aws-sdk/client-sts";
|
|
@@ -56836,162 +56881,57 @@ var GlueProvider = class {
|
|
|
56836
56881
|
return this.cachedAccountId;
|
|
56837
56882
|
}
|
|
56838
56883
|
};
|
|
56839
|
-
|
|
56840
|
-
// src/provisioning/providers/kms-provider.ts
|
|
56841
|
-
import {
|
|
56842
|
-
KMSClient as KMSClient2,
|
|
56843
|
-
CreateKeyCommand,
|
|
56844
|
-
DescribeKeyCommand,
|
|
56845
|
-
GetKeyPolicyCommand,
|
|
56846
|
-
GetKeyRotationStatusCommand,
|
|
56847
|
-
ListAliasesCommand as ListAliasesCommand2,
|
|
56848
|
-
ListKeysCommand,
|
|
56849
|
-
ListResourceTagsCommand,
|
|
56850
|
-
ScheduleKeyDeletionCommand,
|
|
56851
|
-
CreateAliasCommand,
|
|
56852
|
-
DeleteAliasCommand,
|
|
56853
|
-
UpdateAliasCommand,
|
|
56854
|
-
EnableKeyRotationCommand,
|
|
56855
|
-
DisableKeyRotationCommand,
|
|
56856
|
-
UpdateKeyDescriptionCommand,
|
|
56857
|
-
PutKeyPolicyCommand,
|
|
56858
|
-
EnableKeyCommand,
|
|
56859
|
-
DisableKeyCommand,
|
|
56860
|
-
TagResourceCommand as TagResourceCommand14,
|
|
56861
|
-
UntagResourceCommand as UntagResourceCommand14,
|
|
56862
|
-
NotFoundException as NotFoundException5
|
|
56863
|
-
} from "@aws-sdk/client-kms";
|
|
56864
|
-
var KMSProvider = class {
|
|
56884
|
+
var GlueWorkflowProvider = class {
|
|
56865
56885
|
client;
|
|
56886
|
+
stsClient;
|
|
56887
|
+
cachedAccountId;
|
|
56866
56888
|
providerRegion = process.env["AWS_REGION"];
|
|
56867
|
-
logger = getLogger().child("
|
|
56889
|
+
logger = getLogger().child("GlueWorkflowProvider");
|
|
56868
56890
|
handledProperties = /* @__PURE__ */ new Map([
|
|
56869
56891
|
[
|
|
56870
|
-
"AWS::
|
|
56871
|
-
/* @__PURE__ */ new Set([
|
|
56872
|
-
|
|
56873
|
-
"KeyPolicy",
|
|
56874
|
-
"KeySpec",
|
|
56875
|
-
"KeyUsage",
|
|
56876
|
-
"EnableKeyRotation",
|
|
56877
|
-
"Tags",
|
|
56878
|
-
"Enabled",
|
|
56879
|
-
"MultiRegion",
|
|
56880
|
-
"PendingWindowInDays",
|
|
56881
|
-
"RotationPeriodInDays",
|
|
56882
|
-
"Origin",
|
|
56883
|
-
"BypassPolicyLockoutSafetyCheck"
|
|
56884
|
-
])
|
|
56885
|
-
],
|
|
56886
|
-
["AWS::KMS::Alias", /* @__PURE__ */ new Set(["AliasName", "TargetKeyId"])]
|
|
56892
|
+
"AWS::Glue::Workflow",
|
|
56893
|
+
/* @__PURE__ */ new Set(["Name", "Description", "DefaultRunProperties", "MaxConcurrentRuns", "Tags"])
|
|
56894
|
+
]
|
|
56887
56895
|
]);
|
|
56888
56896
|
getClient() {
|
|
56889
56897
|
if (!this.client) {
|
|
56890
|
-
this.client = new
|
|
56898
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
56891
56899
|
}
|
|
56892
56900
|
return this.client;
|
|
56893
56901
|
}
|
|
56894
|
-
// ─── Dispatch ─────────────────────────────────────────────────────
|
|
56895
56902
|
async create(logicalId, resourceType, properties) {
|
|
56896
|
-
|
|
56897
|
-
|
|
56898
|
-
|
|
56899
|
-
|
|
56900
|
-
|
|
56901
|
-
|
|
56902
|
-
|
|
56903
|
-
|
|
56904
|
-
resourceType,
|
|
56905
|
-
logicalId
|
|
56906
|
-
);
|
|
56907
|
-
}
|
|
56908
|
-
}
|
|
56909
|
-
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
56910
|
-
switch (resourceType) {
|
|
56911
|
-
case "AWS::KMS::Key":
|
|
56912
|
-
return this.updateKey(logicalId, physicalId, resourceType, properties, _previousProperties);
|
|
56913
|
-
case "AWS::KMS::Alias":
|
|
56914
|
-
return this.updateAlias(logicalId, physicalId, resourceType, properties);
|
|
56915
|
-
default:
|
|
56916
|
-
throw new ProvisioningError(
|
|
56917
|
-
`Unsupported resource type: ${resourceType}`,
|
|
56918
|
-
resourceType,
|
|
56919
|
-
logicalId,
|
|
56920
|
-
physicalId
|
|
56921
|
-
);
|
|
56922
|
-
}
|
|
56923
|
-
}
|
|
56924
|
-
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
56925
|
-
switch (resourceType) {
|
|
56926
|
-
case "AWS::KMS::Key":
|
|
56927
|
-
return this.deleteKey(logicalId, physicalId, resourceType, _properties, context);
|
|
56928
|
-
case "AWS::KMS::Alias":
|
|
56929
|
-
return this.deleteAlias(logicalId, physicalId, resourceType, context);
|
|
56930
|
-
default:
|
|
56931
|
-
throw new ProvisioningError(
|
|
56932
|
-
`Unsupported resource type: ${resourceType}`,
|
|
56933
|
-
resourceType,
|
|
56934
|
-
logicalId,
|
|
56935
|
-
physicalId
|
|
56936
|
-
);
|
|
56903
|
+
this.logger.debug(`Creating Glue Workflow ${logicalId}`);
|
|
56904
|
+
const name = properties["Name"];
|
|
56905
|
+
if (!name) {
|
|
56906
|
+
throw new ProvisioningError(
|
|
56907
|
+
`Name is required for Glue Workflow ${logicalId}`,
|
|
56908
|
+
resourceType,
|
|
56909
|
+
logicalId
|
|
56910
|
+
);
|
|
56937
56911
|
}
|
|
56938
|
-
}
|
|
56939
|
-
// ─── AWS::KMS::Key ─────────────────────────────────────────────────
|
|
56940
|
-
async createKey(logicalId, resourceType, properties) {
|
|
56941
|
-
this.logger.debug(`Creating KMS Key ${logicalId}`);
|
|
56942
|
-
const description = properties["Description"];
|
|
56943
|
-
const keyPolicy = properties["KeyPolicy"];
|
|
56944
|
-
const keySpec = properties["KeySpec"];
|
|
56945
|
-
const keyUsage = properties["KeyUsage"];
|
|
56946
|
-
const enableKeyRotation = properties["EnableKeyRotation"];
|
|
56947
|
-
const tags = properties["Tags"];
|
|
56948
|
-
const multiRegion = properties["MultiRegion"];
|
|
56949
|
-
const origin = properties["Origin"];
|
|
56950
|
-
const bypassPolicyLockoutSafetyCheck = properties["BypassPolicyLockoutSafetyCheck"];
|
|
56951
56912
|
try {
|
|
56952
|
-
const
|
|
56953
|
-
|
|
56954
|
-
|
|
56955
|
-
|
|
56956
|
-
|
|
56957
|
-
|
|
56958
|
-
|
|
56959
|
-
|
|
56960
|
-
|
|
56961
|
-
|
|
56913
|
+
const tags = workflowTagsForCreate(properties["Tags"]);
|
|
56914
|
+
await this.getClient().send(
|
|
56915
|
+
new CreateWorkflowCommand({
|
|
56916
|
+
Name: name,
|
|
56917
|
+
...properties["Description"] !== void 0 && {
|
|
56918
|
+
Description: properties["Description"]
|
|
56919
|
+
},
|
|
56920
|
+
...properties["DefaultRunProperties"] !== void 0 && {
|
|
56921
|
+
DefaultRunProperties: properties["DefaultRunProperties"]
|
|
56922
|
+
},
|
|
56923
|
+
...properties["MaxConcurrentRuns"] !== void 0 && {
|
|
56924
|
+
MaxConcurrentRuns: properties["MaxConcurrentRuns"]
|
|
56925
|
+
},
|
|
56926
|
+
...tags && { Tags: tags }
|
|
56962
56927
|
})
|
|
56963
56928
|
);
|
|
56964
|
-
|
|
56965
|
-
|
|
56966
|
-
if (enableKeyRotation) {
|
|
56967
|
-
const rotationPeriodInDays = properties["RotationPeriodInDays"];
|
|
56968
|
-
this.logger.debug(`Enabling key rotation for KMS Key ${logicalId}`);
|
|
56969
|
-
await this.getClient().send(
|
|
56970
|
-
new EnableKeyRotationCommand({
|
|
56971
|
-
KeyId: keyId,
|
|
56972
|
-
...rotationPeriodInDays !== void 0 && {
|
|
56973
|
-
RotationPeriodInDays: rotationPeriodInDays
|
|
56974
|
-
}
|
|
56975
|
-
})
|
|
56976
|
-
);
|
|
56977
|
-
}
|
|
56978
|
-
const enabled = properties["Enabled"];
|
|
56979
|
-
if (enabled === false) {
|
|
56980
|
-
this.logger.debug(`Disabling KMS Key ${logicalId}`);
|
|
56981
|
-
await this.getClient().send(new DisableKeyCommand({ KeyId: keyId }));
|
|
56982
|
-
}
|
|
56983
|
-
this.logger.debug(`Successfully created KMS Key ${logicalId}: ${keyId}`);
|
|
56984
|
-
return {
|
|
56985
|
-
physicalId: keyId,
|
|
56986
|
-
attributes: {
|
|
56987
|
-
Arn: keyArn,
|
|
56988
|
-
KeyId: keyId
|
|
56989
|
-
}
|
|
56990
|
-
};
|
|
56929
|
+
this.logger.debug(`Successfully created Glue Workflow ${logicalId}: ${name}`);
|
|
56930
|
+
return { physicalId: name, attributes: {} };
|
|
56991
56931
|
} catch (error) {
|
|
56992
56932
|
const cause = error instanceof Error ? error : void 0;
|
|
56993
56933
|
throw new ProvisioningError(
|
|
56994
|
-
`Failed to create
|
|
56934
|
+
`Failed to create Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
56995
56935
|
resourceType,
|
|
56996
56936
|
logicalId,
|
|
56997
56937
|
void 0,
|
|
@@ -56999,75 +56939,29 @@ var KMSProvider = class {
|
|
|
56999
56939
|
);
|
|
57000
56940
|
}
|
|
57001
56941
|
}
|
|
57002
|
-
async
|
|
57003
|
-
this.logger.debug(`Updating
|
|
56942
|
+
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
56943
|
+
this.logger.debug(`Updating Glue Workflow ${logicalId}: ${physicalId}`);
|
|
57004
56944
|
try {
|
|
57005
|
-
|
|
57006
|
-
|
|
57007
|
-
|
|
57008
|
-
|
|
57009
|
-
|
|
57010
|
-
|
|
57011
|
-
|
|
57012
|
-
|
|
57013
|
-
}
|
|
57014
|
-
|
|
57015
|
-
|
|
57016
|
-
|
|
57017
|
-
|
|
57018
|
-
if (newEnableKeyRotation !== oldEnableKeyRotation) {
|
|
57019
|
-
if (newEnableKeyRotation) {
|
|
57020
|
-
const rotationPeriodInDays = properties["RotationPeriodInDays"];
|
|
57021
|
-
this.logger.debug(`Enabling key rotation for KMS Key ${logicalId}`);
|
|
57022
|
-
await this.getClient().send(
|
|
57023
|
-
new EnableKeyRotationCommand({
|
|
57024
|
-
KeyId: physicalId,
|
|
57025
|
-
...rotationPeriodInDays !== void 0 && {
|
|
57026
|
-
RotationPeriodInDays: rotationPeriodInDays
|
|
57027
|
-
}
|
|
57028
|
-
})
|
|
57029
|
-
);
|
|
57030
|
-
} else {
|
|
57031
|
-
this.logger.debug(`Disabling key rotation for KMS Key ${logicalId}`);
|
|
57032
|
-
await this.getClient().send(new DisableKeyRotationCommand({ KeyId: physicalId }));
|
|
57033
|
-
}
|
|
57034
|
-
}
|
|
57035
|
-
const newEnabled = properties["Enabled"];
|
|
57036
|
-
const oldEnabled = previousProperties["Enabled"];
|
|
57037
|
-
if (newEnabled !== oldEnabled) {
|
|
57038
|
-
if (newEnabled === false) {
|
|
57039
|
-
this.logger.debug(`Disabling KMS Key ${logicalId}`);
|
|
57040
|
-
await this.getClient().send(new DisableKeyCommand({ KeyId: physicalId }));
|
|
57041
|
-
} else {
|
|
57042
|
-
this.logger.debug(`Enabling KMS Key ${logicalId}`);
|
|
57043
|
-
await this.getClient().send(new EnableKeyCommand({ KeyId: physicalId }));
|
|
57044
|
-
}
|
|
57045
|
-
}
|
|
57046
|
-
await this.applyTagDiff(
|
|
57047
|
-
physicalId,
|
|
57048
|
-
previousProperties["Tags"],
|
|
57049
|
-
properties["Tags"]
|
|
56945
|
+
await this.getClient().send(
|
|
56946
|
+
new UpdateWorkflowCommand({
|
|
56947
|
+
Name: physicalId,
|
|
56948
|
+
...properties["Description"] !== void 0 && {
|
|
56949
|
+
Description: properties["Description"]
|
|
56950
|
+
},
|
|
56951
|
+
...properties["DefaultRunProperties"] !== void 0 && {
|
|
56952
|
+
DefaultRunProperties: properties["DefaultRunProperties"]
|
|
56953
|
+
},
|
|
56954
|
+
...properties["MaxConcurrentRuns"] !== void 0 && {
|
|
56955
|
+
MaxConcurrentRuns: properties["MaxConcurrentRuns"]
|
|
56956
|
+
}
|
|
56957
|
+
})
|
|
57050
56958
|
);
|
|
57051
|
-
|
|
57052
|
-
const oldKeyPolicy = previousProperties["KeyPolicy"];
|
|
57053
|
-
const newPolicyStr = newKeyPolicy ? typeof newKeyPolicy === "string" ? newKeyPolicy : JSON.stringify(newKeyPolicy) : void 0;
|
|
57054
|
-
const oldPolicyStr = oldKeyPolicy ? typeof oldKeyPolicy === "string" ? oldKeyPolicy : JSON.stringify(oldKeyPolicy) : void 0;
|
|
57055
|
-
if (newPolicyStr !== oldPolicyStr && newPolicyStr) {
|
|
57056
|
-
this.logger.debug(`Updating key policy for KMS Key ${logicalId}`);
|
|
57057
|
-
await this.getClient().send(
|
|
57058
|
-
new PutKeyPolicyCommand({
|
|
57059
|
-
KeyId: physicalId,
|
|
57060
|
-
PolicyName: "default",
|
|
57061
|
-
Policy: newPolicyStr
|
|
57062
|
-
})
|
|
57063
|
-
);
|
|
57064
|
-
}
|
|
57065
|
-
this.logger.debug(`Successfully updated KMS Key ${logicalId}`);
|
|
56959
|
+
this.logger.debug(`Successfully updated Glue Workflow ${logicalId}`);
|
|
57066
56960
|
return { physicalId, wasReplaced: false };
|
|
57067
56961
|
} catch (error) {
|
|
57068
56962
|
const cause = error instanceof Error ? error : void 0;
|
|
57069
56963
|
throw new ProvisioningError(
|
|
57070
|
-
`Failed to update
|
|
56964
|
+
`Failed to update Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57071
56965
|
resourceType,
|
|
57072
56966
|
logicalId,
|
|
57073
56967
|
physicalId,
|
|
@@ -57075,19 +56969,13 @@ var KMSProvider = class {
|
|
|
57075
56969
|
);
|
|
57076
56970
|
}
|
|
57077
56971
|
}
|
|
57078
|
-
async
|
|
57079
|
-
this.logger.debug(`
|
|
57080
|
-
const pendingWindowInDays = properties?.["PendingWindowInDays"] ?? 7;
|
|
56972
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
56973
|
+
this.logger.debug(`Deleting Glue Workflow ${logicalId}: ${physicalId}`);
|
|
57081
56974
|
try {
|
|
57082
|
-
await this.getClient().send(
|
|
57083
|
-
|
|
57084
|
-
KeyId: physicalId,
|
|
57085
|
-
PendingWindowInDays: pendingWindowInDays
|
|
57086
|
-
})
|
|
57087
|
-
);
|
|
57088
|
-
this.logger.debug(`Successfully scheduled deletion for KMS Key ${logicalId}`);
|
|
56975
|
+
await this.getClient().send(new DeleteWorkflowCommand({ Name: physicalId }));
|
|
56976
|
+
this.logger.debug(`Successfully deleted Glue Workflow ${logicalId}`);
|
|
57089
56977
|
} catch (error) {
|
|
57090
|
-
if (error instanceof
|
|
56978
|
+
if (error instanceof EntityNotFoundException) {
|
|
57091
56979
|
const clientRegion = await this.getClient().config.region();
|
|
57092
56980
|
assertRegionMatch(
|
|
57093
56981
|
clientRegion,
|
|
@@ -57096,12 +56984,12 @@ var KMSProvider = class {
|
|
|
57096
56984
|
logicalId,
|
|
57097
56985
|
physicalId
|
|
57098
56986
|
);
|
|
57099
|
-
this.logger.debug(`
|
|
56987
|
+
this.logger.debug(`Glue Workflow ${physicalId} does not exist, skipping deletion`);
|
|
57100
56988
|
return;
|
|
57101
56989
|
}
|
|
57102
56990
|
const cause = error instanceof Error ? error : void 0;
|
|
57103
56991
|
throw new ProvisioningError(
|
|
57104
|
-
`Failed to
|
|
56992
|
+
`Failed to delete Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57105
56993
|
resourceType,
|
|
57106
56994
|
logicalId,
|
|
57107
56995
|
physicalId,
|
|
@@ -57109,10 +56997,636 @@ var KMSProvider = class {
|
|
|
57109
56997
|
);
|
|
57110
56998
|
}
|
|
57111
56999
|
}
|
|
57112
|
-
|
|
57113
|
-
|
|
57114
|
-
|
|
57115
|
-
|
|
57000
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57001
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
57002
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
57003
|
+
return physicalId;
|
|
57004
|
+
}
|
|
57005
|
+
return void 0;
|
|
57006
|
+
}
|
|
57007
|
+
/**
|
|
57008
|
+
* Read AWS-current Workflow shape via `GetWorkflow`. Surfaces every
|
|
57009
|
+
* user-controllable top-level CFn key with always-emit placeholders
|
|
57010
|
+
* (PR #145):
|
|
57011
|
+
* - `Description` → `?? ''`
|
|
57012
|
+
* - `DefaultRunProperties` → `?? {}`
|
|
57013
|
+
* - `MaxConcurrentRuns` → omitted when AWS reports `undefined` (no
|
|
57014
|
+
* AWS-side default to anchor a placeholder against; cdkd state may
|
|
57015
|
+
* legitimately leave this unset)
|
|
57016
|
+
* - `Tags` → `?? []` (filtered against `aws:cdk:path` and the rest of
|
|
57017
|
+
* the `aws:`-prefixed reserved space)
|
|
57018
|
+
*/
|
|
57019
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
57020
|
+
let workflow;
|
|
57021
|
+
try {
|
|
57022
|
+
const resp = await this.getClient().send(
|
|
57023
|
+
new GetWorkflowCommand({ Name: physicalId, IncludeGraph: false })
|
|
57024
|
+
);
|
|
57025
|
+
workflow = resp.Workflow;
|
|
57026
|
+
} catch (err) {
|
|
57027
|
+
if (err instanceof EntityNotFoundException)
|
|
57028
|
+
return void 0;
|
|
57029
|
+
throw err;
|
|
57030
|
+
}
|
|
57031
|
+
if (!workflow)
|
|
57032
|
+
return void 0;
|
|
57033
|
+
const result = {
|
|
57034
|
+
Name: workflow.Name ?? physicalId,
|
|
57035
|
+
Description: workflow.Description ?? "",
|
|
57036
|
+
DefaultRunProperties: workflow.DefaultRunProperties ?? {}
|
|
57037
|
+
};
|
|
57038
|
+
if (workflow.MaxConcurrentRuns !== void 0) {
|
|
57039
|
+
result["MaxConcurrentRuns"] = workflow.MaxConcurrentRuns;
|
|
57040
|
+
}
|
|
57041
|
+
const arn = await this.buildWorkflowArn(physicalId);
|
|
57042
|
+
let tags = [];
|
|
57043
|
+
try {
|
|
57044
|
+
const tagResp = await this.getClient().send(new GetTagsCommand({ ResourceArn: arn }));
|
|
57045
|
+
tags = normalizeAwsTagsToCfn(tagResp.Tags);
|
|
57046
|
+
} catch (err) {
|
|
57047
|
+
this.logger.debug(
|
|
57048
|
+
`GetTags failed for Glue Workflow ${physicalId}: ${err instanceof Error ? err.message : String(err)}`
|
|
57049
|
+
);
|
|
57050
|
+
}
|
|
57051
|
+
result["Tags"] = tags;
|
|
57052
|
+
return result;
|
|
57053
|
+
}
|
|
57054
|
+
async import(input) {
|
|
57055
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
57056
|
+
if (explicitName) {
|
|
57057
|
+
try {
|
|
57058
|
+
await this.getClient().send(new GetWorkflowCommand({ Name: explicitName }));
|
|
57059
|
+
return { physicalId: explicitName, attributes: {} };
|
|
57060
|
+
} catch (err) {
|
|
57061
|
+
if (err instanceof EntityNotFoundException)
|
|
57062
|
+
return null;
|
|
57063
|
+
throw err;
|
|
57064
|
+
}
|
|
57065
|
+
}
|
|
57066
|
+
if (!input.cdkPath)
|
|
57067
|
+
return null;
|
|
57068
|
+
let nextToken;
|
|
57069
|
+
do {
|
|
57070
|
+
const list = await this.getClient().send(
|
|
57071
|
+
new ListWorkflowsCommand({ ...nextToken && { NextToken: nextToken } })
|
|
57072
|
+
);
|
|
57073
|
+
for (const name of list.Workflows ?? []) {
|
|
57074
|
+
const arn = await this.buildWorkflowArn(name);
|
|
57075
|
+
if (await this.tagsMatchCdkPath(arn, input.cdkPath)) {
|
|
57076
|
+
return { physicalId: name, attributes: {} };
|
|
57077
|
+
}
|
|
57078
|
+
}
|
|
57079
|
+
nextToken = list.NextToken;
|
|
57080
|
+
} while (nextToken);
|
|
57081
|
+
return null;
|
|
57082
|
+
}
|
|
57083
|
+
async tagsMatchCdkPath(arn, cdkPath) {
|
|
57084
|
+
try {
|
|
57085
|
+
const resp = await this.getClient().send(new GetTagsCommand({ ResourceArn: arn }));
|
|
57086
|
+
return resp.Tags?.[CDK_PATH_TAG] === cdkPath;
|
|
57087
|
+
} catch (err) {
|
|
57088
|
+
if (err instanceof EntityNotFoundException)
|
|
57089
|
+
return false;
|
|
57090
|
+
throw err;
|
|
57091
|
+
}
|
|
57092
|
+
}
|
|
57093
|
+
async buildWorkflowArn(workflowName) {
|
|
57094
|
+
const region = await this.getRegion();
|
|
57095
|
+
const account = await this.getAccountId();
|
|
57096
|
+
return `arn:aws:glue:${region}:${account}:workflow/${workflowName}`;
|
|
57097
|
+
}
|
|
57098
|
+
async getRegion() {
|
|
57099
|
+
const region = await this.getClient().config.region();
|
|
57100
|
+
return region || this.providerRegion || "us-east-1";
|
|
57101
|
+
}
|
|
57102
|
+
async getAccountId() {
|
|
57103
|
+
if (this.cachedAccountId)
|
|
57104
|
+
return this.cachedAccountId;
|
|
57105
|
+
if (!this.stsClient) {
|
|
57106
|
+
this.stsClient = new STSClient8(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57107
|
+
}
|
|
57108
|
+
const identity = await this.stsClient.send(new GetCallerIdentityCommand8({}));
|
|
57109
|
+
if (!identity.Account) {
|
|
57110
|
+
throw new Error("Failed to resolve AWS account id from STS");
|
|
57111
|
+
}
|
|
57112
|
+
this.cachedAccountId = identity.Account;
|
|
57113
|
+
return this.cachedAccountId;
|
|
57114
|
+
}
|
|
57115
|
+
};
|
|
57116
|
+
var GlueSecurityConfigurationProvider = class {
|
|
57117
|
+
client;
|
|
57118
|
+
providerRegion = process.env["AWS_REGION"];
|
|
57119
|
+
logger = getLogger().child("GlueSecurityConfigurationProvider");
|
|
57120
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
57121
|
+
["AWS::Glue::SecurityConfiguration", /* @__PURE__ */ new Set(["Name", "EncryptionConfiguration"])]
|
|
57122
|
+
]);
|
|
57123
|
+
getClient() {
|
|
57124
|
+
if (!this.client) {
|
|
57125
|
+
this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57126
|
+
}
|
|
57127
|
+
return this.client;
|
|
57128
|
+
}
|
|
57129
|
+
async create(logicalId, resourceType, properties) {
|
|
57130
|
+
this.logger.debug(`Creating Glue SecurityConfiguration ${logicalId}`);
|
|
57131
|
+
const name = properties["Name"];
|
|
57132
|
+
if (!name) {
|
|
57133
|
+
throw new ProvisioningError(
|
|
57134
|
+
`Name is required for Glue SecurityConfiguration ${logicalId}`,
|
|
57135
|
+
resourceType,
|
|
57136
|
+
logicalId
|
|
57137
|
+
);
|
|
57138
|
+
}
|
|
57139
|
+
const encryptionConfiguration = properties["EncryptionConfiguration"];
|
|
57140
|
+
if (!encryptionConfiguration) {
|
|
57141
|
+
throw new ProvisioningError(
|
|
57142
|
+
`EncryptionConfiguration is required for Glue SecurityConfiguration ${logicalId}`,
|
|
57143
|
+
resourceType,
|
|
57144
|
+
logicalId
|
|
57145
|
+
);
|
|
57146
|
+
}
|
|
57147
|
+
try {
|
|
57148
|
+
await this.getClient().send(
|
|
57149
|
+
new CreateSecurityConfigurationCommand({
|
|
57150
|
+
Name: name,
|
|
57151
|
+
EncryptionConfiguration: buildEncryptionConfiguration(encryptionConfiguration)
|
|
57152
|
+
})
|
|
57153
|
+
);
|
|
57154
|
+
this.logger.debug(`Successfully created Glue SecurityConfiguration ${logicalId}: ${name}`);
|
|
57155
|
+
return { physicalId: name, attributes: {} };
|
|
57156
|
+
} catch (error) {
|
|
57157
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57158
|
+
throw new ProvisioningError(
|
|
57159
|
+
`Failed to create Glue SecurityConfiguration ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57160
|
+
resourceType,
|
|
57161
|
+
logicalId,
|
|
57162
|
+
void 0,
|
|
57163
|
+
cause
|
|
57164
|
+
);
|
|
57165
|
+
}
|
|
57166
|
+
}
|
|
57167
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57168
|
+
async update(logicalId, _physicalId, resourceType, _properties, _previousProperties) {
|
|
57169
|
+
throw new ResourceUpdateNotSupportedError(
|
|
57170
|
+
resourceType,
|
|
57171
|
+
logicalId,
|
|
57172
|
+
"AWS::Glue::SecurityConfiguration is immutable; AWS provides no Update API. Use cdkd deploy --replace, or destroy + redeploy with the new EncryptionConfiguration."
|
|
57173
|
+
);
|
|
57174
|
+
}
|
|
57175
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
57176
|
+
this.logger.debug(`Deleting Glue SecurityConfiguration ${logicalId}: ${physicalId}`);
|
|
57177
|
+
try {
|
|
57178
|
+
await this.getClient().send(new DeleteSecurityConfigurationCommand({ Name: physicalId }));
|
|
57179
|
+
this.logger.debug(`Successfully deleted Glue SecurityConfiguration ${logicalId}`);
|
|
57180
|
+
} catch (error) {
|
|
57181
|
+
if (error instanceof EntityNotFoundException) {
|
|
57182
|
+
const clientRegion = await this.getClient().config.region();
|
|
57183
|
+
assertRegionMatch(
|
|
57184
|
+
clientRegion,
|
|
57185
|
+
context?.expectedRegion,
|
|
57186
|
+
resourceType,
|
|
57187
|
+
logicalId,
|
|
57188
|
+
physicalId
|
|
57189
|
+
);
|
|
57190
|
+
this.logger.debug(
|
|
57191
|
+
`Glue SecurityConfiguration ${physicalId} does not exist, skipping deletion`
|
|
57192
|
+
);
|
|
57193
|
+
return;
|
|
57194
|
+
}
|
|
57195
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57196
|
+
throw new ProvisioningError(
|
|
57197
|
+
`Failed to delete Glue SecurityConfiguration ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57198
|
+
resourceType,
|
|
57199
|
+
logicalId,
|
|
57200
|
+
physicalId,
|
|
57201
|
+
cause
|
|
57202
|
+
);
|
|
57203
|
+
}
|
|
57204
|
+
}
|
|
57205
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- explicit-override-only intentionally has no AWS calls
|
|
57206
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
57207
|
+
if (attributeName === "Id" || attributeName === "Ref" || attributeName === "Name") {
|
|
57208
|
+
return physicalId;
|
|
57209
|
+
}
|
|
57210
|
+
return void 0;
|
|
57211
|
+
}
|
|
57212
|
+
/**
|
|
57213
|
+
* Read AWS-current SecurityConfiguration shape via
|
|
57214
|
+
* `GetSecurityConfiguration`. Always emits the three CFn-modeled
|
|
57215
|
+
* sub-configs (`S3Encryption: []`, `CloudWatchEncryption: {}`,
|
|
57216
|
+
* `JobBookmarksEncryption: {}`) per PR #145 even when AWS reports
|
|
57217
|
+
* nothing — closes the "console-side encryption enable on a previously
|
|
57218
|
+
* default config" detection gap on the v3 baseline.
|
|
57219
|
+
*
|
|
57220
|
+
* `DataQualityEncryption` is silently dropped: the CFn schema for
|
|
57221
|
+
* `AWS::Glue::SecurityConfiguration` does not model it, so surfacing it
|
|
57222
|
+
* would fire false drift on every clean run for a key cdkd state can
|
|
57223
|
+
* never carry.
|
|
57224
|
+
*/
|
|
57225
|
+
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
57226
|
+
let cfg;
|
|
57227
|
+
try {
|
|
57228
|
+
const resp = await this.getClient().send(
|
|
57229
|
+
new GetSecurityConfigurationCommand({ Name: physicalId })
|
|
57230
|
+
);
|
|
57231
|
+
cfg = resp.SecurityConfiguration;
|
|
57232
|
+
} catch (err) {
|
|
57233
|
+
if (err instanceof EntityNotFoundException)
|
|
57234
|
+
return void 0;
|
|
57235
|
+
throw err;
|
|
57236
|
+
}
|
|
57237
|
+
if (!cfg)
|
|
57238
|
+
return void 0;
|
|
57239
|
+
return {
|
|
57240
|
+
Name: cfg.Name ?? physicalId,
|
|
57241
|
+
EncryptionConfiguration: mapEncryptionConfigurationToCfn(cfg.EncryptionConfiguration)
|
|
57242
|
+
};
|
|
57243
|
+
}
|
|
57244
|
+
async import(input) {
|
|
57245
|
+
const explicitName = input.knownPhysicalId ?? input.properties["Name"];
|
|
57246
|
+
if (explicitName) {
|
|
57247
|
+
try {
|
|
57248
|
+
await this.getClient().send(new GetSecurityConfigurationCommand({ Name: explicitName }));
|
|
57249
|
+
return { physicalId: explicitName, attributes: {} };
|
|
57250
|
+
} catch (err) {
|
|
57251
|
+
if (err instanceof EntityNotFoundException)
|
|
57252
|
+
return null;
|
|
57253
|
+
throw err;
|
|
57254
|
+
}
|
|
57255
|
+
}
|
|
57256
|
+
if (!explicitName) {
|
|
57257
|
+
let nextToken;
|
|
57258
|
+
do {
|
|
57259
|
+
const list = await this.getClient().send(
|
|
57260
|
+
new GetSecurityConfigurationsCommand({ ...nextToken && { NextToken: nextToken } })
|
|
57261
|
+
);
|
|
57262
|
+
for (const _entry of list.SecurityConfigurations ?? []) {
|
|
57263
|
+
}
|
|
57264
|
+
nextToken = list.NextToken;
|
|
57265
|
+
} while (nextToken);
|
|
57266
|
+
return null;
|
|
57267
|
+
}
|
|
57268
|
+
return null;
|
|
57269
|
+
}
|
|
57270
|
+
};
|
|
57271
|
+
function workflowTagsForCreate(tags) {
|
|
57272
|
+
if (!Array.isArray(tags) || tags.length === 0)
|
|
57273
|
+
return void 0;
|
|
57274
|
+
const out = {};
|
|
57275
|
+
for (const t of tags) {
|
|
57276
|
+
const obj = t;
|
|
57277
|
+
const k = typeof obj["Key"] === "string" ? obj["Key"] : void 0;
|
|
57278
|
+
const v = typeof obj["Value"] === "string" ? obj["Value"] : "";
|
|
57279
|
+
if (!k)
|
|
57280
|
+
continue;
|
|
57281
|
+
out[k] = v;
|
|
57282
|
+
}
|
|
57283
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
57284
|
+
}
|
|
57285
|
+
function buildEncryptionConfiguration(input) {
|
|
57286
|
+
const result = {};
|
|
57287
|
+
if (Array.isArray(input["S3Encryption"])) {
|
|
57288
|
+
result.S3Encryption = input["S3Encryption"].map((entry) => {
|
|
57289
|
+
const e = entry;
|
|
57290
|
+
const item = {};
|
|
57291
|
+
if (typeof e["S3EncryptionMode"] === "string") {
|
|
57292
|
+
item.S3EncryptionMode = e["S3EncryptionMode"];
|
|
57293
|
+
}
|
|
57294
|
+
if (typeof e["KmsKeyArn"] === "string") {
|
|
57295
|
+
item.KmsKeyArn = e["KmsKeyArn"];
|
|
57296
|
+
}
|
|
57297
|
+
return item;
|
|
57298
|
+
});
|
|
57299
|
+
}
|
|
57300
|
+
if (input["CloudWatchEncryption"] !== void 0) {
|
|
57301
|
+
const cw = input["CloudWatchEncryption"];
|
|
57302
|
+
const item = {};
|
|
57303
|
+
if (typeof cw["CloudWatchEncryptionMode"] === "string") {
|
|
57304
|
+
item.CloudWatchEncryptionMode = cw["CloudWatchEncryptionMode"];
|
|
57305
|
+
}
|
|
57306
|
+
if (typeof cw["KmsKeyArn"] === "string") {
|
|
57307
|
+
item.KmsKeyArn = cw["KmsKeyArn"];
|
|
57308
|
+
}
|
|
57309
|
+
result.CloudWatchEncryption = item;
|
|
57310
|
+
}
|
|
57311
|
+
if (input["JobBookmarksEncryption"] !== void 0) {
|
|
57312
|
+
const jb = input["JobBookmarksEncryption"];
|
|
57313
|
+
const item = {};
|
|
57314
|
+
if (typeof jb["JobBookmarksEncryptionMode"] === "string") {
|
|
57315
|
+
item.JobBookmarksEncryptionMode = jb["JobBookmarksEncryptionMode"];
|
|
57316
|
+
}
|
|
57317
|
+
if (typeof jb["KmsKeyArn"] === "string") {
|
|
57318
|
+
item.KmsKeyArn = jb["KmsKeyArn"];
|
|
57319
|
+
}
|
|
57320
|
+
result.JobBookmarksEncryption = item;
|
|
57321
|
+
}
|
|
57322
|
+
return result;
|
|
57323
|
+
}
|
|
57324
|
+
function mapEncryptionConfigurationToCfn(cfg) {
|
|
57325
|
+
const c = cfg ?? {};
|
|
57326
|
+
return {
|
|
57327
|
+
S3Encryption: (c.S3Encryption ?? []).map((entry) => {
|
|
57328
|
+
const out = {};
|
|
57329
|
+
if (entry.S3EncryptionMode !== void 0)
|
|
57330
|
+
out["S3EncryptionMode"] = entry.S3EncryptionMode;
|
|
57331
|
+
if (entry.KmsKeyArn !== void 0)
|
|
57332
|
+
out["KmsKeyArn"] = entry.KmsKeyArn;
|
|
57333
|
+
return out;
|
|
57334
|
+
}),
|
|
57335
|
+
CloudWatchEncryption: c.CloudWatchEncryption ? cleanCfnObject({
|
|
57336
|
+
CloudWatchEncryptionMode: c.CloudWatchEncryption.CloudWatchEncryptionMode,
|
|
57337
|
+
KmsKeyArn: c.CloudWatchEncryption.KmsKeyArn
|
|
57338
|
+
}) : {},
|
|
57339
|
+
JobBookmarksEncryption: c.JobBookmarksEncryption ? cleanCfnObject({
|
|
57340
|
+
JobBookmarksEncryptionMode: c.JobBookmarksEncryption.JobBookmarksEncryptionMode,
|
|
57341
|
+
KmsKeyArn: c.JobBookmarksEncryption.KmsKeyArn
|
|
57342
|
+
}) : {}
|
|
57343
|
+
};
|
|
57344
|
+
}
|
|
57345
|
+
function cleanCfnObject(obj) {
|
|
57346
|
+
const out = {};
|
|
57347
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
57348
|
+
if (v !== void 0)
|
|
57349
|
+
out[k] = v;
|
|
57350
|
+
}
|
|
57351
|
+
return out;
|
|
57352
|
+
}
|
|
57353
|
+
|
|
57354
|
+
// src/provisioning/providers/kms-provider.ts
|
|
57355
|
+
import {
|
|
57356
|
+
KMSClient as KMSClient2,
|
|
57357
|
+
CreateKeyCommand,
|
|
57358
|
+
DescribeKeyCommand,
|
|
57359
|
+
GetKeyPolicyCommand,
|
|
57360
|
+
GetKeyRotationStatusCommand,
|
|
57361
|
+
ListAliasesCommand as ListAliasesCommand2,
|
|
57362
|
+
ListKeysCommand,
|
|
57363
|
+
ListResourceTagsCommand,
|
|
57364
|
+
ScheduleKeyDeletionCommand,
|
|
57365
|
+
CreateAliasCommand,
|
|
57366
|
+
DeleteAliasCommand,
|
|
57367
|
+
UpdateAliasCommand,
|
|
57368
|
+
EnableKeyRotationCommand,
|
|
57369
|
+
DisableKeyRotationCommand,
|
|
57370
|
+
UpdateKeyDescriptionCommand,
|
|
57371
|
+
PutKeyPolicyCommand,
|
|
57372
|
+
EnableKeyCommand,
|
|
57373
|
+
DisableKeyCommand,
|
|
57374
|
+
TagResourceCommand as TagResourceCommand14,
|
|
57375
|
+
UntagResourceCommand as UntagResourceCommand14,
|
|
57376
|
+
NotFoundException as NotFoundException5
|
|
57377
|
+
} from "@aws-sdk/client-kms";
|
|
57378
|
+
var KMSProvider = class {
|
|
57379
|
+
client;
|
|
57380
|
+
providerRegion = process.env["AWS_REGION"];
|
|
57381
|
+
logger = getLogger().child("KMSProvider");
|
|
57382
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
57383
|
+
[
|
|
57384
|
+
"AWS::KMS::Key",
|
|
57385
|
+
/* @__PURE__ */ new Set([
|
|
57386
|
+
"Description",
|
|
57387
|
+
"KeyPolicy",
|
|
57388
|
+
"KeySpec",
|
|
57389
|
+
"KeyUsage",
|
|
57390
|
+
"EnableKeyRotation",
|
|
57391
|
+
"Tags",
|
|
57392
|
+
"Enabled",
|
|
57393
|
+
"MultiRegion",
|
|
57394
|
+
"PendingWindowInDays",
|
|
57395
|
+
"RotationPeriodInDays",
|
|
57396
|
+
"Origin",
|
|
57397
|
+
"BypassPolicyLockoutSafetyCheck"
|
|
57398
|
+
])
|
|
57399
|
+
],
|
|
57400
|
+
["AWS::KMS::Alias", /* @__PURE__ */ new Set(["AliasName", "TargetKeyId"])]
|
|
57401
|
+
]);
|
|
57402
|
+
getClient() {
|
|
57403
|
+
if (!this.client) {
|
|
57404
|
+
this.client = new KMSClient2(this.providerRegion ? { region: this.providerRegion } : {});
|
|
57405
|
+
}
|
|
57406
|
+
return this.client;
|
|
57407
|
+
}
|
|
57408
|
+
// ─── Dispatch ─────────────────────────────────────────────────────
|
|
57409
|
+
async create(logicalId, resourceType, properties) {
|
|
57410
|
+
switch (resourceType) {
|
|
57411
|
+
case "AWS::KMS::Key":
|
|
57412
|
+
return this.createKey(logicalId, resourceType, properties);
|
|
57413
|
+
case "AWS::KMS::Alias":
|
|
57414
|
+
return this.createAlias(logicalId, resourceType, properties);
|
|
57415
|
+
default:
|
|
57416
|
+
throw new ProvisioningError(
|
|
57417
|
+
`Unsupported resource type: ${resourceType}`,
|
|
57418
|
+
resourceType,
|
|
57419
|
+
logicalId
|
|
57420
|
+
);
|
|
57421
|
+
}
|
|
57422
|
+
}
|
|
57423
|
+
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
57424
|
+
switch (resourceType) {
|
|
57425
|
+
case "AWS::KMS::Key":
|
|
57426
|
+
return this.updateKey(logicalId, physicalId, resourceType, properties, _previousProperties);
|
|
57427
|
+
case "AWS::KMS::Alias":
|
|
57428
|
+
return this.updateAlias(logicalId, physicalId, resourceType, properties);
|
|
57429
|
+
default:
|
|
57430
|
+
throw new ProvisioningError(
|
|
57431
|
+
`Unsupported resource type: ${resourceType}`,
|
|
57432
|
+
resourceType,
|
|
57433
|
+
logicalId,
|
|
57434
|
+
physicalId
|
|
57435
|
+
);
|
|
57436
|
+
}
|
|
57437
|
+
}
|
|
57438
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
57439
|
+
switch (resourceType) {
|
|
57440
|
+
case "AWS::KMS::Key":
|
|
57441
|
+
return this.deleteKey(logicalId, physicalId, resourceType, _properties, context);
|
|
57442
|
+
case "AWS::KMS::Alias":
|
|
57443
|
+
return this.deleteAlias(logicalId, physicalId, resourceType, context);
|
|
57444
|
+
default:
|
|
57445
|
+
throw new ProvisioningError(
|
|
57446
|
+
`Unsupported resource type: ${resourceType}`,
|
|
57447
|
+
resourceType,
|
|
57448
|
+
logicalId,
|
|
57449
|
+
physicalId
|
|
57450
|
+
);
|
|
57451
|
+
}
|
|
57452
|
+
}
|
|
57453
|
+
// ─── AWS::KMS::Key ─────────────────────────────────────────────────
|
|
57454
|
+
async createKey(logicalId, resourceType, properties) {
|
|
57455
|
+
this.logger.debug(`Creating KMS Key ${logicalId}`);
|
|
57456
|
+
const description = properties["Description"];
|
|
57457
|
+
const keyPolicy = properties["KeyPolicy"];
|
|
57458
|
+
const keySpec = properties["KeySpec"];
|
|
57459
|
+
const keyUsage = properties["KeyUsage"];
|
|
57460
|
+
const enableKeyRotation = properties["EnableKeyRotation"];
|
|
57461
|
+
const tags = properties["Tags"];
|
|
57462
|
+
const multiRegion = properties["MultiRegion"];
|
|
57463
|
+
const origin = properties["Origin"];
|
|
57464
|
+
const bypassPolicyLockoutSafetyCheck = properties["BypassPolicyLockoutSafetyCheck"];
|
|
57465
|
+
try {
|
|
57466
|
+
const result = await this.getClient().send(
|
|
57467
|
+
new CreateKeyCommand({
|
|
57468
|
+
Description: description,
|
|
57469
|
+
KeySpec: keySpec,
|
|
57470
|
+
KeyUsage: keyUsage,
|
|
57471
|
+
Policy: keyPolicy ? typeof keyPolicy === "string" ? keyPolicy : JSON.stringify(keyPolicy) : void 0,
|
|
57472
|
+
Tags: tags ? tags.map((t) => ({ TagKey: t.Key, TagValue: t.Value })) : void 0,
|
|
57473
|
+
MultiRegion: multiRegion,
|
|
57474
|
+
Origin: origin,
|
|
57475
|
+
BypassPolicyLockoutSafetyCheck: bypassPolicyLockoutSafetyCheck
|
|
57476
|
+
})
|
|
57477
|
+
);
|
|
57478
|
+
const keyId = result.KeyMetadata.KeyId;
|
|
57479
|
+
const keyArn = result.KeyMetadata.Arn;
|
|
57480
|
+
if (enableKeyRotation) {
|
|
57481
|
+
const rotationPeriodInDays = properties["RotationPeriodInDays"];
|
|
57482
|
+
this.logger.debug(`Enabling key rotation for KMS Key ${logicalId}`);
|
|
57483
|
+
await this.getClient().send(
|
|
57484
|
+
new EnableKeyRotationCommand({
|
|
57485
|
+
KeyId: keyId,
|
|
57486
|
+
...rotationPeriodInDays !== void 0 && {
|
|
57487
|
+
RotationPeriodInDays: rotationPeriodInDays
|
|
57488
|
+
}
|
|
57489
|
+
})
|
|
57490
|
+
);
|
|
57491
|
+
}
|
|
57492
|
+
const enabled = properties["Enabled"];
|
|
57493
|
+
if (enabled === false) {
|
|
57494
|
+
this.logger.debug(`Disabling KMS Key ${logicalId}`);
|
|
57495
|
+
await this.getClient().send(new DisableKeyCommand({ KeyId: keyId }));
|
|
57496
|
+
}
|
|
57497
|
+
this.logger.debug(`Successfully created KMS Key ${logicalId}: ${keyId}`);
|
|
57498
|
+
return {
|
|
57499
|
+
physicalId: keyId,
|
|
57500
|
+
attributes: {
|
|
57501
|
+
Arn: keyArn,
|
|
57502
|
+
KeyId: keyId
|
|
57503
|
+
}
|
|
57504
|
+
};
|
|
57505
|
+
} catch (error) {
|
|
57506
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57507
|
+
throw new ProvisioningError(
|
|
57508
|
+
`Failed to create KMS Key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57509
|
+
resourceType,
|
|
57510
|
+
logicalId,
|
|
57511
|
+
void 0,
|
|
57512
|
+
cause
|
|
57513
|
+
);
|
|
57514
|
+
}
|
|
57515
|
+
}
|
|
57516
|
+
async updateKey(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
57517
|
+
this.logger.debug(`Updating KMS Key ${logicalId}: ${physicalId}`);
|
|
57518
|
+
try {
|
|
57519
|
+
const newDescription = properties["Description"];
|
|
57520
|
+
const oldDescription = previousProperties["Description"];
|
|
57521
|
+
if (newDescription !== oldDescription) {
|
|
57522
|
+
this.logger.debug(`Updating description for KMS Key ${logicalId}`);
|
|
57523
|
+
await this.getClient().send(
|
|
57524
|
+
new UpdateKeyDescriptionCommand({
|
|
57525
|
+
KeyId: physicalId,
|
|
57526
|
+
Description: newDescription ?? ""
|
|
57527
|
+
})
|
|
57528
|
+
);
|
|
57529
|
+
}
|
|
57530
|
+
const newEnableKeyRotation = properties["EnableKeyRotation"];
|
|
57531
|
+
const oldEnableKeyRotation = previousProperties["EnableKeyRotation"];
|
|
57532
|
+
if (newEnableKeyRotation !== oldEnableKeyRotation) {
|
|
57533
|
+
if (newEnableKeyRotation) {
|
|
57534
|
+
const rotationPeriodInDays = properties["RotationPeriodInDays"];
|
|
57535
|
+
this.logger.debug(`Enabling key rotation for KMS Key ${logicalId}`);
|
|
57536
|
+
await this.getClient().send(
|
|
57537
|
+
new EnableKeyRotationCommand({
|
|
57538
|
+
KeyId: physicalId,
|
|
57539
|
+
...rotationPeriodInDays !== void 0 && {
|
|
57540
|
+
RotationPeriodInDays: rotationPeriodInDays
|
|
57541
|
+
}
|
|
57542
|
+
})
|
|
57543
|
+
);
|
|
57544
|
+
} else {
|
|
57545
|
+
this.logger.debug(`Disabling key rotation for KMS Key ${logicalId}`);
|
|
57546
|
+
await this.getClient().send(new DisableKeyRotationCommand({ KeyId: physicalId }));
|
|
57547
|
+
}
|
|
57548
|
+
}
|
|
57549
|
+
const newEnabled = properties["Enabled"];
|
|
57550
|
+
const oldEnabled = previousProperties["Enabled"];
|
|
57551
|
+
if (newEnabled !== oldEnabled) {
|
|
57552
|
+
if (newEnabled === false) {
|
|
57553
|
+
this.logger.debug(`Disabling KMS Key ${logicalId}`);
|
|
57554
|
+
await this.getClient().send(new DisableKeyCommand({ KeyId: physicalId }));
|
|
57555
|
+
} else {
|
|
57556
|
+
this.logger.debug(`Enabling KMS Key ${logicalId}`);
|
|
57557
|
+
await this.getClient().send(new EnableKeyCommand({ KeyId: physicalId }));
|
|
57558
|
+
}
|
|
57559
|
+
}
|
|
57560
|
+
await this.applyTagDiff(
|
|
57561
|
+
physicalId,
|
|
57562
|
+
previousProperties["Tags"],
|
|
57563
|
+
properties["Tags"]
|
|
57564
|
+
);
|
|
57565
|
+
const newKeyPolicy = properties["KeyPolicy"];
|
|
57566
|
+
const oldKeyPolicy = previousProperties["KeyPolicy"];
|
|
57567
|
+
const newPolicyStr = newKeyPolicy ? typeof newKeyPolicy === "string" ? newKeyPolicy : JSON.stringify(newKeyPolicy) : void 0;
|
|
57568
|
+
const oldPolicyStr = oldKeyPolicy ? typeof oldKeyPolicy === "string" ? oldKeyPolicy : JSON.stringify(oldKeyPolicy) : void 0;
|
|
57569
|
+
if (newPolicyStr !== oldPolicyStr && newPolicyStr) {
|
|
57570
|
+
this.logger.debug(`Updating key policy for KMS Key ${logicalId}`);
|
|
57571
|
+
await this.getClient().send(
|
|
57572
|
+
new PutKeyPolicyCommand({
|
|
57573
|
+
KeyId: physicalId,
|
|
57574
|
+
PolicyName: "default",
|
|
57575
|
+
Policy: newPolicyStr
|
|
57576
|
+
})
|
|
57577
|
+
);
|
|
57578
|
+
}
|
|
57579
|
+
this.logger.debug(`Successfully updated KMS Key ${logicalId}`);
|
|
57580
|
+
return { physicalId, wasReplaced: false };
|
|
57581
|
+
} catch (error) {
|
|
57582
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57583
|
+
throw new ProvisioningError(
|
|
57584
|
+
`Failed to update KMS Key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57585
|
+
resourceType,
|
|
57586
|
+
logicalId,
|
|
57587
|
+
physicalId,
|
|
57588
|
+
cause
|
|
57589
|
+
);
|
|
57590
|
+
}
|
|
57591
|
+
}
|
|
57592
|
+
async deleteKey(logicalId, physicalId, resourceType, properties, context) {
|
|
57593
|
+
this.logger.debug(`Scheduling deletion for KMS Key ${logicalId}: ${physicalId}`);
|
|
57594
|
+
const pendingWindowInDays = properties?.["PendingWindowInDays"] ?? 7;
|
|
57595
|
+
try {
|
|
57596
|
+
await this.getClient().send(
|
|
57597
|
+
new ScheduleKeyDeletionCommand({
|
|
57598
|
+
KeyId: physicalId,
|
|
57599
|
+
PendingWindowInDays: pendingWindowInDays
|
|
57600
|
+
})
|
|
57601
|
+
);
|
|
57602
|
+
this.logger.debug(`Successfully scheduled deletion for KMS Key ${logicalId}`);
|
|
57603
|
+
} catch (error) {
|
|
57604
|
+
if (error instanceof NotFoundException5) {
|
|
57605
|
+
const clientRegion = await this.getClient().config.region();
|
|
57606
|
+
assertRegionMatch(
|
|
57607
|
+
clientRegion,
|
|
57608
|
+
context?.expectedRegion,
|
|
57609
|
+
resourceType,
|
|
57610
|
+
logicalId,
|
|
57611
|
+
physicalId
|
|
57612
|
+
);
|
|
57613
|
+
this.logger.debug(`KMS Key ${physicalId} does not exist, skipping deletion`);
|
|
57614
|
+
return;
|
|
57615
|
+
}
|
|
57616
|
+
const cause = error instanceof Error ? error : void 0;
|
|
57617
|
+
throw new ProvisioningError(
|
|
57618
|
+
`Failed to schedule deletion for KMS Key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
57619
|
+
resourceType,
|
|
57620
|
+
logicalId,
|
|
57621
|
+
physicalId,
|
|
57622
|
+
cause
|
|
57623
|
+
);
|
|
57624
|
+
}
|
|
57625
|
+
}
|
|
57626
|
+
/**
|
|
57627
|
+
* Apply a diff between old and new CFn-shape Tags arrays via KMS's
|
|
57628
|
+
* `TagResource` / `UntagResource` APIs. KMS uses `{TagKey, TagValue}`
|
|
57629
|
+
* (NOT the standard `{Key, Value}` shape) keyed by `KeyId`.
|
|
57116
57630
|
*/
|
|
57117
57631
|
async applyTagDiff(keyId, oldTagsRaw, newTagsRaw) {
|
|
57118
57632
|
const toMap = (tags) => {
|
|
@@ -57944,6 +58458,349 @@ var KinesisStreamProvider = class {
|
|
|
57944
58458
|
}
|
|
57945
58459
|
};
|
|
57946
58460
|
|
|
58461
|
+
// src/provisioning/providers/kinesis-streamconsumer-provider.ts
|
|
58462
|
+
import {
|
|
58463
|
+
KinesisClient as KinesisClient2,
|
|
58464
|
+
RegisterStreamConsumerCommand,
|
|
58465
|
+
DeregisterStreamConsumerCommand,
|
|
58466
|
+
DescribeStreamConsumerCommand,
|
|
58467
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand18,
|
|
58468
|
+
TagResourceCommand as TagResourceCommand15,
|
|
58469
|
+
UntagResourceCommand as UntagResourceCommand15,
|
|
58470
|
+
ResourceNotFoundException as ResourceNotFoundException14
|
|
58471
|
+
} from "@aws-sdk/client-kinesis";
|
|
58472
|
+
var KinesisStreamConsumerProvider = class {
|
|
58473
|
+
client;
|
|
58474
|
+
providerRegion = process.env["AWS_REGION"];
|
|
58475
|
+
logger = getLogger().child("KinesisStreamConsumerProvider");
|
|
58476
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
58477
|
+
["AWS::Kinesis::StreamConsumer", /* @__PURE__ */ new Set(["ConsumerName", "StreamARN", "Tags"])]
|
|
58478
|
+
]);
|
|
58479
|
+
getClient() {
|
|
58480
|
+
if (!this.client) {
|
|
58481
|
+
this.client = new KinesisClient2(this.providerRegion ? { region: this.providerRegion } : {});
|
|
58482
|
+
}
|
|
58483
|
+
return this.client;
|
|
58484
|
+
}
|
|
58485
|
+
/**
|
|
58486
|
+
* Register a Kinesis stream consumer.
|
|
58487
|
+
*
|
|
58488
|
+
* Polls `DescribeStreamConsumer` until ConsumerStatus flips from
|
|
58489
|
+
* `CREATING` to `ACTIVE` (matches CFn behavior). 1s polling interval
|
|
58490
|
+
* is faster than the CC API exponential backoff used to be.
|
|
58491
|
+
*/
|
|
58492
|
+
async create(logicalId, resourceType, properties) {
|
|
58493
|
+
const consumerName = properties["ConsumerName"];
|
|
58494
|
+
const streamArn = properties["StreamARN"];
|
|
58495
|
+
if (!consumerName) {
|
|
58496
|
+
throw new ProvisioningError(
|
|
58497
|
+
"AWS::Kinesis::StreamConsumer requires ConsumerName",
|
|
58498
|
+
resourceType,
|
|
58499
|
+
logicalId
|
|
58500
|
+
);
|
|
58501
|
+
}
|
|
58502
|
+
if (!streamArn) {
|
|
58503
|
+
throw new ProvisioningError(
|
|
58504
|
+
"AWS::Kinesis::StreamConsumer requires StreamARN",
|
|
58505
|
+
resourceType,
|
|
58506
|
+
logicalId
|
|
58507
|
+
);
|
|
58508
|
+
}
|
|
58509
|
+
this.logger.debug(`Registering Kinesis stream consumer ${logicalId}: ${consumerName}`);
|
|
58510
|
+
const tagList = Array.isArray(properties["Tags"]) ? properties["Tags"] : void 0;
|
|
58511
|
+
const tagMap = tagListToMap(tagList);
|
|
58512
|
+
try {
|
|
58513
|
+
const resp = await this.getClient().send(
|
|
58514
|
+
new RegisterStreamConsumerCommand({
|
|
58515
|
+
StreamARN: streamArn,
|
|
58516
|
+
ConsumerName: consumerName,
|
|
58517
|
+
...tagMap && Object.keys(tagMap).length > 0 ? { Tags: tagMap } : {}
|
|
58518
|
+
})
|
|
58519
|
+
);
|
|
58520
|
+
const consumer = resp.Consumer;
|
|
58521
|
+
if (!consumer?.ConsumerARN || !consumer.ConsumerName) {
|
|
58522
|
+
throw new ProvisioningError(
|
|
58523
|
+
"RegisterStreamConsumer did not return ConsumerARN/ConsumerName",
|
|
58524
|
+
resourceType,
|
|
58525
|
+
logicalId
|
|
58526
|
+
);
|
|
58527
|
+
}
|
|
58528
|
+
const consumerArn = consumer.ConsumerARN;
|
|
58529
|
+
await this.waitForConsumerActive(consumerArn);
|
|
58530
|
+
this.logger.debug(`Successfully registered Kinesis stream consumer ${logicalId}`);
|
|
58531
|
+
return {
|
|
58532
|
+
physicalId: consumerArn,
|
|
58533
|
+
attributes: {
|
|
58534
|
+
ConsumerARN: consumerArn,
|
|
58535
|
+
ConsumerName: consumer.ConsumerName,
|
|
58536
|
+
ConsumerStatus: consumer.ConsumerStatus,
|
|
58537
|
+
ConsumerCreationTimestamp: consumer.ConsumerCreationTimestamp?.toISOString() ?? void 0,
|
|
58538
|
+
// CFn `Id` for StreamConsumer is the ConsumerARN (matches the
|
|
58539
|
+
// CFn return-values doc).
|
|
58540
|
+
Id: consumerArn,
|
|
58541
|
+
StreamARN: streamArn
|
|
58542
|
+
}
|
|
58543
|
+
};
|
|
58544
|
+
} catch (error) {
|
|
58545
|
+
if (error instanceof ProvisioningError)
|
|
58546
|
+
throw error;
|
|
58547
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58548
|
+
throw new ProvisioningError(
|
|
58549
|
+
`Failed to register Kinesis stream consumer ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58550
|
+
resourceType,
|
|
58551
|
+
logicalId,
|
|
58552
|
+
consumerName,
|
|
58553
|
+
cause
|
|
58554
|
+
);
|
|
58555
|
+
}
|
|
58556
|
+
}
|
|
58557
|
+
/**
|
|
58558
|
+
* Update is a no-op for the immutable `ConsumerName` / `StreamARN`
|
|
58559
|
+
* fields (the deploy engine's replacement-detection layer triggers
|
|
58560
|
+
* DELETE + CREATE for those changes). Tags ARE mutable via
|
|
58561
|
+
* `TagResource` / `UntagResource` so the diff is applied here.
|
|
58562
|
+
*
|
|
58563
|
+
* If a non-Tags property changes, throw `ResourceUpdateNotSupportedError`
|
|
58564
|
+
* — `cdkd drift --revert` will surface that to the user with the
|
|
58565
|
+
* "use cdkd deploy --replace" suggestion.
|
|
58566
|
+
*/
|
|
58567
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
58568
|
+
const newConsumerName = properties["ConsumerName"];
|
|
58569
|
+
const oldConsumerName = previousProperties["ConsumerName"];
|
|
58570
|
+
const newStreamArn = properties["StreamARN"];
|
|
58571
|
+
const oldStreamArn = previousProperties["StreamARN"];
|
|
58572
|
+
if (newConsumerName !== oldConsumerName || newStreamArn !== oldStreamArn) {
|
|
58573
|
+
throw new ResourceUpdateNotSupportedError(
|
|
58574
|
+
resourceType,
|
|
58575
|
+
logicalId,
|
|
58576
|
+
"AWS::Kinesis::StreamConsumer ConsumerName / StreamARN are immutable; re-deploy with cdkd deploy --replace, or destroy + redeploy"
|
|
58577
|
+
);
|
|
58578
|
+
}
|
|
58579
|
+
await this.applyTagDiff(
|
|
58580
|
+
physicalId,
|
|
58581
|
+
previousProperties["Tags"],
|
|
58582
|
+
properties["Tags"]
|
|
58583
|
+
);
|
|
58584
|
+
let attrs = {};
|
|
58585
|
+
try {
|
|
58586
|
+
const resp = await this.getClient().send(
|
|
58587
|
+
new DescribeStreamConsumerCommand({ ConsumerARN: physicalId })
|
|
58588
|
+
);
|
|
58589
|
+
const desc = resp.ConsumerDescription;
|
|
58590
|
+
if (desc) {
|
|
58591
|
+
attrs = {
|
|
58592
|
+
ConsumerARN: desc.ConsumerARN,
|
|
58593
|
+
ConsumerName: desc.ConsumerName,
|
|
58594
|
+
ConsumerStatus: desc.ConsumerStatus,
|
|
58595
|
+
ConsumerCreationTimestamp: desc.ConsumerCreationTimestamp?.toISOString() ?? void 0,
|
|
58596
|
+
Id: desc.ConsumerARN,
|
|
58597
|
+
StreamARN: desc.StreamARN
|
|
58598
|
+
};
|
|
58599
|
+
}
|
|
58600
|
+
} catch (err) {
|
|
58601
|
+
this.logger.debug(
|
|
58602
|
+
`DescribeStreamConsumer(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
58603
|
+
);
|
|
58604
|
+
}
|
|
58605
|
+
return {
|
|
58606
|
+
physicalId,
|
|
58607
|
+
wasReplaced: false,
|
|
58608
|
+
attributes: attrs
|
|
58609
|
+
};
|
|
58610
|
+
}
|
|
58611
|
+
/**
|
|
58612
|
+
* Deregister a Kinesis stream consumer.
|
|
58613
|
+
*
|
|
58614
|
+
* Per CFn semantics, DELETE returns once `DeregisterStreamConsumer`
|
|
58615
|
+
* returns — AWS handles eventual disappearance asynchronously, but
|
|
58616
|
+
* cdkd does not need to poll for that. `ResourceNotFoundException`
|
|
58617
|
+
* is treated as idempotent success (subject to the standard region
|
|
58618
|
+
* verification for delete idempotency).
|
|
58619
|
+
*/
|
|
58620
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
58621
|
+
this.logger.debug(`Deregistering Kinesis stream consumer ${logicalId}: ${physicalId}`);
|
|
58622
|
+
try {
|
|
58623
|
+
await this.getClient().send(new DeregisterStreamConsumerCommand({ ConsumerARN: physicalId }));
|
|
58624
|
+
this.logger.debug(`Successfully deregistered Kinesis stream consumer ${logicalId}`);
|
|
58625
|
+
} catch (error) {
|
|
58626
|
+
if (error instanceof ResourceNotFoundException14) {
|
|
58627
|
+
const clientRegion = await this.getClient().config.region();
|
|
58628
|
+
assertRegionMatch(
|
|
58629
|
+
clientRegion,
|
|
58630
|
+
context?.expectedRegion,
|
|
58631
|
+
resourceType,
|
|
58632
|
+
logicalId,
|
|
58633
|
+
physicalId
|
|
58634
|
+
);
|
|
58635
|
+
this.logger.debug(`Kinesis stream consumer ${physicalId} not found, skipping`);
|
|
58636
|
+
return;
|
|
58637
|
+
}
|
|
58638
|
+
const cause = error instanceof Error ? error : void 0;
|
|
58639
|
+
throw new ProvisioningError(
|
|
58640
|
+
`Failed to deregister Kinesis stream consumer ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
58641
|
+
resourceType,
|
|
58642
|
+
logicalId,
|
|
58643
|
+
physicalId,
|
|
58644
|
+
cause
|
|
58645
|
+
);
|
|
58646
|
+
}
|
|
58647
|
+
}
|
|
58648
|
+
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
58649
|
+
if (attributeName === "ConsumerARN" || attributeName === "Id") {
|
|
58650
|
+
return physicalId;
|
|
58651
|
+
}
|
|
58652
|
+
const resp = await this.getClient().send(
|
|
58653
|
+
new DescribeStreamConsumerCommand({ ConsumerARN: physicalId })
|
|
58654
|
+
);
|
|
58655
|
+
const desc = resp.ConsumerDescription;
|
|
58656
|
+
if (!desc)
|
|
58657
|
+
return void 0;
|
|
58658
|
+
switch (attributeName) {
|
|
58659
|
+
case "ConsumerName":
|
|
58660
|
+
return desc.ConsumerName;
|
|
58661
|
+
case "ConsumerStatus":
|
|
58662
|
+
return desc.ConsumerStatus;
|
|
58663
|
+
case "ConsumerCreationTimestamp":
|
|
58664
|
+
return desc.ConsumerCreationTimestamp?.toISOString() ?? void 0;
|
|
58665
|
+
case "StreamARN":
|
|
58666
|
+
return desc.StreamARN;
|
|
58667
|
+
default:
|
|
58668
|
+
return void 0;
|
|
58669
|
+
}
|
|
58670
|
+
}
|
|
58671
|
+
/**
|
|
58672
|
+
* Read the AWS-current StreamConsumer configuration in CFn-property shape.
|
|
58673
|
+
*
|
|
58674
|
+
* Surfaces `ConsumerName` + `StreamARN` (the only user-controllable
|
|
58675
|
+
* top-level CFn properties). AWS-managed read-only fields
|
|
58676
|
+
* (`ConsumerARN`, `ConsumerCreationTimestamp`, `ConsumerStatus`) are
|
|
58677
|
+
* omitted — they are not in `handledProperties` and surface only as
|
|
58678
|
+
* `getAttribute` results.
|
|
58679
|
+
*
|
|
58680
|
+
* `Tags` are surfaced via `ListTagsForResource(ResourceARN=ConsumerARN)`
|
|
58681
|
+
* with `aws:*` filtered out and the always-emit `[]` placeholder
|
|
58682
|
+
* pattern (PR #145). The CFn schema for `AWS::Kinesis::StreamConsumer`
|
|
58683
|
+
* does not currently model Tags as a top-level property, but cdkd
|
|
58684
|
+
* surfaces it defensively so future schema revisions or custom
|
|
58685
|
+
* property overrides can round-trip cleanly.
|
|
58686
|
+
*
|
|
58687
|
+
* Returns `undefined` when the consumer is gone
|
|
58688
|
+
* (`ResourceNotFoundException`).
|
|
58689
|
+
*/
|
|
58690
|
+
async readCurrentState(physicalId, _logicalId, resourceType) {
|
|
58691
|
+
if (resourceType !== "AWS::Kinesis::StreamConsumer")
|
|
58692
|
+
return void 0;
|
|
58693
|
+
let desc;
|
|
58694
|
+
try {
|
|
58695
|
+
const resp = await this.getClient().send(
|
|
58696
|
+
new DescribeStreamConsumerCommand({ ConsumerARN: physicalId })
|
|
58697
|
+
);
|
|
58698
|
+
desc = resp.ConsumerDescription;
|
|
58699
|
+
} catch (err) {
|
|
58700
|
+
if (err instanceof ResourceNotFoundException14)
|
|
58701
|
+
return void 0;
|
|
58702
|
+
throw err;
|
|
58703
|
+
}
|
|
58704
|
+
if (!desc)
|
|
58705
|
+
return void 0;
|
|
58706
|
+
const result = {};
|
|
58707
|
+
if (desc.ConsumerName !== void 0)
|
|
58708
|
+
result["ConsumerName"] = desc.ConsumerName;
|
|
58709
|
+
if (desc.StreamARN !== void 0)
|
|
58710
|
+
result["StreamARN"] = desc.StreamARN;
|
|
58711
|
+
try {
|
|
58712
|
+
const tagsResp = await this.getClient().send(
|
|
58713
|
+
new ListTagsForResourceCommand18({ ResourceARN: physicalId })
|
|
58714
|
+
);
|
|
58715
|
+
result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
|
|
58716
|
+
} catch (err) {
|
|
58717
|
+
if (err instanceof ResourceNotFoundException14)
|
|
58718
|
+
return void 0;
|
|
58719
|
+
this.logger.debug(
|
|
58720
|
+
`ListTagsForResource(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
58721
|
+
);
|
|
58722
|
+
result["Tags"] = [];
|
|
58723
|
+
}
|
|
58724
|
+
return result;
|
|
58725
|
+
}
|
|
58726
|
+
/**
|
|
58727
|
+
* Apply a diff between old and new CFn-shape Tags arrays via Kinesis's
|
|
58728
|
+
* generic `TagResource` (TagMap shape) / `UntagResource` (TagKeys list)
|
|
58729
|
+
* APIs. Mirrors `KinesisStreamProvider.applyTagDiff`, except the
|
|
58730
|
+
* Kinesis service splits the per-resource-type tag APIs vs the generic
|
|
58731
|
+
* tag APIs — StreamConsumer uses the generic ones (which accept any
|
|
58732
|
+
* Kinesis resource ARN).
|
|
58733
|
+
*/
|
|
58734
|
+
async applyTagDiff(consumerArn, oldTagsRaw, newTagsRaw) {
|
|
58735
|
+
const oldMap = tagListToMap(oldTagsRaw) ?? {};
|
|
58736
|
+
const newMap = tagListToMap(newTagsRaw) ?? {};
|
|
58737
|
+
const tagsToAdd = {};
|
|
58738
|
+
for (const [k, v] of Object.entries(newMap)) {
|
|
58739
|
+
if (oldMap[k] !== v)
|
|
58740
|
+
tagsToAdd[k] = v;
|
|
58741
|
+
}
|
|
58742
|
+
const tagsToRemove = [];
|
|
58743
|
+
for (const k of Object.keys(oldMap)) {
|
|
58744
|
+
if (!(k in newMap))
|
|
58745
|
+
tagsToRemove.push(k);
|
|
58746
|
+
}
|
|
58747
|
+
if (tagsToRemove.length > 0) {
|
|
58748
|
+
await this.getClient().send(
|
|
58749
|
+
new UntagResourceCommand15({ ResourceARN: consumerArn, TagKeys: tagsToRemove })
|
|
58750
|
+
);
|
|
58751
|
+
this.logger.debug(
|
|
58752
|
+
`Removed ${tagsToRemove.length} tag(s) from Kinesis stream consumer ${consumerArn}`
|
|
58753
|
+
);
|
|
58754
|
+
}
|
|
58755
|
+
if (Object.keys(tagsToAdd).length > 0) {
|
|
58756
|
+
await this.getClient().send(
|
|
58757
|
+
new TagResourceCommand15({ ResourceARN: consumerArn, Tags: tagsToAdd })
|
|
58758
|
+
);
|
|
58759
|
+
this.logger.debug(
|
|
58760
|
+
`Added/updated ${Object.keys(tagsToAdd).length} tag(s) on Kinesis stream consumer ${consumerArn}`
|
|
58761
|
+
);
|
|
58762
|
+
}
|
|
58763
|
+
}
|
|
58764
|
+
/**
|
|
58765
|
+
* Poll DescribeStreamConsumer until the consumer reaches `ACTIVE`.
|
|
58766
|
+
*
|
|
58767
|
+
* Uses 1s polling intervals — consumer registration is typically
|
|
58768
|
+
* sub-second, but AWS can take up to ~30s under load. Caps at 60
|
|
58769
|
+
* attempts (1 minute total) which is bounded above by the per-resource
|
|
58770
|
+
* `--resource-timeout` deadline.
|
|
58771
|
+
*/
|
|
58772
|
+
async waitForConsumerActive(consumerArn, maxAttempts = 60) {
|
|
58773
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
58774
|
+
const resp = await this.getClient().send(
|
|
58775
|
+
new DescribeStreamConsumerCommand({ ConsumerARN: consumerArn })
|
|
58776
|
+
);
|
|
58777
|
+
const status = resp.ConsumerDescription?.ConsumerStatus;
|
|
58778
|
+
this.logger.debug(
|
|
58779
|
+
`Consumer ${consumerArn} status: ${status} (attempt ${attempt}/${maxAttempts})`
|
|
58780
|
+
);
|
|
58781
|
+
if (status === "ACTIVE")
|
|
58782
|
+
return;
|
|
58783
|
+
if (status !== "CREATING") {
|
|
58784
|
+
throw new Error(`Unexpected consumer status: ${status}`);
|
|
58785
|
+
}
|
|
58786
|
+
await new Promise((resolve4) => setTimeout(resolve4, 1e3));
|
|
58787
|
+
}
|
|
58788
|
+
throw new Error(
|
|
58789
|
+
`Consumer ${consumerArn} did not reach ACTIVE status within ${maxAttempts} seconds`
|
|
58790
|
+
);
|
|
58791
|
+
}
|
|
58792
|
+
};
|
|
58793
|
+
function tagListToMap(tags) {
|
|
58794
|
+
if (!tags || tags.length === 0)
|
|
58795
|
+
return void 0;
|
|
58796
|
+
const out = {};
|
|
58797
|
+
for (const t of tags) {
|
|
58798
|
+
if (t.Key !== void 0 && t.Value !== void 0)
|
|
58799
|
+
out[t.Key] = t.Value;
|
|
58800
|
+
}
|
|
58801
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
58802
|
+
}
|
|
58803
|
+
|
|
57947
58804
|
// src/provisioning/providers/efs-provider.ts
|
|
57948
58805
|
import {
|
|
57949
58806
|
EFSClient,
|
|
@@ -58757,7 +59614,7 @@ import {
|
|
|
58757
59614
|
DescribeDeliveryStreamCommand,
|
|
58758
59615
|
ListDeliveryStreamsCommand,
|
|
58759
59616
|
ListTagsForDeliveryStreamCommand,
|
|
58760
|
-
ResourceNotFoundException as
|
|
59617
|
+
ResourceNotFoundException as ResourceNotFoundException15
|
|
58761
59618
|
} from "@aws-sdk/client-firehose";
|
|
58762
59619
|
var FirehoseProvider = class {
|
|
58763
59620
|
client;
|
|
@@ -58990,7 +59847,7 @@ var FirehoseProvider = class {
|
|
|
58990
59847
|
);
|
|
58991
59848
|
this.logger.debug(`Successfully deleted Firehose delivery stream ${logicalId}`);
|
|
58992
59849
|
} catch (error) {
|
|
58993
|
-
if (error instanceof
|
|
59850
|
+
if (error instanceof ResourceNotFoundException15) {
|
|
58994
59851
|
const clientRegion = await this.getClient().config.region();
|
|
58995
59852
|
assertRegionMatch(
|
|
58996
59853
|
clientRegion,
|
|
@@ -59169,7 +60026,7 @@ var FirehoseProvider = class {
|
|
|
59169
60026
|
);
|
|
59170
60027
|
desc = resp.DeliveryStreamDescription;
|
|
59171
60028
|
} catch (err) {
|
|
59172
|
-
if (err instanceof
|
|
60029
|
+
if (err instanceof ResourceNotFoundException15)
|
|
59173
60030
|
return void 0;
|
|
59174
60031
|
throw err;
|
|
59175
60032
|
}
|
|
@@ -59240,7 +60097,7 @@ var FirehoseProvider = class {
|
|
|
59240
60097
|
);
|
|
59241
60098
|
result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
|
|
59242
60099
|
} catch (err) {
|
|
59243
|
-
if (err instanceof
|
|
60100
|
+
if (err instanceof ResourceNotFoundException15)
|
|
59244
60101
|
return void 0;
|
|
59245
60102
|
this.logger.debug(
|
|
59246
60103
|
`Firehose ListTagsForDeliveryStream(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -59284,7 +60141,7 @@ var FirehoseProvider = class {
|
|
|
59284
60141
|
);
|
|
59285
60142
|
return { physicalId: explicit, attributes: {} };
|
|
59286
60143
|
} catch (err) {
|
|
59287
|
-
if (err instanceof
|
|
60144
|
+
if (err instanceof ResourceNotFoundException15)
|
|
59288
60145
|
return null;
|
|
59289
60146
|
throw err;
|
|
59290
60147
|
}
|
|
@@ -59919,7 +60776,7 @@ import {
|
|
|
59919
60776
|
UpdateProjectCommand,
|
|
59920
60777
|
BatchGetProjectsCommand,
|
|
59921
60778
|
ListProjectsCommand,
|
|
59922
|
-
ResourceNotFoundException as
|
|
60779
|
+
ResourceNotFoundException as ResourceNotFoundException16
|
|
59923
60780
|
} from "@aws-sdk/client-codebuild";
|
|
59924
60781
|
var CodeBuildProvider = class {
|
|
59925
60782
|
client;
|
|
@@ -60157,7 +61014,7 @@ var CodeBuildProvider = class {
|
|
|
60157
61014
|
await this.getClient().send(new DeleteProjectCommand({ name: physicalId }));
|
|
60158
61015
|
this.logger.debug(`Successfully deleted CodeBuild Project ${logicalId}`);
|
|
60159
61016
|
} catch (error) {
|
|
60160
|
-
if (error instanceof
|
|
61017
|
+
if (error instanceof ResourceNotFoundException16) {
|
|
60161
61018
|
const clientRegion = await this.getClient().config.region();
|
|
60162
61019
|
assertRegionMatch(
|
|
60163
61020
|
clientRegion,
|
|
@@ -60228,7 +61085,7 @@ var CodeBuildProvider = class {
|
|
|
60228
61085
|
);
|
|
60229
61086
|
project = resp.projects?.[0];
|
|
60230
61087
|
} catch (err) {
|
|
60231
|
-
if (err instanceof
|
|
61088
|
+
if (err instanceof ResourceNotFoundException16)
|
|
60232
61089
|
return void 0;
|
|
60233
61090
|
throw err;
|
|
60234
61091
|
}
|
|
@@ -60475,7 +61332,7 @@ var CodeBuildProvider = class {
|
|
|
60475
61332
|
);
|
|
60476
61333
|
return resp.projects?.[0]?.name ? { physicalId: explicit, attributes: {} } : null;
|
|
60477
61334
|
} catch (err) {
|
|
60478
|
-
if (err instanceof
|
|
61335
|
+
if (err instanceof ResourceNotFoundException16)
|
|
60479
61336
|
return null;
|
|
60480
61337
|
throw err;
|
|
60481
61338
|
}
|
|
@@ -60515,7 +61372,7 @@ import {
|
|
|
60515
61372
|
GetVectorBucketCommand,
|
|
60516
61373
|
ListIndexesCommand,
|
|
60517
61374
|
ListVectorBucketsCommand,
|
|
60518
|
-
ListTagsForResourceCommand as
|
|
61375
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand19,
|
|
60519
61376
|
DeleteIndexCommand
|
|
60520
61377
|
} from "@aws-sdk/client-s3vectors";
|
|
60521
61378
|
var S3VectorsProvider = class {
|
|
@@ -60749,7 +61606,7 @@ var S3VectorsProvider = class {
|
|
|
60749
61606
|
continue;
|
|
60750
61607
|
try {
|
|
60751
61608
|
const tagsResp = await this.getClient().send(
|
|
60752
|
-
new
|
|
61609
|
+
new ListTagsForResourceCommand19({ resourceArn: bucket.vectorBucketArn })
|
|
60753
61610
|
);
|
|
60754
61611
|
if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
60755
61612
|
return { physicalId: bucket.vectorBucketName, attributes: {} };
|
|
@@ -61093,7 +61950,7 @@ import {
|
|
|
61093
61950
|
ListNamespacesCommand as ListNamespacesCommand2,
|
|
61094
61951
|
ListTablesCommand as ListTablesCommand2,
|
|
61095
61952
|
ListTableBucketsCommand,
|
|
61096
|
-
ListTagsForResourceCommand as
|
|
61953
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand20,
|
|
61097
61954
|
NotFoundException as NotFoundException6
|
|
61098
61955
|
} from "@aws-sdk/client-s3tables";
|
|
61099
61956
|
var S3TablesProvider = class {
|
|
@@ -61577,7 +62434,7 @@ var S3TablesProvider = class {
|
|
|
61577
62434
|
if (input.cdkPath) {
|
|
61578
62435
|
try {
|
|
61579
62436
|
const tagsResp = await this.getClient().send(
|
|
61580
|
-
new
|
|
62437
|
+
new ListTagsForResourceCommand20({ resourceArn: bucket.arn })
|
|
61581
62438
|
);
|
|
61582
62439
|
if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
61583
62440
|
return { physicalId: bucket.arn, attributes: {} };
|
|
@@ -61657,7 +62514,7 @@ var S3TablesProvider = class {
|
|
|
61657
62514
|
continue;
|
|
61658
62515
|
try {
|
|
61659
62516
|
const tagsResp = await this.getClient().send(
|
|
61660
|
-
new
|
|
62517
|
+
new ListTagsForResourceCommand20({ resourceArn: table.tableARN })
|
|
61661
62518
|
);
|
|
61662
62519
|
if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
61663
62520
|
return {
|
|
@@ -61742,8 +62599,8 @@ import {
|
|
|
61742
62599
|
SetRepositoryPolicyCommand,
|
|
61743
62600
|
PutImageScanningConfigurationCommand,
|
|
61744
62601
|
PutImageTagMutabilityCommand,
|
|
61745
|
-
TagResourceCommand as
|
|
61746
|
-
ListTagsForResourceCommand as
|
|
62602
|
+
TagResourceCommand as TagResourceCommand16,
|
|
62603
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand21,
|
|
61747
62604
|
LifecyclePolicyNotFoundException,
|
|
61748
62605
|
RepositoryNotFoundException
|
|
61749
62606
|
} from "@aws-sdk/client-ecr";
|
|
@@ -61931,7 +62788,7 @@ var ECRProvider = class {
|
|
|
61931
62788
|
const repoArn = describeResponse.repositories?.[0]?.repositoryArn;
|
|
61932
62789
|
if (repoArn && newTags) {
|
|
61933
62790
|
await this.getClient().send(
|
|
61934
|
-
new
|
|
62791
|
+
new TagResourceCommand16({
|
|
61935
62792
|
resourceArn: repoArn,
|
|
61936
62793
|
tags: newTags
|
|
61937
62794
|
})
|
|
@@ -62073,7 +62930,7 @@ var ECRProvider = class {
|
|
|
62073
62930
|
if (r.repositoryArn) {
|
|
62074
62931
|
try {
|
|
62075
62932
|
const tagsResp = await this.getClient().send(
|
|
62076
|
-
new
|
|
62933
|
+
new ListTagsForResourceCommand21({ resourceArn: r.repositoryArn })
|
|
62077
62934
|
);
|
|
62078
62935
|
const tags = normalizeAwsTagsToCfn(tagsResp.tags);
|
|
62079
62936
|
result["Tags"] = tags;
|
|
@@ -62119,7 +62976,7 @@ var ECRProvider = class {
|
|
|
62119
62976
|
continue;
|
|
62120
62977
|
try {
|
|
62121
62978
|
const tagsResp = await this.getClient().send(
|
|
62122
|
-
new
|
|
62979
|
+
new ListTagsForResourceCommand21({ resourceArn: repo.repositoryArn })
|
|
62123
62980
|
);
|
|
62124
62981
|
if (matchesCdkPath(tagsResp.tags, input.cdkPath)) {
|
|
62125
62982
|
return { physicalId: repo.repositoryName, attributes: {} };
|
|
@@ -63174,10 +64031,13 @@ function registerAllProviders(registry) {
|
|
|
63174
64031
|
const glueProvider = new GlueProvider();
|
|
63175
64032
|
registry.register("AWS::Glue::Database", glueProvider);
|
|
63176
64033
|
registry.register("AWS::Glue::Table", glueProvider);
|
|
64034
|
+
registry.register("AWS::Glue::Workflow", new GlueWorkflowProvider());
|
|
64035
|
+
registry.register("AWS::Glue::SecurityConfiguration", new GlueSecurityConfigurationProvider());
|
|
63177
64036
|
const kmsProvider = new KMSProvider();
|
|
63178
64037
|
registry.register("AWS::KMS::Key", kmsProvider);
|
|
63179
64038
|
registry.register("AWS::KMS::Alias", kmsProvider);
|
|
63180
64039
|
registry.register("AWS::Kinesis::Stream", new KinesisStreamProvider());
|
|
64040
|
+
registry.register("AWS::Kinesis::StreamConsumer", new KinesisStreamConsumerProvider());
|
|
63181
64041
|
const efsProvider = new EFSProvider();
|
|
63182
64042
|
registry.register("AWS::EFS::FileSystem", efsProvider);
|
|
63183
64043
|
registry.register("AWS::EFS::MountTarget", efsProvider);
|
|
@@ -67993,7 +68853,7 @@ function reorderArgs(argv) {
|
|
|
67993
68853
|
}
|
|
67994
68854
|
async function main() {
|
|
67995
68855
|
const program = new Command14();
|
|
67996
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
68856
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.64.0");
|
|
67997
68857
|
program.addCommand(createBootstrapCommand());
|
|
67998
68858
|
program.addCommand(createSynthCommand());
|
|
67999
68859
|
program.addCommand(createListCommand());
|