@go-to-k/cdkd 0.284.68 → 0.284.69
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/{asg-provider-CRANVDS-.js → asg-provider-CLnf8ct8.js} +2 -2
- package/dist/{asg-provider-CRANVDS-.js.map → asg-provider-CLnf8ct8.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-PNoV56rY.js → deploy-engine-CHLe31Fh.js} +323 -11
- package/dist/deploy-engine-CHLe31Fh.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-acYSO1I9.js → program-CA4cxyPX.js} +4 -4
- package/dist/{program-acYSO1I9.js.map → program-CA4cxyPX.js.map} +1 -1
- package/dist/{version-r1IKN_QV.js → version-C-t2pnSY.js} +2 -2
- package/dist/{version-r1IKN_QV.js.map → version-C-t2pnSY.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-PNoV56rY.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as generateResourceName, f as generateResourceNameWithFallback, g as withStackName, m as looksLikeCdkdGeneratedName, n as getLogger, o as getLiveRenderer, p as getCurrentStackName, u as applyDefaultNameForFallback } from "./logger-C9-E73FI.js";
|
|
2
|
-
import { t as getCdkdVersion } from "./version-
|
|
2
|
+
import { t as getCdkdVersion } from "./version-C-t2pnSY.js";
|
|
3
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -12545,10 +12545,16 @@ function isUniquelyKeyedBy(items, key) {
|
|
|
12545
12545
|
* the unchanged-resource path the value scan is also a no-op, so such a leaf
|
|
12546
12546
|
* keeps its plaintext — narrow (an identity field is a name, not a
|
|
12547
12547
|
* credential) but real.
|
|
12548
|
-
* - **Arrays of arrays.** `M: [[{Name, Value}]]` pairs nothing, because the
|
|
12548
|
+
* - **Arrays of arrays.** `M: [[{Name, Value}]]` pairs nothing HERE, because the
|
|
12549
12549
|
* OUTER elements are arrays rather than plain objects and have no identity
|
|
12550
|
-
* field to key on.
|
|
12551
|
-
* the order assumption this function exists to avoid.
|
|
12550
|
+
* field to key on. Blind positional descent into the outer list would
|
|
12551
|
+
* reintroduce the order assumption this function exists to avoid. On the
|
|
12552
|
+
* READBACK paths it is no longer a dead end:
|
|
12553
|
+
* {@link refuseUncertifiedReadbackPositions} (issue #2012) walks the outer
|
|
12554
|
+
* list positionally when {@link unkeyedArrayPairsByAnchors} says the inner
|
|
12555
|
+
* elements' own anchors vouch for the alignment, which meets the order
|
|
12556
|
+
* objection instead of ignoring it. The gate decides; it does not walk. Everywhere else — and whenever
|
|
12557
|
+
* those anchors do not match — the shape still falls to the value scan.
|
|
12552
12558
|
*/
|
|
12553
12559
|
function identityKeyFor(bag, source) {
|
|
12554
12560
|
for (const key of ARRAY_IDENTITY_KEYS) if (isUniquelyKeyedBy(bag, key) && isUniquelyKeyedBy(source, key)) return key;
|
|
@@ -12822,6 +12828,286 @@ function mixedLeafMayCarryPublicReference(source, secrets) {
|
|
|
12822
12828
|
return dynamicReferenceTokens(source).some((token) => token.startsWith("{{resolve:ssm:") && !isRecordedSecretExpression(token));
|
|
12823
12829
|
}
|
|
12824
12830
|
/**
|
|
12831
|
+
* Does this value carry an ORDINARY object prototype?
|
|
12832
|
+
*
|
|
12833
|
+
* `isPlainObject` answers `typeof === 'object' && !Array.isArray`, which admits
|
|
12834
|
+
* CLASS INSTANCES, and that is a hole under {@link deepEqualJsonValue}: an AWS
|
|
12835
|
+
* SDK v3 readback reaching `drainObservedCaptures` is PRE-JSON and really does
|
|
12836
|
+
* carry `Date` values (`LastModified`, `CreationDate`). `Object.keys(new
|
|
12837
|
+
* Date())` is `[]`, so without this check a `Date` compared equal to `{}` and
|
|
12838
|
+
* to every other `Date` -- an anchor that corroborates a pairing while proving
|
|
12839
|
+
* nothing. Widening `isPlainObject` itself was rejected: it is read by three
|
|
12840
|
+
* other walks whose behaviour would change with it, and the defect is in what
|
|
12841
|
+
* EQUALITY means here, not in what counts as a container.
|
|
12842
|
+
*
|
|
12843
|
+
* A `Date` anchor now corroborates NOTHING, so an element carrying one refuses
|
|
12844
|
+
* rather than pairs. That is the conservative direction this module always
|
|
12845
|
+
* takes -- the residual stays a refusal -- and it is stated because the
|
|
12846
|
+
* opposite reading (that a `Date` on both sides is evidence) is the one a
|
|
12847
|
+
* future edit will be tempted by.
|
|
12848
|
+
*/
|
|
12849
|
+
function hasPlainPrototype(value) {
|
|
12850
|
+
const proto = Object.getPrototypeOf(value);
|
|
12851
|
+
return proto === Object.prototype || proto === null;
|
|
12852
|
+
}
|
|
12853
|
+
/**
|
|
12854
|
+
* Structural equality over the JSON shapes this module walks (issue #2012).
|
|
12855
|
+
*
|
|
12856
|
+
* Own ENUMERABLE keys only, and a key count on both sides, so an inherited
|
|
12857
|
+
* field is not equality and neither is a bag that merely CONTAINS the source's
|
|
12858
|
+
* keys. That agrees with the two walks beside it -- `isUniquelyKeyedBy` and the
|
|
12859
|
+
* object arm of {@link refuseUncertifiedReadbackPositions} both use
|
|
12860
|
+
* `Object.hasOwn` -- and it matters here rather than being hygiene: this
|
|
12861
|
+
* predicate is the evidence an anchor pairing rests on, so a comparison that
|
|
12862
|
+
* reads the prototype chain would let a constructed bag corroborate a pairing
|
|
12863
|
+
* it does not actually match.
|
|
12864
|
+
*
|
|
12865
|
+
* `JSON.stringify` was the obvious alternative and is wrong twice over: it is
|
|
12866
|
+
* key-ORDER sensitive (an AWS readback routinely reorders object keys, which
|
|
12867
|
+
* says nothing about the values) and it silently drops `undefined`, so
|
|
12868
|
+
* `{A: undefined}` and `{}` would compare equal while their key counts differ.
|
|
12869
|
+
*/
|
|
12870
|
+
function deepEqualJsonValue(a, b) {
|
|
12871
|
+
if (a === b) return true;
|
|
12872
|
+
if (Array.isArray(a)) {
|
|
12873
|
+
if (!Array.isArray(b) || a.length !== b.length) return false;
|
|
12874
|
+
return a.every((item, i) => deepEqualJsonValue(item, b[i]));
|
|
12875
|
+
}
|
|
12876
|
+
if (isPlainObject$2(a)) {
|
|
12877
|
+
if (!isPlainObject$2(b)) return false;
|
|
12878
|
+
if (!hasPlainPrototype(a) || !hasPlainPrototype(b)) return false;
|
|
12879
|
+
const keys = Object.keys(a);
|
|
12880
|
+
if (keys.length !== Object.keys(b).length) return false;
|
|
12881
|
+
return keys.every((k) => Object.hasOwn(b, k) && deepEqualJsonValue(a[k], b[k]));
|
|
12882
|
+
}
|
|
12883
|
+
return false;
|
|
12884
|
+
}
|
|
12885
|
+
/**
|
|
12886
|
+
* Is an equal SOURCE value at an anchor position actually EVIDENCE that the two
|
|
12887
|
+
* containers describe the same element?
|
|
12888
|
+
*
|
|
12889
|
+
* A NON-EMPTY STRING is, and deliberately nothing else is. This is the same bar
|
|
12890
|
+
* {@link isUniquelyKeyedBy} already applies to an identity field, and for the
|
|
12891
|
+
* same reason: `''` is not a distinguishing value (it is also why the value
|
|
12892
|
+
* scan refuses it as a needle), and a non-string carries so few inhabitants
|
|
12893
|
+
* that equality is nearly free -- `{Name: 1, Value: <literal>}` and `{Name: 1,
|
|
12894
|
+
* Value: <expression>}` agree on `Name` whether or not they are the same entry,
|
|
12895
|
+
* so pairing on it would copy a secret reference onto an unrelated literal.
|
|
12896
|
+
* Both shapes are pinned in `secret-redaction-array-identity.test.ts` on the
|
|
12897
|
+
* IDENTITY arm and again in `secret-redaction-anchor-pairing.test.ts` on this
|
|
12898
|
+
* one; an anchor that accepted them would reopen from the positional side
|
|
12899
|
+
* exactly what that arm refuses.
|
|
12900
|
+
*
|
|
12901
|
+
* Containers count when something inside them does, so a nested literal object
|
|
12902
|
+
* can anchor a pairing its own level cannot. That recursion is also why this
|
|
12903
|
+
* predicate ALONE is not enough, and the review that measured it is worth
|
|
12904
|
+
* recording: `AWS::AmazonMQ::Broker.Users` renders `Groups: ['admin']`
|
|
12905
|
+
* identically on every element, which is distinguishing by this test and yet
|
|
12906
|
+
* tells two users APART not at all. Distinguishing is a property of ONE value;
|
|
12907
|
+
* telling elements apart is a property of the WHOLE array, and
|
|
12908
|
+
* {@link unkeyedArrayPairsByAnchors} is where the second one is enforced.
|
|
12909
|
+
*
|
|
12910
|
+
* This is a REFINEMENT of the formulation recorded on issue #2012, which said
|
|
12911
|
+
* only "every position whose SOURCE carries no dynamic reference is deep-equal
|
|
12912
|
+
* on both sides". Taken literally that admits a pairing corroborated ONLY by
|
|
12913
|
+
* `Name: ''` or `Name: 1`, which is measurably wrong: the counterexample the
|
|
12914
|
+
* issue states (`{Name:'', Value:'lit'}` against `{Name:'db', Value:<expr>}`)
|
|
12915
|
+
* has DIFFERING names and refuses on inequality alone, but the fence actually
|
|
12916
|
+
* in the tree carries `Name: ''` on BOTH sides, where equality holds and only
|
|
12917
|
+
* this predicate stands between an unrelated literal and a false redaction.
|
|
12918
|
+
*/
|
|
12919
|
+
function isDistinguishingAnchor(value) {
|
|
12920
|
+
if (typeof value === "string") return value !== "";
|
|
12921
|
+
if (Array.isArray(value)) return value.some(isDistinguishingAnchor);
|
|
12922
|
+
if (isPlainObject$2(value)) return Object.values(value).some(isDistinguishingAnchor);
|
|
12923
|
+
return false;
|
|
12924
|
+
}
|
|
12925
|
+
/**
|
|
12926
|
+
* Stands in for a reference-bearing leaf inside an {@link anchorSignature}.
|
|
12927
|
+
*
|
|
12928
|
+
* Written UNQUOTED while `JSON.stringify` quotes every real string, so no
|
|
12929
|
+
* literal can spell it and collide with a masked reference.
|
|
12930
|
+
*/
|
|
12931
|
+
const ANCHOR_REFERENCE_MASK = "<ref>";
|
|
12932
|
+
/**
|
|
12933
|
+
* The part of a SOURCE element the anchors can actually see: the element with
|
|
12934
|
+
* every reference-bearing leaf masked, serialized canonically.
|
|
12935
|
+
*
|
|
12936
|
+
* Two elements with the same signature are INDISTINGUISHABLE to this pass --
|
|
12937
|
+
* the anchors say the same thing about both -- so a permutation swapping them
|
|
12938
|
+
* preserves every anchor and the alignment is not determined. That is the
|
|
12939
|
+
* property {@link isUniquelyKeyedBy} enforces for an identity FIELD, restated
|
|
12940
|
+
* for a whole projection instead of a single key.
|
|
12941
|
+
*
|
|
12942
|
+
* The signature is ORDER-INSENSITIVE in both directions -- object keys AND list
|
|
12943
|
+
* elements are sorted -- and that is not cosmetic normalisation. Rule 3's
|
|
12944
|
+
* question is "could AWS hand these two elements back SWAPPED without the swap
|
|
12945
|
+
* being visible", so the projection has to quotient by everything AWS may
|
|
12946
|
+
* itself reorder. Outer list order is the gate's own subject; order WITHIN an
|
|
12947
|
+
* anchor's list is this function's, for exactly the reason `descendArrays:
|
|
12948
|
+
* false` exists at all. A first cut sorted only the keys, and the security
|
|
12949
|
+
* review measured the hole on `AWS::AmazonMQ::Broker.Users`: two users whose
|
|
12950
|
+
* `Groups` were `['admin','ops']` and `['ops','admin']` signed DIFFERENTLY, so
|
|
12951
|
+
* rule 3 passed while the anchors still deep-equalled position for position,
|
|
12952
|
+
* and a reordered `DescribeBroker` put the admin's `Username` / `Password`
|
|
12953
|
+
* expressions at the app user's index. Byte-identical anchor content was being
|
|
12954
|
+
* assumed -- the order assumption this module refuses everywhere else.
|
|
12955
|
+
*
|
|
12956
|
+
* Sorting FAILS CLOSED, which is why it is the right shape of fix: it can only
|
|
12957
|
+
* make two signatures COLLIDE that previously differed, never the reverse, so
|
|
12958
|
+
* its only possible effect is an extra refusal. A missed closure, never a leak.
|
|
12959
|
+
*
|
|
12960
|
+
* The asymmetry with {@link deepEqualJsonValue} is deliberate and must survive
|
|
12961
|
+
* a reader who notices it. That predicate stays order-SENSITIVE on lists
|
|
12962
|
+
* because rule 1 asks a different question -- "did AWS return THIS position
|
|
12963
|
+
* unchanged" -- and a reordered list is a changed position. Making rule 1
|
|
12964
|
+
* order-blind too would weaken the corroboration rather than align it; the case
|
|
12965
|
+
* pinning that is `REFUSES an anchor list REORDERED in place` in
|
|
12966
|
+
* `secret-redaction-anchor-pairing.test.ts`.
|
|
12967
|
+
*/
|
|
12968
|
+
function anchorSignature(source) {
|
|
12969
|
+
if (isDynamicReferenceString(source)) return ANCHOR_REFERENCE_MASK;
|
|
12970
|
+
if (Array.isArray(source)) return `[${source.map(anchorSignature).sort().join(",")}]`;
|
|
12971
|
+
if (isPlainObject$2(source)) return `{${Object.keys(source).sort().map((k) => `${JSON.stringify(k)}:${anchorSignature(source[k])}`).join(",")}}`;
|
|
12972
|
+
return JSON.stringify(source) ?? "undefined";
|
|
12973
|
+
}
|
|
12974
|
+
/**
|
|
12975
|
+
* ANCHOR PAIRING (issue #2012): do these two containers corroborate each other
|
|
12976
|
+
* position by position?
|
|
12977
|
+
*
|
|
12978
|
+
* Two conditions, both required:
|
|
12979
|
+
*
|
|
12980
|
+
* 1. the key sets (objects) or index counts (arrays) match, and
|
|
12981
|
+
* 2. every position whose SOURCE carries no dynamic reference is deep-equal on
|
|
12982
|
+
* both sides -- the *anchors*.
|
|
12983
|
+
*
|
|
12984
|
+
* Anchors are what make the pairing EVIDENCE rather than a guess: a position
|
|
12985
|
+
* AWS did not rewrite proves the two containers describe the same element. It
|
|
12986
|
+
* answers the `descendArrays: false` objection on its own terms the way keying
|
|
12987
|
+
* does -- a REORDERED list normally puts a different element under each index,
|
|
12988
|
+
* so its anchors stop matching and the whole array is refused.
|
|
12989
|
+
*
|
|
12990
|
+
* "Normally" is doing real work in that sentence, and an earlier revision of it
|
|
12991
|
+
* did not have the word. A reorder is INVISIBLE to the anchors when the
|
|
12992
|
+
* elements it swaps look the same to them, which is the whole subject of
|
|
12993
|
+
* {@link unkeyedArrayPairsByAnchors}. This function answers only "does position
|
|
12994
|
+
* i corroborate position i"; whether the array as a whole may be walked at all
|
|
12995
|
+
* is decided there, and nothing here is sufficient on its own.
|
|
12996
|
+
*
|
|
12997
|
+
* What it deliberately CANNOT buy is baseline content. Every substitution the
|
|
12998
|
+
* caller then makes is a STRING leaf at a position the bag already has, so a
|
|
12999
|
+
* corroborated pairing never adds a key, adds an element, or writes a scalar
|
|
13000
|
+
* over a container. The principle this module is built on -- **redaction may
|
|
13001
|
+
* not buy itself a fabricated baseline** -- is preserved structurally rather
|
|
13002
|
+
* than by a special case, which is what the first attempt at these rows (taking
|
|
13003
|
+
* the SOURCE array wholesale) failed to do.
|
|
13004
|
+
*
|
|
13005
|
+
* The cost, stated rather than discovered: one deep compare per candidate
|
|
13006
|
+
* position, and a yield that drops to ZERO as soon as AWS normalises any
|
|
13007
|
+
* sibling field in the same container. That is common, so this closes a SUBSET
|
|
13008
|
+
* of the shapes issue #2012 lists rather than all of them, and the residual
|
|
13009
|
+
* stays a refusal -- which is the correct direction to be wrong in here.
|
|
13010
|
+
*/
|
|
13011
|
+
function anchorsCorroboratePairing(bag, source, anchors) {
|
|
13012
|
+
if (!subtreeHasDynamicReference(source)) {
|
|
13013
|
+
if (!deepEqualJsonValue(bag, source)) return false;
|
|
13014
|
+
if (isDistinguishingAnchor(source)) anchors.distinguishing += 1;
|
|
13015
|
+
return true;
|
|
13016
|
+
}
|
|
13017
|
+
if (isDynamicReferenceString(source)) return typeof bag === "string";
|
|
13018
|
+
if (isPlainObject$2(source)) {
|
|
13019
|
+
if (!isPlainObject$2(bag)) return false;
|
|
13020
|
+
const sourceKeys = Object.keys(source);
|
|
13021
|
+
if (sourceKeys.length !== Object.keys(bag).length) return false;
|
|
13022
|
+
return sourceKeys.every((k) => Object.hasOwn(bag, k) && anchorsCorroboratePairing(bag[k], source[k], anchors));
|
|
13023
|
+
}
|
|
13024
|
+
if (Array.isArray(source)) {
|
|
13025
|
+
if (!Array.isArray(bag) || bag.length !== source.length) return false;
|
|
13026
|
+
return source.every((item, i) => anchorsCorroboratePairing(bag[i], item, anchors));
|
|
13027
|
+
}
|
|
13028
|
+
return false;
|
|
13029
|
+
}
|
|
13030
|
+
/**
|
|
13031
|
+
* May this UNKEYED array be walked positionally? The gate the anchor relaxation
|
|
13032
|
+
* actually rests on (issue #2012 review).
|
|
13033
|
+
*
|
|
13034
|
+
* {@link anchorsCorroboratePairing} answers per POSITION. Asking it once for
|
|
13035
|
+
* the whole array and requiring one distinguishing anchor ANYWHERE in the
|
|
13036
|
+
* result -- which an earlier revision did -- is unsound in two INDEPENDENT
|
|
13037
|
+
* ways, both measured by review against real shapes rather than reasoned about:
|
|
13038
|
+
*
|
|
13039
|
+
* - **Evidence for one element was credited to another.** `[{Name:'db',
|
|
13040
|
+
* Value:<exprA>}, {Name:'', Value:<exprB>}]` has a distinguishing anchor at
|
|
13041
|
+
* index 0 and NONE at index 1, and the array-wide counter licensed both -- so
|
|
13042
|
+
* an unrelated literal at index 1 took `<exprB>`. That is precisely the false
|
|
13043
|
+
* redaction `isDistinguishingAnchor` exists to prevent, arriving through the
|
|
13044
|
+
* counter's SCOPE instead of through its definition.
|
|
13045
|
+
* - **Equal anchors cannot detect a reorder.** `['--pw', <exprA>, '--pw',
|
|
13046
|
+
* <exprB>]` against a readback holding the two values swapped matches every
|
|
13047
|
+
* anchor at every index, because both anchors are `'--pw'` -- so each
|
|
13048
|
+
* position was pinned to the OTHER secret's expression.
|
|
13049
|
+
* `AWS::AmazonMQ::Broker.Users` is the shape that makes this real rather than
|
|
13050
|
+
* contrived: no `Name`/`Key`, both `Username` and `Password` rendered through
|
|
13051
|
+
* `secretValueFromJson`, and `Groups: ['admin']` equal on every element, so a
|
|
13052
|
+
* `DescribeBroker` returning the users in the other order records the ADMIN
|
|
13053
|
+
* credential's reference at the app user's position -- which `cdkd drift
|
|
13054
|
+
* --revert` then pushes to the live broker.
|
|
13055
|
+
*
|
|
13056
|
+
* So the gate is:
|
|
13057
|
+
*
|
|
13058
|
+
* 1. **Every position corroborates**, with the counter scoped PER top-level
|
|
13059
|
+
* element rather than shared across the array.
|
|
13060
|
+
* 2. **Every reference-bearing element carries its own evidence.** A CONTAINER
|
|
13061
|
+
* must hold a distinguishing anchor INSIDE it: it has an interior where an
|
|
13062
|
+
* identity could live, so the absence of one is meaningful. A BARE reference
|
|
13063
|
+
* leaf has no interior, so absence says nothing about it and the only
|
|
13064
|
+
* evidence available is the FRAME -- the array's non-reference-bearing
|
|
13065
|
+
* elements, which must then supply a distinguishing anchor between them.
|
|
13066
|
+
* That distinction is exactly what separates `['--pw', <expr>, '--verbose']`
|
|
13067
|
+
* (CLOSES: the literal flags pin the one free slot) from `[{V:'us-east-1'},
|
|
13068
|
+
* {V:<expr>}]` (REFUSES: the second element could hold anything, and
|
|
13069
|
+
* overwriting it would erase a genuine out-of-band change from the drift
|
|
13070
|
+
* baseline, so `cdkd drift` reports clean and `--revert` never sees it).
|
|
13071
|
+
* 3. **Reference-bearing elements are pairwise DISTINGUISHABLE**, by
|
|
13072
|
+
* {@link anchorSignature}. Two elements the anchors describe identically
|
|
13073
|
+
* admit a permutation that preserves every anchor, so the alignment is not
|
|
13074
|
+
* determined and no amount of per-position equality makes it so.
|
|
13075
|
+
*
|
|
13076
|
+
* Checking uniqueness on the SOURCE side alone is sufficient, and the argument
|
|
13077
|
+
* is worth stating because the bag side looks like it needs checking too: rule
|
|
13078
|
+
* 1 has already established that the bag matches the source at every anchor
|
|
13079
|
+
* position, so the two projections are equal element-wise. If some permutation
|
|
13080
|
+
* other than the identity also satisfied the anchors, two SOURCE elements would
|
|
13081
|
+
* have to share a signature -- which rule 3 excludes. This is the same
|
|
13082
|
+
* multiset-correctness argument `isUniquelyKeyedBy` makes for a single field.
|
|
13083
|
+
*
|
|
13084
|
+
* NESTED arrays are not re-checked here, and do not need to be: the caller
|
|
13085
|
+
* recurses through {@link refuseUncertifiedReadbackPositions}, which re-enters
|
|
13086
|
+
* its own array arm for every nested list and consults this gate again with
|
|
13087
|
+
* that list's own elements. A nested array whose elements are indistinguishable
|
|
13088
|
+
* is therefore refused on its own terms while its parent may still pair.
|
|
13089
|
+
*/
|
|
13090
|
+
function unkeyedArrayPairsByAnchors(bag, source) {
|
|
13091
|
+
if (bag.length !== source.length) return false;
|
|
13092
|
+
const distinguishingPerElement = [];
|
|
13093
|
+
for (const [i, item] of source.entries()) {
|
|
13094
|
+
const anchors = { distinguishing: 0 };
|
|
13095
|
+
if (!anchorsCorroboratePairing(bag[i], item, anchors)) return false;
|
|
13096
|
+
distinguishingPerElement.push(anchors.distinguishing);
|
|
13097
|
+
}
|
|
13098
|
+
const frameDistinguishing = source.reduce((total, item, i) => subtreeHasDynamicReference(item) ? total : total + distinguishingPerElement[i], 0);
|
|
13099
|
+
const signatures = /* @__PURE__ */ new Set();
|
|
13100
|
+
for (const [i, item] of source.entries()) {
|
|
13101
|
+
if (!subtreeHasDynamicReference(item)) continue;
|
|
13102
|
+
const signature = anchorSignature(item);
|
|
13103
|
+
if (signatures.has(signature)) return false;
|
|
13104
|
+
signatures.add(signature);
|
|
13105
|
+
if (distinguishingPerElement[i] > 0) continue;
|
|
13106
|
+
if (!isDynamicReferenceString(item) || frameDistinguishing === 0) return false;
|
|
13107
|
+
}
|
|
13108
|
+
return true;
|
|
13109
|
+
}
|
|
13110
|
+
/**
|
|
12825
13111
|
* Refuse to persist a readback leaf the path pass could not CERTIFY, at any
|
|
12826
13112
|
* position the STATE source proves is secret-bearing (issue #1926 review).
|
|
12827
13113
|
*
|
|
@@ -12841,8 +13127,9 @@ function mixedLeafMayCarryPublicReference(source, secrets) {
|
|
|
12841
13127
|
* ----------------------------------------------- ------------ ---------------
|
|
12842
13128
|
* `postgres://u:{{resolve:...}}@h` (MIXED string) LEAK take source
|
|
12843
13129
|
* ...the same MIXED leaf inside a PAIRED element LEAK take source
|
|
12844
|
-
* `['--pw', '{{resolve:...}}']` (no identity key) LEAK
|
|
12845
|
-
* `[{Field, Val: '{{resolve:...}}'}]` (no `Name`) LEAK
|
|
13130
|
+
* `['--pw', '{{resolve:...}}']` (no identity key) LEAK take source*
|
|
13131
|
+
* `[{Field, Val: '{{resolve:...}}'}]` (no `Name`) LEAK take source*
|
|
13132
|
+
* ...either of those, but REORDERED / normalised LEAK LEAK (#2012)
|
|
12846
13133
|
* an UNPAIRED element beside a paired one LEAK LEAK (#2012)
|
|
12847
13134
|
* an observed KEY the source does not carry LEAK LEAK (#2012)
|
|
12848
13135
|
* whole `{{resolve:...}}` token ok ok
|
|
@@ -12864,7 +13151,27 @@ function mixedLeafMayCarryPublicReference(source, secrets) {
|
|
|
12864
13151
|
* not a WHOLE token. Everything it takes is the record's own value at the
|
|
12865
13152
|
* record's own path.
|
|
12866
13153
|
*
|
|
12867
|
-
* The
|
|
13154
|
+
* The starred rows are the two ANCHOR PAIRING closed for issue #2012, and the
|
|
13155
|
+
* star is load-bearing: they close only when the pairing is CORROBORATED. Four
|
|
13156
|
+
* conditions, all required — the index counts match; every position the source
|
|
13157
|
+
* does not spell as a reference is deep-equal on both sides; every
|
|
13158
|
+
* reference-bearing ELEMENT carries its own distinguishing anchor, or, being a
|
|
13159
|
+
* bare reference leaf with no interior to carry one, leans on the array's
|
|
13160
|
+
* literal FRAME; and no two reference-bearing elements look alike to the
|
|
13161
|
+
* anchors. That is why the row beneath them exists. As soon as AWS reorders the
|
|
13162
|
+
* list or normalises any sibling field, the anchors stop matching and the same
|
|
13163
|
+
* two shapes refuse again, so the closure is a SUBSET of each row rather than
|
|
13164
|
+
* the whole of it.
|
|
13165
|
+
*
|
|
13166
|
+
* An earlier revision of this paragraph stated only the first two conditions
|
|
13167
|
+
* plus "at least one of them distinguishing", which was the gate BEFORE the
|
|
13168
|
+
* #2012 review — under it `['--pw', <exprA>, '--pw', <exprB>]` closes and
|
|
13169
|
+
* misattributes, so the text documented the defect as the design. See
|
|
13170
|
+
* {@link unkeyedArrayPairsByAnchors}, which is where all four live;
|
|
13171
|
+
* {@link anchorsCorroboratePairing} answers only one of them and its own doc
|
|
13172
|
+
* says nothing in it is sufficient alone.
|
|
13173
|
+
*
|
|
13174
|
+
* The residual rows are one root cause, not several: no needle and no
|
|
12868
13175
|
* position, so nothing distinguishes a resolved secret from an ordinary
|
|
12869
13176
|
* literal. They are NOT closed by taking the source subtree, which an earlier
|
|
12870
13177
|
* revision did and the issue #1915 fences correctly rejected — measured, it
|
|
@@ -12872,7 +13179,9 @@ function mixedLeafMayCarryPublicReference(source, secrets) {
|
|
|
12872
13179
|
* turned an AWS-reported `[{Value:'x'}]` into `[{Name:'db', Value:<expr>}]`,
|
|
12873
13180
|
* fabricating drift-baseline content AWS never reported that `cdkd drift
|
|
12874
13181
|
* --revert` then pushes to the live resource. Redaction may not buy itself a
|
|
12875
|
-
* fabricated baseline
|
|
13182
|
+
* fabricated baseline — which is also the bar anchor pairing had to clear, and
|
|
13183
|
+
* clears structurally: it only ever licenses a walk of positions the BAG
|
|
13184
|
+
* already has, so it can add no key, no element and no scalar-over-container.
|
|
12876
13185
|
*
|
|
12877
13186
|
* The MIXED row is the shape this module itself calls DOMINANT for CDK — an
|
|
12878
13187
|
* `Fn::Join` around `secret.secretValueFromJson(...)`.
|
|
@@ -12907,7 +13216,10 @@ function refuseUncertifiedReadbackPositions(bag, source, secrets) {
|
|
|
12907
13216
|
}
|
|
12908
13217
|
if (Array.isArray(bag) && Array.isArray(source)) {
|
|
12909
13218
|
const key = identityKeyFor(bag, source);
|
|
12910
|
-
if (key === void 0)
|
|
13219
|
+
if (key === void 0) {
|
|
13220
|
+
if (!unkeyedArrayPairsByAnchors(bag, source)) return bag;
|
|
13221
|
+
return bag.map((item, i) => refuseUncertifiedReadbackPositions(item, source[i], secrets));
|
|
13222
|
+
}
|
|
12911
13223
|
const sourceByIdentity = /* @__PURE__ */ new Map();
|
|
12912
13224
|
for (const item of source) sourceByIdentity.set(item[key], item);
|
|
12913
13225
|
return bag.map((item) => {
|
|
@@ -18844,7 +19156,7 @@ var CloudControlProvider = class {
|
|
|
18844
19156
|
if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
|
|
18845
19157
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
18846
19158
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
18847
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
19159
|
+
const { ASGProvider } = await import("./asg-provider-CLnf8ct8.js").then((n) => n.n);
|
|
18848
19160
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
18849
19161
|
}
|
|
18850
19162
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -30631,4 +30943,4 @@ var DeployEngine = class {
|
|
|
30631
30943
|
|
|
30632
30944
|
//#endregion
|
|
30633
30945
|
export { maskerOrIdentity as $, findLargeInlineResources as $n, TemplateParser as $t, renderStatefulReason as A, formatDockerLoginError as An, StackHasActiveImportsError as Ar, STATE_SOURCED_READBACK_RULES as At, exportAliasCollisionScrubWarning as B, getLegacyStateBucketName as Bn, isThrottlingError as Br, classifyReplaySecretRegion as Bt, isFinalSnapshotError as C, parseBootstrapMarker as Cn, LockError as Cr, configStringRefusal as Ct, extractDeploymentEventError as D, buildDenyExternalAccessPolicy as Dn, ProvisioningError as Dr, requireConfigObject as Dt, makeCanonicalizePropertiesFn as E, validateContainerRepoName as En, PartialFailureError as Er, requireConfigArray as Et, green as F, AssetManifestLoader as Fn, isCdkdError as Fr, isSingleDynamicReferenceToken as Ft, IAMRoleProvider as G, resolveStateBucketWithDefault as Gn, s3BucketRegionalDomainName as Gt, secretBearingStateKeyWarning as H, resolveAutoAssetStorage as Hn, __exportAll as Hr, s3BucketArn as Ht, red as I, getDockerImageBySourceHash as In, normalizeAwsError as Ir, maskSecretsInError as It, ProviderRegistry as J, stateBucketExistenceConfirmed as Jn, DiffCalculator as Jt, collectInlinePolicyNamesManagedBySiblings as K, resolveStateBucketWithDefaultAndSource as Kn, s3BucketWebsiteUrl as Kt, yellow as L, Synthesizer as Ln, withErrorHandling as Lr, maskSecretsInText as Lt, bold as M, partitionSensitiveEnv as Mn, StateError as Mr, createSecretMasker as Mt, cyan as N, runDockerForeground as Nn, SynthesisError as Nr, dynamicReferenceTokens as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, buildDockerImage as On, ResourceTimeoutError as Or, requireConfigString as Ot, gray as P, runDockerStreaming as Pn, formatError as Pr, errorCauseChain as Pt, maskDeep as Q, MIGRATE_TMP_PREFIX as Qn, DagBuilder as Qt, collectDeclaredOutputNames as R, synthesisStatusMessage as Rn, isMarkedNonRetryable as Rr, redactSecretsForState as Rt, createPreDeleteFinalSnapshot as S, isCrossRegionRedirect as Sn, LocalStartServiceError as Sr, configBooleanRefusal as St, unsupportedFinalSnapshotError as T, validateAssetBucketName as Tn, NestedStackChildDirectDestroyError as Tr, replayWarn as Tt, stateKeySecretExposure as U, resolveCaptureObservedState as Un, s3BucketDomainName as Ut, isExportAliasCollision as V, resolveApp as Vn, markNonRetryable as Vr, producerRegionsFromState as Vt, getCurrentResourceSecrets as W, resolveSkipPrefix as Wn, s3BucketDualStackDomainName as Wt, findSilentDropProperties as X, CFN_TEMPLATE_BODY_LIMIT as Xn, describeTypeWithThrottleRetry as Xt, findActionableSilentDrops as Y, warnDeprecatedNoPrefixCliFlag as Yn, INTRINSIC_KEYS as Yt, createMaskedRetryLogger as Z, CFN_TEMPLATE_URL_LIMIT as Zn, withRetry as Zt, computeImplicitDeleteEdges as _, AssetModeResolver as _n, DependencyError as _r, WAFv2WebACLProvider as _t, DeploymentEventsStore as a, importableOutputKeys as an, AssemblyReader as ar, isInterruptedWaitError as at, buildFinalSnapshotIdentifier as b, ensureAssetStorage as bn, LocalInvokeBuildError as br, assertRegionMatch as bt, replayFailedOperations as c, AssetPublisher as cn, resolveBucketRegion as cr, slowCcOperationTimeoutMs as ct, updatePartialReason as d, buildAssetRedirectMap as dn, resetAwsClients as dr, IntrinsicFunctionResolver as dt, LockManager as en, uploadCfnTemplate as er, CUSTOM_RESOURCE_RESPONSE_PREFIX as et, UNSPECIFIED_SKIP_REASON as f, createAssetRedirectResolver as fn, setAwsClients as fr, carriesDynamicReference as ft, IMPLICIT_DELETE_DEPENDENCIES as g, stripControlChars as gn, CrossAccountSecretRefusalError as gr, refStateLookupFromResource as gt, maskingRetryLogger as h, escapeRegExp$1 as hn, ConfigError as hr, parameterTypeMayLoseSecretIdentity as ht, DeploymentEventsReader as i, exportNamesCarriedFrom as in, derivePartitionAndUrlSuffix as ir, interruptWatchListenerCount as it, formatResourceLine as j, getDockerCmd as jn, StackTerminationProtectionError as jr, TEMPLATE_SOURCED_RULES as jt, isStatefulRecreateTargetSync as k, dockerSpawnEnvWithSensitive as kn, ResourceUpdateNotSupportedError as kr, STATE_SOURCED_CROSS_GENERATION_RULES as kt, replayRollback as l, stringifyValue as ln, AwsClients as lr, disableInstanceApiTermination as lt, withResourceDeadline as m, rewriteTemplateAssetReferences as mn, CdkdError as mr, getAccountInfo as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, S3StateBackend as nn, PARTITION_TABLE as nr, beginCommandInterruptScope as nt, planFailedOps as o, importableOutputs as on, processStackMessages as or, startInterruptWatch as ot, deleteSkipReason as p, loadPublishableAssetManifest as pn, AssetError as pr, cfnRefValueFromPhysicalId as pt, clearOnUpdateRemoval as q, resolveUseCdkBootstrapAssets as qn, applyRoleArnIfSet as qt, DeployEngine as r, rebuildClientForBucketRegion as rn, canonicalizeRegion as rr, endCommandInterruptScope as rt, planRollback as s, shouldRetainResource as sn, clearBucketRegionCache as sr, CloudControlProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, displaySafe as tn, expectedOwnerParam as tr, DEFAULT_STATE_PREFIX as tt, updatePartialMessage as u, WorkGraph as un, getAwsClients as ur, isTerminationProtectionPropagationError as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, BOOTSTRAP_MARKER_PREFIX as vn, DeployCancelledError as vr, normalizeAwsTagsToCfn as vt, refusesFinalSnapshot as w, readBootstrapMarkerBody as wn, MissingCdkCliError as wr, readConfigString as wt, ccRoutedFinalSnapshotError as x, getBootstrapMarkerKey as xn, LocalMigrateError as xr, coerceCfnBoolean as xt, PRE_DELETE_SNAPSHOT_TYPES as y, assertAssetBucketRegion as yn, DynamicReferenceRegionAmbiguousError as yr, resolveExplicitPhysicalId as yt, collectPublishedOutputNames as z, getDefaultStateBucketName as zn, isRetryableTransientError as zr, scrubResourceRecord as zt };
|
|
30634
|
-
//# sourceMappingURL=deploy-engine-
|
|
30946
|
+
//# sourceMappingURL=deploy-engine-CHLe31Fh.js.map
|