@go-to-k/cdkd 0.280.27 → 0.280.28
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-BFeeVgCN.js → asg-provider-C3rBE_Ni.js} +2 -2
- package/dist/{asg-provider-BFeeVgCN.js.map → asg-provider-C3rBE_Ni.js.map} +1 -1
- package/dist/cli.js +3 -3
- package/dist/{deploy-engine-Cz2xWrzZ.js → deploy-engine-Dkep5i7x.js} +139 -4
- package/dist/deploy-engine-Dkep5i7x.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-Cz2xWrzZ.js.map +0 -1
|
@@ -12870,7 +12870,7 @@ var CloudControlProvider = class {
|
|
|
12870
12870
|
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);
|
|
12871
12871
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
12872
12872
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
12873
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
12873
|
+
const { ASGProvider } = await import("./asg-provider-C3rBE_Ni.js").then((n) => n.n);
|
|
12874
12874
|
await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
12875
12875
|
return;
|
|
12876
12876
|
}
|
|
@@ -16474,6 +16474,111 @@ function findActionableSilentDrops(resourceType, templateProperties, allowedKeys
|
|
|
16474
16474
|
return drops.filter(({ property }) => !allowedKeys.has(`${resourceType}:${property}`));
|
|
16475
16475
|
}
|
|
16476
16476
|
|
|
16477
|
+
//#endregion
|
|
16478
|
+
//#region src/provisioning/mutually-exclusive-properties.ts
|
|
16479
|
+
/**
|
|
16480
|
+
* The rule table, keyed by CFn resource type.
|
|
16481
|
+
*
|
|
16482
|
+
* Deliberately seeded with the ONE combination this repo has verified end to
|
|
16483
|
+
* end (`AWS::EC2::Route`, refused by `EC2Provider.createRoute` since #1566 and
|
|
16484
|
+
* normalized on both diff sides since #1591). The mechanism is general; the
|
|
16485
|
+
* data is not speculative. See "Adding a rule" above.
|
|
16486
|
+
*/
|
|
16487
|
+
const MUTUALLY_EXCLUSIVE_PROPERTIES = /* @__PURE__ */ new Map([["AWS::EC2::Route", [{
|
|
16488
|
+
properties: [
|
|
16489
|
+
"DestinationCidrBlock",
|
|
16490
|
+
"DestinationIpv6CidrBlock",
|
|
16491
|
+
"DestinationPrefixListId"
|
|
16492
|
+
],
|
|
16493
|
+
rationale: "CloudFormation and the EC2 CreateRoute API accept exactly one destination per route.",
|
|
16494
|
+
firstDeclaredWins: true
|
|
16495
|
+
}]]]);
|
|
16496
|
+
/**
|
|
16497
|
+
* True for a single-key object whose key is `Ref` or `Fn::*` — the shape of an
|
|
16498
|
+
* unresolved CloudFormation intrinsic. Mirrors `isIntrinsicShaped` in
|
|
16499
|
+
* {@link ./create-only-properties}; kept local because the two modules answer
|
|
16500
|
+
* different questions about the shape and should not drift into one another's
|
|
16501
|
+
* behavior by accident.
|
|
16502
|
+
*/
|
|
16503
|
+
function isUnresolvedIntrinsic(value) {
|
|
16504
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
16505
|
+
const keys = Object.keys(value);
|
|
16506
|
+
return keys.length === 1 && (keys[0] === "Ref" || keys[0].startsWith("Fn::"));
|
|
16507
|
+
}
|
|
16508
|
+
/**
|
|
16509
|
+
* True when `value` is unconditionally present in the template.
|
|
16510
|
+
*
|
|
16511
|
+
* The predicate is `Boolean`, not a hand-listed `undefined | null | ''` set,
|
|
16512
|
+
* matching `narrowRouteDestinations`' truthiness narrowing in
|
|
16513
|
+
* `ec2-provider.ts`: the property bag is `unknown`-valued at runtime, so an
|
|
16514
|
+
* unquoted YAML `0` must be skipped here exactly as the provider's `||` chain
|
|
16515
|
+
* skips it — otherwise pre-flight refuses a template the provider would have
|
|
16516
|
+
* accepted. An unresolved intrinsic is truthy but its resolved presence is
|
|
16517
|
+
* NOT yet known, so it is excluded ahead of the truthiness test.
|
|
16518
|
+
*/
|
|
16519
|
+
function isDeclared(value) {
|
|
16520
|
+
if (isUnresolvedIntrinsic(value)) return false;
|
|
16521
|
+
return Boolean(value);
|
|
16522
|
+
}
|
|
16523
|
+
/**
|
|
16524
|
+
* Find every mutually-exclusive rule this resource violates.
|
|
16525
|
+
*
|
|
16526
|
+
* Returns `[]` for a type with no rules, an absent property bag, and any
|
|
16527
|
+
* combination that is only reached through an unresolved intrinsic.
|
|
16528
|
+
*/
|
|
16529
|
+
function findMutuallyExclusiveViolations(resourceType, templateProperties) {
|
|
16530
|
+
if (!templateProperties) return [];
|
|
16531
|
+
const rules = MUTUALLY_EXCLUSIVE_PROPERTIES.get(resourceType);
|
|
16532
|
+
if (!rules) return [];
|
|
16533
|
+
return findViolationsForRules(resourceType, rules, templateProperties);
|
|
16534
|
+
}
|
|
16535
|
+
/**
|
|
16536
|
+
* The table-free core of {@link findMutuallyExclusiveViolations}, taking the
|
|
16537
|
+
* rules explicitly.
|
|
16538
|
+
*
|
|
16539
|
+
* Exported so the multi-rule and multi-violation paths are reachable from
|
|
16540
|
+
* tests: the shipped table has a single type with a single rule, so those
|
|
16541
|
+
* branches would otherwise be dead code that no assertion can exercise.
|
|
16542
|
+
*/
|
|
16543
|
+
function findViolationsForRules(resourceType, rules, templateProperties) {
|
|
16544
|
+
const violations = [];
|
|
16545
|
+
for (const rule of rules) {
|
|
16546
|
+
const declared = rule.properties.filter((property) => isDeclared(templateProperties[property]));
|
|
16547
|
+
if (declared.length <= 1) continue;
|
|
16548
|
+
const winnerCertain = !rule.properties.slice(0, rule.properties.indexOf(declared[0])).some((property) => isUnresolvedIntrinsic(templateProperties[property]));
|
|
16549
|
+
violations.push({
|
|
16550
|
+
resourceType,
|
|
16551
|
+
rule,
|
|
16552
|
+
declared,
|
|
16553
|
+
winnerCertain
|
|
16554
|
+
});
|
|
16555
|
+
}
|
|
16556
|
+
return violations;
|
|
16557
|
+
}
|
|
16558
|
+
/**
|
|
16559
|
+
* Render one violation as a per-resource error line.
|
|
16560
|
+
*
|
|
16561
|
+
* For a `firstDeclaredWins` rule the message names the key that would actually
|
|
16562
|
+
* be SENT, which is what makes the remedy actionable.
|
|
16563
|
+
*
|
|
16564
|
+
* It deliberately stops short of promising the deployed resource is unaffected.
|
|
16565
|
+
* Pre-flight has no state, so it cannot know which destination the LIVE
|
|
16566
|
+
* resource was created from: for a route deployed with only
|
|
16567
|
+
* `DestinationIpv6CidrBlock` whose template later GAINS
|
|
16568
|
+
* `DestinationCidrBlock`, deleting the IPv6 key makes the CIDR key the sole
|
|
16569
|
+
* destination — a create-only change that REPLACES the route. Saying "removing
|
|
16570
|
+
* the others leaves the resource unchanged" would be false exactly there.
|
|
16571
|
+
*
|
|
16572
|
+
* The sentence is omitted entirely when
|
|
16573
|
+
* {@link MutuallyExclusiveViolation.winnerCertain} is false — naming a winner
|
|
16574
|
+
* the raw template does not determine would be a confident falsehood.
|
|
16575
|
+
*/
|
|
16576
|
+
function buildMutuallyExclusiveMessage(logicalId, violation) {
|
|
16577
|
+
const { resourceType, rule, declared, winnerCertain } = violation;
|
|
16578
|
+
const winnerNote = rule.firstDeclaredWins && winnerCertain ? ` cdkd would send only ${declared[0]}; ${declared.slice(1).join(" / ")} would be dropped. Deleting the dropped keys changes nothing cdkd sends — but if the LIVE resource was created from one of them, making ${declared[0]} the sole value is a create-only change that REPLACES it.` : "";
|
|
16579
|
+
return ` - ${logicalId} (${resourceType}) declares ${declared.join(" and ")}\n ${rule.rationale}${winnerNote}\n Declare at most one of: ${rule.properties.join(" / ")}`;
|
|
16580
|
+
}
|
|
16581
|
+
|
|
16477
16582
|
//#endregion
|
|
16478
16583
|
//#region src/provisioning/provider-registry.ts
|
|
16479
16584
|
/**
|
|
@@ -16772,11 +16877,41 @@ var ProviderRegistry = class {
|
|
|
16772
16877
|
* the property check is a no-op (`findSilentDropProperties` returns `[]`
|
|
16773
16878
|
* for non-Tier-1 / unknown types).
|
|
16774
16879
|
*
|
|
16880
|
+
* Since issue [#1634](https://github.com/go-to-k/cdkd/issues/1634) this
|
|
16881
|
+
* ALSO runs the mutually-exclusive-property check
|
|
16882
|
+
* ({@link validateMutuallyExclusiveProperties}), which throws BEFORE any
|
|
16883
|
+
* routing decision is logged — a template CloudFormation itself rejects
|
|
16884
|
+
* should not first produce a page of routing chatter.
|
|
16885
|
+
*
|
|
16775
16886
|
* @see findAutoRouteHits for the pure-functional pre-deploy plan-builder
|
|
16776
16887
|
* that returns the same information without logging.
|
|
16777
16888
|
*/
|
|
16778
16889
|
validateResourceProperties(resources) {
|
|
16779
|
-
|
|
16890
|
+
const materialized = [...resources];
|
|
16891
|
+
this.validateMutuallyExclusiveProperties(materialized);
|
|
16892
|
+
this.reportSilentDropDecisions(materialized);
|
|
16893
|
+
}
|
|
16894
|
+
/**
|
|
16895
|
+
* Reject a template that declares two or more MUTUALLY EXCLUSIVE top-level
|
|
16896
|
+
* properties on one resource (issue
|
|
16897
|
+
* [#1634](https://github.com/go-to-k/cdkd/issues/1634)).
|
|
16898
|
+
*
|
|
16899
|
+
* Aggregated into ONE error listing every offending resource, mirroring
|
|
16900
|
+
* {@link validateResourceTypes} — a template with three bad routes should
|
|
16901
|
+
* report three, not fail three deploys in a row. There is deliberately no
|
|
16902
|
+
* `--allow-*` escape hatch: the combination is invalid at CloudFormation and
|
|
16903
|
+
* at the service API, so the only correct outcome is a template edit (see
|
|
16904
|
+
* the rule module's header).
|
|
16905
|
+
*
|
|
16906
|
+
* Unlike the provider-side refusal this fires even when the resource already
|
|
16907
|
+
* exists and the deploy diff classifies NO_CHANGE, which is the gap the
|
|
16908
|
+
* issue was filed for.
|
|
16909
|
+
*/
|
|
16910
|
+
validateMutuallyExclusiveProperties(resources) {
|
|
16911
|
+
const lines = [];
|
|
16912
|
+
for (const { logicalId, resourceType, properties } of resources) for (const violation of findMutuallyExclusiveViolations(resourceType, properties)) lines.push(buildMutuallyExclusiveMessage(logicalId, violation));
|
|
16913
|
+
if (lines.length === 0) return;
|
|
16914
|
+
throw new Error(`The following resources declare mutually exclusive properties:\n` + lines.join("\n") + "\n\nCloudFormation rejects these combinations too — edit the template to declare only one of each set.");
|
|
16780
16915
|
}
|
|
16781
16916
|
/**
|
|
16782
16917
|
* Info-log every silent-drop routing decision (auto-route via CC API) and
|
|
@@ -19386,7 +19521,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
19386
19521
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
19387
19522
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
19388
19523
|
function getCdkdVersion() {
|
|
19389
|
-
return "0.280.
|
|
19524
|
+
return "0.280.28";
|
|
19390
19525
|
}
|
|
19391
19526
|
/**
|
|
19392
19527
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -21519,4 +21654,4 @@ var DeployEngine = class {
|
|
|
21519
21654
|
|
|
21520
21655
|
//#endregion
|
|
21521
21656
|
export { requireConfigObject as $, AssemblyReader as $t, green as A, __exportAll as An, runDockerForeground as At, disableInstanceApiTermination as B, resolveCaptureObservedState as Bt, MULTI_REGION_RECREATE_BLOCKED_TYPES as C, StackTerminationProtectionError as Cn, getBootstrapMarkerKey as Ct, bold as D, isCdkdError as Dn, buildDockerImage as Dt, formatResourceLine as E, formatError as En, validateContainerRepoName as Et, clearOnUpdateRemoval as F, synthesisStatusMessage as Ft, WAFv2WebACLProvider as G, stateBucketExistenceConfirmed as Gt, IntrinsicFunctionResolver as H, resolveStateBucketWithDefault as Ht, ProviderRegistry as I, getDefaultStateBucketName as It, assertRegionMatch as J, CFN_TEMPLATE_URL_LIMIT as Jt, normalizeAwsTagsToCfn as K, warnDeprecatedNoPrefixCliFlag as Kt, findActionableSilentDrops as L, getLegacyStateBucketName as Lt, yellow as M, AssetManifestLoader as Mt, IAMRoleProvider as N, getDockerImageBySourceHash as Nt, cyan as O, normalizeAwsError as On, formatDockerLoginError as Ot, collectInlinePolicyNamesManagedBySiblings as P, Synthesizer as Pt, requireConfigArray as Q, expectedOwnerParam as Qt, CloudControlProvider as R, resolveApp as Rt, extractDeploymentEventError as S, StackHasActiveImportsError as Sn, ensureAssetStorage as St, renderStatefulReason as T, SynthesisError as Tn, validateAssetBucketName as Tt, cfnRefValueFromPhysicalId as U, resolveStateBucketWithDefaultAndSource as Ut, isTerminationProtectionPropagationError as V, resolveSkipPrefix as Vt, refStateLookupFromResource as W, resolveUseCdkBootstrapAssets as Wt, readConfigString as X, findLargeInlineResources as Xt, configStringRefusal as Y, MIGRATE_TMP_PREFIX as Yt, replayWarn as Z, uploadCfnTemplate as Zt, createPreDeleteFinalSnapshot as _, NestedStackChildDirectDestroyError as _n, createAssetRedirectResolver as _t, DeploymentEventsStore as a, resetAwsClients as an, isRetryableTransientError as at, unsupportedFinalSnapshotError as b, ResourceTimeoutError as bn, AssetModeResolver as bt, replayFailedOperations as c, CdkdError as cn, TemplateParser as ct, IMPLICIT_DELETE_DEPENDENCIES as d, DeployCancelledError as dn, rebuildClientForBucketRegion as dt, processStackMessages as en, requireConfigString as et, computeImplicitDeleteEdges as f, LocalInvokeBuildError as fn, shouldRetainResource as ft, ccRoutedFinalSnapshotError as g, MissingCdkCliError as gn, buildAssetRedirectMap as gt, buildFinalSnapshotIdentifier as h, LockError as hn, WorkGraph as ht, DeploymentEventsReader as i, getAwsClients as in, withRetry as it, red as j, runDockerStreaming as jt, gray as k, withErrorHandling as kn, getDockerCmd as kt, replayRollback as l, ConfigError as ln, LockManager as lt, PRE_DELETE_SNAPSHOT_TYPES as m, LocalStartServiceError as mn, stringifyValue as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, resolveBucketRegion as nn, DiffCalculator as nt, planFailedOps as o, setAwsClients as on, isThrottlingError as ot, ATOMIC_FINAL_SNAPSHOT_TYPES as p, LocalMigrateError as pn, AssetPublisher as pt, resolveExplicitPhysicalId as q, CFN_TEMPLATE_BODY_LIMIT as qt, DeployEngine as r, AwsClients as rn, describeTypeWithThrottleRetry as rt, planRollback as s, AssetError as sn, DagBuilder as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, clearBucketRegionCache as tn, applyRoleArnIfSet as tt, withResourceDeadline as u, DependencyError as un, S3StateBackend as ut, isFinalSnapshotError as v, PartialFailureError as vn, loadPublishableAssetManifest as vt, isStatefulRecreateTargetSync as w, StateError as wn, parseBootstrapMarker as wt, makeCanonicalizePropertiesFn as x, ResourceUpdateNotSupportedError as xn, BOOTSTRAP_MARKER_PREFIX as xt, refusesFinalSnapshot as y, ProvisioningError as yn, rewriteTemplateAssetReferences as yt, slowCcOperationTimeoutMs as z, resolveAutoAssetStorage as zt };
|
|
21522
|
-
//# sourceMappingURL=deploy-engine-
|
|
21657
|
+
//# sourceMappingURL=deploy-engine-Dkep5i7x.js.map
|