@go-to-k/cdkd 0.63.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 CHANGED
@@ -56180,6 +56180,15 @@ import {
56180
56180
  GetTableCommand,
56181
56181
  GetTablesCommand,
56182
56182
  GetTagsCommand,
56183
+ CreateWorkflowCommand,
56184
+ UpdateWorkflowCommand,
56185
+ DeleteWorkflowCommand,
56186
+ GetWorkflowCommand,
56187
+ ListWorkflowsCommand,
56188
+ CreateSecurityConfigurationCommand,
56189
+ DeleteSecurityConfigurationCommand,
56190
+ GetSecurityConfigurationCommand,
56191
+ GetSecurityConfigurationsCommand,
56183
56192
  EntityNotFoundException
56184
56193
  } from "@aws-sdk/client-glue";
56185
56194
  import { STSClient as STSClient8, GetCallerIdentityCommand as GetCallerIdentityCommand8 } from "@aws-sdk/client-sts";
@@ -56872,6 +56881,475 @@ var GlueProvider = class {
56872
56881
  return this.cachedAccountId;
56873
56882
  }
56874
56883
  };
56884
+ var GlueWorkflowProvider = class {
56885
+ client;
56886
+ stsClient;
56887
+ cachedAccountId;
56888
+ providerRegion = process.env["AWS_REGION"];
56889
+ logger = getLogger().child("GlueWorkflowProvider");
56890
+ handledProperties = /* @__PURE__ */ new Map([
56891
+ [
56892
+ "AWS::Glue::Workflow",
56893
+ /* @__PURE__ */ new Set(["Name", "Description", "DefaultRunProperties", "MaxConcurrentRuns", "Tags"])
56894
+ ]
56895
+ ]);
56896
+ getClient() {
56897
+ if (!this.client) {
56898
+ this.client = new GlueClient(this.providerRegion ? { region: this.providerRegion } : {});
56899
+ }
56900
+ return this.client;
56901
+ }
56902
+ async create(logicalId, resourceType, properties) {
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
+ );
56911
+ }
56912
+ try {
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 }
56927
+ })
56928
+ );
56929
+ this.logger.debug(`Successfully created Glue Workflow ${logicalId}: ${name}`);
56930
+ return { physicalId: name, attributes: {} };
56931
+ } catch (error) {
56932
+ const cause = error instanceof Error ? error : void 0;
56933
+ throw new ProvisioningError(
56934
+ `Failed to create Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
56935
+ resourceType,
56936
+ logicalId,
56937
+ void 0,
56938
+ cause
56939
+ );
56940
+ }
56941
+ }
56942
+ async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
56943
+ this.logger.debug(`Updating Glue Workflow ${logicalId}: ${physicalId}`);
56944
+ try {
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
+ })
56958
+ );
56959
+ this.logger.debug(`Successfully updated Glue Workflow ${logicalId}`);
56960
+ return { physicalId, wasReplaced: false };
56961
+ } catch (error) {
56962
+ const cause = error instanceof Error ? error : void 0;
56963
+ throw new ProvisioningError(
56964
+ `Failed to update Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
56965
+ resourceType,
56966
+ logicalId,
56967
+ physicalId,
56968
+ cause
56969
+ );
56970
+ }
56971
+ }
56972
+ async delete(logicalId, physicalId, resourceType, _properties, context) {
56973
+ this.logger.debug(`Deleting Glue Workflow ${logicalId}: ${physicalId}`);
56974
+ try {
56975
+ await this.getClient().send(new DeleteWorkflowCommand({ Name: physicalId }));
56976
+ this.logger.debug(`Successfully deleted Glue Workflow ${logicalId}`);
56977
+ } catch (error) {
56978
+ if (error instanceof EntityNotFoundException) {
56979
+ const clientRegion = await this.getClient().config.region();
56980
+ assertRegionMatch(
56981
+ clientRegion,
56982
+ context?.expectedRegion,
56983
+ resourceType,
56984
+ logicalId,
56985
+ physicalId
56986
+ );
56987
+ this.logger.debug(`Glue Workflow ${physicalId} does not exist, skipping deletion`);
56988
+ return;
56989
+ }
56990
+ const cause = error instanceof Error ? error : void 0;
56991
+ throw new ProvisioningError(
56992
+ `Failed to delete Glue Workflow ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
56993
+ resourceType,
56994
+ logicalId,
56995
+ physicalId,
56996
+ cause
56997
+ );
56998
+ }
56999
+ }
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
+ }
56875
57353
 
56876
57354
  // src/provisioning/providers/kms-provider.ts
56877
57355
  import {
@@ -63553,6 +64031,8 @@ function registerAllProviders(registry) {
63553
64031
  const glueProvider = new GlueProvider();
63554
64032
  registry.register("AWS::Glue::Database", glueProvider);
63555
64033
  registry.register("AWS::Glue::Table", glueProvider);
64034
+ registry.register("AWS::Glue::Workflow", new GlueWorkflowProvider());
64035
+ registry.register("AWS::Glue::SecurityConfiguration", new GlueSecurityConfigurationProvider());
63556
64036
  const kmsProvider = new KMSProvider();
63557
64037
  registry.register("AWS::KMS::Key", kmsProvider);
63558
64038
  registry.register("AWS::KMS::Alias", kmsProvider);
@@ -68373,7 +68853,7 @@ function reorderArgs(argv) {
68373
68853
  }
68374
68854
  async function main() {
68375
68855
  const program = new Command14();
68376
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.63.0");
68856
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.64.0");
68377
68857
  program.addCommand(createBootstrapCommand());
68378
68858
  program.addCommand(createSynthCommand());
68379
68859
  program.addCommand(createListCommand());