@go-to-k/cdkd 0.222.1 → 0.223.1
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 +334 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1553,7 +1553,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
1553
1553
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
1554
1554
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
1555
1555
|
function getCdkdVersion() {
|
|
1556
|
-
return "0.
|
|
1556
|
+
return "0.223.1";
|
|
1557
1557
|
}
|
|
1558
1558
|
/**
|
|
1559
1559
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -5850,6 +5850,76 @@ var S3BucketProvider = class {
|
|
|
5850
5850
|
//#endregion
|
|
5851
5851
|
//#region src/provisioning/providers/s3-bucket-policy-provider.ts
|
|
5852
5852
|
/**
|
|
5853
|
+
* Matches a CloudFront Origin Access Identity (OAI) principal ARN, e.g.
|
|
5854
|
+
* `arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E1UREC9EUJDVG5`.
|
|
5855
|
+
* The capture group is the OAI id, which resolves to the OAI's S3 canonical
|
|
5856
|
+
* user id via `GetCloudFrontOriginAccessIdentity`.
|
|
5857
|
+
*/
|
|
5858
|
+
const OAI_USER_ARN_RE = /^arn:aws[a-z-]*:iam::cloudfront:user\/CloudFront Origin Access Identity ([A-Z0-9]+)$/;
|
|
5859
|
+
/**
|
|
5860
|
+
* Matches a bare IAM principal unique id (e.g. `AIDAIBJOSOJSBZ753XCAW`). S3
|
|
5861
|
+
* returns an OAI grant's principal in this transient form immediately after
|
|
5862
|
+
* `PutBucketPolicy` (before it settles to the friendly cloudfront-user ARN).
|
|
5863
|
+
* It carries no recoverable link back to the OAI, so it can only be
|
|
5864
|
+
* canonicalized by matching against the template's `{ CanonicalUser }` form.
|
|
5865
|
+
*/
|
|
5866
|
+
const IAM_UNIQUE_ID_RE = /^A[A-Z0-9]{15,}$/;
|
|
5867
|
+
/**
|
|
5868
|
+
* Process-lifetime cache of OAI id -> S3 canonical user id (or `null` when the
|
|
5869
|
+
* lookup failed / the OAI is gone), so a `cdkd drift` run with many OAI-granting
|
|
5870
|
+
* bucket policies issues at most one `GetCloudFrontOriginAccessIdentity` per OAI.
|
|
5871
|
+
*/
|
|
5872
|
+
const oaiCanonicalUserIdCache = /* @__PURE__ */ new Map();
|
|
5873
|
+
/**
|
|
5874
|
+
* Build an `oaiId -> S3CanonicalUserId` map from the same-stack sibling
|
|
5875
|
+
* `AWS::CloudFront::CloudFrontOriginAccessIdentity` resources in the read
|
|
5876
|
+
* context. The OAI's `S3CanonicalUserId` is a readOnly attribute cdkd already
|
|
5877
|
+
* resolved at deploy time (the bucket-policy grant `Fn::GetAtt`s it), so this
|
|
5878
|
+
* lets the bucket-policy drift read reconcile the OAI principal forms with zero
|
|
5879
|
+
* extra AWS calls (and no `cloudfront:GetCloudFrontOriginAccessIdentity` IAM
|
|
5880
|
+
* grant) whenever the OAI lives in the same stack. The OAI resource's
|
|
5881
|
+
* `physicalId` IS the OAI id embedded in the cloudfront-user ARN.
|
|
5882
|
+
*/
|
|
5883
|
+
function buildSiblingOaiCanonicalMap(context) {
|
|
5884
|
+
const map = /* @__PURE__ */ new Map();
|
|
5885
|
+
for (const sib of Object.values(context?.siblings ?? {})) {
|
|
5886
|
+
if (sib.resourceType !== "AWS::CloudFront::CloudFrontOriginAccessIdentity") continue;
|
|
5887
|
+
const canonical = sib.attributes?.["S3CanonicalUserId"];
|
|
5888
|
+
if (sib.physicalId && typeof canonical === "string") map.set(sib.physicalId, canonical);
|
|
5889
|
+
}
|
|
5890
|
+
return map;
|
|
5891
|
+
}
|
|
5892
|
+
/**
|
|
5893
|
+
* Pull the `Statement` array out of a parsed policy document, tolerating both
|
|
5894
|
+
* the single-object and array shapes (and a non-object input). Returns the live
|
|
5895
|
+
* statement objects so callers can mutate their `Principal` in place.
|
|
5896
|
+
*/
|
|
5897
|
+
function extractStatements(policyDoc) {
|
|
5898
|
+
if (!policyDoc || typeof policyDoc !== "object") return [];
|
|
5899
|
+
const stmt = policyDoc["Statement"];
|
|
5900
|
+
return (Array.isArray(stmt) ? stmt : stmt ? [stmt] : []).filter((s) => !!s && typeof s === "object" && !Array.isArray(s));
|
|
5901
|
+
}
|
|
5902
|
+
/**
|
|
5903
|
+
* Find the `CanonicalUser` principal of the template statement that matches a
|
|
5904
|
+
* given AWS-side statement by Effect / Action / Resource, used to canonicalize
|
|
5905
|
+
* the unresolvable transient `{ AWS: <IAM-unique-id> }` OAI form. Returns
|
|
5906
|
+
* `undefined` when no single matching template statement carries one.
|
|
5907
|
+
*/
|
|
5908
|
+
function findTemplateCanonicalUser(awsStmt, templateStmts) {
|
|
5909
|
+
const key = (s) => JSON.stringify([
|
|
5910
|
+
s["Effect"],
|
|
5911
|
+
s["Action"],
|
|
5912
|
+
s["Resource"]
|
|
5913
|
+
]);
|
|
5914
|
+
const want = key(awsStmt);
|
|
5915
|
+
const matches = templateStmts.filter((t) => key(t) === want);
|
|
5916
|
+
if (matches.length !== 1) return void 0;
|
|
5917
|
+
const principal = matches[0]["Principal"];
|
|
5918
|
+
if (!principal || typeof principal !== "object" || Array.isArray(principal)) return void 0;
|
|
5919
|
+
const canonical = principal["CanonicalUser"];
|
|
5920
|
+
return typeof canonical === "string" ? canonical : void 0;
|
|
5921
|
+
}
|
|
5922
|
+
/**
|
|
5853
5923
|
* AWS S3 Bucket Policy Provider
|
|
5854
5924
|
*
|
|
5855
5925
|
* Implements resource provisioning for AWS::S3::BucketPolicy using the S3 SDK.
|
|
@@ -5953,7 +6023,7 @@ var S3BucketPolicyProvider = class {
|
|
|
5953
6023
|
* Returns `undefined` when the bucket is gone (`NoSuchBucket`) or when
|
|
5954
6024
|
* no policy is currently attached (`NoSuchBucketPolicy`).
|
|
5955
6025
|
*/
|
|
5956
|
-
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
6026
|
+
async readCurrentState(physicalId, _logicalId, _resourceType, properties, context) {
|
|
5957
6027
|
let policyJson;
|
|
5958
6028
|
try {
|
|
5959
6029
|
policyJson = (await this.s3Client.send(new GetBucketPolicyCommand({ Bucket: physicalId }))).Policy;
|
|
@@ -5964,14 +6034,90 @@ var S3BucketPolicyProvider = class {
|
|
|
5964
6034
|
}
|
|
5965
6035
|
if (!policyJson) return void 0;
|
|
5966
6036
|
const result = { Bucket: physicalId };
|
|
6037
|
+
let policyDoc;
|
|
5967
6038
|
try {
|
|
5968
|
-
|
|
6039
|
+
policyDoc = JSON.parse(policyJson);
|
|
5969
6040
|
} catch {
|
|
5970
6041
|
result["PolicyDocument"] = policyJson;
|
|
6042
|
+
return result;
|
|
5971
6043
|
}
|
|
6044
|
+
await this.normalizeOaiPrincipals(policyDoc, properties, context);
|
|
6045
|
+
result["PolicyDocument"] = policyDoc;
|
|
5972
6046
|
return result;
|
|
5973
6047
|
}
|
|
5974
6048
|
/**
|
|
6049
|
+
* Normalize CloudFront OAI grant principals in a (parsed) bucket policy to
|
|
6050
|
+
* the `{ CanonicalUser: <id> }` form, in place (issue #872):
|
|
6051
|
+
* - `{ AWS: <oai-user-arn> }` -> map the OAI id in the ARN to its
|
|
6052
|
+
* `S3CanonicalUserId`, preferring the sibling OAI resource's already-read
|
|
6053
|
+
* state attributes (zero AWS call — the OAI's `S3CanonicalUserId` is a
|
|
6054
|
+
* readOnly attribute cdkd already resolved at deploy time) and falling
|
|
6055
|
+
* back to `GetCloudFrontOriginAccessIdentity` only when the OAI is not a
|
|
6056
|
+
* same-stack sibling (e.g. an imported / external OAI). This is the SAFE
|
|
6057
|
+
* path: a genuinely-different OAI resolves to a different canonical id, so
|
|
6058
|
+
* real drift is still detected.
|
|
6059
|
+
* - `{ AWS: <bare-IAM-unique-id> }` -> the transient post-PutBucketPolicy
|
|
6060
|
+
* rendering, which carries no recoverable link to the OAI. Canonicalize
|
|
6061
|
+
* it only by matching the corresponding template statement (same Effect /
|
|
6062
|
+
* Action / Resource) carrying a `{ CanonicalUser }` principal. A user
|
|
6063
|
+
* cannot author a bare IAM unique id as a bucket-policy principal, so
|
|
6064
|
+
* adopting the template form here only fires for AWS's transient
|
|
6065
|
+
* rendering. NOTE: once the principal settles to the ARN form (seconds
|
|
6066
|
+
* to minutes), a genuine out-of-band OAI repoint IS detected via the ARN
|
|
6067
|
+
* path above; the only masking window is a repoint observed during the
|
|
6068
|
+
* transient bare-id phase, which the next drift run (ARN form) reports.
|
|
6069
|
+
* Statements whose principal is not a single-string `AWS` OAI form (e.g. a
|
|
6070
|
+
* wildcard, a service principal, a normal role ARN, or an `AWS` ARRAY of
|
|
6071
|
+
* principals) are left untouched — skipping is safe (it can only leave a
|
|
6072
|
+
* residual false positive, never hide real drift). CDK's single-OAI grant
|
|
6073
|
+
* emits the single-string form.
|
|
6074
|
+
*/
|
|
6075
|
+
async normalizeOaiPrincipals(policyDoc, templateProps, context) {
|
|
6076
|
+
const stmts = extractStatements(policyDoc);
|
|
6077
|
+
if (stmts.length === 0) return;
|
|
6078
|
+
const templateStmts = extractStatements(templateProps?.["PolicyDocument"]);
|
|
6079
|
+
const siblingCanonicalById = buildSiblingOaiCanonicalMap(context);
|
|
6080
|
+
for (const stmt of stmts) {
|
|
6081
|
+
const principal = stmt["Principal"];
|
|
6082
|
+
if (!principal || typeof principal !== "object" || Array.isArray(principal)) continue;
|
|
6083
|
+
const awsPrincipal = principal["AWS"];
|
|
6084
|
+
if (typeof awsPrincipal !== "string") continue;
|
|
6085
|
+
const arnMatch = OAI_USER_ARN_RE.exec(awsPrincipal);
|
|
6086
|
+
if (arnMatch) {
|
|
6087
|
+
const oaiId = arnMatch[1];
|
|
6088
|
+
const canonical = siblingCanonicalById.get(oaiId) ?? await this.resolveOaiCanonicalUserId(oaiId);
|
|
6089
|
+
if (canonical) stmt["Principal"] = { CanonicalUser: canonical };
|
|
6090
|
+
continue;
|
|
6091
|
+
}
|
|
6092
|
+
if (IAM_UNIQUE_ID_RE.test(awsPrincipal)) {
|
|
6093
|
+
const tmplCanonical = findTemplateCanonicalUser(stmt, templateStmts);
|
|
6094
|
+
if (tmplCanonical) stmt["Principal"] = { CanonicalUser: tmplCanonical };
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
6097
|
+
}
|
|
6098
|
+
/**
|
|
6099
|
+
* Resolve a CloudFront OAI id to its S3 canonical user id via
|
|
6100
|
+
* `GetCloudFrontOriginAccessIdentity`, cached for the process lifetime. Used
|
|
6101
|
+
* only as a FALLBACK when the OAI is not a same-stack sibling (its
|
|
6102
|
+
* `S3CanonicalUserId` is otherwise read straight from sibling state — see
|
|
6103
|
+
* {@link buildSiblingOaiCanonicalMap}). Best-effort: returns `null` (and
|
|
6104
|
+
* caches it) on any failure so a missing OAI / missing permission leaves the
|
|
6105
|
+
* principal unchanged rather than failing the drift read.
|
|
6106
|
+
*/
|
|
6107
|
+
async resolveOaiCanonicalUserId(oaiId) {
|
|
6108
|
+
const cached = oaiCanonicalUserIdCache.get(oaiId);
|
|
6109
|
+
if (cached !== void 0) return cached;
|
|
6110
|
+
let canonical = null;
|
|
6111
|
+
try {
|
|
6112
|
+
canonical = (await getAwsClients().cloudFront.send(new GetCloudFrontOriginAccessIdentityCommand({ Id: oaiId }))).CloudFrontOriginAccessIdentity?.S3CanonicalUserId ?? null;
|
|
6113
|
+
} catch (err) {
|
|
6114
|
+
this.logger.debug(`Could not resolve CloudFront OAI ${oaiId} canonical user id for bucket-policy drift normalization: ${err instanceof Error ? err.message : String(err)} — leaving the principal unchanged.`);
|
|
6115
|
+
canonical = null;
|
|
6116
|
+
}
|
|
6117
|
+
oaiCanonicalUserIdCache.set(oaiId, canonical);
|
|
6118
|
+
return canonical;
|
|
6119
|
+
}
|
|
6120
|
+
/**
|
|
5975
6121
|
* Adopt an existing S3 bucket policy into cdkd state.
|
|
5976
6122
|
*
|
|
5977
6123
|
* The operational identifier for an `S3::BucketPolicy` is the **bucket
|
|
@@ -18384,6 +18530,88 @@ var CloudFrontDistributionProvider = class {
|
|
|
18384
18530
|
}
|
|
18385
18531
|
}
|
|
18386
18532
|
/**
|
|
18533
|
+
* Read the AWS-current `DistributionConfig` for drift detection.
|
|
18534
|
+
*
|
|
18535
|
+
* Calls the read-only `GetDistributionConfigCommand` and inverts the
|
|
18536
|
+
* provider's own `convertToSdkFormat` (the CFn-shape → SDK-shape
|
|
18537
|
+
* `{ Quantity, Items }` mapping the create / update path applies) back
|
|
18538
|
+
* into the CloudFormation `DistributionConfig` shape that cdkd state
|
|
18539
|
+
* stores — so the drift comparator sees the same structure on both
|
|
18540
|
+
* the deploy-time observed snapshot and a later drift read.
|
|
18541
|
+
*
|
|
18542
|
+
* The comparator only descends into keys present in cdkd state (or the
|
|
18543
|
+
* union of state + AWS when an observed baseline exists), so this does
|
|
18544
|
+
* not need to surface every AWS-injected field; it returns the same
|
|
18545
|
+
* `DistributionConfig` / `Tags` keys the provider manages.
|
|
18546
|
+
*
|
|
18547
|
+
* `CallerReference` (a create-time idempotency token AWS echoes back
|
|
18548
|
+
* but CDK never templates) is dropped so it cannot fire phantom drift.
|
|
18549
|
+
* The remaining write-only / never-readable sub-fields are declared in
|
|
18550
|
+
* `getDriftUnknownPaths`.
|
|
18551
|
+
*/
|
|
18552
|
+
async readCurrentState(physicalId, _logicalId, resourceType, _properties) {
|
|
18553
|
+
if (resourceType !== "AWS::CloudFront::Distribution") return void 0;
|
|
18554
|
+
let config;
|
|
18555
|
+
try {
|
|
18556
|
+
config = (await this.cloudFrontClient.send(new GetDistributionConfigCommand({ Id: physicalId }))).DistributionConfig;
|
|
18557
|
+
} catch (error) {
|
|
18558
|
+
if (error instanceof NoSuchDistribution) return void 0;
|
|
18559
|
+
throw error;
|
|
18560
|
+
}
|
|
18561
|
+
if (!config) return void 0;
|
|
18562
|
+
const result = { DistributionConfig: this.convertToCfnFormat(config) };
|
|
18563
|
+
try {
|
|
18564
|
+
const arn = (await this.cloudFrontClient.send(new GetDistributionCommand({ Id: physicalId }))).Distribution?.ARN;
|
|
18565
|
+
if (arn) {
|
|
18566
|
+
const cfnTags = ((await this.cloudFrontClient.send(new ListTagsForResourceCommand$3({ Resource: arn }))).Tags?.Items ?? []).filter((t) => typeof t.Key === "string" && !t.Key.startsWith("aws:cdk:")).map((t) => ({
|
|
18567
|
+
Key: t.Key,
|
|
18568
|
+
Value: t.Value ?? ""
|
|
18569
|
+
}));
|
|
18570
|
+
if (cfnTags.length > 0) result["Tags"] = cfnTags;
|
|
18571
|
+
}
|
|
18572
|
+
} catch (error) {
|
|
18573
|
+
this.logger.debug(`Tag read for CloudFront Distribution ${physicalId} failed during drift read: ${error instanceof Error ? error.message : String(error)}`);
|
|
18574
|
+
}
|
|
18575
|
+
return result;
|
|
18576
|
+
}
|
|
18577
|
+
/**
|
|
18578
|
+
* State property paths cdkd cannot read back faithfully from AWS, so
|
|
18579
|
+
* the drift comparator skips them rather than firing a guaranteed
|
|
18580
|
+
* false positive every run (mirrors the Lambda `Code.S3*` precedent).
|
|
18581
|
+
*
|
|
18582
|
+
* - `DistributionConfig.CallerReference`: a create-time idempotency
|
|
18583
|
+
* token. cdkd generates it internally (`<ts>-<logicalId>-<rand>`);
|
|
18584
|
+
* AWS echoes it back, but it is never templated by CDK, so comparing
|
|
18585
|
+
* it would diff cdkd's generated value on every run. `convertToCfnFormat`
|
|
18586
|
+
* already drops it from the AWS side; declaring it here also excludes
|
|
18587
|
+
* it from the observed-baseline side.
|
|
18588
|
+
* - `DistributionConfig.Logging.Bucket`: CloudFront normalizes the S3
|
|
18589
|
+
* logging bucket to its `<bucket>.s3.amazonaws.com` regional domain on
|
|
18590
|
+
* read, which never matches the bare bucket domain a template may
|
|
18591
|
+
* carry; treat it as drift-unknown to avoid a guaranteed mismatch.
|
|
18592
|
+
* - `DistributionConfig.OriginGroups`: each origin group carries its own
|
|
18593
|
+
* inner `{ Quantity, Items }` wrappers (`Members`,
|
|
18594
|
+
* `FailoverCriteria.StatusCodes`) that `convertToCfnFormat` does not yet
|
|
18595
|
+
* unwrap symmetrically (only the top-level OriginGroups list is unwrapped;
|
|
18596
|
+
* there is no `revertOriginGroup` pass, and `convertToSdkFormat` likewise
|
|
18597
|
+
* does not descend into them). Against the observed baseline both sides go
|
|
18598
|
+
* through the same `readCurrentState` so this never false-positives on a
|
|
18599
|
+
* normal deploy, but against the `properties`-fallback baseline (older
|
|
18600
|
+
* state without `observedProperties`) the raw `{ Quantity, Items }` shape
|
|
18601
|
+
* would diff the bare-array template form. Suppress it until a dedicated
|
|
18602
|
+
* fix lands a `revertOriginGroup` + a real OriginGroups integ fixture
|
|
18603
|
+
* (there is no OriginGroups fixture to verify the inner shape today). See
|
|
18604
|
+
* the PR #871 review thread.
|
|
18605
|
+
*/
|
|
18606
|
+
getDriftUnknownPaths(resourceType) {
|
|
18607
|
+
if (resourceType !== "AWS::CloudFront::Distribution") return [];
|
|
18608
|
+
return [
|
|
18609
|
+
"DistributionConfig.CallerReference",
|
|
18610
|
+
"DistributionConfig.Logging.Bucket",
|
|
18611
|
+
"DistributionConfig.OriginGroups"
|
|
18612
|
+
];
|
|
18613
|
+
}
|
|
18614
|
+
/**
|
|
18387
18615
|
* Get resource attribute (for Fn::GetAtt resolution)
|
|
18388
18616
|
*/
|
|
18389
18617
|
async getAttribute(physicalId, _resourceType, attributeName) {
|
|
@@ -18462,6 +18690,105 @@ var CloudFrontDistributionProvider = class {
|
|
|
18462
18690
|
return result;
|
|
18463
18691
|
}
|
|
18464
18692
|
/**
|
|
18693
|
+
* Invert {@link convertToSdkFormat}: map an AWS-returned SDK-shape
|
|
18694
|
+
* `DistributionConfig` ({@link GetDistributionConfigCommand} output) back
|
|
18695
|
+
* into the CloudFormation `DistributionConfig` shape cdkd state stores.
|
|
18696
|
+
*
|
|
18697
|
+
* The inversion is the mirror image of the create / update conversion:
|
|
18698
|
+
* every `{ Quantity, Items }` wrapper becomes its bare `Items` array
|
|
18699
|
+
* (top-level list fields + the nested cache-behavior / origin fields),
|
|
18700
|
+
* and `CallerReference` is dropped (a create-time idempotency token CDK
|
|
18701
|
+
* never templates — see `getDriftUnknownPaths`).
|
|
18702
|
+
*
|
|
18703
|
+
* Lossiness note: the conversion is NOT perfectly lossless because
|
|
18704
|
+
* `convertToSdkFormat` injects SDK-required defaults the CFn template may
|
|
18705
|
+
* omit (`Comment: ''`, `Logging.{Enabled,IncludeCookies,Prefix}`,
|
|
18706
|
+
* `CustomOriginConfig.HTTP{,S}Port`). Those defaults are preserved on the
|
|
18707
|
+
* inverted side, which is correct for the drift comparator: the
|
|
18708
|
+
* deploy-time observed baseline (also produced by THIS method) carries the
|
|
18709
|
+
* same defaults, so they compare equal. They would only matter against the
|
|
18710
|
+
* `properties` fallback baseline (resources with no observedProperties),
|
|
18711
|
+
* where an AWS-injected default the template omitted is legitimately a
|
|
18712
|
+
* key cdkd never set — but the comparator's state-keys-only walk in that
|
|
18713
|
+
* mode never descends into a key absent from the template, so the extra
|
|
18714
|
+
* defaults cannot fire false drift there either.
|
|
18715
|
+
*/
|
|
18716
|
+
convertToCfnFormat(config) {
|
|
18717
|
+
const result = { ...config };
|
|
18718
|
+
delete result["CallerReference"];
|
|
18719
|
+
for (const field of QUANTITY_ITEM_FIELDS) if (result[field] !== void 0) result[field] = this.unwrapQuantity(result[field]);
|
|
18720
|
+
if (result["DefaultCacheBehavior"] && typeof result["DefaultCacheBehavior"] === "object") result["DefaultCacheBehavior"] = this.revertCacheBehavior(result["DefaultCacheBehavior"]);
|
|
18721
|
+
if (Array.isArray(result["CacheBehaviors"])) result["CacheBehaviors"] = result["CacheBehaviors"].map((cb) => this.revertCacheBehavior(cb));
|
|
18722
|
+
if (Array.isArray(result["Origins"])) result["Origins"] = result["Origins"].map((origin) => this.revertOrigin(origin));
|
|
18723
|
+
return result;
|
|
18724
|
+
}
|
|
18725
|
+
/**
|
|
18726
|
+
* Inverse of {@link wrapWithQuantity}: a `{ Quantity, Items }` object
|
|
18727
|
+
* becomes its bare `Items` array; anything else is returned unchanged.
|
|
18728
|
+
*/
|
|
18729
|
+
unwrapQuantity(value) {
|
|
18730
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
18731
|
+
const obj = value;
|
|
18732
|
+
if (Array.isArray(obj["Items"])) return obj["Items"];
|
|
18733
|
+
}
|
|
18734
|
+
return value;
|
|
18735
|
+
}
|
|
18736
|
+
/**
|
|
18737
|
+
* Inverse of {@link convertCacheBehavior}: unwrap the Quantity + Items
|
|
18738
|
+
* fields nested inside a CacheBehavior back to bare arrays.
|
|
18739
|
+
*/
|
|
18740
|
+
revertCacheBehavior(behavior) {
|
|
18741
|
+
const result = { ...behavior };
|
|
18742
|
+
if (result["AllowedMethods"] && typeof result["AllowedMethods"] === "object") {
|
|
18743
|
+
const allowed = result["AllowedMethods"];
|
|
18744
|
+
if (allowed["CachedMethods"] !== void 0 && result["CachedMethods"] === void 0) {
|
|
18745
|
+
result["CachedMethods"] = allowed["CachedMethods"];
|
|
18746
|
+
const allowedCopy = { ...allowed };
|
|
18747
|
+
delete allowedCopy["CachedMethods"];
|
|
18748
|
+
result["AllowedMethods"] = allowedCopy;
|
|
18749
|
+
}
|
|
18750
|
+
}
|
|
18751
|
+
for (const fieldPath of CACHE_BEHAVIOR_QUANTITY_FIELDS) {
|
|
18752
|
+
const parts = fieldPath.split(".");
|
|
18753
|
+
this.unwrapQuantityAtPath(result, parts);
|
|
18754
|
+
}
|
|
18755
|
+
return result;
|
|
18756
|
+
}
|
|
18757
|
+
/**
|
|
18758
|
+
* Inverse of {@link convertOrigin}: unwrap CustomHeaders and
|
|
18759
|
+
* CustomOriginConfig.OriginSslProtocols back to bare arrays.
|
|
18760
|
+
*/
|
|
18761
|
+
revertOrigin(origin) {
|
|
18762
|
+
const result = { ...origin };
|
|
18763
|
+
if (result["CustomHeaders"] !== void 0) result["CustomHeaders"] = this.unwrapQuantity(result["CustomHeaders"]);
|
|
18764
|
+
if (result["CustomOriginConfig"] && typeof result["CustomOriginConfig"] === "object") {
|
|
18765
|
+
const customOriginConfig = { ...result["CustomOriginConfig"] };
|
|
18766
|
+
if (customOriginConfig["OriginSslProtocols"] !== void 0) customOriginConfig["OriginSslProtocols"] = this.unwrapQuantity(customOriginConfig["OriginSslProtocols"]);
|
|
18767
|
+
result["CustomOriginConfig"] = customOriginConfig;
|
|
18768
|
+
}
|
|
18769
|
+
return result;
|
|
18770
|
+
}
|
|
18771
|
+
/**
|
|
18772
|
+
* Inverse of {@link applyQuantityAtPath}: unwrap a `{ Quantity, Items }`
|
|
18773
|
+
* value at a nested path (e.g. "ForwardedValues.Headers") back to a bare
|
|
18774
|
+
* array.
|
|
18775
|
+
*/
|
|
18776
|
+
unwrapQuantityAtPath(obj, path) {
|
|
18777
|
+
if (path.length === 0) return;
|
|
18778
|
+
if (path.length === 1) {
|
|
18779
|
+
const key = path[0];
|
|
18780
|
+
if (obj[key] !== void 0) obj[key] = this.unwrapQuantity(obj[key]);
|
|
18781
|
+
return;
|
|
18782
|
+
}
|
|
18783
|
+
const [head, ...rest] = path;
|
|
18784
|
+
const headKey = head;
|
|
18785
|
+
if (obj[headKey] && typeof obj[headKey] === "object") {
|
|
18786
|
+
const nested = { ...obj[headKey] };
|
|
18787
|
+
obj[headKey] = nested;
|
|
18788
|
+
this.unwrapQuantityAtPath(nested, rest);
|
|
18789
|
+
}
|
|
18790
|
+
}
|
|
18791
|
+
/**
|
|
18465
18792
|
* Wrap a value with the Quantity + Items pattern if needed.
|
|
18466
18793
|
*
|
|
18467
18794
|
* Handles three cases:
|
|
@@ -38233,7 +38560,9 @@ function buildReadCurrentStateContext(state, excludedLogicalId) {
|
|
|
38233
38560
|
if (lid === excludedLogicalId) continue;
|
|
38234
38561
|
siblings[lid] = {
|
|
38235
38562
|
resourceType: res.resourceType,
|
|
38236
|
-
|
|
38563
|
+
physicalId: res.physicalId,
|
|
38564
|
+
properties: res.properties ?? {},
|
|
38565
|
+
attributes: res.attributes ?? {}
|
|
38237
38566
|
};
|
|
38238
38567
|
}
|
|
38239
38568
|
return { siblings };
|
|
@@ -54198,7 +54527,7 @@ function reorderArgs(argv) {
|
|
|
54198
54527
|
async function main() {
|
|
54199
54528
|
installPipeCloseHandler();
|
|
54200
54529
|
const program = new Command();
|
|
54201
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
54530
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.223.1");
|
|
54202
54531
|
program.addCommand(createBootstrapCommand());
|
|
54203
54532
|
program.addCommand(createSynthCommand());
|
|
54204
54533
|
program.addCommand(createListCommand());
|