@go-to-k/cdkd 0.252.0 → 0.252.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 +133 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1888,7 +1888,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
1888
1888
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
1889
1889
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
1890
1890
|
function getCdkdVersion() {
|
|
1891
|
-
return "0.252.
|
|
1891
|
+
return "0.252.1";
|
|
1892
1892
|
}
|
|
1893
1893
|
/**
|
|
1894
1894
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -35555,6 +35555,38 @@ var FSxFileSystemProvider = class {
|
|
|
35555
35555
|
];
|
|
35556
35556
|
}
|
|
35557
35557
|
/**
|
|
35558
|
+
* Plain-string arrays FSx returns as unordered sets.
|
|
35559
|
+
*
|
|
35560
|
+
* - `WindowsConfiguration.Aliases` — DNS alias names (`files.example.com`).
|
|
35561
|
+
* Alternate names the file system answers to; the API documents no
|
|
35562
|
+
* ordering semantics and no name is privileged over another, so a
|
|
35563
|
+
* `DescribeFileSystems` reorder carries no meaning.
|
|
35564
|
+
*
|
|
35565
|
+
* This does not match the shared normalizer's AWS-id / ARN heuristic, so
|
|
35566
|
+
* without the declaration a reorder would surface as phantom drift. Declared
|
|
35567
|
+
* here rather than sorted in `readWindowsConfiguration` so the sort applies
|
|
35568
|
+
* to BOTH comparison sides — see
|
|
35569
|
+
* {@link ResourceProvider.getDriftUnorderedPaths}.
|
|
35570
|
+
*
|
|
35571
|
+
* Deliberately NOT declared:
|
|
35572
|
+
*
|
|
35573
|
+
* - `WindowsConfiguration.SelfManagedActiveDirectoryConfiguration.DnsIps` —
|
|
35574
|
+
* the API reference describes it only as "A list of IP addresses of DNS
|
|
35575
|
+
* servers or domain controllers in the self-managed AD directory"
|
|
35576
|
+
* (https://docs.aws.amazon.com/fsx/latest/APIReference/API_SelfManagedActiveDirectoryConfiguration.html),
|
|
35577
|
+
* with no statement that order is insignificant. DNS resolver lists are
|
|
35578
|
+
* conventionally preference-ordered (primary first), and if FSx honors
|
|
35579
|
+
* that when joining the domain, sorting would HIDE a real reorder. A
|
|
35580
|
+
* false positive is visible and correctable; silently hiding drift is
|
|
35581
|
+
* not. Same reasoning excludes ElastiCache `PreferredAvailabilityZones`.
|
|
35582
|
+
* - `OntapConfiguration.RouteTableIds` / `OpenZFSConfiguration.RouteTableIds`
|
|
35583
|
+
* — their `rtb-` elements already match the shared id heuristic.
|
|
35584
|
+
*/
|
|
35585
|
+
getDriftUnorderedPaths(resourceType) {
|
|
35586
|
+
if (resourceType !== "AWS::FSx::FileSystem") return [];
|
|
35587
|
+
return ["WindowsConfiguration.Aliases"];
|
|
35588
|
+
}
|
|
35589
|
+
/**
|
|
35558
35590
|
* Read the AWS-current file system configuration in CFn-property shape
|
|
35559
35591
|
* via `DescribeFileSystems`. Lustre data-repository fields (`ImportPath`
|
|
35560
35592
|
* / `ExportPath` / `AutoImportPolicy` / `ImportedFileChunkSize`) are
|
|
@@ -44691,6 +44723,19 @@ function createDiffCommand() {
|
|
|
44691
44723
|
* on BOTH sides before the diff. These two passes were surfaced by dogfooding
|
|
44692
44724
|
* the sibling cdk-real-drift (cdkrd) tool, which hit the same false-positive
|
|
44693
44725
|
* classes against the same kind of AWS-snapshot baseline.
|
|
44726
|
+
*
|
|
44727
|
+
* Plain-string arrays are NOT canonicalized by the two heuristic passes above,
|
|
44728
|
+
* because a scalar list can be order-significant. But several CFn inputs are
|
|
44729
|
+
* semantically unordered sets of plain strings (FSx `WindowsConfiguration.Aliases`,
|
|
44730
|
+
* `...SelfManagedActiveDirectoryConfiguration.DnsIps`, ...), so
|
|
44731
|
+
* {@link canonicalizeUnorderedArraysAtPaths} sorts them at an explicit,
|
|
44732
|
+
* provider-declared path list only — an opt-in seam mirroring
|
|
44733
|
+
* `getDriftUnknownPaths` (see `ResourceProvider.getDriftUnorderedPaths`).
|
|
44734
|
+
* Doing it HERE rather than inside the provider's reverse-mapper is load-bearing:
|
|
44735
|
+
* the normalizer runs on BOTH comparison sides, so it stays correct for the
|
|
44736
|
+
* `properties`-fallback baseline (a resource deployed before observed-capture,
|
|
44737
|
+
* whose baseline is the user's TEMPLATE order). Sorting only the AWS read side
|
|
44738
|
+
* would manufacture drift on exactly that path.
|
|
44694
44739
|
*/
|
|
44695
44740
|
function canonicalizeTagListsDeep(v) {
|
|
44696
44741
|
if (Array.isArray(v)) {
|
|
@@ -44725,6 +44770,72 @@ function canonicalizeIdArraysDeep(v) {
|
|
|
44725
44770
|
}
|
|
44726
44771
|
return v;
|
|
44727
44772
|
}
|
|
44773
|
+
/**
|
|
44774
|
+
* Match a dotted property path against a provider-declared path list.
|
|
44775
|
+
*
|
|
44776
|
+
* An entry matches when the path is exactly equal to it, OR when the entry is
|
|
44777
|
+
* a prefix followed by `.`. Every entry is therefore a SUBTREE declaration:
|
|
44778
|
+
* `'VpcConfig'` matches `VpcConfig`, `VpcConfig.SubnetIds`, and anything
|
|
44779
|
+
* deeper. There is no leaf-only form.
|
|
44780
|
+
*
|
|
44781
|
+
* Shared by the two provider-declared path lists so their semantics cannot
|
|
44782
|
+
* drift apart: `getDriftUnknownPaths` (via `isIgnoredPath` in
|
|
44783
|
+
* `drift-calculator.ts`) and `getDriftUnorderedPaths` (via
|
|
44784
|
+
* {@link canonicalizeUnorderedArraysAtPaths} below).
|
|
44785
|
+
*/
|
|
44786
|
+
function matchesPathPrefix(path, entries) {
|
|
44787
|
+
for (const entry of entries) {
|
|
44788
|
+
if (path === entry) return true;
|
|
44789
|
+
if (path.startsWith(`${entry}.`)) return true;
|
|
44790
|
+
}
|
|
44791
|
+
return false;
|
|
44792
|
+
}
|
|
44793
|
+
/**
|
|
44794
|
+
* Sort plain-string arrays found at one of the provider-declared `paths`, and
|
|
44795
|
+
* ONLY there. Unlike the two heuristic passes above, this one is opt-in per
|
|
44796
|
+
* resource type via `ResourceProvider.getDriftUnorderedPaths` — a scalar list
|
|
44797
|
+
* is order-significant unless the provider says otherwise.
|
|
44798
|
+
*
|
|
44799
|
+
* Paths use dot-notation for nested keys and are matched by the shared
|
|
44800
|
+
* {@link matchesPathPrefix} rule, the same one `getDriftUnknownPaths` uses. So
|
|
44801
|
+
* `'WindowsConfiguration'` covers every plain-string array in that subtree, and
|
|
44802
|
+
* `'WindowsConfiguration.Aliases'` covers that path and everything beneath it
|
|
44803
|
+
* (every entry is a subtree declaration — there is no leaf-only form).
|
|
44804
|
+
*
|
|
44805
|
+
* One semantic DIVERGENCE from `getDriftUnknownPaths`, required for this pass
|
|
44806
|
+
* to work: `isIgnoredPath` never sees a path that crosses an array, because the
|
|
44807
|
+
* comparator's `diffAt` compares arrays wholesale via `deepEqual` and never
|
|
44808
|
+
* descends into elements. This walk DOES descend into array elements, giving
|
|
44809
|
+
* each element its parent's path (array indices never appear in paths). So
|
|
44810
|
+
* `'Items.Aliases'` is meaningful here — it reaches an `Aliases` array inside
|
|
44811
|
+
* each element of `Items` — while being inert as an ignore-path. The divergence
|
|
44812
|
+
* is strictly more permissive; nothing that matches for ignore-paths fails to
|
|
44813
|
+
* match here.
|
|
44814
|
+
*
|
|
44815
|
+
* Only arrays whose every element is a plain string are sorted, so a
|
|
44816
|
+
* mis-declared path can never reorder object or mixed-type elements. Nested
|
|
44817
|
+
* arrays are also left alone: an array element that is itself an array is not
|
|
44818
|
+
* descended into, so `{P: [['b','a']]}` never has its INNER list sorted by a
|
|
44819
|
+
* `'P'` declaration (no CFn shape in tree is an array-of-arrays, and sorting
|
|
44820
|
+
* one would contradict the plain-string-elements-only rule).
|
|
44821
|
+
*/
|
|
44822
|
+
function canonicalizeUnorderedArraysAtPaths(v, paths) {
|
|
44823
|
+
if (paths.length === 0) return v;
|
|
44824
|
+
return walkUnordered(v, "", paths);
|
|
44825
|
+
}
|
|
44826
|
+
function walkUnordered(v, path, paths) {
|
|
44827
|
+
if (Array.isArray(v)) {
|
|
44828
|
+
const mapped = v.map((el) => Array.isArray(el) ? el : walkUnordered(el, path, paths));
|
|
44829
|
+
if (mapped.length > 1 && matchesPathPrefix(path, paths) && mapped.every((el) => typeof el === "string")) return [...mapped].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
44830
|
+
return mapped;
|
|
44831
|
+
}
|
|
44832
|
+
if (v && typeof v === "object") {
|
|
44833
|
+
const out = {};
|
|
44834
|
+
for (const [k, val] of Object.entries(v)) out[k] = walkUnordered(val, path === "" ? k : `${path}.${k}`, paths);
|
|
44835
|
+
return out;
|
|
44836
|
+
}
|
|
44837
|
+
return v;
|
|
44838
|
+
}
|
|
44728
44839
|
|
|
44729
44840
|
//#endregion
|
|
44730
44841
|
//#region src/analyzer/drift-calculator.ts
|
|
@@ -44784,25 +44895,35 @@ function canonicalizeIdArraysDeep(v) {
|
|
|
44784
44895
|
* it is exactly equal to the entry, or when the entry is a prefix followed
|
|
44785
44896
|
* by `.` — so `'Code'` excludes the whole `Code` subtree, and
|
|
44786
44897
|
* `'VpcConfig.SubnetIds'` excludes only that leaf.
|
|
44898
|
+
*
|
|
44899
|
+
* `options.unorderedPaths` is supplied by the provider (via
|
|
44900
|
+
* `getDriftUnorderedPaths`) for plain-string arrays that are semantically
|
|
44901
|
+
* UNORDERED sets — e.g. FSx `WindowsConfiguration.Aliases`. Those are sorted on
|
|
44902
|
+
* BOTH sides before comparison so an AWS-side reorder is not phantom drift.
|
|
44903
|
+
* Path matching uses the same prefix rule as `ignorePaths`.
|
|
44787
44904
|
*/
|
|
44788
44905
|
function calculateResourceDrift(stateProperties, awsProperties, options) {
|
|
44789
44906
|
const drifts = [];
|
|
44790
44907
|
const ignore = options?.ignorePaths ?? [];
|
|
44791
44908
|
const union = options?.unionWalkObjects ?? false;
|
|
44792
|
-
|
|
44793
|
-
|
|
44909
|
+
const unordered = options?.unorderedPaths ?? [];
|
|
44910
|
+
stateProperties = canonicalizeUnorderedArraysAtPaths(canonicalizeIdArraysDeep(canonicalizeTagListsDeep(stateProperties)), unordered);
|
|
44911
|
+
awsProperties = canonicalizeUnorderedArraysAtPaths(canonicalizeIdArraysDeep(canonicalizeTagListsDeep(awsProperties)), unordered);
|
|
44794
44912
|
for (const key of Object.keys(stateProperties)) {
|
|
44795
44913
|
if (isIgnoredPath(key, ignore)) continue;
|
|
44796
44914
|
diffAt(key, stateProperties[key], awsProperties[key], drifts, ignore, union);
|
|
44797
44915
|
}
|
|
44798
44916
|
return drifts;
|
|
44799
44917
|
}
|
|
44918
|
+
/**
|
|
44919
|
+
* Thin alias over the shared {@link matchesPathPrefix} rule, kept as a named
|
|
44920
|
+
* function because "ignored" is what the path list means at these call sites.
|
|
44921
|
+
* Sharing the implementation with `getDriftUnorderedPaths` is deliberate: both
|
|
44922
|
+
* lists are provider-declared and documented as reading the same way, so they
|
|
44923
|
+
* must not be able to drift apart.
|
|
44924
|
+
*/
|
|
44800
44925
|
function isIgnoredPath(path, ignorePaths) {
|
|
44801
|
-
|
|
44802
|
-
if (path === entry) return true;
|
|
44803
|
-
if (path.startsWith(`${entry}.`)) return true;
|
|
44804
|
-
}
|
|
44805
|
-
return false;
|
|
44926
|
+
return matchesPathPrefix(path, ignorePaths);
|
|
44806
44927
|
}
|
|
44807
44928
|
/**
|
|
44808
44929
|
* Recursive worker. Pushes drift entries into `out` rather than
|
|
@@ -45204,10 +45325,12 @@ async function runDriftForStack(stackName, region, stateBackend, providerRegistr
|
|
|
45204
45325
|
continue;
|
|
45205
45326
|
}
|
|
45206
45327
|
const ignorePaths = provider.getDriftUnknownPaths ? provider.getDriftUnknownPaths(resource.resourceType) : [];
|
|
45328
|
+
const unorderedPaths = provider.getDriftUnorderedPaths ? provider.getDriftUnorderedPaths(resource.resourceType) : [];
|
|
45207
45329
|
const useObserved = resource.observedProperties !== void 0;
|
|
45208
45330
|
const changes = calculateResourceDrift(useObserved ? resource.observedProperties : resource.properties ?? {}, aws, {
|
|
45209
45331
|
ignorePaths,
|
|
45210
|
-
unionWalkObjects: useObserved
|
|
45332
|
+
unionWalkObjects: useObserved,
|
|
45333
|
+
unorderedPaths
|
|
45211
45334
|
});
|
|
45212
45335
|
if (changes.length === 0) outcomes.push({
|
|
45213
45336
|
kind: "clean",
|
|
@@ -62017,7 +62140,7 @@ function reorderArgs(argv) {
|
|
|
62017
62140
|
async function main() {
|
|
62018
62141
|
installPipeCloseHandler();
|
|
62019
62142
|
const program = new Command();
|
|
62020
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.252.
|
|
62143
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.252.1");
|
|
62021
62144
|
program.addCommand(createBootstrapCommand());
|
|
62022
62145
|
program.addCommand(createSynthCommand());
|
|
62023
62146
|
program.addCommand(createListCommand());
|