@go-to-k/cdkd 0.297.0 → 0.298.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/{asg-provider-D9Po293s.js → asg-provider-semUK44T.js} +4 -4
- package/dist/{asg-provider-D9Po293s.js.map → asg-provider-semUK44T.js.map} +1 -1
- package/dist/{aws-failure-text-BaWeCWRz.js → aws-failure-text-DtvlUugx.js} +2 -2
- package/dist/{aws-failure-text-BaWeCWRz.js.map → aws-failure-text-DtvlUugx.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-dvf1UDuo.js → deploy-engine-A-Ys_mhE.js} +2781 -716
- package/dist/deploy-engine-A-Ys_mhE.js.map +1 -0
- package/dist/{iam-policy-targets-Cz2tPxXk.js → iam-policy-targets-CwKiK9nS.js} +2 -2
- package/dist/{iam-policy-targets-Cz2tPxXk.js.map → iam-policy-targets-CwKiK9nS.js.map} +1 -1
- package/dist/{iam-role-provider--5HuX51Z.js → iam-role-provider-CpqTal4K.js} +24 -4
- package/dist/{iam-role-provider--5HuX51Z.js.map → iam-role-provider-CpqTal4K.js.map} +1 -1
- package/dist/index.d.ts +22 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{neptune-provider-xROL9y31.js → neptune-provider-C4A86Y7P.js} +4 -4
- package/dist/{neptune-provider-xROL9y31.js.map → neptune-provider-C4A86Y7P.js.map} +1 -1
- package/dist/{program-NRnM6vPK.js → program-D5gcmWad.js} +247 -46
- package/dist/program-D5gcmWad.js.map +1 -0
- package/dist/{provider-classes-uUFRfL9s.js → provider-classes-CuZ-P4gB.js} +78 -11
- package/dist/provider-classes-CuZ-P4gB.js.map +1 -0
- package/dist/{rds-provider-CU0LZr05.js → rds-provider-X4mc-nGw.js} +4 -4
- package/dist/{rds-provider-CU0LZr05.js.map → rds-provider-X4mc-nGw.js.map} +1 -1
- package/dist/{version-DE-djeB0.js → version-CItAaDXu.js} +2 -2
- package/dist/{version-DE-djeB0.js.map → version-CItAaDXu.js.map} +1 -1
- package/package.json +8 -7
- package/dist/deploy-engine-dvf1UDuo.js.map +0 -1
- package/dist/program-NRnM6vPK.js.map +0 -1
- package/dist/provider-classes-uUFRfL9s.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { r as getAwsClients, s as __exportAll } from "./aws-clients-CnmtbrxD.js";
|
|
2
|
-
import { A as UNRENDERABLE, C as looksLikeCdkdGeneratedName, E as withoutGeneratedFallbackName, F as displayStackName, I as isPasteableIdent, M as displayAwsMessage, N as displayIdent, O as SECRET_REF_MAX_CODE_POINTS, P as displaySafe, R as plainIdentOr, S as getCurrentStackName, T as withStackName, V as
|
|
3
|
-
import { $ as protectedReplacementAdvice, $n as isAmbiguousOutcomeError, $t as credentialFingerprint, A as isQuotableImportValue, An as UNSHOWABLE_VALUE, At as isAuxiliaryMarkOf, B as isTerminalDeleteFailure, Bn as withheldTargetClause, Bt as recoveryCommandFlags, Ct as RETRY_AUXILIARY_OWNER, Dt as createdResourceIdentityBeforeFailure, E as assertRegionMatch, Et as createdBeforeFailure, F as resolveExplicitPhysicalId, Fn as physicalIdShownBesideCommand, G as runDeleteAttempt, Gn as isNameCollisionErrorFrom, H as observeThenDisableProtection, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, J as DELETION_PROTECTION_DOC_POINTER, Jn as isReplayedNameCollisionFrom, Kn as isNameCooldownError, L as ProtectionFlipRegistry, Ln as quotedOrDescribed, Lt as formatLockExpiry, M as quotedRemedyLogicalId, Mt as markCreatedBeforeFailure, N as refusalTypeShown, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, On as SHELL_ACTIVE, Ot as hasCreatedBeforeFailure, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Q as pasteableAwsCommand, Qn as isAmbiguousCcHandlerErrorCode, Qt as clientDefaultsFor, R as compensateProtectionFlip, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, St as withDerivedNameMasks, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, U as protectionFlipKey, Un as isUpdateUnsupportedError, Ut as DEFAULT_STATE_PREFIX, Vt as sanitizeRecoveryValue, Wn as hasReplayMayCollide, Wt as injectiveKey, Xn as markReplayMayCollide, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Zn as formatRetryClassificationSignals, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, _t as createMaskedLogSinks, an as DependencyError, ar as isMarkedNonRetryable, at as startInterruptWatch, bt as maskDeep, cn as IntrinsicResolutionRefusalError, cr as markRedactedCause, ct as canonicalizeRoute53QueryName, d as prepareRemovalForUpdate, dn as LockError, en as AccountIdUnavailableError, er as isIamPropagationError, f as removalWarning, fn as MacroExpansionError, ft as logicalIdShown, gn as ProvisioningError, gt as stateOrphanRecordRemedy, ht as segmentAfterAnchor, i as holdsSecretDerivedEntry, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, j as normalizeAwsTagsToCfn, jn as commandHole, jt as markAuxiliaryFailure, kn as SHELL_ACTIVE_WHY, kt as isAuxiliaryFailure, l as withUnchangedSecretPrincipalLists, lr as wrapMaskedAwsError, m as withoutInjectedRemovals, mt as resourceTypeShown, nn as CdkdError, nr as isTransientServerError, or as isThrottlingError, ot as ElapsedBudgetRegistry, pn as MalformedProducerRecordRefusalError, qn as isRecreateRetryableError, qt as producerRecordKey, rr as retryClassificationText, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, st as monotonicNowMs, tn as AssetError, tr as isRetryableTransientError, ut as compositeIdSeparatorRefusal, vn as ResourceUpdateNotSupportedError, vt as createMaskedRetryLogger, w as withoutServerErrorRetries, wt as carryCreatedBeforeFailure, xn as StateError, xt as maskerOrIdentity, yt as isSecretDerivedValue, z as deleteWithProtectionCompensation, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-
|
|
2
|
+
import { A as UNRENDERABLE, C as looksLikeCdkdGeneratedName, E as withoutGeneratedFallbackName, F as displayStackName, H as truncateCodePoints, I as isPasteableIdent, M as displayAwsMessage, N as displayIdent, O as SECRET_REF_MAX_CODE_POINTS, P as displaySafe, R as plainIdentOr, S as getCurrentStackName, T as withStackName, V as terminalSafe, a as getLogger, b as generateResourceNameWithFallback, d as installLogLineMaskerSource, f as getLiveRenderer, g as applyDefaultNameForFallback, k as STACK_REF_MAX_CODE_POINTS, o as isStdoutReservedForPayload, r as safeStringify$1, t as describeAwsFailure, u as currentLogLineMasker, v as explicitNamePropertyFor, w as withSkipPrefix, x as getCurrentSkipPrefix, y as generateResourceName, z as safeMsg } from "./aws-failure-text-DtvlUugx.js";
|
|
3
|
+
import { $ as protectedReplacementAdvice, $n as isAmbiguousOutcomeError, $t as credentialFingerprint, A as isQuotableImportValue, An as UNSHOWABLE_VALUE, At as isAuxiliaryMarkOf, B as isTerminalDeleteFailure, Bn as withheldTargetClause, Bt as recoveryCommandFlags, Ct as RETRY_AUXILIARY_OWNER, Dt as createdResourceIdentityBeforeFailure, E as assertRegionMatch, Et as createdBeforeFailure, F as resolveExplicitPhysicalId, Fn as physicalIdShownBesideCommand, G as runDeleteAttempt, Gn as isNameCollisionErrorFrom, H as observeThenDisableProtection, Ht as CUSTOM_RESOURCE_RESPONSE_PREFIX, In as plainOrDescribed, J as DELETION_PROTECTION_DOC_POINTER, Jn as isReplayedNameCollisionFrom, Kn as isNameCooldownError, L as ProtectionFlipRegistry, Ln as quotedOrDescribed, Lt as formatLockExpiry, M as quotedRemedyLogicalId, Mt as markCreatedBeforeFailure, N as refusalTypeShown, Nn as isInertUnquoted, Nt as UNREPRODUCIBLE_LOCK_CLAUSE, On as SHELL_ACTIVE, Ot as hasCreatedBeforeFailure, Pn as pasteableCommand, Pt as buildForceUnlockCommand, Q as pasteableAwsCommand, Qn as isAmbiguousCcHandlerErrorCode, Qt as clientDefaultsFor, R as compensateProtectionFlip, Rn as shellBoundedDisplay, Rt as formatLockOperation, Sn as SynthesisError, St as withDerivedNameMasks, T as RESOURCE_NOT_FOUND, Tn as normalizeAwsError, U as protectionFlipKey, Un as isUpdateUnsupportedError, Ut as DEFAULT_STATE_PREFIX, Vt as sanitizeRecoveryValue, Wn as hasReplayMayCollide, Wt as injectiveKey, Xn as markReplayMayCollide, Xt as ambientClientDefaults, Yt as withPasteableAwsProfile, Zn as formatRetryClassificationSignals, Zt as ambientCredentialConfig, _n as ResourceTimeoutError, _t as createMaskedLogSinks, an as DependencyError, ar as isMarkedNonRetryable, at as startInterruptWatch, bt as maskDeep, cn as IntrinsicResolutionRefusalError, cr as markRedactedCause, ct as canonicalizeRoute53QueryName, d as prepareRemovalForUpdate, dn as LockError, en as AccountIdUnavailableError, er as isIamPropagationError, f as removalWarning, fn as MacroExpansionError, ft as logicalIdShown, gn as ProvisioningError, gt as stateOrphanRecordRemedy, ht as segmentAfterAnchor, i as holdsSecretDerivedEntry, in as CrossAccountSecretRefusalError, it as isInterruptedWaitError, j as normalizeAwsTagsToCfn, jn as commandHole, jt as markAuxiliaryFailure, kn as SHELL_ACTIVE_WHY, kt as isAuxiliaryFailure, l as withUnchangedSecretPrincipalLists, lr as wrapMaskedAwsError, m as withoutInjectedRemovals, mt as resourceTypeShown, nn as CdkdError, nr as isTransientServerError, or as isThrottlingError, ot as ElapsedBudgetRegistry, pn as MalformedProducerRecordRefusalError, qn as isRecreateRetryableError, qt as producerRecordKey, rr as retryClassificationText, sn as DynamicReferenceRegionAmbiguousError, sr as markNonRetryable, st as monotonicNowMs, tn as AssetError, tr as isRetryableTransientError, ut as compositeIdSeparatorRefusal, vn as ResourceUpdateNotSupportedError, vt as createMaskedRetryLogger, w as withoutServerErrorRetries, wt as carryCreatedBeforeFailure, xn as StateError, xt as maskerOrIdentity, yt as isSecretDerivedValue, z as deleteWithProtectionCompensation, zn as shellQuote, zt as formatLockOwner } from "./iam-policy-targets-CwKiK9nS.js";
|
|
4
4
|
import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, s as ambientRegion, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-D0q0z4dG.js";
|
|
5
|
-
import { t as getCdkdVersion } from "./version-
|
|
5
|
+
import { t as getCdkdVersion } from "./version-CItAaDXu.js";
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
7
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
8
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketLifecycleConfigurationCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -637,6 +637,7 @@ var AssemblyReader = class {
|
|
|
637
637
|
if (!resolvedNested.contained) throw new SynthesisError(`Stack ${displayStackName(stackName)} nested-stack ${displayIdent(logicalId)} has Metadata['aws:asset:path']=${displayAssemblyPath(assetPath)} which ${renderAssemblyPathEscape(resolvedNested, assemblyDir)}`);
|
|
638
638
|
nestedTemplates[logicalId] = resolvedNested.path;
|
|
639
639
|
}
|
|
640
|
+
const lookupRoleArn = props?.lookupRole?.arn;
|
|
640
641
|
return {
|
|
641
642
|
stackName,
|
|
642
643
|
displayName: artifact.displayName ?? stackName,
|
|
@@ -649,6 +650,7 @@ var AssemblyReader = class {
|
|
|
649
650
|
account: env?.account !== "unknown-account" ? env?.account : void 0,
|
|
650
651
|
...props?.terminationProtection !== void 0 && { terminationProtection: props.terminationProtection },
|
|
651
652
|
...Object.keys(nestedTemplates).length > 0 && { nestedTemplates },
|
|
653
|
+
...typeof lookupRoleArn === "string" && { lookupRoleArn },
|
|
652
654
|
messages: collectStackMessages(assemblyDir, artifact)
|
|
653
655
|
};
|
|
654
656
|
}
|
|
@@ -7437,6 +7439,23 @@ function positionByCrossStackSource(bag, source, secrets) {
|
|
|
7437
7439
|
return certifiedExpressionForLeaf(secrets, association, bag);
|
|
7438
7440
|
}
|
|
7439
7441
|
|
|
7442
|
+
//#endregion
|
|
7443
|
+
//#region src/deployment/secret-redaction/physical-name-copies.ts
|
|
7444
|
+
const physicalNameCopiesOf = /* @__PURE__ */ new WeakMap();
|
|
7445
|
+
function recordPhysicalNameCopy(secrets, physicalId) {
|
|
7446
|
+
if (physicalId === "") return;
|
|
7447
|
+
sideSetOf(physicalNameCopiesOf, secrets).add(physicalId);
|
|
7448
|
+
}
|
|
7449
|
+
function physicalNameSpans(names, value) {
|
|
7450
|
+
const spans = [];
|
|
7451
|
+
if (names === void 0) return spans;
|
|
7452
|
+
for (const name of names) for (let at = value.indexOf(name); at !== -1; at = value.indexOf(name, at + 1)) spans.push({
|
|
7453
|
+
start: at,
|
|
7454
|
+
end: at + name.length
|
|
7455
|
+
});
|
|
7456
|
+
return spans;
|
|
7457
|
+
}
|
|
7458
|
+
|
|
7440
7459
|
//#endregion
|
|
7441
7460
|
//#region src/deployment/secret-redaction/fresh-noecho.ts
|
|
7442
7461
|
function embedsFreshNoEchoValue(text, secrets, freshClass) {
|
|
@@ -7505,9 +7524,14 @@ function isStrictlyInsideASpan(spans, start, end) {
|
|
|
7505
7524
|
}
|
|
7506
7525
|
function embedsNeedleOutsideReferences(leaf, needles, secrets) {
|
|
7507
7526
|
let spans;
|
|
7527
|
+
let names;
|
|
7508
7528
|
for (const needle of needles) for (let at = leaf.indexOf(needle); at >= 0; at = leaf.indexOf(needle, at + 1)) {
|
|
7509
7529
|
spans ??= isDynamicReferenceString(leaf) ? resolvableReferenceSpans(leaf, new Set(secrets.values())) : [];
|
|
7510
|
-
if (
|
|
7530
|
+
if (isStrictlyInsideASpan(spans, at, at + needle.length)) continue;
|
|
7531
|
+
names ??= physicalNameSpans(physicalNameCopiesOf.get(secrets), leaf);
|
|
7532
|
+
const end = at + needle.length;
|
|
7533
|
+
if (names.some((n) => n.start <= at && end <= n.end)) continue;
|
|
7534
|
+
return true;
|
|
7511
7535
|
}
|
|
7512
7536
|
return false;
|
|
7513
7537
|
}
|
|
@@ -8424,17 +8448,22 @@ function redactSecretsForStatePasses(bag, secrets, source, rules) {
|
|
|
8424
8448
|
}
|
|
8425
8449
|
const regex = buildNeedleRegex(substringNeedlesOf(secrets));
|
|
8426
8450
|
const wholeValueExpr = (s) => s === "" ? void 0 : secrets.get(s);
|
|
8451
|
+
const physicalNames = physicalNameCopiesOf.get(secrets);
|
|
8427
8452
|
let vouched;
|
|
8428
8453
|
const vouchedExpressions = () => vouched ??= new Set(secrets.values());
|
|
8429
8454
|
const scanLeaf = (value, needles) => {
|
|
8430
8455
|
const spans = isDynamicReferenceString(value) ? resolvableReferenceSpans(value, vouchedExpressions()) : [];
|
|
8456
|
+
const names = physicalNameSpans(physicalNames, value);
|
|
8431
8457
|
return value.replace(needles, (match, offset) => {
|
|
8432
8458
|
if (isStrictlyInsideASpan(spans, offset, offset + match.length)) return match;
|
|
8459
|
+
const end = offset + match.length;
|
|
8460
|
+
if (names.some((n) => n.start <= offset && end <= n.end)) return match;
|
|
8433
8461
|
return secrets.get(match) ?? "***";
|
|
8434
8462
|
});
|
|
8435
8463
|
};
|
|
8436
8464
|
const walk = (value) => {
|
|
8437
8465
|
if (typeof value === "string") {
|
|
8466
|
+
if (physicalNames?.has(value) === true) return value;
|
|
8438
8467
|
const whole = wholeValueExpr(value);
|
|
8439
8468
|
if (whole !== void 0) return whole;
|
|
8440
8469
|
if (isSingleDynamicReferenceToken(value) && spanNamesResolvableService(value)) return value;
|
|
@@ -8467,6 +8496,133 @@ function scrubResourceRecord(record, secrets, sourceProperties, observedRules) {
|
|
|
8467
8496
|
if (record.observedProperties) next.observedProperties = redactSecretsForState(record.observedProperties, secrets, sourceProperties ?? next.properties, observedRules ?? (sourceProperties !== void 0 ? TEMPLATE_SOURCED_RULES : secrets.size === 0 && isSameGenerationBag(record.observedProperties) ? STATE_SOURCED_BASELINE_RULES : STATE_SOURCED_READBACK_RULES));
|
|
8468
8497
|
return next;
|
|
8469
8498
|
}
|
|
8499
|
+
function withoutPhysicalNameCopies(secrets, run) {
|
|
8500
|
+
const names = physicalNameCopiesOf.get(secrets);
|
|
8501
|
+
if (names === void 0) return run();
|
|
8502
|
+
physicalNameCopiesOf.delete(secrets);
|
|
8503
|
+
try {
|
|
8504
|
+
return run();
|
|
8505
|
+
} finally {
|
|
8506
|
+
physicalNameCopiesOf.set(secrets, names);
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
function withPhysicalNameCopies(secrets, ids, run) {
|
|
8510
|
+
const previous = physicalNameCopiesOf.get(secrets);
|
|
8511
|
+
const names = new Set(previous);
|
|
8512
|
+
for (const id of ids) if (id !== "") names.add(id);
|
|
8513
|
+
physicalNameCopiesOf.set(secrets, names);
|
|
8514
|
+
try {
|
|
8515
|
+
return run();
|
|
8516
|
+
} finally {
|
|
8517
|
+
if (previous === void 0) physicalNameCopiesOf.delete(secrets);
|
|
8518
|
+
else physicalNameCopiesOf.set(secrets, previous);
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
function repairPhysicalNameCopyLeaves(stored, legacy, current) {
|
|
8522
|
+
if (typeof stored === "string") return typeof legacy === "string" && typeof current === "string" && stored === legacy && current !== legacy ? current : stored;
|
|
8523
|
+
if (Array.isArray(stored)) {
|
|
8524
|
+
if (!Array.isArray(legacy) || !Array.isArray(current)) return stored;
|
|
8525
|
+
if (legacy.length !== stored.length || current.length !== stored.length) return stored;
|
|
8526
|
+
let changed = false;
|
|
8527
|
+
const out = stored.map((item, i) => {
|
|
8528
|
+
const next = repairPhysicalNameCopyLeaves(item, legacy[i], current[i]);
|
|
8529
|
+
if (next !== item) changed = true;
|
|
8530
|
+
return next;
|
|
8531
|
+
});
|
|
8532
|
+
return changed ? out : stored;
|
|
8533
|
+
}
|
|
8534
|
+
if (stored !== null && typeof stored === "object") {
|
|
8535
|
+
if (legacy === null || typeof legacy !== "object" || Array.isArray(legacy)) return stored;
|
|
8536
|
+
if (current === null || typeof current !== "object" || Array.isArray(current)) return stored;
|
|
8537
|
+
const l = legacy;
|
|
8538
|
+
const c = current;
|
|
8539
|
+
let out;
|
|
8540
|
+
for (const [key, value] of Object.entries(stored)) {
|
|
8541
|
+
if (!Object.hasOwn(l, key) || !Object.hasOwn(c, key)) continue;
|
|
8542
|
+
const next = repairPhysicalNameCopyLeaves(value, l[key], c[key]);
|
|
8543
|
+
if (next !== value) {
|
|
8544
|
+
out ??= { ...stored };
|
|
8545
|
+
out[key] = next;
|
|
8546
|
+
}
|
|
8547
|
+
}
|
|
8548
|
+
return out ?? stored;
|
|
8549
|
+
}
|
|
8550
|
+
return stored;
|
|
8551
|
+
}
|
|
8552
|
+
function embeddedPhysicalNameRewrites(secrets, legacySecrets = secrets) {
|
|
8553
|
+
const names = physicalNameCopiesOf.get(secrets);
|
|
8554
|
+
if (names === void 0) return [];
|
|
8555
|
+
const pairs = [];
|
|
8556
|
+
withoutPhysicalNameCopies(legacySecrets, () => {
|
|
8557
|
+
for (const name of names) {
|
|
8558
|
+
const legacy = redactSecretsForState(name, legacySecrets);
|
|
8559
|
+
if (typeof legacy === "string" && legacy !== name && legacy.includes("{{resolve:") && !isSingleDynamicReferenceToken(legacy) && !legacy.includes("***")) pairs.push([legacy, name]);
|
|
8560
|
+
}
|
|
8561
|
+
});
|
|
8562
|
+
return pairs;
|
|
8563
|
+
}
|
|
8564
|
+
function replaceEmbeddedPhysicalNameRewrites(value, pairs) {
|
|
8565
|
+
if (pairs.length === 0) return value;
|
|
8566
|
+
if (typeof value === "string") {
|
|
8567
|
+
let next = value;
|
|
8568
|
+
for (const [legacy, name] of pairs) next = next.split(legacy).join(name);
|
|
8569
|
+
return next;
|
|
8570
|
+
}
|
|
8571
|
+
if (Array.isArray(value)) {
|
|
8572
|
+
let changed = false;
|
|
8573
|
+
const out = value.map((item) => {
|
|
8574
|
+
const next = replaceEmbeddedPhysicalNameRewrites(item, pairs);
|
|
8575
|
+
if (next !== item) changed = true;
|
|
8576
|
+
return next;
|
|
8577
|
+
});
|
|
8578
|
+
return changed ? out : value;
|
|
8579
|
+
}
|
|
8580
|
+
if (value !== null && typeof value === "object") {
|
|
8581
|
+
let out;
|
|
8582
|
+
for (const [key, item] of Object.entries(value)) {
|
|
8583
|
+
const next = replaceEmbeddedPhysicalNameRewrites(item, pairs);
|
|
8584
|
+
if (next !== item) {
|
|
8585
|
+
out ??= { ...value };
|
|
8586
|
+
out[key] = next;
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
return out ?? value;
|
|
8590
|
+
}
|
|
8591
|
+
return value;
|
|
8592
|
+
}
|
|
8593
|
+
function repairEmbeddedPhysicalNamesTowards(stored, target, pairs) {
|
|
8594
|
+
if (pairs.length === 0) return stored;
|
|
8595
|
+
if (typeof stored === "string") {
|
|
8596
|
+
if (typeof target !== "string" || stored === target) return stored;
|
|
8597
|
+
const repaired = replaceEmbeddedPhysicalNameRewrites(stored, pairs);
|
|
8598
|
+
return repaired === target ? repaired : stored;
|
|
8599
|
+
}
|
|
8600
|
+
if (Array.isArray(stored)) {
|
|
8601
|
+
if (!Array.isArray(target) || target.length !== stored.length) return stored;
|
|
8602
|
+
let changed = false;
|
|
8603
|
+
const out = stored.map((item, i) => {
|
|
8604
|
+
const next = repairEmbeddedPhysicalNamesTowards(item, target[i], pairs);
|
|
8605
|
+
if (next !== item) changed = true;
|
|
8606
|
+
return next;
|
|
8607
|
+
});
|
|
8608
|
+
return changed ? out : stored;
|
|
8609
|
+
}
|
|
8610
|
+
if (stored !== null && typeof stored === "object") {
|
|
8611
|
+
if (target === null || typeof target !== "object" || Array.isArray(target)) return stored;
|
|
8612
|
+
const t = target;
|
|
8613
|
+
let out;
|
|
8614
|
+
for (const [key, value] of Object.entries(stored)) {
|
|
8615
|
+
if (!Object.hasOwn(t, key)) continue;
|
|
8616
|
+
const next = repairEmbeddedPhysicalNamesTowards(value, t[key], pairs);
|
|
8617
|
+
if (next !== value) {
|
|
8618
|
+
out ??= { ...stored };
|
|
8619
|
+
out[key] = next;
|
|
8620
|
+
}
|
|
8621
|
+
}
|
|
8622
|
+
return out ?? stored;
|
|
8623
|
+
}
|
|
8624
|
+
return stored;
|
|
8625
|
+
}
|
|
8470
8626
|
|
|
8471
8627
|
//#endregion
|
|
8472
8628
|
//#region src/deployment/secret-redaction/positions.ts
|
|
@@ -9587,7 +9743,7 @@ function noEchoParametersReadBy(node, sources) {
|
|
|
9587
9743
|
}
|
|
9588
9744
|
function noEchoComparison(options) {
|
|
9589
9745
|
const { sources, values, minNeedleLength, publicTokens } = options;
|
|
9590
|
-
return ({ templateProperties, desired, current
|
|
9746
|
+
return ({ templateProperties, desired, current }) => {
|
|
9591
9747
|
const coordinates = noEchoCoordinatesOf(templateProperties, desired, sources);
|
|
9592
9748
|
const needles = [];
|
|
9593
9749
|
for (const name of noEchoParametersReadBy(templateProperties, sources)) {
|
|
@@ -9623,10 +9779,6 @@ function noEchoComparison(options) {
|
|
|
9623
9779
|
};
|
|
9624
9780
|
masked = walk(masked);
|
|
9625
9781
|
}
|
|
9626
|
-
if (noEchoLeavesOf(record) !== void 0) return {
|
|
9627
|
-
desired: masked,
|
|
9628
|
-
current
|
|
9629
|
-
};
|
|
9630
9782
|
const witnessed = witnessNormalize(current, desired, masked);
|
|
9631
9783
|
const shown = maskAtCoordinatesWith(witnessed.current, witnessed.differing, PREVIOUS_NOECHO_VALUE);
|
|
9632
9784
|
return {
|
|
@@ -17450,6 +17602,15 @@ function conditionsAssumedFalse(conditions) {
|
|
|
17450
17602
|
return assumedConditionNames.get(conditions) ?? /* @__PURE__ */ new Set();
|
|
17451
17603
|
}
|
|
17452
17604
|
|
|
17605
|
+
//#endregion
|
|
17606
|
+
//#region src/deployment/noecho-declared.ts
|
|
17607
|
+
function isNoEchoDeclared(noEcho) {
|
|
17608
|
+
return noEcho === true || noEcho === "true";
|
|
17609
|
+
}
|
|
17610
|
+
function declaresNoEcho(definition) {
|
|
17611
|
+
return definition !== null && typeof definition === "object" && isNoEchoDeclared(definition.NoEcho);
|
|
17612
|
+
}
|
|
17613
|
+
|
|
17453
17614
|
//#endregion
|
|
17454
17615
|
//#region src/deployment/masked-property-fingerprints.ts
|
|
17455
17616
|
const FINGERPRINT_LAYOUT$1 = 1;
|
|
@@ -17526,7 +17687,7 @@ function parameterInputsFor(args) {
|
|
|
17526
17687
|
continue;
|
|
17527
17688
|
}
|
|
17528
17689
|
const value = values[name];
|
|
17529
|
-
let secret = isPlainObject$2(definition) && (definition
|
|
17690
|
+
let secret = isPlainObject$2(definition) && declaresNoEcho(definition) || carriesSecretValue(value, []);
|
|
17530
17691
|
if (!secret && args.nestedChild === true && args.supplied !== void 0) {
|
|
17531
17692
|
if (Object.hasOwn(args.supplied, name)) {
|
|
17532
17693
|
const passed = args.passedClasses?.get(name);
|
|
@@ -17951,7 +18112,7 @@ function childParameterInputs(template, passed) {
|
|
|
17951
18112
|
const inputs = /* @__PURE__ */ new Map();
|
|
17952
18113
|
for (const name of Object.keys(declared)) {
|
|
17953
18114
|
const definition = declared[name];
|
|
17954
|
-
if (isPlainObject$2(definition) && (definition
|
|
18115
|
+
if (isPlainObject$2(definition) && declaresNoEcho(definition)) inputs.set(name, { kind: "secret" });
|
|
17955
18116
|
else if (passed.has(name)) {
|
|
17956
18117
|
const passedClass = passed.get(name);
|
|
17957
18118
|
inputs.set(name, passedClass === "clean" ? {
|
|
@@ -18960,7 +19121,7 @@ function inheritedSecretsCarriedBy(value, inherited) {
|
|
|
18960
19121
|
return carried;
|
|
18961
19122
|
}
|
|
18962
19123
|
function stringifyParameterForLog(paramDef, value) {
|
|
18963
|
-
if (paramDef
|
|
19124
|
+
if (declaresNoEcho(paramDef)) return "<redacted>";
|
|
18964
19125
|
return stringifyValue(value);
|
|
18965
19126
|
}
|
|
18966
19127
|
function boundAltered(original, shown, maxCodePoints) {
|
|
@@ -18994,6 +19155,80 @@ function quotedRender(rendered, quote, described = "(not shown: it is not a plai
|
|
|
18994
19155
|
return QUOTABLE_RENDER.test(rendered) ? `${quote}${rendered}${quote}` : described;
|
|
18995
19156
|
}
|
|
18996
19157
|
|
|
19158
|
+
//#endregion
|
|
19159
|
+
//#region src/deployment/secret-region-classification.ts
|
|
19160
|
+
const REPLAY_SECRET_SERVICES = /* @__PURE__ */ new Set([
|
|
19161
|
+
"secretsmanager",
|
|
19162
|
+
"ssm",
|
|
19163
|
+
"ssm-secure"
|
|
19164
|
+
]);
|
|
19165
|
+
function secretsManagerSecretId(inner) {
|
|
19166
|
+
const afterService = inner.substring(15);
|
|
19167
|
+
let stringIdx = afterService.indexOf(":SecretString:");
|
|
19168
|
+
let binaryIdx = afterService.indexOf(":SecretBinary:");
|
|
19169
|
+
if (stringIdx < 0 && afterService.endsWith(":SecretString")) stringIdx = afterService.length - 13;
|
|
19170
|
+
if (binaryIdx < 0 && afterService.endsWith(":SecretBinary")) binaryIdx = afterService.length - 13;
|
|
19171
|
+
const delimiterIdx = stringIdx >= 0 && binaryIdx >= 0 ? Math.min(stringIdx, binaryIdx) : stringIdx >= 0 ? stringIdx : binaryIdx;
|
|
19172
|
+
return delimiterIdx >= 0 ? afterService.substring(0, delimiterIdx) : afterService;
|
|
19173
|
+
}
|
|
19174
|
+
function ssmParameterName(inner) {
|
|
19175
|
+
const serviceEnd = inner.indexOf(":");
|
|
19176
|
+
return serviceEnd < 0 ? "" : inner.substring(serviceEnd + 1);
|
|
19177
|
+
}
|
|
19178
|
+
function arnRegion(secretId) {
|
|
19179
|
+
if (!secretId.startsWith("arn:")) return void 0;
|
|
19180
|
+
const region = secretId.split(":")[3];
|
|
19181
|
+
return region ? region : void 0;
|
|
19182
|
+
}
|
|
19183
|
+
function producerRegionsFromState(state) {
|
|
19184
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19185
|
+
const regions = [];
|
|
19186
|
+
for (const entry of [...state.imports ?? [], ...state.outputReads ?? []]) {
|
|
19187
|
+
const canonical = canonicalizeRegion(entry.sourceRegion);
|
|
19188
|
+
if (!canonical || seen.has(canonical)) continue;
|
|
19189
|
+
seen.add(canonical);
|
|
19190
|
+
regions.push(entry.sourceRegion);
|
|
19191
|
+
}
|
|
19192
|
+
return regions;
|
|
19193
|
+
}
|
|
19194
|
+
function secretReferenceName(expression) {
|
|
19195
|
+
const inner = expression.startsWith("{{resolve:") ? expression.slice(10, -2) : void 0;
|
|
19196
|
+
if (inner === void 0) return void 0;
|
|
19197
|
+
const service = inner.split(":")[0];
|
|
19198
|
+
if (service === void 0 || !REPLAY_SECRET_SERVICES.has(service)) return void 0;
|
|
19199
|
+
const secretName = service === "secretsmanager" ? secretsManagerSecretId(inner) : ssmParameterName(inner);
|
|
19200
|
+
return secretName ? secretName : void 0;
|
|
19201
|
+
}
|
|
19202
|
+
function regionLessSecretName(expression) {
|
|
19203
|
+
const secretName = secretReferenceName(expression);
|
|
19204
|
+
return secretName !== void 0 && arnRegion(secretName) === void 0 ? secretName : void 0;
|
|
19205
|
+
}
|
|
19206
|
+
function classifyReplaySecretRegion(expression, consumerRegion, importedProducerRegions) {
|
|
19207
|
+
const secretName = secretReferenceName(expression);
|
|
19208
|
+
if (!secretName) return { kind: "local" };
|
|
19209
|
+
const named = arnRegion(secretName);
|
|
19210
|
+
if (named !== void 0) return canonicalizeRegion(named) === canonicalizeRegion(consumerRegion) ? { kind: "local" } : {
|
|
19211
|
+
kind: "named-region",
|
|
19212
|
+
secretName,
|
|
19213
|
+
region: named
|
|
19214
|
+
};
|
|
19215
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19216
|
+
const foreignProducerRegions = [];
|
|
19217
|
+
for (const candidate of importedProducerRegions ?? []) {
|
|
19218
|
+
const canonical = canonicalizeRegion(candidate);
|
|
19219
|
+
if (!canonical || canonical === canonicalizeRegion(consumerRegion)) continue;
|
|
19220
|
+
if (seen.has(canonical)) continue;
|
|
19221
|
+
seen.add(canonical);
|
|
19222
|
+
foreignProducerRegions.push(candidate);
|
|
19223
|
+
}
|
|
19224
|
+
if (foreignProducerRegions.length === 0) return { kind: "local" };
|
|
19225
|
+
return {
|
|
19226
|
+
kind: "ambiguous",
|
|
19227
|
+
secretName,
|
|
19228
|
+
foreignProducerRegions
|
|
19229
|
+
};
|
|
19230
|
+
}
|
|
19231
|
+
|
|
18997
19232
|
//#endregion
|
|
18998
19233
|
//#region src/utils/s3-endpoints.ts
|
|
18999
19234
|
const S3_WEBSITE_ENDPOINT_LEGACY_DASH_REGIONS = /* @__PURE__ */ new Set([
|
|
@@ -19581,7 +19816,7 @@ async function resolveGetAtt(getAtt, context) {
|
|
|
19581
19816
|
redacted: isSensitiveAttributeName(attributeName)
|
|
19582
19817
|
})}`);
|
|
19583
19818
|
if (reresolvesNestedReference) return await this.reresolveCrossStackValue(flatValue, nestedStackChildRegionFromLocalArn(resource.physicalId), context, `nested stack ${logicalId} ${this.displayLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
|
|
19584
|
-
return notedFlatValue;
|
|
19819
|
+
return await this.reresolveRecordedReferences(notedFlatValue, logicalId, context, `${logicalId}.${this.displayLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
|
|
19585
19820
|
}
|
|
19586
19821
|
if (attributeName.includes(".")) {
|
|
19587
19822
|
const parts = attributeName.split(".");
|
|
@@ -19597,7 +19832,7 @@ async function resolveGetAtt(getAtt, context) {
|
|
|
19597
19832
|
structured: isStructured(cursor),
|
|
19598
19833
|
redacted: isSensitiveAttributeName(attributeName)
|
|
19599
19834
|
})}`);
|
|
19600
|
-
return notedCursor;
|
|
19835
|
+
return await this.reresolveRecordedReferences(notedCursor, logicalId, context, `${logicalId}.${this.displayLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
|
|
19601
19836
|
}
|
|
19602
19837
|
}
|
|
19603
19838
|
}
|
|
@@ -19642,6 +19877,7 @@ function noteAttributeSecrecy(logicalId, attributeName, value, context) {
|
|
|
19642
19877
|
const served = override !== void 0 && Object.hasOwn(override, attributeName);
|
|
19643
19878
|
if (served) value = override[attributeName];
|
|
19644
19879
|
recordSecretNamedRead(logicalId, value, context);
|
|
19880
|
+
recordProducerSecretPairs(logicalId, value, context);
|
|
19645
19881
|
const declared = context.noEchoAttributeResources?.get(logicalId);
|
|
19646
19882
|
if ((served || declared === true || declared !== void 0 && declared.has(attributeName)) && context.recordedSecretValues) recordFreshNoEchoValuesIn(value, context.recordedSecretValues, void 0, this.publicNoEchoTokens(context, logicalId));
|
|
19647
19883
|
if (context.redactedAttributeReads !== void 0 && carriesSecretMask(value)) {
|
|
@@ -19658,6 +19894,24 @@ function noteAttributeSecrecy(logicalId, attributeName, value, context) {
|
|
|
19658
19894
|
}
|
|
19659
19895
|
return value;
|
|
19660
19896
|
}
|
|
19897
|
+
function recordProducerSecretPairs(logicalId, value, context) {
|
|
19898
|
+
const bag = context.recordedSecretValues;
|
|
19899
|
+
if (bag === void 0 || context.producerSecrets === void 0) return;
|
|
19900
|
+
const producer = context.producerSecrets(logicalId);
|
|
19901
|
+
if (producer === void 0 || producer === bag || producer.size === 0) return;
|
|
19902
|
+
const preRun = context.producerPreRunPhysicalId?.(logicalId);
|
|
19903
|
+
const record = Object.hasOwn(context.resources, logicalId) ? context.resources[logicalId] : void 0;
|
|
19904
|
+
if (typeof preRun !== "string" || record?.physicalId !== preRun) return;
|
|
19905
|
+
const physicalId = preRun.toLowerCase();
|
|
19906
|
+
const leaves = [...wholeStringLeavesOf(value)];
|
|
19907
|
+
if (leaves.length === 0) return;
|
|
19908
|
+
for (const [plaintext, expression] of producer) {
|
|
19909
|
+
if (plaintext.length < 4 || bag.has(plaintext)) continue;
|
|
19910
|
+
if (typeof expression !== "string" || !expression.startsWith("{{resolve:")) continue;
|
|
19911
|
+
if (!physicalId.includes(plaintext.toLowerCase())) continue;
|
|
19912
|
+
if (leaves.some((leaf) => leaf.includes(plaintext))) bag.set(plaintext, expression);
|
|
19913
|
+
}
|
|
19914
|
+
}
|
|
19661
19915
|
function recordSecretNamedRead(logicalId, value, context) {
|
|
19662
19916
|
const bag = context.secretNameSink ?? context.printingSecrets ?? context.recordedSecretValues;
|
|
19663
19917
|
if (bag === void 0 || context.secretNameNeedles === void 0) return;
|
|
@@ -19669,6 +19923,75 @@ function recordSecretNamedRead(logicalId, value, context) {
|
|
|
19669
19923
|
break;
|
|
19670
19924
|
}
|
|
19671
19925
|
}
|
|
19926
|
+
async function reresolveRecordedReferences(value, logicalId, context, origin, sourceKey) {
|
|
19927
|
+
if (!carriesDynamicReference(value) || carriesSecretMask(value)) return value;
|
|
19928
|
+
if (context.recordedSecretValues === void 0) return value;
|
|
19929
|
+
if (!referencesProvenLocal(value, logicalId, context) && !referencesRegionProven(value, context, this.resolverRegion)) {
|
|
19930
|
+
this.logger.debug(safeMsg`Not re-resolving the reference(s) in ${this.displayMasked(origin, context)}: the template of ${this.displayMasked(logicalId, context)} does not spell them, and this stack may read a stack in another region, so the region that resolved them is unknown`);
|
|
19931
|
+
return value;
|
|
19932
|
+
}
|
|
19933
|
+
if (!await this.referencesMatchPhysicalId(value, logicalId, context)) {
|
|
19934
|
+
this.logger.warn(safeMsg`Serving ${this.displayMasked(origin, context)} as recorded, with its {{resolve:...}} reference(s) unresolved: cdkd cannot confirm the secret still holds the value ${this.displayMasked(logicalId, context)} was deployed with, because its physical id does not contain it. Either the secret changed since then (update ${this.displayMasked(logicalId, context)} so cdkd deploys it with the new value), or the value is not part of its name (a custom resource's Data, a name shorter than four characters), and cdkd sends the recorded reference as before.`);
|
|
19935
|
+
return value;
|
|
19936
|
+
}
|
|
19937
|
+
return await this.reresolveCrossStackValue(value, void 0, context, origin, sourceKey);
|
|
19938
|
+
}
|
|
19939
|
+
async function referencesMatchPhysicalId(value, logicalId, context) {
|
|
19940
|
+
const record = Object.hasOwn(context.resources, logicalId) ? context.resources[logicalId] : void 0;
|
|
19941
|
+
const physicalId = typeof record?.physicalId === "string" ? record.physicalId.toLowerCase() : "";
|
|
19942
|
+
for (const leaf of wholeStringLeavesOf(value)) for (const token of dynamicReferenceTokens(leaf)) {
|
|
19943
|
+
const plaintext = await this.resolveDynamicReferences(token, context);
|
|
19944
|
+
if (plaintext.includes("{{resolve:")) continue;
|
|
19945
|
+
if (plaintext.length < 4) return false;
|
|
19946
|
+
if (!physicalId.includes(plaintext.toLowerCase())) return false;
|
|
19947
|
+
}
|
|
19948
|
+
return true;
|
|
19949
|
+
}
|
|
19950
|
+
function referencesRegionProven(value, context, region) {
|
|
19951
|
+
const evidence = context.secretRegionEvidence?.();
|
|
19952
|
+
if (evidence?.complete !== true) return false;
|
|
19953
|
+
return [...wholeStringLeavesOf(value)].every((leaf) => dynamicReferenceTokens(leaf).every((token) => classifyReplaySecretRegion(token, region, evidence.regions).kind !== "ambiguous"));
|
|
19954
|
+
}
|
|
19955
|
+
function readsAnotherStack(node) {
|
|
19956
|
+
if (Object.hasOwn(node, "Fn::ImportValue") || Object.hasOwn(node, "Fn::GetStackOutput")) return true;
|
|
19957
|
+
if (!Object.hasOwn(node, "Fn::GetAtt")) return false;
|
|
19958
|
+
const getAtt = node["Fn::GetAtt"];
|
|
19959
|
+
const attributeName = typeof getAtt === "string" ? splitGetAttStringForm(getAtt)?.attributeName : Array.isArray(getAtt) ? getAtt[1] : void 0;
|
|
19960
|
+
return typeof attributeName !== "string" || attributeName.startsWith("Outputs.");
|
|
19961
|
+
}
|
|
19962
|
+
function takenIfBranch(node, context) {
|
|
19963
|
+
if (Array.isArray(node) || !Object.hasOwn(node, "Fn::If")) return void 0;
|
|
19964
|
+
const args = node["Fn::If"];
|
|
19965
|
+
if (!Array.isArray(args) || args.length !== 3 || typeof args[0] !== "string") return void 0;
|
|
19966
|
+
const conditions = context.conditions;
|
|
19967
|
+
if (conditions === void 0 || !Object.hasOwn(conditions, args[0])) return void 0;
|
|
19968
|
+
const verdict = conditions[args[0]];
|
|
19969
|
+
if (typeof verdict !== "boolean") return void 0;
|
|
19970
|
+
return { branch: verdict ? args[1] : args[2] };
|
|
19971
|
+
}
|
|
19972
|
+
function referencesProvenLocal(value, logicalId, context) {
|
|
19973
|
+
const resources = context.template.Resources ?? {};
|
|
19974
|
+
if (!Object.hasOwn(resources, logicalId)) return false;
|
|
19975
|
+
const literals = [];
|
|
19976
|
+
let crossStack = false;
|
|
19977
|
+
const walk = (node) => {
|
|
19978
|
+
if (typeof node === "string") {
|
|
19979
|
+
if (node.includes("{{resolve:")) literals.push(node);
|
|
19980
|
+
return;
|
|
19981
|
+
}
|
|
19982
|
+
if (node === null || typeof node !== "object") return;
|
|
19983
|
+
if (!Array.isArray(node) && readsAnotherStack(node)) crossStack = true;
|
|
19984
|
+
const taken = takenIfBranch(node, context);
|
|
19985
|
+
if (taken !== void 0) {
|
|
19986
|
+
walk(taken.branch);
|
|
19987
|
+
return;
|
|
19988
|
+
}
|
|
19989
|
+
for (const child of Object.values(node)) walk(child);
|
|
19990
|
+
};
|
|
19991
|
+
walk(resources[logicalId]?.Properties);
|
|
19992
|
+
if (crossStack) return false;
|
|
19993
|
+
return [...wholeStringLeavesOf(value)].every((leaf) => dynamicReferenceTokens(leaf).every((token) => literals.some((l) => l.includes(token))));
|
|
19994
|
+
}
|
|
19672
19995
|
function rejectPlaceholderArnAttribute(resource, attributeName, value, logicalId, context, healOutcome) {
|
|
19673
19996
|
if (!isStalePlaceholderArnAttribute(resource.resourceType, attributeName, value)) return;
|
|
19674
19997
|
throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${this.displayMasked(logicalId, context)}, ${this.displayMasked(attributeName, context)}] for ${resource.resourceType}: the recorded value ${quotedRender(stringifyValue(this.maskValueLeaves(value, context)), "\"")} is a placeholder written by an older cdkd version — its region and account fields are literal wildcards, so it is not a usable ARN. ` + this.staleRecordRemedy(healOutcome, context)));
|
|
@@ -19863,6 +20186,13 @@ async function reresolveCrossStackValue(value, producerRegion, context, origin,
|
|
|
19863
20186
|
});
|
|
19864
20187
|
}
|
|
19865
20188
|
}
|
|
20189
|
+
if (context.recordedSecretValues !== void 0 && producerOutput !== void 0 && producerOutput.crossAccount !== true && context.stateBackend !== void 0 && context.skipDynamicReferences !== true) {
|
|
20190
|
+
const plain = [...wholeStringLeavesOf(value)].filter((leaf) => !leaf.includes("{{resolve:") && !carriesSecretMask(leaf));
|
|
20191
|
+
if (plain.length > 0) {
|
|
20192
|
+
const ids = await producerPhysicalIds(context.recordedImports ?? context.recordedSecretValues, context.stateBackend, producerOutput.stackName, producerOutput.region || this.resolverRegion, () => this.logger.debug(safeMsg`Could not read the state of producer ${this.displayMasked(producerOutput.stackName, context)} for its physical ids; no cross-stack copy of one is kept (go-to-k/cdkd#4819)`));
|
|
20193
|
+
for (const leaf of plain) if (ids.has(leaf)) recordPhysicalNameCopy(context.recordedSecretValues, leaf);
|
|
20194
|
+
}
|
|
20195
|
+
}
|
|
19866
20196
|
if (!carriesDynamicReference(value)) return value;
|
|
19867
20197
|
const resolver = this.resolverForProducerRegion(producerRegion, context, producerRegionLogText);
|
|
19868
20198
|
const pinnedContext = producerRegion ? withoutProducerRegions(context) : context;
|
|
@@ -19981,6 +20311,33 @@ function recordImport(context, exportName, producerStack, producerRegion) {
|
|
|
19981
20311
|
sourceRegion: producerRegion
|
|
19982
20312
|
});
|
|
19983
20313
|
}
|
|
20314
|
+
const producerPhysicalIdReads = /* @__PURE__ */ new WeakMap();
|
|
20315
|
+
function producerPhysicalIds(scope, stateBackend, stackName, region, onFailure) {
|
|
20316
|
+
let reads = producerPhysicalIdReads.get(scope);
|
|
20317
|
+
if (reads === void 0) {
|
|
20318
|
+
reads = /* @__PURE__ */ new Map();
|
|
20319
|
+
producerPhysicalIdReads.set(scope, reads);
|
|
20320
|
+
}
|
|
20321
|
+
const key = JSON.stringify([stackName, region]);
|
|
20322
|
+
let read = reads.get(key);
|
|
20323
|
+
if (read === void 0) {
|
|
20324
|
+
read = (async () => {
|
|
20325
|
+
const ids = /* @__PURE__ */ new Set();
|
|
20326
|
+
try {
|
|
20327
|
+
const data = await stateBackend.getState(stackName, region);
|
|
20328
|
+
for (const record of Object.values(data?.state.resources ?? {})) {
|
|
20329
|
+
const id = record?.physicalId;
|
|
20330
|
+
if (typeof id === "string" && id !== "") ids.add(id);
|
|
20331
|
+
}
|
|
20332
|
+
} catch {
|
|
20333
|
+
onFailure();
|
|
20334
|
+
}
|
|
20335
|
+
return ids;
|
|
20336
|
+
})();
|
|
20337
|
+
reads.set(key, read);
|
|
20338
|
+
}
|
|
20339
|
+
return read;
|
|
20340
|
+
}
|
|
19984
20341
|
|
|
19985
20342
|
//#endregion
|
|
19986
20343
|
//#region src/deployment/intrinsic-resolver/cfn-fallback.ts
|
|
@@ -20071,143 +20428,6 @@ function getCfnClient(rawRegion) {
|
|
|
20071
20428
|
return client;
|
|
20072
20429
|
}
|
|
20073
20430
|
|
|
20074
|
-
//#endregion
|
|
20075
|
-
//#region src/deployment/intrinsic-resolver/stack-output.ts
|
|
20076
|
-
async function resolveGetStackOutput(arg, context) {
|
|
20077
|
-
if (!arg || typeof arg !== "object" || Array.isArray(arg)) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: argument must be an object with StackName/OutputName/Region/RoleArn, got ${arg === null ? "null" : Array.isArray(arg) ? "array" : typeof arg}`));
|
|
20078
|
-
const args = arg;
|
|
20079
|
-
if (!("StackName" in args)) throw markNonRetryable(/* @__PURE__ */ new Error("Fn::GetStackOutput: StackName is required"));
|
|
20080
|
-
if (!("OutputName" in args)) throw markNonRetryable(/* @__PURE__ */ new Error("Fn::GetStackOutput: OutputName is required"));
|
|
20081
|
-
const sourceKey = crossStackSourceKey({ "Fn::GetStackOutput": args });
|
|
20082
|
-
const stackName = await this.resolveValue(args["StackName"], context);
|
|
20083
|
-
if (typeof stackName !== "string" || stackName === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: StackName must resolve to a non-empty string, got ${typeof stackName}`));
|
|
20084
|
-
const outputName = await this.resolveValue(args["OutputName"], context);
|
|
20085
|
-
if (typeof outputName !== "string" || outputName === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: OutputName must resolve to a non-empty string, got ${typeof outputName}`));
|
|
20086
|
-
let region = this.resolverRegion;
|
|
20087
|
-
let loggedRegionText = this.logTextOfLeaf(region, context);
|
|
20088
|
-
if ("Region" in args && args["Region"] !== void 0 && args["Region"] !== null) {
|
|
20089
|
-
const resolvedRegion = await this.resolveValue(args["Region"], context);
|
|
20090
|
-
if (typeof resolvedRegion !== "string" || resolvedRegion === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: Region must resolve to a non-empty string, got ${typeof resolvedRegion}`));
|
|
20091
|
-
const requestedRegion = canonicalizeRegion(resolvedRegion);
|
|
20092
|
-
if (!isClientSafeRegion(requestedRegion)) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: ${this.displayMaskedIdent(this.logTextOfLeaf(resolvedRegion, context) !== resolvedRegion ? "***" : resolvedRegion, context, 64)} is not a valid AWS region name. The region selects both the AWS endpoint and the state-file key, so cdkd will not use it.`));
|
|
20093
|
-
region = requestedRegion;
|
|
20094
|
-
loggedRegionText = this.regionLogText(resolvedRegion, context);
|
|
20095
|
-
}
|
|
20096
|
-
let roleArn;
|
|
20097
|
-
if ("RoleArn" in args && args["RoleArn"] !== void 0 && args["RoleArn"] !== null) {
|
|
20098
|
-
const raw = args["RoleArn"];
|
|
20099
|
-
if (typeof raw !== "string" || raw === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: RoleArn must be a literal string in the template (no Ref / Fn::GetAtt / Fn::Sub allowed for cross-account references). Got ${raw === null ? "null" : Array.isArray(raw) ? "array" : typeof raw}${typeof raw === "object" ? ` (intrinsic shape: ${this.displayMasked(JSON.stringify(raw).slice(0, 80), context)})` : ""}.`));
|
|
20100
|
-
roleArn = raw;
|
|
20101
|
-
}
|
|
20102
|
-
if (!roleArn && context.stackName && context.stackName === stackName && sameRegion(region, this.resolverRegion)) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: cannot reference own stack ${this.displayMaskedIdent(stackName, context, STACK_REF_MAX_CODE_POINTS)} in the same region ${this.displayMaskedIdent(loggedRegionText, context)}`));
|
|
20103
|
-
const loggedStackName = this.displayMaskedIdent(stackName, context, STACK_REF_MAX_CODE_POINTS);
|
|
20104
|
-
const loggedOutputName = this.displayMaskedIdent(outputName, context);
|
|
20105
|
-
const loggedRegion = this.displayMasked(loggedRegionText, context);
|
|
20106
|
-
const shownRoleArn = roleArn ? displayIdent(roleArn, { maxCodePoints: 613 }) : "";
|
|
20107
|
-
this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${shownRoleArn}` : ""}`);
|
|
20108
|
-
let stateData;
|
|
20109
|
-
try {
|
|
20110
|
-
stateData = roleArn ? await this.getCrossAccountStackState(roleArn, stackName, region, context) : await this.getSameAccountStackState(stackName, region, context);
|
|
20111
|
-
} catch (error) {
|
|
20112
|
-
this.maskStateReadError(error, [[stackName, this.displayMasked(stackName, context)], [region, loggedRegion]], context);
|
|
20113
|
-
}
|
|
20114
|
-
if (!stateData) {
|
|
20115
|
-
if (!roleArn && this.cfnFallback) {
|
|
20116
|
-
const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region, context, loggedRegionText);
|
|
20117
|
-
if (cfnOutputs) {
|
|
20118
|
-
if (!Object.hasOwn(cfnOutputs, outputName)) {
|
|
20119
|
-
const available = this.describeAvailableOutputs(Object.keys(cfnOutputs), context);
|
|
20120
|
-
throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: output ${loggedOutputName} not found in CloudFormation stack ${loggedStackName} (${displayIdent(loggedRegion)}). Available outputs: ${available}`));
|
|
20121
|
-
}
|
|
20122
|
-
const value = cfnOutputs[outputName];
|
|
20123
|
-
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName} (from CloudFormation stack outputs; weak reference — producer is not cdkd-managed)`);
|
|
20124
|
-
return value;
|
|
20125
|
-
}
|
|
20126
|
-
}
|
|
20127
|
-
throw new Error(`Fn::GetStackOutput: stack ${loggedStackName} not found in region ${displayIdent(loggedRegion)}${roleArn ? ` (cross-account via ${shownRoleArn})` : ""}. ${!roleArn && this.cfnFallback ? "Searched cdkd state and CloudFormation stacks. Make sure the producer stack has been deployed (via cdkd or CloudFormation)." : `Make sure the producer stack has been deployed via cdkd.`}`);
|
|
20128
|
-
}
|
|
20129
|
-
if (!hasReadableOutputs(stateData.state)) throw markNonRetryable(new MalformedProducerRecordRefusalError(`Fn::GetStackOutput: the state record of producer stack ${loggedStackName} (${displayIdent(loggedRegion)}) has no readable 'outputs' map — the record is malformed or truncated. cdkd refuses to resolve from it rather than reading it as a map: 'Object.hasOwn' answers TRUE for '0' on a string and for an index on a list, so continuing would resolve ONE CHARACTER or element of the record as this reference's value and this deploy would send it to AWS. Inspect the producer's record with 'cdkd state show' --json, repair or remove it, then re-run.`));
|
|
20130
|
-
const outputs = stateData.state.outputs ?? {};
|
|
20131
|
-
if (!Object.hasOwn(outputs, outputName)) {
|
|
20132
|
-
const available = this.describeAvailableOutputs(Object.keys(outputs), context);
|
|
20133
|
-
throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: output ${loggedOutputName} not found in stack ${loggedStackName} (${displayIdent(loggedRegion)}). Available outputs: ${available}`));
|
|
20134
|
-
}
|
|
20135
|
-
const value = outputs[outputName];
|
|
20136
|
-
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${shownRoleArn}` : ""} (${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
20137
|
-
if (!roleArn) this.recordOutputRead(context, stackName, region, outputName);
|
|
20138
|
-
if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new CrossAccountSecretRefusalError(`Fn::GetStackOutput: output ${loggedOutputName} of stack ${loggedStackName} (${displayIdent(loggedRegion)}) is a redacted dynamic reference, and this is a CROSS-ACCOUNT reference (RoleArn ${shownRoleArn}). cdkd will not resolve a producer account's secret with the consumer's credentials — a same-named secret in the consumer account would answer instead. Export a non-secret value (e.g. the secret's ARN) and resolve it in the consumer stack, or reference the producer stack from within its own account.`));
|
|
20139
|
-
return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput ${quotedRender(this.displayLeaf(outputName, context), "'")} (producer ${this.displayLeaf(stackName, context)} / ${this.displayLeaf(loggedRegionText, context)})`, sourceKey, {
|
|
20140
|
-
stackName,
|
|
20141
|
-
region,
|
|
20142
|
-
outputKey: outputName,
|
|
20143
|
-
...roleArn ? { crossAccount: true } : {}
|
|
20144
|
-
}, loggedRegionText);
|
|
20145
|
-
}
|
|
20146
|
-
function recordOutputRead(context, producerStack, producerRegion, outputName) {
|
|
20147
|
-
if (!context.recordedOutputReads) return;
|
|
20148
|
-
if (context.recordedOutputReads.some((e) => e.sourceStack === producerStack && sameRegion(e.sourceRegion, producerRegion) && e.outputName === outputName)) return;
|
|
20149
|
-
context.recordedOutputReads.push({
|
|
20150
|
-
sourceStack: producerStack,
|
|
20151
|
-
sourceRegion: producerRegion,
|
|
20152
|
-
outputName
|
|
20153
|
-
});
|
|
20154
|
-
}
|
|
20155
|
-
function positionalNameMask(pairs) {
|
|
20156
|
-
const substitutions = pairs.filter(([raw, masked]) => raw !== "" && raw !== masked).flatMap(([raw, masked]) => {
|
|
20157
|
-
const shown = displaySafe(raw, { asciiOnly: true });
|
|
20158
|
-
const escaped = (text) => JSON.stringify(text).slice(1, -1);
|
|
20159
|
-
const rendered = displayStackName(raw);
|
|
20160
|
-
const escapedPair = [...shown !== "" && escaped(shown) !== shown ? [[escaped(shown), escaped(displaySafe(masked, { asciiOnly: true }))]] : [], ...rendered !== raw && rendered !== shown && rendered !== escaped(shown) ? [[rendered, displayStackName(displaySafe(masked, { asciiOnly: true }))]] : []];
|
|
20161
|
-
if (shown === raw) return [[raw, masked], ...escapedPair];
|
|
20162
|
-
const shownMask = displaySafe(masked, { asciiOnly: true });
|
|
20163
|
-
return shown === "" || shownMask === "" ? [[raw, masked]] : [
|
|
20164
|
-
[raw, masked],
|
|
20165
|
-
[shown, shownMask],
|
|
20166
|
-
...escapedPair
|
|
20167
|
-
];
|
|
20168
|
-
}).sort(([a], [b]) => b.length - a.length);
|
|
20169
|
-
if (substitutions.length === 0) return void 0;
|
|
20170
|
-
return (text) => {
|
|
20171
|
-
let out = text;
|
|
20172
|
-
for (const [raw, masked] of substitutions) out = out.split(raw).join(masked);
|
|
20173
|
-
return out;
|
|
20174
|
-
};
|
|
20175
|
-
}
|
|
20176
|
-
function maskStateReadError(error, pairs, context) {
|
|
20177
|
-
throw this.maskNamedError(error, this.positionalNameMask(pairs), context);
|
|
20178
|
-
}
|
|
20179
|
-
function maskNamedError(error, extraMask, context) {
|
|
20180
|
-
let masked = error;
|
|
20181
|
-
let positional = extraMask;
|
|
20182
|
-
const union = unionOfSecretBags([
|
|
20183
|
-
context?.inheritedSecrets,
|
|
20184
|
-
context?.recordedSecretValues,
|
|
20185
|
-
context?.printingSecrets
|
|
20186
|
-
]);
|
|
20187
|
-
if (hasMaskableValues(union)) {
|
|
20188
|
-
masked = maskSecretsInError(masked, union, positional);
|
|
20189
|
-
positional = void 0;
|
|
20190
|
-
}
|
|
20191
|
-
if (positional) masked = maskSecretsInError(masked, /* @__PURE__ */ new Map(), positional);
|
|
20192
|
-
return masked;
|
|
20193
|
-
}
|
|
20194
|
-
function namedRequestMasks(pairs, context) {
|
|
20195
|
-
const positional = this.positionalNameMask(this.explicitRegion !== void 0 && this.explicitRegionLogText !== void 0 ? [...pairs, [this.explicitRegion, this.explicitRegionLogText]] : pairs);
|
|
20196
|
-
const text = (message) => this.displayMasked(positional ? positional(message) : message, context);
|
|
20197
|
-
const line = (message) => {
|
|
20198
|
-
const indent = /^ */.exec(message)?.[0] ?? "";
|
|
20199
|
-
return indent + text(message.slice(indent.length));
|
|
20200
|
-
};
|
|
20201
|
-
return {
|
|
20202
|
-
error: (error) => this.maskNamedError(error, positional, context),
|
|
20203
|
-
text,
|
|
20204
|
-
retryLogger: {
|
|
20205
|
-
debug: (message) => this.logger.debug(line(message)),
|
|
20206
|
-
warn: (message) => this.logger.warn(line(message))
|
|
20207
|
-
}
|
|
20208
|
-
};
|
|
20209
|
-
}
|
|
20210
|
-
|
|
20211
20431
|
//#endregion
|
|
20212
20432
|
//#region src/utils/caller-credentials.ts
|
|
20213
20433
|
const AWS_CREDENTIAL_ENV_KEYS = [
|
|
@@ -20380,6 +20600,353 @@ async function applyRoleArnIfSet(opts) {
|
|
|
20380
20600
|
}
|
|
20381
20601
|
}
|
|
20382
20602
|
|
|
20603
|
+
//#endregion
|
|
20604
|
+
//#region src/deployment/intrinsic-resolver/cdk-cross-account-ref.ts
|
|
20605
|
+
function producerLookupOver(stacks) {
|
|
20606
|
+
return (stackName, account, region) => stacks.find((s) => s.stackName === stackName && s.account === account && sameRegion(s.region, region));
|
|
20607
|
+
}
|
|
20608
|
+
const ROLE_NAME = "[\\w+=,.@-]{1,64}";
|
|
20609
|
+
const LITERAL_ROLE_ARN_RE = new RegExp(`^arn:aws[a-z0-9-]*:iam::(\\d{12}):role/(${ROLE_NAME})$`);
|
|
20610
|
+
const JOIN_TAIL_RE = new RegExp(`^:iam::(\\d{12}):role/(${ROLE_NAME})$`);
|
|
20611
|
+
function isExactlyKeyed(value, key) {
|
|
20612
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
20613
|
+
const keys = Object.keys(value);
|
|
20614
|
+
return keys.length === 1 && keys[0] === key;
|
|
20615
|
+
}
|
|
20616
|
+
function roleArnShape(raw) {
|
|
20617
|
+
if (typeof raw === "string") {
|
|
20618
|
+
const match = LITERAL_ROLE_ARN_RE.exec(raw);
|
|
20619
|
+
if (!match || !match[1] || !match[2] || !parseIamRoleArn(raw)) return void 0;
|
|
20620
|
+
return {
|
|
20621
|
+
form: "literal",
|
|
20622
|
+
accountId: match[1],
|
|
20623
|
+
roleName: match[2]
|
|
20624
|
+
};
|
|
20625
|
+
}
|
|
20626
|
+
if (!isExactlyKeyed(raw, "Fn::Join")) return void 0;
|
|
20627
|
+
const join = raw["Fn::Join"];
|
|
20628
|
+
if (!Array.isArray(join) || join.length !== 2 || join[0] !== "") return void 0;
|
|
20629
|
+
const parts = join[1];
|
|
20630
|
+
if (!Array.isArray(parts) || parts.length !== 3 || parts[0] !== "arn:") return void 0;
|
|
20631
|
+
const ref = parts[1];
|
|
20632
|
+
if (!isExactlyKeyed(ref, "Ref") || ref["Ref"] !== "AWS::Partition") return void 0;
|
|
20633
|
+
const tail = parts[2];
|
|
20634
|
+
if (typeof tail !== "string") return void 0;
|
|
20635
|
+
const match = JOIN_TAIL_RE.exec(tail);
|
|
20636
|
+
if (!match || !match[1] || !match[2]) return void 0;
|
|
20637
|
+
return {
|
|
20638
|
+
form: "join",
|
|
20639
|
+
accountId: match[1],
|
|
20640
|
+
roleName: match[2]
|
|
20641
|
+
};
|
|
20642
|
+
}
|
|
20643
|
+
function roleArnOf(shape, region) {
|
|
20644
|
+
const { partition } = derivePartitionAndUrlSuffix(region);
|
|
20645
|
+
return `arn:${partition}:iam::${shape.accountId}:role/${shape.roleName}`;
|
|
20646
|
+
}
|
|
20647
|
+
const CFN_EXEC_ROLE_PRINCIPAL_RE = /^arn:(?:\$\{AWS::Partition\}|aws[a-z0-9-]*):iam::\d{12}:role\/[^/]*cfn-exec-role[^/]*$/;
|
|
20648
|
+
function isCfnExecRolePrincipal(principal) {
|
|
20649
|
+
return isExactlyKeyed(principal, "Fn::Sub") && typeof principal["Fn::Sub"] === "string" && CFN_EXEC_ROLE_PRINCIPAL_RE.test(principal["Fn::Sub"]);
|
|
20650
|
+
}
|
|
20651
|
+
function trustsOnlyCfnExecRoles(document) {
|
|
20652
|
+
if (document === null || typeof document !== "object" || Array.isArray(document)) return false;
|
|
20653
|
+
const statements = document["Statement"];
|
|
20654
|
+
if (!Array.isArray(statements) || statements.length === 0) return false;
|
|
20655
|
+
for (const statement of statements) {
|
|
20656
|
+
if (statement === null || typeof statement !== "object" || Array.isArray(statement)) return false;
|
|
20657
|
+
const principal = statement["Principal"];
|
|
20658
|
+
if (!isExactlyKeyed(principal, "AWS")) return false;
|
|
20659
|
+
const aws = principal["AWS"];
|
|
20660
|
+
const list = Array.isArray(aws) ? aws : [aws];
|
|
20661
|
+
if (list.length === 0 || !list.every(isCfnExecRolePrincipal)) return false;
|
|
20662
|
+
}
|
|
20663
|
+
return true;
|
|
20664
|
+
}
|
|
20665
|
+
function isGeneratedReaderRole(template, roleName) {
|
|
20666
|
+
const resources = template.Resources;
|
|
20667
|
+
if (!resources || typeof resources !== "object") return false;
|
|
20668
|
+
for (const resource of Object.values(resources)) {
|
|
20669
|
+
if (resource === null || typeof resource !== "object") continue;
|
|
20670
|
+
const { Type: type, Properties: properties } = resource;
|
|
20671
|
+
if (type !== "AWS::IAM::Role") continue;
|
|
20672
|
+
if (properties === null || typeof properties !== "object") continue;
|
|
20673
|
+
const props = properties;
|
|
20674
|
+
if (props["RoleName"] !== roleName) continue;
|
|
20675
|
+
if (trustsOnlyCfnExecRoles(props["AssumeRolePolicyDocument"])) return true;
|
|
20676
|
+
}
|
|
20677
|
+
return false;
|
|
20678
|
+
}
|
|
20679
|
+
function producerLookupRoleArn(lookupRoleArn, producerRegion, producerAccount) {
|
|
20680
|
+
if (typeof lookupRoleArn !== "string" || lookupRoleArn === "") return void 0;
|
|
20681
|
+
const { partition } = derivePartitionAndUrlSuffix(producerRegion);
|
|
20682
|
+
const arn = lookupRoleArn.split("${AWS::Partition}").join(partition);
|
|
20683
|
+
const parsed = parseIamRoleArn(arn);
|
|
20684
|
+
if (!parsed || parsed.accountId !== producerAccount) return void 0;
|
|
20685
|
+
return arn;
|
|
20686
|
+
}
|
|
20687
|
+
function classifyCdkCrossAccountRef(shape, producerStackName, producerRegion, lookup) {
|
|
20688
|
+
if (lookup === void 0) return { kind: "not-generated" };
|
|
20689
|
+
const producer = lookup(producerStackName, shape.accountId, producerRegion);
|
|
20690
|
+
if (!producer) return shape.form === "join" ? {
|
|
20691
|
+
kind: "producer-absent",
|
|
20692
|
+
shape
|
|
20693
|
+
} : { kind: "not-generated" };
|
|
20694
|
+
if (!isGeneratedReaderRole(producer.template, shape.roleName)) return { kind: "not-generated" };
|
|
20695
|
+
return {
|
|
20696
|
+
kind: "generated",
|
|
20697
|
+
shape,
|
|
20698
|
+
lookupRoleArn: producerLookupRoleArn(producer.lookupRoleArn, producerRegion, shape.accountId)
|
|
20699
|
+
};
|
|
20700
|
+
}
|
|
20701
|
+
function quotedArg(rendered) {
|
|
20702
|
+
return rendered.startsWith("\"") ? rendered : `'${rendered}'`;
|
|
20703
|
+
}
|
|
20704
|
+
function cdkCrossAccountRefRefusal(parts) {
|
|
20705
|
+
const consumerAccount = parts.consumerAccount !== void 0 && /^\d{12}$/.test(parts.consumerAccount) ? parts.consumerAccount : "<consumer-account>";
|
|
20706
|
+
const reason = parts.reason.replace(/[\s.]+$/, "");
|
|
20707
|
+
const trust = `'cdk bootstrap --trust-for-lookup ${consumerAccount}' (or '--trust ${consumerAccount}')`;
|
|
20708
|
+
const remedyOne = parts.noLookupRole ? `(1) synthesize stack ${parts.producer} with a stack synthesizer that names a lookup role (the default DefaultStackSynthesizer), and in account ${parts.producerAccount} run ${trust} so the identity running cdkd can assume it; or ` : `(1) in account ${parts.producerAccount}, run ${trust} so the identity running cdkd can assume the lookup role; or `;
|
|
20709
|
+
return `Fn::GetStackOutput: cannot read output ${parts.output} of stack ${parts.producer} (region ${parts.region}, account ${parts.producerAccount})${parts.consumer ? ` for stack ${parts.consumer}` : ""}. Its RoleArn names ${parts.roleName}, a role the AWS CDK generates for a cross-account reference that trusts only the consumer account's CloudFormation execution role, which cdkd does not use; cdkd reads the producer's cdkd state through the producer account's CDK lookup role instead, but ${reason}. Fix it one of two ways: ` + remedyOne + `(2) write the reference as cdk.Fn.getStackOutput(${quotedArg(parts.producer)}, ${quotedArg(parts.output)}, ${quotedArg(parts.region)}, '<roleArn>') with a role in account ${parts.producerAccount} that trusts the identity running cdkd and allows s3:GetBucketLocation and s3:GetObject on cdkd-state-${parts.producerAccount}. See https://cdkd.dev/cross-stack-references/#reading-from-another-account`;
|
|
20710
|
+
}
|
|
20711
|
+
function producerAbsentReason(producerAccount) {
|
|
20712
|
+
return `this producer stack (account ${producerAccount}) is not in this app's cloud assembly, so cdkd can neither confirm the role is the generated one nor find the lookup role`;
|
|
20713
|
+
}
|
|
20714
|
+
function noLookupRoleReason(producerAccount) {
|
|
20715
|
+
return `the producer stack's artifact names no CDK lookup role in account ${producerAccount} (its stack synthesizer does not use the bootstrap lookup role)`;
|
|
20716
|
+
}
|
|
20717
|
+
function isLookupRoleDenial(error) {
|
|
20718
|
+
let current = error;
|
|
20719
|
+
for (let depth = 0; depth < 6 && current !== null && typeof current === "object"; depth++) {
|
|
20720
|
+
const name = current.name;
|
|
20721
|
+
if (name === "AccessDenied" || name === "AccessDeniedException" || name === "NoSuchEntity" || name === "NoSuchEntityException") return true;
|
|
20722
|
+
if (current.$metadata?.httpStatusCode === 403) return true;
|
|
20723
|
+
current = current.cause;
|
|
20724
|
+
}
|
|
20725
|
+
return false;
|
|
20726
|
+
}
|
|
20727
|
+
function describeInnermostAwsError(error) {
|
|
20728
|
+
let innermost = error;
|
|
20729
|
+
for (let depth = 0; depth < 6; depth++) {
|
|
20730
|
+
const cause = innermost !== null && typeof innermost === "object" ? innermost.cause : void 0;
|
|
20731
|
+
if (cause === null || typeof cause !== "object") break;
|
|
20732
|
+
innermost = cause;
|
|
20733
|
+
}
|
|
20734
|
+
if (!(innermost instanceof Error)) return displayAwsMessage(String(innermost));
|
|
20735
|
+
const code = innermost.Code;
|
|
20736
|
+
const name = typeof code === "string" && code !== "" ? code : innermost.name;
|
|
20737
|
+
const message = displayAwsMessage(innermost.message);
|
|
20738
|
+
return name && name !== "Error" ? `${displayIdent(name)}: ${message}` : message;
|
|
20739
|
+
}
|
|
20740
|
+
function refuseUnreadableCdkCrossAccountRefs(refs, deployed, consumerOf, lookup) {
|
|
20741
|
+
for (const { consumer, args } of refs) {
|
|
20742
|
+
if (!deployed.has(consumer)) continue;
|
|
20743
|
+
const shape = roleArnShape(args["RoleArn"]);
|
|
20744
|
+
if (shape === void 0) continue;
|
|
20745
|
+
const stackName = args["StackName"];
|
|
20746
|
+
const outputName = args["OutputName"];
|
|
20747
|
+
const consumerStack = consumerOf(consumer);
|
|
20748
|
+
const region = args["Region"] ?? consumerStack.region;
|
|
20749
|
+
if (typeof stackName !== "string" || typeof outputName !== "string") continue;
|
|
20750
|
+
if (typeof region !== "string" || region === "") continue;
|
|
20751
|
+
const verdict = classifyCdkCrossAccountRef(shape, stackName, region, lookup);
|
|
20752
|
+
let reason;
|
|
20753
|
+
if (verdict.kind === "producer-absent") reason = producerAbsentReason(shape.accountId);
|
|
20754
|
+
else if (verdict.kind === "generated" && verdict.lookupRoleArn === void 0) reason = noLookupRoleReason(shape.accountId);
|
|
20755
|
+
if (reason === void 0) continue;
|
|
20756
|
+
throw markNonRetryable(new Error(cdkCrossAccountRefRefusal({
|
|
20757
|
+
consumer: displayStackName(consumer),
|
|
20758
|
+
output: displayIdent(outputName),
|
|
20759
|
+
producer: displayStackName(stackName),
|
|
20760
|
+
region: displayIdent(region),
|
|
20761
|
+
producerAccount: shape.accountId,
|
|
20762
|
+
roleName: displayIdent(shape.roleName),
|
|
20763
|
+
consumerAccount: consumerStack.account,
|
|
20764
|
+
reason,
|
|
20765
|
+
noLookupRole: verdict.kind === "generated"
|
|
20766
|
+
})));
|
|
20767
|
+
}
|
|
20768
|
+
}
|
|
20769
|
+
|
|
20770
|
+
//#endregion
|
|
20771
|
+
//#region src/deployment/intrinsic-resolver/stack-output.ts
|
|
20772
|
+
async function resolveGetStackOutput(arg, context) {
|
|
20773
|
+
if (!arg || typeof arg !== "object" || Array.isArray(arg)) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: argument must be an object with StackName/OutputName/Region/RoleArn, got ${arg === null ? "null" : Array.isArray(arg) ? "array" : typeof arg}`));
|
|
20774
|
+
const args = arg;
|
|
20775
|
+
if (!("StackName" in args)) throw markNonRetryable(/* @__PURE__ */ new Error("Fn::GetStackOutput: StackName is required"));
|
|
20776
|
+
if (!("OutputName" in args)) throw markNonRetryable(/* @__PURE__ */ new Error("Fn::GetStackOutput: OutputName is required"));
|
|
20777
|
+
const sourceKey = crossStackSourceKey({ "Fn::GetStackOutput": args });
|
|
20778
|
+
const stackName = await this.resolveValue(args["StackName"], context);
|
|
20779
|
+
if (typeof stackName !== "string" || stackName === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: StackName must resolve to a non-empty string, got ${typeof stackName}`));
|
|
20780
|
+
const outputName = await this.resolveValue(args["OutputName"], context);
|
|
20781
|
+
if (typeof outputName !== "string" || outputName === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: OutputName must resolve to a non-empty string, got ${typeof outputName}`));
|
|
20782
|
+
let region = this.resolverRegion;
|
|
20783
|
+
let loggedRegionText = this.logTextOfLeaf(region, context);
|
|
20784
|
+
if ("Region" in args && args["Region"] !== void 0 && args["Region"] !== null) {
|
|
20785
|
+
const resolvedRegion = await this.resolveValue(args["Region"], context);
|
|
20786
|
+
if (typeof resolvedRegion !== "string" || resolvedRegion === "") throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: Region must resolve to a non-empty string, got ${typeof resolvedRegion}`));
|
|
20787
|
+
const requestedRegion = canonicalizeRegion(resolvedRegion);
|
|
20788
|
+
if (!isClientSafeRegion(requestedRegion)) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: ${this.displayMaskedIdent(this.logTextOfLeaf(resolvedRegion, context) !== resolvedRegion ? "***" : resolvedRegion, context, 64)} is not a valid AWS region name. The region selects both the AWS endpoint and the state-file key, so cdkd will not use it.`));
|
|
20789
|
+
region = requestedRegion;
|
|
20790
|
+
loggedRegionText = this.regionLogText(resolvedRegion, context);
|
|
20791
|
+
}
|
|
20792
|
+
let roleArn;
|
|
20793
|
+
let cdkRef;
|
|
20794
|
+
if ("RoleArn" in args && args["RoleArn"] !== void 0 && args["RoleArn"] !== null) {
|
|
20795
|
+
const raw = args["RoleArn"];
|
|
20796
|
+
const refuseNonLiteral = () => markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: RoleArn must be a literal string in the template (no Ref / Fn::GetAtt / Fn::Sub allowed for cross-account references). Got ${raw === null ? "null" : Array.isArray(raw) ? "array" : typeof raw}${typeof raw === "object" ? ` (intrinsic shape: ${this.displayMasked(JSON.stringify(raw).slice(0, 80), context)})` : ""}.`));
|
|
20797
|
+
const shape = roleArnShape(raw);
|
|
20798
|
+
if ((typeof raw !== "string" || raw === "") && shape === void 0) throw refuseNonLiteral();
|
|
20799
|
+
if (shape !== void 0) {
|
|
20800
|
+
const key = JSON.stringify([
|
|
20801
|
+
shape.form,
|
|
20802
|
+
stackName,
|
|
20803
|
+
shape.accountId,
|
|
20804
|
+
canonicalizeRegion(region),
|
|
20805
|
+
shape.roleName
|
|
20806
|
+
]);
|
|
20807
|
+
let verdict = this.cdkCrossAccountRefVerdicts.get(key);
|
|
20808
|
+
if (verdict === void 0) {
|
|
20809
|
+
verdict = classifyCdkCrossAccountRef(shape, stackName, region, this.producerLookup);
|
|
20810
|
+
this.cdkCrossAccountRefVerdicts.set(key, verdict);
|
|
20811
|
+
}
|
|
20812
|
+
if (verdict.kind === "not-generated" && typeof raw !== "string") throw refuseNonLiteral();
|
|
20813
|
+
if (verdict.kind !== "not-generated") cdkRef = verdict;
|
|
20814
|
+
}
|
|
20815
|
+
roleArn = typeof raw === "string" ? raw : shape && roleArnOf(shape, region);
|
|
20816
|
+
}
|
|
20817
|
+
if (!roleArn && context.stackName && context.stackName === stackName && sameRegion(region, this.resolverRegion)) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: cannot reference own stack ${this.displayMaskedIdent(stackName, context, STACK_REF_MAX_CODE_POINTS)} in the same region ${this.displayMaskedIdent(loggedRegionText, context)}`));
|
|
20818
|
+
const loggedStackName = this.displayMaskedIdent(stackName, context, STACK_REF_MAX_CODE_POINTS);
|
|
20819
|
+
const loggedOutputName = this.displayMaskedIdent(outputName, context);
|
|
20820
|
+
const loggedRegion = this.displayMasked(loggedRegionText, context);
|
|
20821
|
+
const shownRoleArn = roleArn ? displayIdent(roleArn, { maxCodePoints: 613 }) : "";
|
|
20822
|
+
this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${shownRoleArn}` : ""}`);
|
|
20823
|
+
let readRoleArn = roleArn;
|
|
20824
|
+
let refuseCdkRead;
|
|
20825
|
+
if (cdkRef !== void 0) {
|
|
20826
|
+
const ref = cdkRef;
|
|
20827
|
+
const producerAccount = ref.shape.accountId;
|
|
20828
|
+
const refuseCdkRef = (reason, cause, noLookupRole = false) => markNonRetryable(new Error(cdkCrossAccountRefRefusal({
|
|
20829
|
+
consumer: context.stackName ? this.displayMaskedIdent(context.stackName, context, STACK_REF_MAX_CODE_POINTS) : void 0,
|
|
20830
|
+
output: loggedOutputName,
|
|
20831
|
+
producer: loggedStackName,
|
|
20832
|
+
region: displayIdent(loggedRegion),
|
|
20833
|
+
producerAccount,
|
|
20834
|
+
roleName: displayIdent(ref.shape.roleName),
|
|
20835
|
+
consumerAccount: this.consumerAccount,
|
|
20836
|
+
reason,
|
|
20837
|
+
noLookupRole
|
|
20838
|
+
}), cause === void 0 ? void 0 : { cause }));
|
|
20839
|
+
if (ref.kind === "producer-absent") throw refuseCdkRef(producerAbsentReason(producerAccount));
|
|
20840
|
+
if (ref.lookupRoleArn === void 0) throw refuseCdkRef(noLookupRoleReason(producerAccount), void 0, true);
|
|
20841
|
+
readRoleArn = ref.lookupRoleArn;
|
|
20842
|
+
const shownLookupRoleArn = displayIdent(readRoleArn, { maxCodePoints: 613 });
|
|
20843
|
+
refuseCdkRead = (error) => refuseCdkRef(`assuming the lookup role ${shownLookupRoleArn} or reading cdkd-state-${producerAccount} with it was denied: ${describeInnermostAwsError(error)}`, error);
|
|
20844
|
+
this.logger.debug(safeMsg`Fn::GetStackOutput: ${shownRoleArn} is the AWS CDK-generated cross-account reader role; reading through the producer account's lookup role ${shownLookupRoleArn}`);
|
|
20845
|
+
}
|
|
20846
|
+
const shownReadRoleArn = readRoleArn === roleArn ? shownRoleArn : displayIdent(readRoleArn, { maxCodePoints: 613 });
|
|
20847
|
+
let stateData;
|
|
20848
|
+
try {
|
|
20849
|
+
stateData = readRoleArn ? await this.getCrossAccountStackState(readRoleArn, stackName, region, context) : await this.getSameAccountStackState(stackName, region, context);
|
|
20850
|
+
} catch (error) {
|
|
20851
|
+
this.maskStateReadError(refuseCdkRead && isLookupRoleDenial(error) ? refuseCdkRead(error) : error, [[stackName, this.displayMasked(stackName, context)], [region, loggedRegion]], context);
|
|
20852
|
+
}
|
|
20853
|
+
if (!stateData) {
|
|
20854
|
+
if (!roleArn && this.cfnFallback) {
|
|
20855
|
+
const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region, context, loggedRegionText);
|
|
20856
|
+
if (cfnOutputs) {
|
|
20857
|
+
if (!Object.hasOwn(cfnOutputs, outputName)) {
|
|
20858
|
+
const available = this.describeAvailableOutputs(Object.keys(cfnOutputs), context);
|
|
20859
|
+
throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: output ${loggedOutputName} not found in CloudFormation stack ${loggedStackName} (${displayIdent(loggedRegion)}). Available outputs: ${available}`));
|
|
20860
|
+
}
|
|
20861
|
+
const value = cfnOutputs[outputName];
|
|
20862
|
+
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName} (from CloudFormation stack outputs; weak reference — producer is not cdkd-managed)`);
|
|
20863
|
+
return value;
|
|
20864
|
+
}
|
|
20865
|
+
}
|
|
20866
|
+
throw new Error(`Fn::GetStackOutput: stack ${loggedStackName} not found in region ${displayIdent(loggedRegion)}${roleArn ? ` (cross-account via ${shownReadRoleArn})` : ""}. ${!roleArn && this.cfnFallback ? "Searched cdkd state and CloudFormation stacks. Make sure the producer stack has been deployed (via cdkd or CloudFormation)." : `Make sure the producer stack has been deployed via cdkd.`}`);
|
|
20867
|
+
}
|
|
20868
|
+
if (!hasReadableOutputs(stateData.state)) throw markNonRetryable(new MalformedProducerRecordRefusalError(`Fn::GetStackOutput: the state record of producer stack ${loggedStackName} (${displayIdent(loggedRegion)}) has no readable 'outputs' map — the record is malformed or truncated. cdkd refuses to resolve from it rather than reading it as a map: 'Object.hasOwn' answers TRUE for '0' on a string and for an index on a list, so continuing would resolve ONE CHARACTER or element of the record as this reference's value and this deploy would send it to AWS. Inspect the producer's record with 'cdkd state show' --json, repair or remove it, then re-run.`));
|
|
20869
|
+
const outputs = stateData.state.outputs ?? {};
|
|
20870
|
+
if (!Object.hasOwn(outputs, outputName)) {
|
|
20871
|
+
const available = this.describeAvailableOutputs(Object.keys(outputs), context);
|
|
20872
|
+
throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::GetStackOutput: output ${loggedOutputName} not found in stack ${loggedStackName} (${displayIdent(loggedRegion)}). Available outputs: ${available}`));
|
|
20873
|
+
}
|
|
20874
|
+
const value = outputs[outputName];
|
|
20875
|
+
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${shownRoleArn}` : ""} (${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
20876
|
+
if (!roleArn) this.recordOutputRead(context, stackName, region, outputName);
|
|
20877
|
+
if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new CrossAccountSecretRefusalError(`Fn::GetStackOutput: output ${loggedOutputName} of stack ${loggedStackName} (${displayIdent(loggedRegion)}) is a redacted dynamic reference, and this is a CROSS-ACCOUNT reference (RoleArn ${shownRoleArn}${readRoleArn !== roleArn ? `, read through the producer account's CDK lookup role ${shownReadRoleArn}` : ""}). cdkd will not resolve a producer account's secret with the consumer's credentials — a same-named secret in the consumer account would answer instead. Export a non-secret value (e.g. the secret's ARN) and resolve it in the consumer stack, or reference the producer stack from within its own account.`));
|
|
20878
|
+
return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput ${quotedRender(this.displayLeaf(outputName, context), "'")} (producer ${this.displayLeaf(stackName, context)} / ${this.displayLeaf(loggedRegionText, context)})`, sourceKey, {
|
|
20879
|
+
stackName,
|
|
20880
|
+
region,
|
|
20881
|
+
outputKey: outputName,
|
|
20882
|
+
...roleArn ? { crossAccount: true } : {}
|
|
20883
|
+
}, loggedRegionText);
|
|
20884
|
+
}
|
|
20885
|
+
function recordOutputRead(context, producerStack, producerRegion, outputName) {
|
|
20886
|
+
if (!context.recordedOutputReads) return;
|
|
20887
|
+
if (context.recordedOutputReads.some((e) => e.sourceStack === producerStack && sameRegion(e.sourceRegion, producerRegion) && e.outputName === outputName)) return;
|
|
20888
|
+
context.recordedOutputReads.push({
|
|
20889
|
+
sourceStack: producerStack,
|
|
20890
|
+
sourceRegion: producerRegion,
|
|
20891
|
+
outputName
|
|
20892
|
+
});
|
|
20893
|
+
}
|
|
20894
|
+
function positionalNameMask(pairs) {
|
|
20895
|
+
const substitutions = pairs.filter(([raw, masked]) => raw !== "" && raw !== masked).flatMap(([raw, masked]) => {
|
|
20896
|
+
const shown = displaySafe(raw, { asciiOnly: true });
|
|
20897
|
+
const escaped = (text) => JSON.stringify(text).slice(1, -1);
|
|
20898
|
+
const rendered = displayStackName(raw);
|
|
20899
|
+
const escapedPair = [...shown !== "" && escaped(shown) !== shown ? [[escaped(shown), escaped(displaySafe(masked, { asciiOnly: true }))]] : [], ...rendered !== raw && rendered !== shown && rendered !== escaped(shown) ? [[rendered, displayStackName(displaySafe(masked, { asciiOnly: true }))]] : []];
|
|
20900
|
+
if (shown === raw) return [[raw, masked], ...escapedPair];
|
|
20901
|
+
const shownMask = displaySafe(masked, { asciiOnly: true });
|
|
20902
|
+
return shown === "" || shownMask === "" ? [[raw, masked]] : [
|
|
20903
|
+
[raw, masked],
|
|
20904
|
+
[shown, shownMask],
|
|
20905
|
+
...escapedPair
|
|
20906
|
+
];
|
|
20907
|
+
}).sort(([a], [b]) => b.length - a.length);
|
|
20908
|
+
if (substitutions.length === 0) return void 0;
|
|
20909
|
+
return (text) => {
|
|
20910
|
+
let out = text;
|
|
20911
|
+
for (const [raw, masked] of substitutions) out = out.split(raw).join(masked);
|
|
20912
|
+
return out;
|
|
20913
|
+
};
|
|
20914
|
+
}
|
|
20915
|
+
function maskStateReadError(error, pairs, context) {
|
|
20916
|
+
throw this.maskNamedError(error, this.positionalNameMask(pairs), context);
|
|
20917
|
+
}
|
|
20918
|
+
function maskNamedError(error, extraMask, context) {
|
|
20919
|
+
let masked = error;
|
|
20920
|
+
let positional = extraMask;
|
|
20921
|
+
const union = unionOfSecretBags([
|
|
20922
|
+
context?.inheritedSecrets,
|
|
20923
|
+
context?.recordedSecretValues,
|
|
20924
|
+
context?.printingSecrets
|
|
20925
|
+
]);
|
|
20926
|
+
if (hasMaskableValues(union)) {
|
|
20927
|
+
masked = maskSecretsInError(masked, union, positional);
|
|
20928
|
+
positional = void 0;
|
|
20929
|
+
}
|
|
20930
|
+
if (positional) masked = maskSecretsInError(masked, /* @__PURE__ */ new Map(), positional);
|
|
20931
|
+
return masked;
|
|
20932
|
+
}
|
|
20933
|
+
function namedRequestMasks(pairs, context) {
|
|
20934
|
+
const positional = this.positionalNameMask(this.explicitRegion !== void 0 && this.explicitRegionLogText !== void 0 ? [...pairs, [this.explicitRegion, this.explicitRegionLogText]] : pairs);
|
|
20935
|
+
const text = (message) => this.displayMasked(positional ? positional(message) : message, context);
|
|
20936
|
+
const line = (message) => {
|
|
20937
|
+
const indent = /^ */.exec(message)?.[0] ?? "";
|
|
20938
|
+
return indent + text(message.slice(indent.length));
|
|
20939
|
+
};
|
|
20940
|
+
return {
|
|
20941
|
+
error: (error) => this.maskNamedError(error, positional, context),
|
|
20942
|
+
text,
|
|
20943
|
+
retryLogger: {
|
|
20944
|
+
debug: (message) => this.logger.debug(line(message)),
|
|
20945
|
+
warn: (message) => this.logger.warn(line(message))
|
|
20946
|
+
}
|
|
20947
|
+
};
|
|
20948
|
+
}
|
|
20949
|
+
|
|
20383
20950
|
//#endregion
|
|
20384
20951
|
//#region src/deployment/intrinsic-resolver/stack-state.ts
|
|
20385
20952
|
async function getSameAccountStackState(stackName, region, context) {
|
|
@@ -20425,80 +20992,6 @@ async function getCrossAccountStackState(roleArn, stackName, region, context) {
|
|
|
20425
20992
|
}).getState(stackName, region);
|
|
20426
20993
|
}
|
|
20427
20994
|
|
|
20428
|
-
//#endregion
|
|
20429
|
-
//#region src/deployment/secret-region-classification.ts
|
|
20430
|
-
const REPLAY_SECRET_SERVICES = /* @__PURE__ */ new Set([
|
|
20431
|
-
"secretsmanager",
|
|
20432
|
-
"ssm",
|
|
20433
|
-
"ssm-secure"
|
|
20434
|
-
]);
|
|
20435
|
-
function secretsManagerSecretId(inner) {
|
|
20436
|
-
const afterService = inner.substring(15);
|
|
20437
|
-
let stringIdx = afterService.indexOf(":SecretString:");
|
|
20438
|
-
let binaryIdx = afterService.indexOf(":SecretBinary:");
|
|
20439
|
-
if (stringIdx < 0 && afterService.endsWith(":SecretString")) stringIdx = afterService.length - 13;
|
|
20440
|
-
if (binaryIdx < 0 && afterService.endsWith(":SecretBinary")) binaryIdx = afterService.length - 13;
|
|
20441
|
-
const delimiterIdx = stringIdx >= 0 && binaryIdx >= 0 ? Math.min(stringIdx, binaryIdx) : stringIdx >= 0 ? stringIdx : binaryIdx;
|
|
20442
|
-
return delimiterIdx >= 0 ? afterService.substring(0, delimiterIdx) : afterService;
|
|
20443
|
-
}
|
|
20444
|
-
function ssmParameterName(inner) {
|
|
20445
|
-
const serviceEnd = inner.indexOf(":");
|
|
20446
|
-
return serviceEnd < 0 ? "" : inner.substring(serviceEnd + 1);
|
|
20447
|
-
}
|
|
20448
|
-
function arnRegion(secretId) {
|
|
20449
|
-
if (!secretId.startsWith("arn:")) return void 0;
|
|
20450
|
-
const region = secretId.split(":")[3];
|
|
20451
|
-
return region ? region : void 0;
|
|
20452
|
-
}
|
|
20453
|
-
function producerRegionsFromState(state) {
|
|
20454
|
-
const seen = /* @__PURE__ */ new Set();
|
|
20455
|
-
const regions = [];
|
|
20456
|
-
for (const entry of [...state.imports ?? [], ...state.outputReads ?? []]) {
|
|
20457
|
-
const canonical = canonicalizeRegion(entry.sourceRegion);
|
|
20458
|
-
if (!canonical || seen.has(canonical)) continue;
|
|
20459
|
-
seen.add(canonical);
|
|
20460
|
-
regions.push(entry.sourceRegion);
|
|
20461
|
-
}
|
|
20462
|
-
return regions;
|
|
20463
|
-
}
|
|
20464
|
-
function secretReferenceName(expression) {
|
|
20465
|
-
const inner = expression.startsWith("{{resolve:") ? expression.slice(10, -2) : void 0;
|
|
20466
|
-
if (inner === void 0) return void 0;
|
|
20467
|
-
const service = inner.split(":")[0];
|
|
20468
|
-
if (service === void 0 || !REPLAY_SECRET_SERVICES.has(service)) return void 0;
|
|
20469
|
-
const secretName = service === "secretsmanager" ? secretsManagerSecretId(inner) : ssmParameterName(inner);
|
|
20470
|
-
return secretName ? secretName : void 0;
|
|
20471
|
-
}
|
|
20472
|
-
function regionLessSecretName(expression) {
|
|
20473
|
-
const secretName = secretReferenceName(expression);
|
|
20474
|
-
return secretName !== void 0 && arnRegion(secretName) === void 0 ? secretName : void 0;
|
|
20475
|
-
}
|
|
20476
|
-
function classifyReplaySecretRegion(expression, consumerRegion, importedProducerRegions) {
|
|
20477
|
-
const secretName = secretReferenceName(expression);
|
|
20478
|
-
if (!secretName) return { kind: "local" };
|
|
20479
|
-
const named = arnRegion(secretName);
|
|
20480
|
-
if (named !== void 0) return canonicalizeRegion(named) === canonicalizeRegion(consumerRegion) ? { kind: "local" } : {
|
|
20481
|
-
kind: "named-region",
|
|
20482
|
-
secretName,
|
|
20483
|
-
region: named
|
|
20484
|
-
};
|
|
20485
|
-
const seen = /* @__PURE__ */ new Set();
|
|
20486
|
-
const foreignProducerRegions = [];
|
|
20487
|
-
for (const candidate of importedProducerRegions ?? []) {
|
|
20488
|
-
const canonical = canonicalizeRegion(candidate);
|
|
20489
|
-
if (!canonical || canonical === canonicalizeRegion(consumerRegion)) continue;
|
|
20490
|
-
if (seen.has(canonical)) continue;
|
|
20491
|
-
seen.add(canonical);
|
|
20492
|
-
foreignProducerRegions.push(candidate);
|
|
20493
|
-
}
|
|
20494
|
-
if (foreignProducerRegions.length === 0) return { kind: "local" };
|
|
20495
|
-
return {
|
|
20496
|
-
kind: "ambiguous",
|
|
20497
|
-
secretName,
|
|
20498
|
-
foreignProducerRegions
|
|
20499
|
-
};
|
|
20500
|
-
}
|
|
20501
|
-
|
|
20502
20995
|
//#endregion
|
|
20503
20996
|
//#region src/deployment/intrinsic-resolver/dynamic-refs.ts
|
|
20504
20997
|
function secretVerdictScope(resolver) {
|
|
@@ -21754,6 +22247,7 @@ function recordInheritedParameterSecrets(parameterName, value, context) {
|
|
|
21754
22247
|
const inherited = context.inheritedSecrets;
|
|
21755
22248
|
const recorded = context.recordedSecretValues;
|
|
21756
22249
|
if (inherited && recorded) carryLogOnlyValuesCarriedBy(inherited, recorded, value);
|
|
22250
|
+
if (recorded) carryPhysicalNameCopiesCarriedBy(context, recorded, value);
|
|
21757
22251
|
if (inherited && recorded) recordInheritedNoEchoListElements(this, inherited, recorded, value, context);
|
|
21758
22252
|
if (!inherited || inherited.size === 0 || !recorded) return;
|
|
21759
22253
|
for (const [plaintext, expression] of inheritedSecretsCarriedBy(value, inherited)) {
|
|
@@ -21762,6 +22256,12 @@ function recordInheritedParameterSecrets(parameterName, value, context) {
|
|
|
21762
22256
|
carryFreshNoEchoMark(inherited, recorded, plaintext);
|
|
21763
22257
|
}
|
|
21764
22258
|
}
|
|
22259
|
+
function carryPhysicalNameCopiesCarriedBy(context, recorded, value) {
|
|
22260
|
+
const names = context.inheritedPhysicalNameCopies ?? (context.inheritedSecrets && physicalNameCopiesOf.get(context.inheritedSecrets));
|
|
22261
|
+
if (names === void 0 || names.size === 0) return;
|
|
22262
|
+
const leaves = [...wholeStringLeavesOf(value)];
|
|
22263
|
+
for (const name of names) if (leaves.some((leaf) => leaf.includes(name))) recordPhysicalNameCopy(recorded, name);
|
|
22264
|
+
}
|
|
21765
22265
|
function carriedExpressionFor(inherited, parameterName, value, plaintext, survivor) {
|
|
21766
22266
|
const own = inheritedParameterExpression(inherited, parameterName, plaintext);
|
|
21767
22267
|
if (typeof own === "string") return own;
|
|
@@ -21857,8 +22357,9 @@ function recordInheritedNoEchoListElements(resolver, inherited, recorded, value,
|
|
|
21857
22357
|
}
|
|
21858
22358
|
function recordNoEchoParameterValue(paramDef, value, context) {
|
|
21859
22359
|
const bag = context.recordedSecretValues;
|
|
21860
|
-
if (paramDef
|
|
22360
|
+
if (!declaresNoEcho(paramDef) || bag === void 0) return;
|
|
21861
22361
|
recordLogOnlyParameterValue(bag, value);
|
|
22362
|
+
if (paramDef?.NoEcho !== true) return;
|
|
21862
22363
|
recordNoEchoParameterFreshValue(value, bag, this.publicNoEchoTokens(context));
|
|
21863
22364
|
}
|
|
21864
22365
|
function refuseCoercedInheritedSecret(name, paramDef, userValue, inherited) {
|
|
@@ -21896,6 +22397,7 @@ function lookupResourceRecord(logicalId, via, context) {
|
|
|
21896
22397
|
const loggedId = this.displayMasked(logicalId, context);
|
|
21897
22398
|
throw markNonRetryable(new IntrinsicResolutionRefusalError(`${via} ${loggedId}: ${isObject ? `the state record's physical id is ${physicalId === null ? "null" : typeof physicalId}, not a string` : `the state record is ${Array.isArray(resource) ? "an array" : typeof resource}, not an object`}. cdkd always records an object with a string id, so this record was edited by hand or written by another tool. ${isObject ? `Set the resource's "physicalId" in the stack's state.json back to the id AWS knows the resource by.` : `Restore the resource's record in the stack's state.json, or remove it and re-import the resource.`}`, void 0, "STATE_PHYSICAL_ID_NOT_STRING"));
|
|
21898
22399
|
}
|
|
22400
|
+
if (context.recordedSecretValues !== void 0) recordPhysicalNameCopy(context.recordedSecretValues, physicalId);
|
|
21899
22401
|
return resource;
|
|
21900
22402
|
}
|
|
21901
22403
|
async function resolveRef(logicalId, context, onParameter) {
|
|
@@ -21904,7 +22406,7 @@ async function resolveRef(logicalId, context, onParameter) {
|
|
|
21904
22406
|
const refValue = this.resolveRefValue(logicalId, resource, context);
|
|
21905
22407
|
recordSecretNamedRead(logicalId, refValue, context);
|
|
21906
22408
|
this.logger.debug(`Resolved Ref to resource: ${this.logRender(logicalId, context)} resolved to ${this.logRender(String(refValue), context)}`);
|
|
21907
|
-
return refValue;
|
|
22409
|
+
return await this.reresolveRecordedReferences(refValue, logicalId, context, `Ref ${logicalId}`, void 0);
|
|
21908
22410
|
}
|
|
21909
22411
|
if (context.parameters && Object.hasOwn(context.parameters, logicalId)) {
|
|
21910
22412
|
const value = context.parameters[logicalId];
|
|
@@ -21914,7 +22416,7 @@ async function resolveRef(logicalId, context, onParameter) {
|
|
|
21914
22416
|
this.recordInheritedParameterSecrets(logicalId, value, context);
|
|
21915
22417
|
this.logger.debug(`Resolved Ref to parameter: ${this.logRender(logicalId, context)} resolved to ${this.logRender(stringifyParameterForLog(paramDef, this.maskValueLeaves(value, context)), context, {
|
|
21916
22418
|
structured: isStructured(value),
|
|
21917
|
-
redacted: paramDef
|
|
22419
|
+
redacted: declaresNoEcho(paramDef)
|
|
21918
22420
|
})}`);
|
|
21919
22421
|
onParameter?.();
|
|
21920
22422
|
return value;
|
|
@@ -21996,6 +22498,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
21996
22498
|
explicitRegionLogText;
|
|
21997
22499
|
strictGetAtt;
|
|
21998
22500
|
cfnFallback;
|
|
22501
|
+
producerLookup;
|
|
22502
|
+
consumerAccount;
|
|
22503
|
+
cdkCrossAccountRefVerdicts = /* @__PURE__ */ new Map();
|
|
21999
22504
|
cfnClients = /* @__PURE__ */ new Map();
|
|
22000
22505
|
cfnExportsPromises = /* @__PURE__ */ new Map();
|
|
22001
22506
|
cfnStackOutputsCache = /* @__PURE__ */ new Map();
|
|
@@ -22007,6 +22512,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
22007
22512
|
this.explicitRegion = region || void 0;
|
|
22008
22513
|
this.strictGetAtt = options?.strictGetAtt ?? false;
|
|
22009
22514
|
this.cfnFallback = options?.cfnFallback ?? true;
|
|
22515
|
+
this.producerLookup = options?.producerLookup;
|
|
22516
|
+
this.consumerAccount = options?.consumerAccount;
|
|
22010
22517
|
}
|
|
22011
22518
|
getPhysicalIdFallbackCount() {
|
|
22012
22519
|
return this.physicalIdFallbackCount;
|
|
@@ -22201,6 +22708,8 @@ IntrinsicFunctionResolver.prototype.pushRedactedAttributeRead = pushRedactedAttr
|
|
|
22201
22708
|
IntrinsicFunctionResolver.prototype.resolveGetAtt = resolveGetAtt;
|
|
22202
22709
|
IntrinsicFunctionResolver.prototype.publicNoEchoTokens = publicNoEchoTokens;
|
|
22203
22710
|
IntrinsicFunctionResolver.prototype.noteAttributeSecrecy = noteAttributeSecrecy;
|
|
22711
|
+
IntrinsicFunctionResolver.prototype.reresolveRecordedReferences = reresolveRecordedReferences;
|
|
22712
|
+
IntrinsicFunctionResolver.prototype.referencesMatchPhysicalId = referencesMatchPhysicalId;
|
|
22204
22713
|
IntrinsicFunctionResolver.prototype.rejectPlaceholderArnAttribute = rejectPlaceholderArnAttribute;
|
|
22205
22714
|
IntrinsicFunctionResolver.prototype.staleRecordRemedy = staleRecordRemedy;
|
|
22206
22715
|
IntrinsicFunctionResolver.prototype.unenrichedRemedy = unenrichedRemedy;
|
|
@@ -22344,8 +22853,7 @@ var DiffCalculator = class DiffCalculator {
|
|
|
22344
22853
|
resourceType: desiredResource.Type,
|
|
22345
22854
|
templateProperties: rawDesiredProps,
|
|
22346
22855
|
desired: desiredPropsForCompare,
|
|
22347
|
-
current: currentPropsForCompare
|
|
22348
|
-
record: currentResource
|
|
22856
|
+
current: currentPropsForCompare
|
|
22349
22857
|
});
|
|
22350
22858
|
const desiredCompared = noEchoCompared?.desired ?? desiredPropsForCompare;
|
|
22351
22859
|
const currentCompared = noEchoCompared?.current ?? currentPropsForCompare;
|
|
@@ -23028,6 +23536,511 @@ function deleteIndeterminateGuards(result) {
|
|
|
23028
23536
|
return out;
|
|
23029
23537
|
}
|
|
23030
23538
|
|
|
23539
|
+
//#endregion
|
|
23540
|
+
//#region src/deployment/inline-policy-claims.ts
|
|
23541
|
+
function isInlinePolicyClaimedByCompletedWriter(args, kind, principal, policyName) {
|
|
23542
|
+
const { selfLogicalId, writers, changes, stateResources } = args;
|
|
23543
|
+
for (const [lid, write] of writers) {
|
|
23544
|
+
if (lid === selfLogicalId || !Object.hasOwn(stateResources, lid)) continue;
|
|
23545
|
+
const record = stateResources[lid];
|
|
23546
|
+
const standalone = standaloneInlinePolicyOf(record.resourceType, record.properties);
|
|
23547
|
+
if (standalone !== void 0) {
|
|
23548
|
+
if (standalone.kind === kind && sameIamName(standalone.principal, principal) && sameIamName(standalone.policyName, policyName)) return true;
|
|
23549
|
+
continue;
|
|
23550
|
+
}
|
|
23551
|
+
if (record.provisionedBy === "cc-api") continue;
|
|
23552
|
+
const props = record.properties ?? {};
|
|
23553
|
+
if (record.resourceType === "AWS::IAM::Policy") {
|
|
23554
|
+
if (!sameIamName(record.physicalId, policyName)) continue;
|
|
23555
|
+
const listed = props[POLICY_LIST_FIELDS[kind]];
|
|
23556
|
+
if (Array.isArray(listed) && listed.some((p) => sameIamName(p, principal))) return true;
|
|
23557
|
+
continue;
|
|
23558
|
+
}
|
|
23559
|
+
if (!Object.hasOwn(PRINCIPAL_KINDS, record.resourceType)) continue;
|
|
23560
|
+
if (PRINCIPAL_KINDS[record.resourceType] !== kind) continue;
|
|
23561
|
+
if (!sameIamName(record.physicalId, principal)) continue;
|
|
23562
|
+
if (write !== "create" && !ownPoliciesChange(changes.get(lid))) continue;
|
|
23563
|
+
const policies = props["Policies"];
|
|
23564
|
+
if (!Array.isArray(policies)) continue;
|
|
23565
|
+
if (policies.some((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && sameIamName(entry["PolicyName"], policyName))) return true;
|
|
23566
|
+
}
|
|
23567
|
+
return false;
|
|
23568
|
+
}
|
|
23569
|
+
var RollbackInlinePolicyWriters = class {
|
|
23570
|
+
entries = /* @__PURE__ */ new Map();
|
|
23571
|
+
removals = /* @__PURE__ */ new Map();
|
|
23572
|
+
unsettled = /* @__PURE__ */ new Map();
|
|
23573
|
+
notePending(ops) {
|
|
23574
|
+
for (const op of ops) if (!this.unsettled.has(op)) this.unsettled.set(op, {
|
|
23575
|
+
logicalId: op.logicalId,
|
|
23576
|
+
state: "pending"
|
|
23577
|
+
});
|
|
23578
|
+
}
|
|
23579
|
+
noteOutcome(op, completed) {
|
|
23580
|
+
if (!completed) {
|
|
23581
|
+
this.unsettled.set(op, {
|
|
23582
|
+
logicalId: op.logicalId,
|
|
23583
|
+
state: "failed"
|
|
23584
|
+
});
|
|
23585
|
+
return;
|
|
23586
|
+
}
|
|
23587
|
+
for (const [key, entry] of this.unsettled) if (key === op || entry.logicalId === op.logicalId) this.unsettled.delete(key);
|
|
23588
|
+
}
|
|
23589
|
+
record(logicalId, write, record, policiesChanged, via) {
|
|
23590
|
+
if (via === "cc-api" && !isStandaloneInlinePolicyType(record.resourceType)) {
|
|
23591
|
+
this.entries.delete(logicalId);
|
|
23592
|
+
return;
|
|
23593
|
+
}
|
|
23594
|
+
this.entries.set(logicalId, {
|
|
23595
|
+
write,
|
|
23596
|
+
record,
|
|
23597
|
+
policiesChanged
|
|
23598
|
+
});
|
|
23599
|
+
}
|
|
23600
|
+
claimedFor(resourceType, logicalId, stateResources) {
|
|
23601
|
+
if (resourceType !== "AWS::IAM::Policy" && !Object.hasOwn(PRINCIPAL_KINDS, resourceType) && !isStandaloneInlinePolicyType(resourceType)) return;
|
|
23602
|
+
return (kind, principal, policyName) => {
|
|
23603
|
+
const writers = /* @__PURE__ */ new Map();
|
|
23604
|
+
const changes = /* @__PURE__ */ new Map();
|
|
23605
|
+
for (const [lid, entry] of this.entries) {
|
|
23606
|
+
if (!Object.hasOwn(stateResources, lid) || stateResources[lid] !== entry.record) continue;
|
|
23607
|
+
writers.set(lid, entry.write);
|
|
23608
|
+
if (entry.policiesChanged) changes.set(lid, {
|
|
23609
|
+
logicalId: lid,
|
|
23610
|
+
changeType: "UPDATE",
|
|
23611
|
+
resourceType: entry.record.resourceType,
|
|
23612
|
+
propertyChanges: [{
|
|
23613
|
+
path: "Policies",
|
|
23614
|
+
oldValue: void 0,
|
|
23615
|
+
newValue: void 0,
|
|
23616
|
+
requiresReplacement: false
|
|
23617
|
+
}]
|
|
23618
|
+
});
|
|
23619
|
+
}
|
|
23620
|
+
const claimed = isInlinePolicyClaimedByCompletedWriter({
|
|
23621
|
+
selfLogicalId: logicalId,
|
|
23622
|
+
writers,
|
|
23623
|
+
changes,
|
|
23624
|
+
stateResources
|
|
23625
|
+
}, kind, principal, policyName);
|
|
23626
|
+
if (!claimed) {
|
|
23627
|
+
const key = removalKey(kind, principal, policyName);
|
|
23628
|
+
const noted = this.removals.get(key) ?? {
|
|
23629
|
+
kind,
|
|
23630
|
+
principal,
|
|
23631
|
+
policyName,
|
|
23632
|
+
removers: /* @__PURE__ */ new Map()
|
|
23633
|
+
};
|
|
23634
|
+
noted.removers.set(logicalId, stateResources[logicalId]);
|
|
23635
|
+
this.removals.set(key, noted);
|
|
23636
|
+
}
|
|
23637
|
+
return claimed;
|
|
23638
|
+
};
|
|
23639
|
+
}
|
|
23640
|
+
takeHeldRemovals(stateResources) {
|
|
23641
|
+
const held = [];
|
|
23642
|
+
for (const [key, { kind, principal, policyName, removers }] of this.removals) {
|
|
23643
|
+
const { holders, unreadable } = inlinePolicyHolders(stateResources, kind, principal, policyName);
|
|
23644
|
+
const others = holders.filter((h) => !removers.has(h.logicalId) || stateResources[h.logicalId] !== removers.get(h.logicalId));
|
|
23645
|
+
if (others.length === 0) continue;
|
|
23646
|
+
this.removals.delete(key);
|
|
23647
|
+
const open = new Set([...this.unsettled.values()].map((u) => u.logicalId));
|
|
23648
|
+
const unsettled = [...new Set(others.map((h) => h.logicalId))].filter((id) => open.has(id));
|
|
23649
|
+
held.push({
|
|
23650
|
+
kind,
|
|
23651
|
+
holders: others,
|
|
23652
|
+
unreadable,
|
|
23653
|
+
unsettled
|
|
23654
|
+
});
|
|
23655
|
+
}
|
|
23656
|
+
return held;
|
|
23657
|
+
}
|
|
23658
|
+
};
|
|
23659
|
+
function inlinePolicyHolders(stateResources, kind, principal, policyName) {
|
|
23660
|
+
const holders = [];
|
|
23661
|
+
const unreadable = [];
|
|
23662
|
+
const unnamed = (v) => typeof v !== "string" || !IAM_NAME.test(v);
|
|
23663
|
+
for (const [logicalId, record] of Object.entries(stateResources)) {
|
|
23664
|
+
if (record === null || typeof record !== "object") continue;
|
|
23665
|
+
const props = record.properties ?? {};
|
|
23666
|
+
const standalone = standaloneInlinePolicyOf(record.resourceType, props);
|
|
23667
|
+
if (standalone !== void 0) {
|
|
23668
|
+
if (standalone.kind !== kind) continue;
|
|
23669
|
+
const principalMatches = sameIamName(standalone.principal, principal);
|
|
23670
|
+
const nameMatches = sameIamName(standalone.policyName, policyName);
|
|
23671
|
+
if (principalMatches && nameMatches) holders.push({
|
|
23672
|
+
logicalId,
|
|
23673
|
+
principal: standalone.principal,
|
|
23674
|
+
policyName: standalone.policyName,
|
|
23675
|
+
document: props["PolicyDocument"]
|
|
23676
|
+
});
|
|
23677
|
+
else if ((principalMatches || unnamed(standalone.principal)) && (nameMatches || unnamed(standalone.policyName))) unreadable.push(logicalId);
|
|
23678
|
+
continue;
|
|
23679
|
+
}
|
|
23680
|
+
if (record.resourceType === "AWS::IAM::Policy") {
|
|
23681
|
+
const nameMatches = sameIamName(record.physicalId, policyName);
|
|
23682
|
+
if (!nameMatches && !unnamed(record.physicalId)) continue;
|
|
23683
|
+
const listed = props[POLICY_LIST_FIELDS[kind]];
|
|
23684
|
+
const entries = Array.isArray(listed) ? listed : [];
|
|
23685
|
+
const named = entries.find((p) => sameIamName(p, principal));
|
|
23686
|
+
if (nameMatches && typeof named === "string") holders.push({
|
|
23687
|
+
logicalId,
|
|
23688
|
+
principal: named,
|
|
23689
|
+
policyName: record.physicalId,
|
|
23690
|
+
document: props["PolicyDocument"]
|
|
23691
|
+
});
|
|
23692
|
+
else if (named !== void 0 || entries.some(unnamed)) unreadable.push(logicalId);
|
|
23693
|
+
continue;
|
|
23694
|
+
}
|
|
23695
|
+
if (!Object.hasOwn(PRINCIPAL_KINDS, record.resourceType)) continue;
|
|
23696
|
+
if (PRINCIPAL_KINDS[record.resourceType] !== kind) continue;
|
|
23697
|
+
const principalMatches = sameIamName(record.physicalId, principal);
|
|
23698
|
+
if (!principalMatches && !unnamed(record.physicalId)) continue;
|
|
23699
|
+
const policies = props["Policies"];
|
|
23700
|
+
if (!Array.isArray(policies)) continue;
|
|
23701
|
+
for (const entry of policies) {
|
|
23702
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
23703
|
+
const name = entry["PolicyName"];
|
|
23704
|
+
if (principalMatches && sameIamName(name, policyName)) holders.push({
|
|
23705
|
+
logicalId,
|
|
23706
|
+
principal: record.physicalId,
|
|
23707
|
+
policyName: name,
|
|
23708
|
+
document: entry["PolicyDocument"]
|
|
23709
|
+
});
|
|
23710
|
+
else if (unnamed(name) || sameIamName(name, policyName)) unreadable.push(logicalId);
|
|
23711
|
+
}
|
|
23712
|
+
}
|
|
23713
|
+
return {
|
|
23714
|
+
holders,
|
|
23715
|
+
unreadable: [...new Set(unreadable)]
|
|
23716
|
+
};
|
|
23717
|
+
}
|
|
23718
|
+
function sameIamName(a, b) {
|
|
23719
|
+
return typeof a === "string" && IAM_NAME.test(a) && a.toLowerCase() === b.toLowerCase();
|
|
23720
|
+
}
|
|
23721
|
+
function removalKey(kind, principal, policyName) {
|
|
23722
|
+
return JSON.stringify([
|
|
23723
|
+
kind,
|
|
23724
|
+
principal.toLowerCase(),
|
|
23725
|
+
policyName.toLowerCase()
|
|
23726
|
+
]);
|
|
23727
|
+
}
|
|
23728
|
+
const IAM_NAME = /^[\w+=,.@-]+$/;
|
|
23729
|
+
const POLICY_LIST_FIELDS = {
|
|
23730
|
+
role: "Roles",
|
|
23731
|
+
group: "Groups",
|
|
23732
|
+
user: "Users"
|
|
23733
|
+
};
|
|
23734
|
+
const PRINCIPAL_KINDS = {
|
|
23735
|
+
"AWS::IAM::Role": "role",
|
|
23736
|
+
"AWS::IAM::Group": "group",
|
|
23737
|
+
"AWS::IAM::User": "user"
|
|
23738
|
+
};
|
|
23739
|
+
const STANDALONE_POLICY_KINDS = {
|
|
23740
|
+
"AWS::IAM::RolePolicy": "role",
|
|
23741
|
+
"AWS::IAM::GroupPolicy": "group",
|
|
23742
|
+
"AWS::IAM::UserPolicy": "user"
|
|
23743
|
+
};
|
|
23744
|
+
function isStandaloneInlinePolicyType(resourceType) {
|
|
23745
|
+
return Object.hasOwn(STANDALONE_POLICY_KINDS, resourceType);
|
|
23746
|
+
}
|
|
23747
|
+
function standaloneInlinePolicyOf(resourceType, properties) {
|
|
23748
|
+
if (!isStandaloneInlinePolicyType(resourceType)) return void 0;
|
|
23749
|
+
const kind = STANDALONE_POLICY_KINDS[resourceType];
|
|
23750
|
+
const props = properties ?? {};
|
|
23751
|
+
return {
|
|
23752
|
+
kind,
|
|
23753
|
+
principal: props[PRINCIPAL_NAME_FIELDS[kind]],
|
|
23754
|
+
policyName: props["PolicyName"]
|
|
23755
|
+
};
|
|
23756
|
+
}
|
|
23757
|
+
function standaloneInlinePolicyHandedOff(resourceType, properties, claimed, physicalId) {
|
|
23758
|
+
if (claimed === void 0) return false;
|
|
23759
|
+
const target = standaloneInlinePolicyOf(resourceType, properties);
|
|
23760
|
+
if (target === void 0) return false;
|
|
23761
|
+
const { kind, principal, policyName } = target;
|
|
23762
|
+
if (typeof principal !== "string" || !IAM_NAME.test(principal)) return false;
|
|
23763
|
+
if (typeof policyName !== "string" || !IAM_NAME.test(policyName)) return false;
|
|
23764
|
+
if (physicalId !== void 0 && physicalId.toLowerCase() !== `${policyName}|${principal}`.toLowerCase()) return false;
|
|
23765
|
+
return claimed(kind, principal, policyName) === true;
|
|
23766
|
+
}
|
|
23767
|
+
function isInlinePolicyPrincipalType(resourceType) {
|
|
23768
|
+
return Object.hasOwn(PRINCIPAL_KINDS, resourceType);
|
|
23769
|
+
}
|
|
23770
|
+
function principalKindOf(resourceType) {
|
|
23771
|
+
return Object.hasOwn(PRINCIPAL_KINDS, resourceType) ? PRINCIPAL_KINDS[resourceType] : void 0;
|
|
23772
|
+
}
|
|
23773
|
+
const ANY = "*";
|
|
23774
|
+
const PRINCIPAL_NAME_FIELDS = {
|
|
23775
|
+
role: "RoleName",
|
|
23776
|
+
group: "GroupName",
|
|
23777
|
+
user: "UserName"
|
|
23778
|
+
};
|
|
23779
|
+
function nameKey(value) {
|
|
23780
|
+
return typeof value === "string" && IAM_NAME.test(value) ? value.toLowerCase() : ANY;
|
|
23781
|
+
}
|
|
23782
|
+
function templatePrincipalKeys(entry, kind, templateResources, stateResources) {
|
|
23783
|
+
if (typeof entry === "string") return [nameKey(entry)];
|
|
23784
|
+
const ref = typeof entry === "object" && entry !== null && !Array.isArray(entry) ? entry["Ref"] : void 0;
|
|
23785
|
+
if (typeof ref !== "string" || !Object.hasOwn(templateResources, ref)) return [ANY];
|
|
23786
|
+
const target = templateResources[ref];
|
|
23787
|
+
if (principalKindOf(target.Type) !== kind) return [ANY];
|
|
23788
|
+
return principalSelfKeys(ref, kind, target, stateResources);
|
|
23789
|
+
}
|
|
23790
|
+
function principalSelfKeys(logicalId, kind, template, stateResources) {
|
|
23791
|
+
const keys = [`ref:${logicalId}`];
|
|
23792
|
+
const declared = template?.Properties?.[PRINCIPAL_NAME_FIELDS[kind]];
|
|
23793
|
+
const declaredKey = nameKey(declared);
|
|
23794
|
+
if (declaredKey !== ANY) keys.push(declaredKey);
|
|
23795
|
+
const record = Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
|
|
23796
|
+
if (record !== void 0 && principalKindOf(record.resourceType) === kind) {
|
|
23797
|
+
const recordedKey = nameKey(record.physicalId);
|
|
23798
|
+
if (recordedKey !== ANY) keys.push(recordedKey);
|
|
23799
|
+
}
|
|
23800
|
+
return keys;
|
|
23801
|
+
}
|
|
23802
|
+
function policiesNames(policies) {
|
|
23803
|
+
if (policies === void 0 || policies === null) return [];
|
|
23804
|
+
if (!Array.isArray(policies)) return [ANY];
|
|
23805
|
+
return policies.map((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) ? nameKey(entry["PolicyName"]) : ANY);
|
|
23806
|
+
}
|
|
23807
|
+
function standaloneClaimSides(logicalId, change, templateResources, stateResources) {
|
|
23808
|
+
const template = Object.hasOwn(templateResources, logicalId) ? templateResources[logicalId] : void 0;
|
|
23809
|
+
const desired = standaloneInlinePolicyOf(change.resourceType, template?.Properties ?? {});
|
|
23810
|
+
if (desired === void 0) return void 0;
|
|
23811
|
+
const { kind } = desired;
|
|
23812
|
+
const name = nameKey(desired.policyName);
|
|
23813
|
+
const sides = {
|
|
23814
|
+
desired: templatePrincipalKeys(desired.principal, kind, templateResources, stateResources).map((principal) => ({
|
|
23815
|
+
kind,
|
|
23816
|
+
principal,
|
|
23817
|
+
name
|
|
23818
|
+
})),
|
|
23819
|
+
old: []
|
|
23820
|
+
};
|
|
23821
|
+
const record = Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
|
|
23822
|
+
if (record?.resourceType === change.resourceType) {
|
|
23823
|
+
const old = standaloneInlinePolicyOf(change.resourceType, record.properties);
|
|
23824
|
+
sides.old.push({
|
|
23825
|
+
kind,
|
|
23826
|
+
principal: nameKey(old.principal),
|
|
23827
|
+
name: nameKey(old.policyName)
|
|
23828
|
+
});
|
|
23829
|
+
}
|
|
23830
|
+
return sides;
|
|
23831
|
+
}
|
|
23832
|
+
function inlinePolicyClaimsOf(logicalId, change, templateResources, stateResources) {
|
|
23833
|
+
const template = Object.hasOwn(templateResources, logicalId) ? templateResources[logicalId] : void 0;
|
|
23834
|
+
const record = Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
|
|
23835
|
+
const recorded = record?.resourceType === change.resourceType ? record : void 0;
|
|
23836
|
+
const claims = [];
|
|
23837
|
+
const cross = (kind, principals, names) => {
|
|
23838
|
+
for (const principal of new Set(principals)) for (const name of new Set(names)) claims.push({
|
|
23839
|
+
kind,
|
|
23840
|
+
principal,
|
|
23841
|
+
name
|
|
23842
|
+
});
|
|
23843
|
+
};
|
|
23844
|
+
const standalone = standaloneClaimSides(logicalId, change, templateResources, stateResources);
|
|
23845
|
+
if (standalone !== void 0) return [...standalone.desired, ...standalone.old];
|
|
23846
|
+
if (change.resourceType === "AWS::IAM::Policy") {
|
|
23847
|
+
const desired = template?.Properties ?? {};
|
|
23848
|
+
const old = recorded?.properties ?? {};
|
|
23849
|
+
const names = [];
|
|
23850
|
+
if (desired["PolicyName"] !== void 0) names.push(nameKey(desired["PolicyName"]));
|
|
23851
|
+
if (old["PolicyName"] !== void 0) names.push(nameKey(old["PolicyName"]));
|
|
23852
|
+
if (recorded !== void 0) names.push(nameKey(typeof recorded.physicalId === "string" ? recorded.physicalId.split(":")[0] : recorded.physicalId));
|
|
23853
|
+
if (names.length === 0) return claims;
|
|
23854
|
+
for (const kind of [
|
|
23855
|
+
"role",
|
|
23856
|
+
"group",
|
|
23857
|
+
"user"
|
|
23858
|
+
]) {
|
|
23859
|
+
const field = POLICY_LIST_FIELDS[kind];
|
|
23860
|
+
const principals = [];
|
|
23861
|
+
const listed = desired[field];
|
|
23862
|
+
if (Array.isArray(listed)) for (const entry of listed) principals.push(...templatePrincipalKeys(entry, kind, templateResources, stateResources));
|
|
23863
|
+
else if (listed !== void 0) principals.push(ANY);
|
|
23864
|
+
const held = old[field];
|
|
23865
|
+
if (Array.isArray(held)) principals.push(...held.map(nameKey));
|
|
23866
|
+
else if (held !== void 0 && held !== null) principals.push(ANY);
|
|
23867
|
+
cross(kind, principals, names);
|
|
23868
|
+
}
|
|
23869
|
+
return claims;
|
|
23870
|
+
}
|
|
23871
|
+
const kind = principalKindOf(change.resourceType);
|
|
23872
|
+
if (kind === void 0) return claims;
|
|
23873
|
+
if (!(change.changeType === "CREATE" || (change.propertyChanges ?? []).some((c) => c.requiresReplacement) || ownPoliciesChange(change))) return claims;
|
|
23874
|
+
cross(kind, principalSelfKeys(logicalId, kind, template, stateResources), [...policiesNames(template?.Properties?.["Policies"]), ...policiesNames(recorded?.properties?.["Policies"])]);
|
|
23875
|
+
return claims;
|
|
23876
|
+
}
|
|
23877
|
+
function orderInlinePolicyWriters(args) {
|
|
23878
|
+
const { writes, changes, templateResources, stateResources, dependencies, rank } = args;
|
|
23879
|
+
const writers = writes.filter((id) => {
|
|
23880
|
+
const type = changes.get(id)?.resourceType;
|
|
23881
|
+
return type === "AWS::IAM::Policy" || type !== void 0 && (isInlinePolicyPrincipalType(type) || isStandaloneInlinePolicyType(type));
|
|
23882
|
+
});
|
|
23883
|
+
if (writers.length < 2) return [];
|
|
23884
|
+
const exact = /* @__PURE__ */ new Map();
|
|
23885
|
+
const loose = [];
|
|
23886
|
+
const all = [];
|
|
23887
|
+
for (const id of writers) for (const claim of inlinePolicyClaimsOf(id, changes.get(id), templateResources, stateResources)) {
|
|
23888
|
+
all.push({
|
|
23889
|
+
id,
|
|
23890
|
+
claim
|
|
23891
|
+
});
|
|
23892
|
+
if (claim.principal === ANY || claim.name === ANY) {
|
|
23893
|
+
loose.push({
|
|
23894
|
+
id,
|
|
23895
|
+
claim
|
|
23896
|
+
});
|
|
23897
|
+
continue;
|
|
23898
|
+
}
|
|
23899
|
+
const key = JSON.stringify([
|
|
23900
|
+
claim.kind,
|
|
23901
|
+
claim.principal,
|
|
23902
|
+
claim.name
|
|
23903
|
+
]);
|
|
23904
|
+
const ids = exact.get(key) ?? /* @__PURE__ */ new Set();
|
|
23905
|
+
ids.add(id);
|
|
23906
|
+
exact.set(key, ids);
|
|
23907
|
+
}
|
|
23908
|
+
const principalRows = new Set(writers.filter((id) => isInlinePolicyPrincipalType(changes.get(id).resourceType)));
|
|
23909
|
+
const standaloneRows = new Set(writers.filter((id) => isStandaloneInlinePolicyType(changes.get(id).resourceType)));
|
|
23910
|
+
const sides = new Map([...standaloneRows].map((id) => [id, standaloneClaimSides(id, changes.get(id), templateResources, stateResources)]));
|
|
23911
|
+
const sameClaim = (p, q) => p.kind === q.kind && (p.principal === ANY || q.principal === ANY || p.principal === q.principal) && (p.name === ANY || q.name === ANY || p.name === q.name);
|
|
23912
|
+
const releasesFor = (a, b) => sides.get(a).old.some((o) => sides.get(b).desired.some((d) => sameClaim(o, d)));
|
|
23913
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
23914
|
+
const pair = (a, b) => {
|
|
23915
|
+
if (a === b || principalRows.has(a) && principalRows.has(b)) return;
|
|
23916
|
+
const sa = standaloneRows.has(a);
|
|
23917
|
+
const sb = standaloneRows.has(b);
|
|
23918
|
+
let first;
|
|
23919
|
+
if (sa !== sb) first = sa ? b : a;
|
|
23920
|
+
else if (sa && sb) {
|
|
23921
|
+
const aReleases = releasesFor(a, b);
|
|
23922
|
+
if (aReleases !== releasesFor(b, a)) first = aReleases ? a : b;
|
|
23923
|
+
}
|
|
23924
|
+
first ??= rank(a) < rank(b) || rank(a) === rank(b) && a < b ? a : b;
|
|
23925
|
+
const [x, y] = first === a ? [a, b] : [b, a];
|
|
23926
|
+
pairs.set(JSON.stringify([x, y]), [x, y]);
|
|
23927
|
+
};
|
|
23928
|
+
for (const ids of exact.values()) {
|
|
23929
|
+
const list = [...ids];
|
|
23930
|
+
for (let i = 0; i < list.length; i++) for (let j = i + 1; j < list.length; j++) pair(list[i], list[j]);
|
|
23931
|
+
}
|
|
23932
|
+
const meets = (a, b) => a === ANY || b === ANY || a === b;
|
|
23933
|
+
for (const { id, claim } of loose) for (const other of all) {
|
|
23934
|
+
if (other.claim.kind !== claim.kind) continue;
|
|
23935
|
+
if (meets(claim.principal, other.claim.principal) && meets(claim.name, other.claim.name)) pair(id, other.id);
|
|
23936
|
+
}
|
|
23937
|
+
if (pairs.size === 0) return [];
|
|
23938
|
+
const reaches = (from, to) => {
|
|
23939
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23940
|
+
const stack = [from];
|
|
23941
|
+
while (stack.length > 0) {
|
|
23942
|
+
const id = stack.pop();
|
|
23943
|
+
if (id === to) return true;
|
|
23944
|
+
if (seen.has(id)) continue;
|
|
23945
|
+
seen.add(id);
|
|
23946
|
+
for (const dep of dependencies.get(id) ?? []) stack.push(dep);
|
|
23947
|
+
}
|
|
23948
|
+
return false;
|
|
23949
|
+
};
|
|
23950
|
+
const added = [];
|
|
23951
|
+
for (const [before, after] of pairs.values()) {
|
|
23952
|
+
if (reaches(after, before) || reaches(before, after)) continue;
|
|
23953
|
+
const deps = dependencies.get(after) ?? /* @__PURE__ */ new Set();
|
|
23954
|
+
deps.add(before);
|
|
23955
|
+
dependencies.set(after, deps);
|
|
23956
|
+
added.push({
|
|
23957
|
+
before,
|
|
23958
|
+
after
|
|
23959
|
+
});
|
|
23960
|
+
}
|
|
23961
|
+
return added;
|
|
23962
|
+
}
|
|
23963
|
+
function recordInlinePolicyKeys(record) {
|
|
23964
|
+
if (record === void 0 || record === null || typeof record !== "object") return [];
|
|
23965
|
+
const props = record.properties ?? {};
|
|
23966
|
+
const keys = [];
|
|
23967
|
+
const add = (kind, principal, name) => {
|
|
23968
|
+
keys.push(JSON.stringify([
|
|
23969
|
+
kind,
|
|
23970
|
+
nameKey(principal),
|
|
23971
|
+
nameKey(name)
|
|
23972
|
+
]));
|
|
23973
|
+
};
|
|
23974
|
+
const standalone = standaloneInlinePolicyOf(record.resourceType, props);
|
|
23975
|
+
if (standalone !== void 0) {
|
|
23976
|
+
add(standalone.kind, standalone.principal, standalone.policyName);
|
|
23977
|
+
return keys;
|
|
23978
|
+
}
|
|
23979
|
+
if (record.resourceType === "AWS::IAM::Policy") {
|
|
23980
|
+
const names = [props["PolicyName"], typeof record.physicalId === "string" ? record.physicalId.split(":")[0] : record.physicalId];
|
|
23981
|
+
for (const kind of [
|
|
23982
|
+
"role",
|
|
23983
|
+
"group",
|
|
23984
|
+
"user"
|
|
23985
|
+
]) {
|
|
23986
|
+
const listed = props[POLICY_LIST_FIELDS[kind]];
|
|
23987
|
+
if (listed === void 0 || listed === null) continue;
|
|
23988
|
+
const principals = Array.isArray(listed) ? listed : [void 0];
|
|
23989
|
+
for (const p of principals) for (const n of names) add(kind, p, n);
|
|
23990
|
+
}
|
|
23991
|
+
return keys;
|
|
23992
|
+
}
|
|
23993
|
+
const kind = principalKindOf(record.resourceType);
|
|
23994
|
+
if (kind === void 0) return keys;
|
|
23995
|
+
for (const name of policiesNames(props["Policies"])) add(kind, record.physicalId, name);
|
|
23996
|
+
return keys;
|
|
23997
|
+
}
|
|
23998
|
+
function orderInlinePolicyReversals(replay, stateResources) {
|
|
23999
|
+
const current = (op) => Object.hasOwn(stateResources, op.logicalId) ? stateResources[op.logicalId] : void 0;
|
|
24000
|
+
const isStandalone = (op) => [current(op), op.previousState].some((r) => r !== void 0 && r !== null && isStandaloneInlinePolicyType(r.resourceType));
|
|
24001
|
+
if (!replay.some(isStandalone)) return [...replay];
|
|
24002
|
+
const keysOf = /* @__PURE__ */ new Map();
|
|
24003
|
+
for (const op of replay) {
|
|
24004
|
+
const keys = [...recordInlinePolicyKeys(current(op)), ...recordInlinePolicyKeys(op.previousState)];
|
|
24005
|
+
if (keys.length > 0) keysOf.set(op, new Set(keys));
|
|
24006
|
+
}
|
|
24007
|
+
if (keysOf.size < 2) return [...replay];
|
|
24008
|
+
const meets = (a, b) => a === ANY || b === ANY || a === b;
|
|
24009
|
+
const collide = (a, b) => {
|
|
24010
|
+
for (const ka of a) {
|
|
24011
|
+
const [kindA, pA, nA] = JSON.parse(ka);
|
|
24012
|
+
for (const kb of b) {
|
|
24013
|
+
const [kindB, pB, nB] = JSON.parse(kb);
|
|
24014
|
+
if (kindA === kindB && meets(pA, pB) && meets(nA, nB)) return true;
|
|
24015
|
+
}
|
|
24016
|
+
}
|
|
24017
|
+
return false;
|
|
24018
|
+
};
|
|
24019
|
+
const dependsOn = (a, b) => [current(a), a.previousState].some((r) => Array.isArray(r?.dependencies) && r.dependencies.includes(b.logicalId));
|
|
24020
|
+
const order = [...replay];
|
|
24021
|
+
for (const op of [...replay].reverse()) {
|
|
24022
|
+
if (!isStandalone(op)) continue;
|
|
24023
|
+
const mine = keysOf.get(op);
|
|
24024
|
+
if (mine === void 0) continue;
|
|
24025
|
+
const at = order.indexOf(op);
|
|
24026
|
+
let last = -1;
|
|
24027
|
+
for (let j = at + 1; j < order.length; j++) {
|
|
24028
|
+
const other = order[j];
|
|
24029
|
+
const theirs = keysOf.get(other);
|
|
24030
|
+
if (dependsOn(op, other) || dependsOn(other, op)) break;
|
|
24031
|
+
if (theirs === void 0 || isStandalone(other)) continue;
|
|
24032
|
+
if (collide(mine, theirs)) last = j;
|
|
24033
|
+
}
|
|
24034
|
+
if (last < 0) continue;
|
|
24035
|
+
order.splice(at, 1);
|
|
24036
|
+
order.splice(last, 0, op);
|
|
24037
|
+
}
|
|
24038
|
+
return order;
|
|
24039
|
+
}
|
|
24040
|
+
function ownPoliciesChange(change) {
|
|
24041
|
+
return (change?.propertyChanges ?? []).some((c) => c.path === "Policies" && c.inPlacePropagated !== true && c.replacementPropagated !== true);
|
|
24042
|
+
}
|
|
24043
|
+
|
|
23031
24044
|
//#endregion
|
|
23032
24045
|
//#region src/provisioning/json-patch-generator.ts
|
|
23033
24046
|
var JsonPatchGenerator = class {
|
|
@@ -23246,6 +24259,10 @@ const WRITABLE_GETATT_ATTRIBUTES = {
|
|
|
23246
24259
|
"AWS::MediaConvert::JobTemplate": ["Name"],
|
|
23247
24260
|
"AWS::MediaConvert::Preset": ["Name"],
|
|
23248
24261
|
"AWS::MediaConvert::Queue": ["Name"],
|
|
24262
|
+
"AWS::NetworkManager::ConnectAttachment": ["ProposedSegmentChange"],
|
|
24263
|
+
"AWS::NetworkManager::SiteToSiteVpnAttachment": ["ProposedSegmentChange"],
|
|
24264
|
+
"AWS::NetworkManager::TransitGatewayRouteTableAttachment": ["ProposedSegmentChange"],
|
|
24265
|
+
"AWS::NetworkManager::VpcAttachment": ["ProposedSegmentChange"],
|
|
23249
24266
|
"AWS::OpsWorks::Instance": ["AvailabilityZone"],
|
|
23250
24267
|
"AWS::OpsWorks::UserProfile": ["SshUsername"],
|
|
23251
24268
|
"AWS::QuickSight::Analysis": ["Errors", "Sheets"],
|
|
@@ -23290,9 +24307,24 @@ const WRITABLE_GETATT_ATTRIBUTES = {
|
|
|
23290
24307
|
"AWS::StepFunctions::Activity": ["Name"],
|
|
23291
24308
|
"AWS::Transfer::User": ["ServerId", "UserName"]
|
|
23292
24309
|
};
|
|
24310
|
+
const SHAPE_MISMATCHED_GETATT_ATTRIBUTES = {
|
|
24311
|
+
"AWS::DocDB::DBCluster": ["Port"],
|
|
24312
|
+
"AWS::Events::EventBus": ["Policy"],
|
|
24313
|
+
"AWS::MediaLive::Input": ["Destinations", "Sources"]
|
|
24314
|
+
};
|
|
23293
24315
|
|
|
23294
24316
|
//#endregion
|
|
23295
24317
|
//#region src/provisioning/read-only-properties.ts
|
|
24318
|
+
function isDefinitiveRefusal(error) {
|
|
24319
|
+
if (isThrottlingError(error)) return false;
|
|
24320
|
+
let current = error;
|
|
24321
|
+
for (let depth = 0; depth < 5 && current != null; depth++) {
|
|
24322
|
+
const status = current.$metadata?.httpStatusCode;
|
|
24323
|
+
if (status !== void 0) return status >= 400 && status < 500;
|
|
24324
|
+
current = current.cause;
|
|
24325
|
+
}
|
|
24326
|
+
return false;
|
|
24327
|
+
}
|
|
23296
24328
|
const readOnlyPropertiesCache = /* @__PURE__ */ new Map();
|
|
23297
24329
|
const attributeNamesCache = /* @__PURE__ */ new Map();
|
|
23298
24330
|
async function getTopLevelAttributeNames(resourceType) {
|
|
@@ -23306,12 +24338,24 @@ async function getTopLevelAttributeNames(resourceType) {
|
|
|
23306
24338
|
attributeNamesCache.set(resourceType, names);
|
|
23307
24339
|
return names;
|
|
23308
24340
|
}
|
|
24341
|
+
const deployAttributeNamesCache = /* @__PURE__ */ new Map();
|
|
24342
|
+
async function getTopLevelDeployAttributeNames(resourceType) {
|
|
24343
|
+
const certified = await getTopLevelAttributeNames(resourceType);
|
|
24344
|
+
if (certified === void 0) return void 0;
|
|
24345
|
+
const mismatched = Object.hasOwn(SHAPE_MISMATCHED_GETATT_ATTRIBUTES, resourceType) ? SHAPE_MISMATCHED_GETATT_ATTRIBUTES[resourceType] : void 0;
|
|
24346
|
+
if (!mismatched || mismatched.length === 0) return certified;
|
|
24347
|
+
const cached = deployAttributeNamesCache.get(resourceType);
|
|
24348
|
+
if (cached) return cached;
|
|
24349
|
+
const names = /* @__PURE__ */ new Set([...certified, ...mismatched]);
|
|
24350
|
+
deployAttributeNamesCache.set(resourceType, names);
|
|
24351
|
+
return names;
|
|
24352
|
+
}
|
|
23309
24353
|
function getTopLevelReadOnlyProperties(resourceType) {
|
|
23310
24354
|
if (hasNoRegistrySchema(resourceType)) return Promise.resolve(void 0);
|
|
23311
24355
|
const cached = readOnlyPropertiesCache.get(resourceType);
|
|
23312
24356
|
if (cached) return cached;
|
|
23313
24357
|
const entry = fetchTopLevelReadOnlyProperties(resourceType).catch((error) => {
|
|
23314
|
-
readOnlyPropertiesCache.delete(resourceType);
|
|
24358
|
+
if (!isDefinitiveRefusal(error)) readOnlyPropertiesCache.delete(resourceType);
|
|
23315
24359
|
const message = describeAwsFailure(error).detail;
|
|
23316
24360
|
getLogger().child("ReadOnlyProperties").debug(`Failed to resolve read-only properties for ${displaySafe(resourceType, { asciiOnly: true })} via cloudformation:DescribeType (${message}).`);
|
|
23317
24361
|
});
|
|
@@ -23728,10 +24772,11 @@ var CloudControlProvider = class {
|
|
|
23728
24772
|
async create(logicalId, resourceType, properties, context) {
|
|
23729
24773
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
23730
24774
|
const idLog = new IdScrubLog(this.logger, mask, holdsSecretDerivedLeaf(properties, mask));
|
|
23731
|
-
return inIdLogScope(idLog, () => this.createInIdLogScope(logicalId, resourceType, properties, idLog));
|
|
24775
|
+
return inIdLogScope(idLog, () => this.createInIdLogScope(logicalId, resourceType, properties, idLog, mask));
|
|
23732
24776
|
}
|
|
23733
|
-
async createInIdLogScope(logicalId, resourceType, properties, idLog) {
|
|
24777
|
+
async createInIdLogScope(logicalId, resourceType, properties, idLog, mask) {
|
|
23734
24778
|
this.logger.debug(`Creating resource ${logicalId} (${resourceType})`);
|
|
24779
|
+
const attributeNamesLookup = getTopLevelDeployAttributeNames(resourceType);
|
|
23735
24780
|
try {
|
|
23736
24781
|
const ccProperties = stringifyJsonProperties(resourceType, stripNullValues(properties));
|
|
23737
24782
|
const desiredState = JSON.stringify(ccProperties);
|
|
@@ -23749,7 +24794,9 @@ var CloudControlProvider = class {
|
|
|
23749
24794
|
const result = { physicalId: progressEvent.Identifier };
|
|
23750
24795
|
if (progressEvent.ResourceModel) result.attributes = this.parseResourceModel(progressEvent.ResourceModel);
|
|
23751
24796
|
result.attributes = await this.mergeSparseModelReadback(resourceType, progressEvent.Identifier, result.attributes || {});
|
|
24797
|
+
const modelKeys = Object.keys(result.attributes);
|
|
23752
24798
|
result.attributes = await this.enrichResourceAttributes(resourceType, progressEvent.Identifier, result.attributes);
|
|
24799
|
+
result.attributes = await this.maskDeployedNonAttributeKeys(result.attributes, modelKeys, resourceType, progressEvent.Identifier, attributeNamesLookup, properties, mask);
|
|
23753
24800
|
return result;
|
|
23754
24801
|
} catch (error) {
|
|
23755
24802
|
idLog.addId(identifierCarriedBy(error));
|
|
@@ -23820,6 +24867,7 @@ var CloudControlProvider = class {
|
|
|
23820
24867
|
sentNothing: true
|
|
23821
24868
|
};
|
|
23822
24869
|
}
|
|
24870
|
+
const attributeNamesLookup = getTopLevelDeployAttributeNames(resourceType);
|
|
23823
24871
|
const writeOnlyProperties = await getTopLevelWriteOnlyProperties(resourceType);
|
|
23824
24872
|
if (writeOnlyProperties.size > 0) {
|
|
23825
24873
|
const keptOnPreviousSide = getTopLevelKeysHoldingUnreadableCreateOnly(resourceType, cleanProperties);
|
|
@@ -23860,7 +24908,9 @@ var CloudControlProvider = class {
|
|
|
23860
24908
|
};
|
|
23861
24909
|
if (progressEvent.ResourceModel) result.attributes = this.parseResourceModel(progressEvent.ResourceModel, idLog);
|
|
23862
24910
|
result.attributes = await this.mergeSparseModelReadback(resourceType, physicalId, result.attributes || {}, idLog);
|
|
24911
|
+
const modelKeys = Object.keys(result.attributes);
|
|
23863
24912
|
result.attributes = await this.enrichResourceAttributes(resourceType, physicalId, result.attributes, idLog);
|
|
24913
|
+
result.attributes = await this.maskDeployedNonAttributeKeys(result.attributes, modelKeys, resourceType, physicalId, attributeNamesLookup, properties, maskerOrIdentity(context?.maskSecrets), idLog);
|
|
23864
24914
|
return result;
|
|
23865
24915
|
} catch (error) {
|
|
23866
24916
|
this.handleError(error, "UPDATE", resourceType, logicalId, physicalId);
|
|
@@ -23885,10 +24935,14 @@ var CloudControlProvider = class {
|
|
|
23885
24935
|
this.logger.debug(`Deleting resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
|
|
23886
24936
|
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);
|
|
23887
24937
|
await this.assertRecordedRegionAgainstClient("pre-delete", context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
24938
|
+
if (standaloneInlinePolicyHandedOff(resourceType, properties, context?.inlinePolicyClaimed, physicalId)) {
|
|
24939
|
+
this.logger.info(` ${logicalId}: not deleting its inline policy, which another resource of this deploy now holds under the same name`);
|
|
24940
|
+
return;
|
|
24941
|
+
}
|
|
23888
24942
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
23889
24943
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
23890
24944
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
23891
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
24945
|
+
const { ASGProvider } = await import("./asg-provider-semUK44T.js");
|
|
23892
24946
|
const delegateRegion = ambientRegion();
|
|
23893
24947
|
let asgProvider = this.asgDeleteDelegates.get(delegateRegion);
|
|
23894
24948
|
if (asgProvider === void 0) {
|
|
@@ -23994,7 +25048,7 @@ var CloudControlProvider = class {
|
|
|
23994
25048
|
const family = SDK_DELETE_FAMILIES.get(resourceType);
|
|
23995
25049
|
const cached = this.sdkDeleteDelegates.get(family);
|
|
23996
25050
|
if (cached !== void 0 && cached.region === ccRegion) return cached.provider;
|
|
23997
|
-
const provider = family === "rds" ? new (await (import("./rds-provider-
|
|
25051
|
+
const provider = family === "rds" ? new (await (import("./rds-provider-X4mc-nGw.js"))).RDSProvider({ region: ccRegion }) : new (await (import("./neptune-provider-C4A86Y7P.js"))).NeptuneProvider({ region: ccRegion });
|
|
23998
25052
|
this.sdkDeleteDelegates.set(family, {
|
|
23999
25053
|
region: ccRegion,
|
|
24000
25054
|
provider
|
|
@@ -24639,6 +25693,25 @@ var CloudControlProvider = class {
|
|
|
24639
25693
|
throw error;
|
|
24640
25694
|
}
|
|
24641
25695
|
}
|
|
25696
|
+
async maskDeployedNonAttributeKeys(attributes, modelKeys, resourceType, physicalId, attributeNamesLookup, desired, mask, log = this.logger) {
|
|
25697
|
+
const safeType = displaySafe(resourceType, { asciiOnly: true });
|
|
25698
|
+
const attributeNames = await attributeNamesLookup;
|
|
25699
|
+
if (attributeNames === void 0) {
|
|
25700
|
+
log.debug(`Could not resolve the CloudFormation schema for ${safeType}; recording its Cloud Control model unnarrowed for ${displaySafe(physicalId, { asciiOnly: true })}.`);
|
|
25701
|
+
return attributes;
|
|
25702
|
+
}
|
|
25703
|
+
const narrowed = new Set(modelKeys.filter((key) => !attributeNames.has(key) && !isLiteralDeployOnlyKey(resourceType, key, desired, mask)));
|
|
25704
|
+
if (narrowed.size === 0) return attributes;
|
|
25705
|
+
const out = Object.create(null);
|
|
25706
|
+
for (const [key, value] of Object.entries(attributes)) Object.defineProperty(out, key, {
|
|
25707
|
+
value: narrowed.has(key) ? maskLeavesDeep(value) : value,
|
|
25708
|
+
enumerable: true,
|
|
25709
|
+
writable: true,
|
|
25710
|
+
configurable: true
|
|
25711
|
+
});
|
|
25712
|
+
log.debug(`Masked ${narrowed.size} non-attribute key(s) of the ${safeType} Cloud Control model for ${displaySafe(physicalId, { asciiOnly: true })}: they are not Fn::GetAtt attributes of the type.`);
|
|
25713
|
+
return out;
|
|
25714
|
+
}
|
|
24642
25715
|
async import(input) {
|
|
24643
25716
|
if (!input.knownPhysicalId) return null;
|
|
24644
25717
|
const identifier = toCloudControlIdentifier({
|
|
@@ -24794,6 +25867,11 @@ function holdsSecretDerivedLeaf(value, mask, depth = 0) {
|
|
|
24794
25867
|
return Object.entries(value).some(([key, entry]) => isSecretDerivedValue(key, mask) || holdsSecretDerivedLeaf(entry, mask, depth + 1));
|
|
24795
25868
|
}
|
|
24796
25869
|
const IMPORT_YIELDED_NO_ATTRIBUTES_CONSEQUENCE = "Attributes the stack's state already records for this physical id are kept; without them, an Fn::GetAtt against this resource falls back to a value constructed from its physical id.";
|
|
25870
|
+
function isLiteralDeployOnlyKey(resourceType, key, desired, mask) {
|
|
25871
|
+
if (resourceType !== "AWS::SSM::Parameter" || key !== "Value") return false;
|
|
25872
|
+
const declared = desired["Value"];
|
|
25873
|
+
return typeof declared === "string" && !isSecretDerivedValue(declared, mask);
|
|
25874
|
+
}
|
|
24797
25875
|
function maskLeavesDeep(value) {
|
|
24798
25876
|
if (Array.isArray(value)) return value.map((element) => maskLeavesDeep(element));
|
|
24799
25877
|
if (value !== null && typeof value === "object") {
|
|
@@ -25152,6 +26230,7 @@ var TemplateNoEchoReresolver = class TemplateNoEchoReresolver {
|
|
|
25152
26230
|
logger = getLogger().child("NoEchoDeleteReresolution");
|
|
25153
26231
|
resolver;
|
|
25154
26232
|
parametersPromise;
|
|
26233
|
+
printingNoEchoPromise;
|
|
25155
26234
|
noEchoParameters;
|
|
25156
26235
|
options;
|
|
25157
26236
|
constructor(options) {
|
|
@@ -25161,7 +26240,7 @@ var TemplateNoEchoReresolver = class TemplateNoEchoReresolver {
|
|
|
25161
26240
|
const section = options.template.Parameters;
|
|
25162
26241
|
if (section !== null && typeof section === "object") for (const [name, definition] of Object.entries(section)) {
|
|
25163
26242
|
const noEcho = definition?.NoEcho;
|
|
25164
|
-
if (noEcho
|
|
26243
|
+
if (isNoEchoDeclared(noEcho)) declared.add(name);
|
|
25165
26244
|
}
|
|
25166
26245
|
for (const name of options.inheritedNoEchoParameters ?? []) declared.add(name);
|
|
25167
26246
|
this.noEchoParameters = declared;
|
|
@@ -25213,6 +26292,33 @@ var TemplateNoEchoReresolver = class TemplateNoEchoReresolver {
|
|
|
25213
26292
|
for (const name of this.noEchoParameters) if (parameters !== void 0 && Object.hasOwn(parameters, name)) recordLogOnlyParameterValue(bag, parameters[name]);
|
|
25214
26293
|
return bag;
|
|
25215
26294
|
}
|
|
26295
|
+
printingNoEchoValues() {
|
|
26296
|
+
this.printingNoEchoPromise ??= this.printingNeedles().then((bag) => hasMaskableValues(bag) ? bag : void 0);
|
|
26297
|
+
return this.printingNoEchoPromise;
|
|
26298
|
+
}
|
|
26299
|
+
async printingNeedles() {
|
|
26300
|
+
const bag = this.newBag();
|
|
26301
|
+
if (this.options.printingSeed !== void 0) carryLogOnlyValues(this.options.printingSeed, bag);
|
|
26302
|
+
if (this.noEchoParameters.size === 0) return bag;
|
|
26303
|
+
const parameters = await this.boundParameters();
|
|
26304
|
+
const section = this.options.template.Parameters ?? {};
|
|
26305
|
+
const supplied = this.options.parameters;
|
|
26306
|
+
for (const name of this.noEchoParameters) {
|
|
26307
|
+
if (parameters !== void 0) {
|
|
26308
|
+
if (Object.hasOwn(parameters, name)) recordLogOnlyParameterValue(bag, parameters[name]);
|
|
26309
|
+
continue;
|
|
26310
|
+
}
|
|
26311
|
+
if (supplied !== void 0 && Object.hasOwn(supplied, name)) {
|
|
26312
|
+
const value = supplied[name];
|
|
26313
|
+
if (!this.options.maskedParameters?.has(name)) recordLogOnlyParameterValue(bag, value);
|
|
26314
|
+
continue;
|
|
26315
|
+
}
|
|
26316
|
+
const definition = Object.hasOwn(section, name) ? section[name] : void 0;
|
|
26317
|
+
if (typeof definition?.Type === "string" && definition.Type.startsWith("AWS::SSM::")) continue;
|
|
26318
|
+
if (definition?.Default !== void 0) recordLogOnlyParameterValue(bag, definition.Default);
|
|
26319
|
+
}
|
|
26320
|
+
return bag;
|
|
26321
|
+
}
|
|
25216
26322
|
async valuesFor(logicalId, record) {
|
|
25217
26323
|
const masked = maskedNoEchoCoordinates(record.properties, noEchoLeavesOf(record));
|
|
25218
26324
|
if (masked.length === 0) return void 0;
|
|
@@ -25287,8 +26393,10 @@ var TemplateNoEchoReresolver = class TemplateNoEchoReresolver {
|
|
|
25287
26393
|
const parameters0 = await this.boundParameters();
|
|
25288
26394
|
const rowTemplate = this.options.template.Resources?.[logicalId];
|
|
25289
26395
|
const passedClasses = parameters0 === void 0 ? void 0 : await classifyPassedParameters(rowTemplate?.Properties?.Parameters, this.inputSources(parameters0)).catch(() => void 0);
|
|
26396
|
+
const printingSeed = await this.printingNoEchoValues().catch(() => void 0);
|
|
25290
26397
|
return new TemplateNoEchoReresolver({
|
|
25291
26398
|
...passedClasses !== void 0 && { passedClasses },
|
|
26399
|
+
...printingSeed !== void 0 && { printingSeed },
|
|
25292
26400
|
template: child.template,
|
|
25293
26401
|
stackName: childStackName,
|
|
25294
26402
|
region: this.options.region,
|
|
@@ -28627,449 +29735,108 @@ var CreateTokenLedger = class {
|
|
|
28627
29735
|
}
|
|
28628
29736
|
});
|
|
28629
29737
|
}
|
|
28630
|
-
noteStateSaved(stackName, region) {
|
|
28631
|
-
if (this.stack === void 0 || this.stack.stackName !== stackName || this.stack.region !== region) return Promise.resolve();
|
|
28632
|
-
this.stateRecorded = true;
|
|
28633
|
-
if (this.stateRecordedPersisted) return Promise.resolve();
|
|
28634
|
-
return this.serialized(async () => {
|
|
28635
|
-
if (this.stateRecordedPersisted) return;
|
|
28636
|
-
try {
|
|
28637
|
-
const doc = await this.current();
|
|
28638
|
-
if (doc === null || doc.stateRecorded === true) {
|
|
28639
|
-
this.stateRecordedPersisted = true;
|
|
28640
|
-
return;
|
|
28641
|
-
}
|
|
28642
|
-
await this.persist(doc);
|
|
28643
|
-
} catch (error) {
|
|
28644
|
-
this.stale = true;
|
|
28645
|
-
this.logger.warn(safeMsg`Could not mark this stack's create-token ledger as recorded (${describeAwsFailure(error).summary}); the next state save tries again.`);
|
|
28646
|
-
}
|
|
28647
|
-
});
|
|
28648
|
-
}
|
|
28649
|
-
};
|
|
28650
|
-
function ledgerForStack(backend, stackName, region) {
|
|
28651
|
-
return new CreateTokenLedger({
|
|
28652
|
-
load: () => backend.loadCreateTokenLedger(stackName, region),
|
|
28653
|
-
save: (doc) => backend.saveCreateTokenLedger(stackName, region, doc)
|
|
28654
|
-
}, {
|
|
28655
|
-
stackName,
|
|
28656
|
-
region
|
|
28657
|
-
});
|
|
28658
|
-
}
|
|
28659
|
-
const ledgerStore = new AsyncLocalStorage();
|
|
28660
|
-
const ADOPTING_CREATE_BASE = "adopt-by-name:";
|
|
28661
|
-
async function recordedAdoptingCreates() {
|
|
28662
|
-
const ledger = ledgerStore.getStore();
|
|
28663
|
-
if (ledger === void 0) return void 0;
|
|
28664
|
-
const out = /* @__PURE__ */ new Map();
|
|
28665
|
-
for (const [logicalId, entry] of Object.entries(await ledger.sentEntries())) if (entry.base.startsWith("adopt-by-name:")) out.set(logicalId, {
|
|
28666
|
-
resourceType: entry.base.slice(14),
|
|
28667
|
-
name: entry.token,
|
|
28668
|
-
firstSentAt: entry.firstSentAt,
|
|
28669
|
-
...entry.failedAt !== void 0 && { failedAt: entry.failedAt }
|
|
28670
|
-
});
|
|
28671
|
-
return out;
|
|
28672
|
-
}
|
|
28673
|
-
async function recordAdoptingCreates(creates) {
|
|
28674
|
-
const ledger = ledgerStore.getStore();
|
|
28675
|
-
if (ledger === void 0 || creates.length === 0) return;
|
|
28676
|
-
await ledger.recordSent(creates.map((c) => ({
|
|
28677
|
-
logicalId: c.logicalId,
|
|
28678
|
-
base: `${ADOPTING_CREATE_BASE}${c.resourceType}`,
|
|
28679
|
-
token: c.name
|
|
28680
|
-
})), Date.now());
|
|
28681
|
-
}
|
|
28682
|
-
async function noteAbandonedRun(at) {
|
|
28683
|
-
const ledger = ledgerStore.getStore();
|
|
28684
|
-
if (ledger === void 0) return true;
|
|
28685
|
-
return ledger.noteAbandoned(at).then(() => true, () => false);
|
|
28686
|
-
}
|
|
28687
|
-
async function ledgerAbandonedAt() {
|
|
28688
|
-
return ledgerStore.getStore()?.abandonedAt();
|
|
28689
|
-
}
|
|
28690
|
-
async function settleAdoptingCreates(drop, failedAt = /* @__PURE__ */ new Map()) {
|
|
28691
|
-
await ledgerStore.getStore()?.settleAdoptingCreates(drop, failedAt);
|
|
28692
|
-
}
|
|
28693
|
-
function withCreateTokenLedger(ledger, fn) {
|
|
28694
|
-
return ledgerStore.run(ledger, () => withStateSavedObserver((stackName, region) => ledger.noteStateSaved(stackName, region), fn));
|
|
28695
|
-
}
|
|
28696
|
-
function noteDeployStateRecord(exists) {
|
|
28697
|
-
ledgerStore.getStore()?.beginDeploy(exists);
|
|
28698
|
-
}
|
|
28699
|
-
function earliestDefined(...times) {
|
|
28700
|
-
const defined = times.filter((t) => t !== void 0);
|
|
28701
|
-
return defined.length === 0 ? void 0 : Math.min(...defined);
|
|
28702
|
-
}
|
|
28703
|
-
async function forgetRecordedCreateTokens(logicalIds) {
|
|
28704
|
-
await ledgerStore.getStore()?.forget(logicalIds);
|
|
28705
|
-
}
|
|
28706
|
-
const LEDGER_TOKEN_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
28707
|
-
"AWS::EFS::FileSystem",
|
|
28708
|
-
"AWS::FSx::FileSystem",
|
|
28709
|
-
"AWS::CloudFront::CloudFrontOriginAccessIdentity"
|
|
28710
|
-
]);
|
|
28711
|
-
async function noteRetainedResource(resourceType, logicalId) {
|
|
28712
|
-
if (!LEDGER_TOKEN_RESOURCE_TYPES.has(resourceType)) return;
|
|
28713
|
-
await ledgerStore.getStore()?.rotate(logicalId);
|
|
28714
|
-
}
|
|
28715
|
-
async function reserveStackCreateToken(options) {
|
|
28716
|
-
const base = stackScopedCreateToken(options);
|
|
28717
|
-
const ledger = ledgerStore.getStore();
|
|
28718
|
-
if (ledger === void 0) return {
|
|
28719
|
-
value: base,
|
|
28720
|
-
base,
|
|
28721
|
-
earlierFirstSentAt: void 0,
|
|
28722
|
-
ledgerStartedThisDeploy: false
|
|
28723
|
-
};
|
|
28724
|
-
const derive = (nonce) => stackScopedCreateToken({
|
|
28725
|
-
...options,
|
|
28726
|
-
immutableInputs: [...options.immutableInputs, { createTokenNonce: nonce }]
|
|
28727
|
-
});
|
|
28728
|
-
return {
|
|
28729
|
-
...await ledger.reserve(options.logicalId, base, derive, Date.now()),
|
|
28730
|
-
base
|
|
28731
|
-
};
|
|
28732
|
-
}
|
|
28733
|
-
|
|
28734
|
-
//#endregion
|
|
28735
|
-
//#region src/deployment/inline-policy-claims.ts
|
|
28736
|
-
function isInlinePolicyClaimedByCompletedWriter(args, kind, principal, policyName) {
|
|
28737
|
-
const { selfLogicalId, writers, changes, stateResources } = args;
|
|
28738
|
-
for (const [lid, write] of writers) {
|
|
28739
|
-
if (lid === selfLogicalId || !Object.hasOwn(stateResources, lid)) continue;
|
|
28740
|
-
const record = stateResources[lid];
|
|
28741
|
-
if (record.provisionedBy === "cc-api") continue;
|
|
28742
|
-
const props = record.properties ?? {};
|
|
28743
|
-
if (record.resourceType === "AWS::IAM::Policy") {
|
|
28744
|
-
if (!sameIamName(record.physicalId, policyName)) continue;
|
|
28745
|
-
const listed = props[POLICY_LIST_FIELDS[kind]];
|
|
28746
|
-
if (Array.isArray(listed) && listed.some((p) => sameIamName(p, principal))) return true;
|
|
28747
|
-
continue;
|
|
28748
|
-
}
|
|
28749
|
-
if (!Object.hasOwn(PRINCIPAL_KINDS, record.resourceType)) continue;
|
|
28750
|
-
if (PRINCIPAL_KINDS[record.resourceType] !== kind) continue;
|
|
28751
|
-
if (!sameIamName(record.physicalId, principal)) continue;
|
|
28752
|
-
if (write !== "create" && !ownPoliciesChange(changes.get(lid))) continue;
|
|
28753
|
-
const policies = props["Policies"];
|
|
28754
|
-
if (!Array.isArray(policies)) continue;
|
|
28755
|
-
if (policies.some((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && sameIamName(entry["PolicyName"], policyName))) return true;
|
|
28756
|
-
}
|
|
28757
|
-
return false;
|
|
28758
|
-
}
|
|
28759
|
-
var RollbackInlinePolicyWriters = class {
|
|
28760
|
-
entries = /* @__PURE__ */ new Map();
|
|
28761
|
-
removals = /* @__PURE__ */ new Map();
|
|
28762
|
-
unsettled = /* @__PURE__ */ new Map();
|
|
28763
|
-
notePending(ops) {
|
|
28764
|
-
for (const op of ops) if (!this.unsettled.has(op)) this.unsettled.set(op, {
|
|
28765
|
-
logicalId: op.logicalId,
|
|
28766
|
-
state: "pending"
|
|
28767
|
-
});
|
|
28768
|
-
}
|
|
28769
|
-
noteOutcome(op, completed) {
|
|
28770
|
-
if (!completed) {
|
|
28771
|
-
this.unsettled.set(op, {
|
|
28772
|
-
logicalId: op.logicalId,
|
|
28773
|
-
state: "failed"
|
|
28774
|
-
});
|
|
28775
|
-
return;
|
|
28776
|
-
}
|
|
28777
|
-
for (const [key, entry] of this.unsettled) if (key === op || entry.logicalId === op.logicalId) this.unsettled.delete(key);
|
|
28778
|
-
}
|
|
28779
|
-
record(logicalId, write, record, policiesChanged, via) {
|
|
28780
|
-
if (via === "cc-api") {
|
|
28781
|
-
this.entries.delete(logicalId);
|
|
28782
|
-
return;
|
|
28783
|
-
}
|
|
28784
|
-
this.entries.set(logicalId, {
|
|
28785
|
-
write,
|
|
28786
|
-
record,
|
|
28787
|
-
policiesChanged
|
|
28788
|
-
});
|
|
28789
|
-
}
|
|
28790
|
-
claimedFor(resourceType, logicalId, stateResources) {
|
|
28791
|
-
if (resourceType !== "AWS::IAM::Policy" && !Object.hasOwn(PRINCIPAL_KINDS, resourceType)) return;
|
|
28792
|
-
return (kind, principal, policyName) => {
|
|
28793
|
-
const writers = /* @__PURE__ */ new Map();
|
|
28794
|
-
const changes = /* @__PURE__ */ new Map();
|
|
28795
|
-
for (const [lid, entry] of this.entries) {
|
|
28796
|
-
if (!Object.hasOwn(stateResources, lid) || stateResources[lid] !== entry.record) continue;
|
|
28797
|
-
writers.set(lid, entry.write);
|
|
28798
|
-
if (entry.policiesChanged) changes.set(lid, {
|
|
28799
|
-
logicalId: lid,
|
|
28800
|
-
changeType: "UPDATE",
|
|
28801
|
-
resourceType: entry.record.resourceType,
|
|
28802
|
-
propertyChanges: [{
|
|
28803
|
-
path: "Policies",
|
|
28804
|
-
oldValue: void 0,
|
|
28805
|
-
newValue: void 0,
|
|
28806
|
-
requiresReplacement: false
|
|
28807
|
-
}]
|
|
28808
|
-
});
|
|
28809
|
-
}
|
|
28810
|
-
const claimed = isInlinePolicyClaimedByCompletedWriter({
|
|
28811
|
-
selfLogicalId: logicalId,
|
|
28812
|
-
writers,
|
|
28813
|
-
changes,
|
|
28814
|
-
stateResources
|
|
28815
|
-
}, kind, principal, policyName);
|
|
28816
|
-
if (!claimed) {
|
|
28817
|
-
const key = removalKey(kind, principal, policyName);
|
|
28818
|
-
const noted = this.removals.get(key) ?? {
|
|
28819
|
-
kind,
|
|
28820
|
-
principal,
|
|
28821
|
-
policyName,
|
|
28822
|
-
removers: /* @__PURE__ */ new Map()
|
|
28823
|
-
};
|
|
28824
|
-
noted.removers.set(logicalId, stateResources[logicalId]);
|
|
28825
|
-
this.removals.set(key, noted);
|
|
28826
|
-
}
|
|
28827
|
-
return claimed;
|
|
28828
|
-
};
|
|
28829
|
-
}
|
|
28830
|
-
takeHeldRemovals(stateResources) {
|
|
28831
|
-
const held = [];
|
|
28832
|
-
for (const [key, { kind, principal, policyName, removers }] of this.removals) {
|
|
28833
|
-
const { holders, unreadable } = inlinePolicyHolders(stateResources, kind, principal, policyName);
|
|
28834
|
-
const others = holders.filter((h) => !removers.has(h.logicalId) || stateResources[h.logicalId] !== removers.get(h.logicalId));
|
|
28835
|
-
if (others.length === 0) continue;
|
|
28836
|
-
this.removals.delete(key);
|
|
28837
|
-
const open = new Set([...this.unsettled.values()].map((u) => u.logicalId));
|
|
28838
|
-
const unsettled = [...new Set(others.map((h) => h.logicalId))].filter((id) => open.has(id));
|
|
28839
|
-
held.push({
|
|
28840
|
-
kind,
|
|
28841
|
-
holders: others,
|
|
28842
|
-
unreadable,
|
|
28843
|
-
unsettled
|
|
28844
|
-
});
|
|
28845
|
-
}
|
|
28846
|
-
return held;
|
|
28847
|
-
}
|
|
28848
|
-
};
|
|
28849
|
-
function inlinePolicyHolders(stateResources, kind, principal, policyName) {
|
|
28850
|
-
const holders = [];
|
|
28851
|
-
const unreadable = [];
|
|
28852
|
-
const unnamed = (v) => typeof v !== "string" || !IAM_NAME.test(v);
|
|
28853
|
-
for (const [logicalId, record] of Object.entries(stateResources)) {
|
|
28854
|
-
if (record === null || typeof record !== "object") continue;
|
|
28855
|
-
const props = record.properties ?? {};
|
|
28856
|
-
if (record.resourceType === "AWS::IAM::Policy") {
|
|
28857
|
-
const nameMatches = sameIamName(record.physicalId, policyName);
|
|
28858
|
-
if (!nameMatches && !unnamed(record.physicalId)) continue;
|
|
28859
|
-
const listed = props[POLICY_LIST_FIELDS[kind]];
|
|
28860
|
-
const entries = Array.isArray(listed) ? listed : [];
|
|
28861
|
-
const named = entries.find((p) => sameIamName(p, principal));
|
|
28862
|
-
if (nameMatches && typeof named === "string") holders.push({
|
|
28863
|
-
logicalId,
|
|
28864
|
-
principal: named,
|
|
28865
|
-
policyName: record.physicalId,
|
|
28866
|
-
document: props["PolicyDocument"]
|
|
28867
|
-
});
|
|
28868
|
-
else if (named !== void 0 || entries.some(unnamed)) unreadable.push(logicalId);
|
|
28869
|
-
continue;
|
|
28870
|
-
}
|
|
28871
|
-
if (!Object.hasOwn(PRINCIPAL_KINDS, record.resourceType)) continue;
|
|
28872
|
-
if (PRINCIPAL_KINDS[record.resourceType] !== kind) continue;
|
|
28873
|
-
const principalMatches = sameIamName(record.physicalId, principal);
|
|
28874
|
-
if (!principalMatches && !unnamed(record.physicalId)) continue;
|
|
28875
|
-
const policies = props["Policies"];
|
|
28876
|
-
if (!Array.isArray(policies)) continue;
|
|
28877
|
-
for (const entry of policies) {
|
|
28878
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
28879
|
-
const name = entry["PolicyName"];
|
|
28880
|
-
if (principalMatches && sameIamName(name, policyName)) holders.push({
|
|
28881
|
-
logicalId,
|
|
28882
|
-
principal: record.physicalId,
|
|
28883
|
-
policyName: name,
|
|
28884
|
-
document: entry["PolicyDocument"]
|
|
28885
|
-
});
|
|
28886
|
-
else if (unnamed(name) || sameIamName(name, policyName)) unreadable.push(logicalId);
|
|
28887
|
-
}
|
|
28888
|
-
}
|
|
28889
|
-
return {
|
|
28890
|
-
holders,
|
|
28891
|
-
unreadable: [...new Set(unreadable)]
|
|
28892
|
-
};
|
|
29738
|
+
noteStateSaved(stackName, region) {
|
|
29739
|
+
if (this.stack === void 0 || this.stack.stackName !== stackName || this.stack.region !== region) return Promise.resolve();
|
|
29740
|
+
this.stateRecorded = true;
|
|
29741
|
+
if (this.stateRecordedPersisted) return Promise.resolve();
|
|
29742
|
+
return this.serialized(async () => {
|
|
29743
|
+
if (this.stateRecordedPersisted) return;
|
|
29744
|
+
try {
|
|
29745
|
+
const doc = await this.current();
|
|
29746
|
+
if (doc === null || doc.stateRecorded === true) {
|
|
29747
|
+
this.stateRecordedPersisted = true;
|
|
29748
|
+
return;
|
|
29749
|
+
}
|
|
29750
|
+
await this.persist(doc);
|
|
29751
|
+
} catch (error) {
|
|
29752
|
+
this.stale = true;
|
|
29753
|
+
this.logger.warn(safeMsg`Could not mark this stack's create-token ledger as recorded (${describeAwsFailure(error).summary}); the next state save tries again.`);
|
|
29754
|
+
}
|
|
29755
|
+
});
|
|
29756
|
+
}
|
|
29757
|
+
};
|
|
29758
|
+
function ledgerForStack(backend, stackName, region) {
|
|
29759
|
+
return new CreateTokenLedger({
|
|
29760
|
+
load: () => backend.loadCreateTokenLedger(stackName, region),
|
|
29761
|
+
save: (doc) => backend.saveCreateTokenLedger(stackName, region, doc)
|
|
29762
|
+
}, {
|
|
29763
|
+
stackName,
|
|
29764
|
+
region
|
|
29765
|
+
});
|
|
28893
29766
|
}
|
|
28894
|
-
|
|
28895
|
-
|
|
29767
|
+
const ledgerStore = new AsyncLocalStorage();
|
|
29768
|
+
const ADOPTING_CREATE_BASE = "adopt-by-name:";
|
|
29769
|
+
async function recordedAdoptingCreates() {
|
|
29770
|
+
const ledger = ledgerStore.getStore();
|
|
29771
|
+
if (ledger === void 0) return void 0;
|
|
29772
|
+
const out = /* @__PURE__ */ new Map();
|
|
29773
|
+
for (const [logicalId, entry] of Object.entries(await ledger.sentEntries())) if (entry.base.startsWith("adopt-by-name:")) out.set(logicalId, {
|
|
29774
|
+
resourceType: entry.base.slice(14),
|
|
29775
|
+
name: entry.token,
|
|
29776
|
+
firstSentAt: entry.firstSentAt,
|
|
29777
|
+
...entry.failedAt !== void 0 && { failedAt: entry.failedAt }
|
|
29778
|
+
});
|
|
29779
|
+
return out;
|
|
28896
29780
|
}
|
|
28897
|
-
function
|
|
28898
|
-
|
|
28899
|
-
|
|
28900
|
-
|
|
28901
|
-
|
|
28902
|
-
|
|
29781
|
+
async function recordAdoptingCreates(creates) {
|
|
29782
|
+
const ledger = ledgerStore.getStore();
|
|
29783
|
+
if (ledger === void 0 || creates.length === 0) return;
|
|
29784
|
+
await ledger.recordSent(creates.map((c) => ({
|
|
29785
|
+
logicalId: c.logicalId,
|
|
29786
|
+
base: `${ADOPTING_CREATE_BASE}${c.resourceType}`,
|
|
29787
|
+
token: c.name
|
|
29788
|
+
})), Date.now());
|
|
28903
29789
|
}
|
|
28904
|
-
|
|
28905
|
-
const
|
|
28906
|
-
|
|
28907
|
-
|
|
28908
|
-
user: "Users"
|
|
28909
|
-
};
|
|
28910
|
-
const PRINCIPAL_KINDS = {
|
|
28911
|
-
"AWS::IAM::Role": "role",
|
|
28912
|
-
"AWS::IAM::Group": "group",
|
|
28913
|
-
"AWS::IAM::User": "user"
|
|
28914
|
-
};
|
|
28915
|
-
function isInlinePolicyPrincipalType(resourceType) {
|
|
28916
|
-
return Object.hasOwn(PRINCIPAL_KINDS, resourceType);
|
|
29790
|
+
async function noteAbandonedRun(at) {
|
|
29791
|
+
const ledger = ledgerStore.getStore();
|
|
29792
|
+
if (ledger === void 0) return true;
|
|
29793
|
+
return ledger.noteAbandoned(at).then(() => true, () => false);
|
|
28917
29794
|
}
|
|
28918
|
-
function
|
|
28919
|
-
return
|
|
29795
|
+
async function ledgerAbandonedAt() {
|
|
29796
|
+
return ledgerStore.getStore()?.abandonedAt();
|
|
28920
29797
|
}
|
|
28921
|
-
|
|
28922
|
-
|
|
28923
|
-
role: "RoleName",
|
|
28924
|
-
group: "GroupName",
|
|
28925
|
-
user: "UserName"
|
|
28926
|
-
};
|
|
28927
|
-
function nameKey(value) {
|
|
28928
|
-
return typeof value === "string" && IAM_NAME.test(value) ? value.toLowerCase() : ANY;
|
|
29798
|
+
async function settleAdoptingCreates(drop, failedAt = /* @__PURE__ */ new Map()) {
|
|
29799
|
+
await ledgerStore.getStore()?.settleAdoptingCreates(drop, failedAt);
|
|
28929
29800
|
}
|
|
28930
|
-
function
|
|
28931
|
-
|
|
28932
|
-
const ref = typeof entry === "object" && entry !== null && !Array.isArray(entry) ? entry["Ref"] : void 0;
|
|
28933
|
-
if (typeof ref !== "string" || !Object.hasOwn(templateResources, ref)) return [ANY];
|
|
28934
|
-
const target = templateResources[ref];
|
|
28935
|
-
if (principalKindOf(target.Type) !== kind) return [ANY];
|
|
28936
|
-
return principalSelfKeys(ref, kind, target, stateResources);
|
|
29801
|
+
function withCreateTokenLedger(ledger, fn) {
|
|
29802
|
+
return ledgerStore.run(ledger, () => withStateSavedObserver((stackName, region) => ledger.noteStateSaved(stackName, region), fn));
|
|
28937
29803
|
}
|
|
28938
|
-
function
|
|
28939
|
-
|
|
28940
|
-
const declared = template?.Properties?.[PRINCIPAL_NAME_FIELDS[kind]];
|
|
28941
|
-
const declaredKey = nameKey(declared);
|
|
28942
|
-
if (declaredKey !== ANY) keys.push(declaredKey);
|
|
28943
|
-
const record = Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
|
|
28944
|
-
if (record !== void 0 && principalKindOf(record.resourceType) === kind) {
|
|
28945
|
-
const recordedKey = nameKey(record.physicalId);
|
|
28946
|
-
if (recordedKey !== ANY) keys.push(recordedKey);
|
|
28947
|
-
}
|
|
28948
|
-
return keys;
|
|
29804
|
+
function noteDeployStateRecord(exists) {
|
|
29805
|
+
ledgerStore.getStore()?.beginDeploy(exists);
|
|
28949
29806
|
}
|
|
28950
|
-
function
|
|
28951
|
-
|
|
28952
|
-
|
|
28953
|
-
return policies.map((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) ? nameKey(entry["PolicyName"]) : ANY);
|
|
29807
|
+
function earliestDefined(...times) {
|
|
29808
|
+
const defined = times.filter((t) => t !== void 0);
|
|
29809
|
+
return defined.length === 0 ? void 0 : Math.min(...defined);
|
|
28954
29810
|
}
|
|
28955
|
-
function
|
|
28956
|
-
|
|
28957
|
-
const record = Object.hasOwn(stateResources, logicalId) ? stateResources[logicalId] : void 0;
|
|
28958
|
-
const recorded = record?.resourceType === change.resourceType ? record : void 0;
|
|
28959
|
-
const claims = [];
|
|
28960
|
-
const cross = (kind, principals, names) => {
|
|
28961
|
-
for (const principal of new Set(principals)) for (const name of new Set(names)) claims.push({
|
|
28962
|
-
kind,
|
|
28963
|
-
principal,
|
|
28964
|
-
name
|
|
28965
|
-
});
|
|
28966
|
-
};
|
|
28967
|
-
if (change.resourceType === "AWS::IAM::Policy") {
|
|
28968
|
-
const desired = template?.Properties ?? {};
|
|
28969
|
-
const old = recorded?.properties ?? {};
|
|
28970
|
-
const names = [];
|
|
28971
|
-
if (desired["PolicyName"] !== void 0) names.push(nameKey(desired["PolicyName"]));
|
|
28972
|
-
if (old["PolicyName"] !== void 0) names.push(nameKey(old["PolicyName"]));
|
|
28973
|
-
if (recorded !== void 0) names.push(nameKey(typeof recorded.physicalId === "string" ? recorded.physicalId.split(":")[0] : recorded.physicalId));
|
|
28974
|
-
if (names.length === 0) return claims;
|
|
28975
|
-
for (const kind of [
|
|
28976
|
-
"role",
|
|
28977
|
-
"group",
|
|
28978
|
-
"user"
|
|
28979
|
-
]) {
|
|
28980
|
-
const field = POLICY_LIST_FIELDS[kind];
|
|
28981
|
-
const principals = [];
|
|
28982
|
-
const listed = desired[field];
|
|
28983
|
-
if (Array.isArray(listed)) for (const entry of listed) principals.push(...templatePrincipalKeys(entry, kind, templateResources, stateResources));
|
|
28984
|
-
else if (listed !== void 0) principals.push(ANY);
|
|
28985
|
-
const held = old[field];
|
|
28986
|
-
if (Array.isArray(held)) principals.push(...held.map(nameKey));
|
|
28987
|
-
else if (held !== void 0 && held !== null) principals.push(ANY);
|
|
28988
|
-
cross(kind, principals, names);
|
|
28989
|
-
}
|
|
28990
|
-
return claims;
|
|
28991
|
-
}
|
|
28992
|
-
const kind = principalKindOf(change.resourceType);
|
|
28993
|
-
if (kind === void 0) return claims;
|
|
28994
|
-
if (!(change.changeType === "CREATE" || (change.propertyChanges ?? []).some((c) => c.requiresReplacement) || ownPoliciesChange(change))) return claims;
|
|
28995
|
-
cross(kind, principalSelfKeys(logicalId, kind, template, stateResources), [...policiesNames(template?.Properties?.["Policies"]), ...policiesNames(recorded?.properties?.["Policies"])]);
|
|
28996
|
-
return claims;
|
|
29811
|
+
async function forgetRecordedCreateTokens(logicalIds) {
|
|
29812
|
+
await ledgerStore.getStore()?.forget(logicalIds);
|
|
28997
29813
|
}
|
|
28998
|
-
|
|
28999
|
-
|
|
29000
|
-
|
|
29001
|
-
|
|
29002
|
-
|
|
29003
|
-
|
|
29004
|
-
if (
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
id,
|
|
29016
|
-
claim
|
|
29017
|
-
});
|
|
29018
|
-
continue;
|
|
29019
|
-
}
|
|
29020
|
-
const key = JSON.stringify([
|
|
29021
|
-
claim.kind,
|
|
29022
|
-
claim.principal,
|
|
29023
|
-
claim.name
|
|
29024
|
-
]);
|
|
29025
|
-
const ids = exact.get(key) ?? /* @__PURE__ */ new Set();
|
|
29026
|
-
ids.add(id);
|
|
29027
|
-
exact.set(key, ids);
|
|
29028
|
-
}
|
|
29029
|
-
const principalRows = new Set(writers.filter((id) => isInlinePolicyPrincipalType(changes.get(id).resourceType)));
|
|
29030
|
-
const pairs = /* @__PURE__ */ new Map();
|
|
29031
|
-
const pair = (a, b) => {
|
|
29032
|
-
if (a === b || principalRows.has(a) && principalRows.has(b)) return;
|
|
29033
|
-
const [x, y] = rank(a) < rank(b) || rank(a) === rank(b) && a < b ? [a, b] : [b, a];
|
|
29034
|
-
pairs.set(JSON.stringify([x, y]), [x, y]);
|
|
29814
|
+
const LEDGER_TOKEN_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
29815
|
+
"AWS::EFS::FileSystem",
|
|
29816
|
+
"AWS::FSx::FileSystem",
|
|
29817
|
+
"AWS::CloudFront::CloudFrontOriginAccessIdentity"
|
|
29818
|
+
]);
|
|
29819
|
+
async function noteRetainedResource(resourceType, logicalId) {
|
|
29820
|
+
if (!LEDGER_TOKEN_RESOURCE_TYPES.has(resourceType)) return;
|
|
29821
|
+
await ledgerStore.getStore()?.rotate(logicalId);
|
|
29822
|
+
}
|
|
29823
|
+
async function reserveStackCreateToken(options) {
|
|
29824
|
+
const base = stackScopedCreateToken(options);
|
|
29825
|
+
const ledger = ledgerStore.getStore();
|
|
29826
|
+
if (ledger === void 0) return {
|
|
29827
|
+
value: base,
|
|
29828
|
+
base,
|
|
29829
|
+
earlierFirstSentAt: void 0,
|
|
29830
|
+
ledgerStartedThisDeploy: false
|
|
29035
29831
|
};
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
}
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
if (meets(claim.principal, other.claim.principal) && meets(claim.name, other.claim.name)) pair(id, other.id);
|
|
29044
|
-
}
|
|
29045
|
-
if (pairs.size === 0) return [];
|
|
29046
|
-
const reaches = (from, to) => {
|
|
29047
|
-
const seen = /* @__PURE__ */ new Set();
|
|
29048
|
-
const stack = [from];
|
|
29049
|
-
while (stack.length > 0) {
|
|
29050
|
-
const id = stack.pop();
|
|
29051
|
-
if (id === to) return true;
|
|
29052
|
-
if (seen.has(id)) continue;
|
|
29053
|
-
seen.add(id);
|
|
29054
|
-
for (const dep of dependencies.get(id) ?? []) stack.push(dep);
|
|
29055
|
-
}
|
|
29056
|
-
return false;
|
|
29832
|
+
const derive = (nonce) => stackScopedCreateToken({
|
|
29833
|
+
...options,
|
|
29834
|
+
immutableInputs: [...options.immutableInputs, { createTokenNonce: nonce }]
|
|
29835
|
+
});
|
|
29836
|
+
return {
|
|
29837
|
+
...await ledger.reserve(options.logicalId, base, derive, Date.now()),
|
|
29838
|
+
base
|
|
29057
29839
|
};
|
|
29058
|
-
const added = [];
|
|
29059
|
-
for (const [before, after] of pairs.values()) {
|
|
29060
|
-
if (reaches(after, before) || reaches(before, after)) continue;
|
|
29061
|
-
const deps = dependencies.get(after) ?? /* @__PURE__ */ new Set();
|
|
29062
|
-
deps.add(before);
|
|
29063
|
-
dependencies.set(after, deps);
|
|
29064
|
-
added.push({
|
|
29065
|
-
before,
|
|
29066
|
-
after
|
|
29067
|
-
});
|
|
29068
|
-
}
|
|
29069
|
-
return added;
|
|
29070
|
-
}
|
|
29071
|
-
function ownPoliciesChange(change) {
|
|
29072
|
-
return (change?.propertyChanges ?? []).some((c) => c.path === "Policies" && c.inPlacePropagated !== true && c.replacementPropagated !== true);
|
|
29073
29840
|
}
|
|
29074
29841
|
|
|
29075
29842
|
//#endregion
|
|
@@ -29993,14 +30760,43 @@ function secretNamedRecordNeedles(resources, secrets, bag = /* @__PURE__ */ new
|
|
|
29993
30760
|
return bag;
|
|
29994
30761
|
}
|
|
29995
30762
|
function secretNamePrintingBag(logicalId, resources) {
|
|
29996
|
-
|
|
29997
|
-
|
|
29998
|
-
|
|
29999
|
-
|
|
30000
|
-
|
|
30763
|
+
return secretNamePrintingBags(resources, void 0)(logicalId);
|
|
30764
|
+
}
|
|
30765
|
+
function secretNamePrintingBags(resources, noEchoValues) {
|
|
30766
|
+
const secrets = noEchoValues !== void 0 && hasMaskableValues(noEchoValues) ? noEchoValues : void 0;
|
|
30767
|
+
const judged = /* @__PURE__ */ new Map();
|
|
30768
|
+
const needlesOf = (logicalId, record) => {
|
|
30769
|
+
const hit = judged.get(logicalId);
|
|
30770
|
+
if (hit !== void 0 && hit.record === record) return hit.needles;
|
|
30771
|
+
const needles = secretNameNeedlesOf(logicalId, record, secrets, { embedded: void 0 });
|
|
30772
|
+
judged.set(logicalId, {
|
|
30773
|
+
record,
|
|
30774
|
+
needles
|
|
30775
|
+
});
|
|
30776
|
+
return needles;
|
|
30777
|
+
};
|
|
30778
|
+
return (logicalId) => {
|
|
30779
|
+
const bag = /* @__PURE__ */ new Map();
|
|
30780
|
+
if (secrets !== void 0) carryLogOnlyValues(secrets, bag);
|
|
30781
|
+
const record = Object.hasOwn(resources, logicalId) ? resources[logicalId] : void 0;
|
|
30782
|
+
for (const needle of needlesOf(logicalId, record) ?? []) recordLogOnlyValue(bag, needle);
|
|
30783
|
+
const leaves = [...wholeStringLeavesOf(record?.properties)].filter((leaf) => leaf !== "");
|
|
30784
|
+
if (leaves.length === 0) return bag;
|
|
30785
|
+
for (const [otherId, other] of Object.entries(resources)) {
|
|
30786
|
+
if (otherId === logicalId) continue;
|
|
30787
|
+
for (const needle of needlesOf(otherId, other) ?? []) if (leavesHoldNeedle(leaves, needle)) recordLogOnlyValue(bag, needle);
|
|
30788
|
+
}
|
|
30789
|
+
return bag;
|
|
30790
|
+
};
|
|
30001
30791
|
}
|
|
30002
|
-
function journaledOrphanPrintingBag(ops, stateResources) {
|
|
30792
|
+
function journaledOrphanPrintingBag(ops, stateResources, noEchoValues) {
|
|
30003
30793
|
const bag = /* @__PURE__ */ new Map();
|
|
30794
|
+
const secrets = noEchoValues !== void 0 && hasMaskableValues(noEchoValues) ? noEchoValues : void 0;
|
|
30795
|
+
if (secrets !== void 0) carryLogOnlyValues(secrets, bag);
|
|
30796
|
+
const judge = {
|
|
30797
|
+
secrets,
|
|
30798
|
+
embedded: void 0
|
|
30799
|
+
};
|
|
30004
30800
|
for (const op of ops) {
|
|
30005
30801
|
const record = {
|
|
30006
30802
|
resourceType: op.resourceType,
|
|
@@ -30009,9 +30805,9 @@ function journaledOrphanPrintingBag(ops, stateResources) {
|
|
|
30009
30805
|
};
|
|
30010
30806
|
const replaced = Object.hasOwn(stateResources, op.logicalId) ? stateResources[op.logicalId] : void 0;
|
|
30011
30807
|
for (const needle of [
|
|
30012
|
-
...secretNameNeedlesOf(op.logicalId, record,
|
|
30013
|
-
...secretNameNeedlesOf(op.logicalId, replaced,
|
|
30014
|
-
...secretNamesReadBy(op.logicalId, record, stateResources)
|
|
30808
|
+
...secretNameNeedlesOf(op.logicalId, record, secrets, judge) ?? [],
|
|
30809
|
+
...secretNameNeedlesOf(op.logicalId, replaced, secrets, judge) ?? [],
|
|
30810
|
+
...secretNamesReadBy(op.logicalId, record, stateResources, () => judge)
|
|
30015
30811
|
]) recordLogOnlyValue(bag, needle);
|
|
30016
30812
|
}
|
|
30017
30813
|
return bag;
|
|
@@ -30031,13 +30827,15 @@ function completedReplayEntries(ops) {
|
|
|
30031
30827
|
attemptedProperties: op.previousState.properties
|
|
30032
30828
|
}]]);
|
|
30033
30829
|
}
|
|
30034
|
-
function orphanRecordsPrintingBag(records) {
|
|
30830
|
+
function orphanRecordsPrintingBag(records, noEchoValues) {
|
|
30035
30831
|
const bag = /* @__PURE__ */ new Map();
|
|
30832
|
+
const secrets = noEchoValues !== void 0 && hasMaskableValues(noEchoValues) ? noEchoValues : void 0;
|
|
30833
|
+
if (secrets !== void 0) carryLogOnlyValues(secrets, bag);
|
|
30036
30834
|
for (const entry of records) {
|
|
30037
30835
|
if (entry === null || typeof entry !== "object") continue;
|
|
30038
30836
|
const { logicalId, state } = entry;
|
|
30039
30837
|
if (typeof logicalId !== "string" || state === null || typeof state !== "object") continue;
|
|
30040
|
-
for (const needle of secretNameNeedlesOf(logicalId, state, void 0) ?? []) recordLogOnlyValue(bag, needle);
|
|
30838
|
+
for (const needle of secretNameNeedlesOf(logicalId, state, secrets, { embedded: void 0 }) ?? []) recordLogOnlyValue(bag, needle);
|
|
30041
30839
|
}
|
|
30042
30840
|
return bag;
|
|
30043
30841
|
}
|
|
@@ -30147,7 +30945,7 @@ function withNoEchoDefaultsMasked(parameters) {
|
|
|
30147
30945
|
const masked = Object.create(null);
|
|
30148
30946
|
for (const [name, decl] of Object.entries(parameters)) {
|
|
30149
30947
|
const body = decl;
|
|
30150
|
-
masked[name] = typeof body === "object" && body !== null && body
|
|
30948
|
+
masked[name] = typeof body === "object" && body !== null && declaresNoEcho(body) && "Default" in body ? {
|
|
30151
30949
|
...body,
|
|
30152
30950
|
Default: NO_ECHO_DEFAULT_MASK
|
|
30153
30951
|
} : decl;
|
|
@@ -30359,7 +31157,7 @@ function noEchoParameterValueSeed(parameters, values, inherited, userParameters)
|
|
|
30359
31157
|
if (values === void 0) return seed;
|
|
30360
31158
|
for (const [name, value] of Object.entries(values)) {
|
|
30361
31159
|
if (isWholeDynamicReferenceValue(value)) continue;
|
|
30362
|
-
if (parameters
|
|
31160
|
+
if (parameters !== void 0 && declaresNoEcho(parameters[name])) {
|
|
30363
31161
|
const type = parameters[name]?.Type;
|
|
30364
31162
|
const ssmTyped = typeof type === "string" && type.startsWith("AWS::SSM::Parameter::Value<");
|
|
30365
31163
|
const spelled = Object.prototype.hasOwnProperty.call(userParameters ?? {}, name) ? userParameters?.[name] : parameters[name]?.Default;
|
|
@@ -31147,13 +31945,52 @@ async function resolveLeafByRegion(leaf, propertyPath, logicalId, execCtx, resol
|
|
|
31147
31945
|
}
|
|
31148
31946
|
return out + leaf.slice(cursor);
|
|
31149
31947
|
}
|
|
31150
|
-
function redactRollbackRecord(record, secrets, journaledProps) {
|
|
31948
|
+
function redactRollbackRecord(record, secrets, journaledProps, journaledAttributes) {
|
|
31151
31949
|
if (secrets.size === 0) return record;
|
|
31152
31950
|
const positioned = journaledProps === void 0 ? record : {
|
|
31153
31951
|
...record,
|
|
31154
31952
|
properties: redactSecretsForState(record.properties, secrets, journaledProps, STATE_DERIVED_RULES)
|
|
31155
31953
|
};
|
|
31156
|
-
return scrubResourceRecord(positioned, secrets)
|
|
31954
|
+
return keepPersistedPlainRecordLeaves(scrubResourceRecord(positioned, secrets), record, {
|
|
31955
|
+
properties: journaledProps,
|
|
31956
|
+
attributes: journaledAttributes
|
|
31957
|
+
});
|
|
31958
|
+
}
|
|
31959
|
+
function keepPersistedPlainRecordLeaves(scrubbed, raw, persisted) {
|
|
31960
|
+
const properties = keepPersistedPlainLeaves(scrubbed.properties, raw.properties, persisted.properties);
|
|
31961
|
+
const attributes = scrubbed.attributes === void 0 ? void 0 : keepPersistedPlainLeaves(scrubbed.attributes, raw.attributes, persisted.attributes);
|
|
31962
|
+
if (properties === scrubbed.properties && attributes === scrubbed.attributes) return scrubbed;
|
|
31963
|
+
return {
|
|
31964
|
+
...scrubbed,
|
|
31965
|
+
properties,
|
|
31966
|
+
...attributes !== void 0 && { attributes }
|
|
31967
|
+
};
|
|
31968
|
+
}
|
|
31969
|
+
function keepPersistedPlainLeaves(redacted, raw, persisted) {
|
|
31970
|
+
if (typeof raw === "string") return typeof persisted === "string" && raw === persisted && redacted !== "***" && dynamicReferenceTokens(persisted).length === 0 ? persisted : redacted;
|
|
31971
|
+
if (Array.isArray(raw)) {
|
|
31972
|
+
if (!Array.isArray(persisted) || !Array.isArray(redacted)) return redacted;
|
|
31973
|
+
if (redacted.length !== raw.length) return redacted;
|
|
31974
|
+
let out;
|
|
31975
|
+
for (let i = 0; i < redacted.length; i++) {
|
|
31976
|
+
const kept = keepPersistedPlainLeaves(redacted[i], raw[i], persisted[i]);
|
|
31977
|
+
if (kept !== redacted[i]) (out ??= [...redacted])[i] = kept;
|
|
31978
|
+
}
|
|
31979
|
+
return out ?? redacted;
|
|
31980
|
+
}
|
|
31981
|
+
if (!isPlainRecord$1(raw) || !isPlainRecord$1(persisted) || !isPlainRecord$1(redacted)) return redacted;
|
|
31982
|
+
let out;
|
|
31983
|
+
for (const key of Object.keys(redacted)) {
|
|
31984
|
+
if (!hasOwnKey(raw, key) || !hasOwnKey(persisted, key)) continue;
|
|
31985
|
+
const kept = keepPersistedPlainLeaves(redacted[key], raw[key], persisted[key]);
|
|
31986
|
+
if (kept === redacted[key]) continue;
|
|
31987
|
+
out ??= { ...redacted };
|
|
31988
|
+
out[key] = kept;
|
|
31989
|
+
}
|
|
31990
|
+
return out ?? redacted;
|
|
31991
|
+
}
|
|
31992
|
+
function isPlainRecord$1(value) {
|
|
31993
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && hasPlainPrototype$1(value);
|
|
31157
31994
|
}
|
|
31158
31995
|
|
|
31159
31996
|
//#endregion
|
|
@@ -32207,7 +33044,7 @@ async function replayRevert(s) {
|
|
|
32207
33044
|
}
|
|
32208
33045
|
], op.logicalId, logger, isInterrupted, secrets, mask));
|
|
32209
33046
|
if (revertResult) recordNoEchoAttributeValues(revertResult, secrets, desiredProps);
|
|
32210
|
-
stateResources[op.logicalId] = maskRestoredNoEchoRecord(redactRollbackRecord(recordAfterRollbackUpdate(previousState, revertResult), secrets, previousState.properties), previousState, noEcho.substituted);
|
|
33047
|
+
stateResources[op.logicalId] = maskRestoredNoEchoRecord(redactRollbackRecord(recordAfterRollbackUpdate(previousState, revertResult), secrets, previousState.properties, previousState.attributes), previousState, noEcho.substituted);
|
|
32211
33048
|
if (updatePartialReason(revertResult) === void 0) inlinePolicyWriters.record(op.logicalId, "update", stateResources[op.logicalId], !deepEqual$1(previousState.properties?.["Policies"], current.properties?.["Policies"]), revertVia);
|
|
32212
33049
|
const rollbackPartial = updatePartialReason(revertResult);
|
|
32213
33050
|
if (rollbackPartial !== void 0) logger.warn(mask(` Rollback: ${safe(op.logicalId)} restored, ${updatePartialMessage(rollbackPartial)}`));
|
|
@@ -32406,7 +33243,7 @@ async function replayReverseReplacement(s) {
|
|
|
32406
33243
|
physicalId: createResult.physicalId,
|
|
32407
33244
|
attributes: createResult.attributes ?? {},
|
|
32408
33245
|
properties: recordedPropertiesAfterReplayCreate(prevRecord, createResult)
|
|
32409
|
-
}, secrets, prevRecord.properties);
|
|
33246
|
+
}, secrets, prevRecord.properties, prevRecord.attributes);
|
|
32410
33247
|
if (!adoptedLiveNewResource) inlinePolicyWriters.record(op.logicalId, "create", stateResources[op.logicalId], false, createProvisionedBy);
|
|
32411
33248
|
await afterOp?.(op.logicalId);
|
|
32412
33249
|
let survivorReason;
|
|
@@ -32577,12 +33414,12 @@ async function replayRollbackUnbound(operations, stateResources, stackName, ctx,
|
|
|
32577
33414
|
inlinePolicyWriters.notePending(operations);
|
|
32578
33415
|
markDeleteFirstBlocked(operations, options.failedOperations);
|
|
32579
33416
|
const { createOps, otherOps } = partitionOps(operations);
|
|
32580
|
-
for (
|
|
33417
|
+
for (const op of orderInlinePolicyReversals([...otherOps].reverse(), stateResources)) {
|
|
32581
33418
|
if (options.isInterrupted?.()) {
|
|
32582
33419
|
result.interrupted = true;
|
|
32583
33420
|
break;
|
|
32584
33421
|
}
|
|
32585
|
-
await replaySingle(
|
|
33422
|
+
await replaySingle(op, stateResources, stackName, ctx, resolver, orphanLogicalIds, result, options.onOrphan, inlinePolicyWriters, options.afterOp, options.isInterrupted);
|
|
32586
33423
|
}
|
|
32587
33424
|
if (!result.interrupted && createOps.length > 0) {
|
|
32588
33425
|
const sorted = sortRollbackCreates(createOps, stateResources);
|
|
@@ -32966,7 +33803,7 @@ async function replayFailedOperationsUnbound(failedOps, stateResources, stackNam
|
|
|
32966
33803
|
}
|
|
32967
33804
|
], op.logicalId, logger, options.isInterrupted, secrets, mask));
|
|
32968
33805
|
if (revertFailedResult) recordNoEchoAttributeValues(revertFailedResult, secrets, desiredProps);
|
|
32969
|
-
stateResources[op.logicalId] = maskRestoredNoEchoRecord(redactRollbackRecord(recordAfterRollbackUpdate(prev, revertFailedResult), secrets, prev.properties), prev, noEcho.substituted);
|
|
33806
|
+
stateResources[op.logicalId] = maskRestoredNoEchoRecord(redactRollbackRecord(recordAfterRollbackUpdate(prev, revertFailedResult), secrets, prev.properties, prev.attributes), prev, noEcho.substituted);
|
|
32970
33807
|
if (updatePartialReason(revertFailedResult) === void 0) inlinePolicyWriters.record(op.logicalId, "update", stateResources[op.logicalId], !deepEqual$1(prev.properties?.["Policies"], (op.attemptedProperties ?? current.properties)?.["Policies"]), revertVia);
|
|
32971
33808
|
const revertFailedPartial = updatePartialReason(revertFailedResult);
|
|
32972
33809
|
if (revertFailedPartial !== void 0) logger.warn(mask(` Rollback: ${safe(op.logicalId)} reverted, ${updatePartialMessage(revertFailedPartial)}`));
|
|
@@ -33124,7 +33961,7 @@ async function deleteJournaledOrphans(orphans, stateResources, stackName, ctx, o
|
|
|
33124
33961
|
const inlinePolicyWriters = new RollbackInlinePolicyWriters();
|
|
33125
33962
|
const failedIds = total.failedLogicalIds;
|
|
33126
33963
|
const record = ctx.recordEvent;
|
|
33127
|
-
const printing = journaledOrphanPrintingBag(orphans.segments.flatMap(({ ops, companions }) => [...companions ?? [], ...ops]), stateResources);
|
|
33964
|
+
const printing = journaledOrphanPrintingBag(orphans.segments.flatMap(({ ops, companions }) => [...companions ?? [], ...ops]), stateResources, options.noEchoValues);
|
|
33128
33965
|
const maskedCtx = record === void 0 ? ctx : {
|
|
33129
33966
|
...ctx,
|
|
33130
33967
|
recordEvent: (event) => record(maskEventTextWithBoundBags(event))
|
|
@@ -33936,11 +34773,14 @@ function redactOperationsForJournal(operations) {
|
|
|
33936
34773
|
if (next.attemptedProperties) next.attemptedProperties = byPosition(redactSecretsForState(markSameGenerationBag({ ...next.attemptedProperties }), ownSecrets, templateProps));
|
|
33937
34774
|
if (next.previousState) {
|
|
33938
34775
|
const previous = next.previousState;
|
|
33939
|
-
|
|
34776
|
+
const adopted = adoptedOrphanRecords.get(this);
|
|
34777
|
+
const loaded = adopted?.has(op.logicalId) ? adopted.get(op.logicalId) : previous;
|
|
34778
|
+
next.previousState = this.applyNoEchoPersist(op.logicalId, previous, keepPersistedPlainRecordLeaves(scrubResourceRecord(previous, ownSecrets, void 0, STATE_SOURCED_READBACK_RULES), previous, loaded ?? {}), void 0, {}, void 0, true);
|
|
33940
34779
|
}
|
|
33941
34780
|
return next;
|
|
33942
34781
|
});
|
|
33943
34782
|
}
|
|
34783
|
+
const adoptedOrphanRecords = /* @__PURE__ */ new WeakMap();
|
|
33944
34784
|
async function adoptRollbackOrphans(currentState, effectiveTemplate) {
|
|
33945
34785
|
const records = currentState.orphans ?? [];
|
|
33946
34786
|
const named = orphanRecordsPrintingBag(records);
|
|
@@ -33967,8 +34807,11 @@ async function adoptRollbackOrphans(currentState, effectiveTemplate) {
|
|
|
33967
34807
|
logger: { debug: (m) => this.logger.debug(m) }
|
|
33968
34808
|
}));
|
|
33969
34809
|
for (const notice of plan.notices) this.logger.info(maskSecretsInText(notice, named));
|
|
34810
|
+
const adoptedFrom = /* @__PURE__ */ new Map();
|
|
34811
|
+
adoptedOrphanRecords.set(this, adoptedFrom);
|
|
33970
34812
|
if (plan.refusals.length > 0) throw new Error(`Deploy refused — cdkd left ${plan.refusals.length} resource(s) in AWS that it cannot safely re-adopt:\n ${plan.refusals.map((r) => maskSecretsInText(r, named)).join("\n ")}`);
|
|
33971
34813
|
for (const [logicalId, record] of Object.entries(plan.adopted)) {
|
|
34814
|
+
adoptedFrom.set(logicalId, records.findLast((r) => r.logicalId === logicalId)?.state);
|
|
33972
34815
|
currentState.resources[logicalId] = record;
|
|
33973
34816
|
this.logger.info(`Adopting ${displayIdent(logicalId)} (${displayIdent(record.resourceType)}) left in AWS by an earlier rollback as ${displaySafe(maskSecretsInText(record.physicalId, named))}`);
|
|
33974
34817
|
}
|
|
@@ -34582,6 +35425,20 @@ async function drainObservedCaptures(stateResources) {
|
|
|
34582
35425
|
}
|
|
34583
35426
|
return installed;
|
|
34584
35427
|
}
|
|
35428
|
+
const STANDALONE_SIBLING = {
|
|
35429
|
+
Roles: {
|
|
35430
|
+
type: "AWS::IAM::RolePolicy",
|
|
35431
|
+
field: "RoleName"
|
|
35432
|
+
},
|
|
35433
|
+
Users: {
|
|
35434
|
+
type: "AWS::IAM::UserPolicy",
|
|
35435
|
+
field: "UserName"
|
|
35436
|
+
},
|
|
35437
|
+
Groups: {
|
|
35438
|
+
type: "AWS::IAM::GroupPolicy",
|
|
35439
|
+
field: "GroupName"
|
|
35440
|
+
}
|
|
35441
|
+
};
|
|
34585
35442
|
async function buildObservedCaptureSiblings(resourceType, capturedLogicalId, capturedPhysicalId, template, stateResources, stackName, parameterValues, conditions) {
|
|
34586
35443
|
if (this.options.captureObservedState !== true) return void 0;
|
|
34587
35444
|
const attachmentField = resourceType === "AWS::IAM::Role" ? "Roles" : resourceType === "AWS::IAM::User" ? "Users" : resourceType === "AWS::IAM::Group" ? "Groups" : void 0;
|
|
@@ -34591,11 +35448,12 @@ async function buildObservedCaptureSiblings(resourceType, capturedLogicalId, cap
|
|
|
34591
35448
|
let resolverContext;
|
|
34592
35449
|
const isRefTo = (value, logicalId) => typeof value === "object" && value !== null && !Array.isArray(value) && value["Ref"] === logicalId;
|
|
34593
35450
|
const siblings = {};
|
|
35451
|
+
const standaloneType = STANDALONE_SIBLING[attachmentField];
|
|
34594
35452
|
for (const [lid, res] of Object.entries(resources)) {
|
|
34595
35453
|
if (lid === capturedLogicalId) continue;
|
|
34596
|
-
if (res.Type !== "AWS::IAM::Policy") continue;
|
|
35454
|
+
if (res.Type !== "AWS::IAM::Policy" && res.Type !== standaloneType.type) continue;
|
|
34597
35455
|
const props = res.Properties ?? {};
|
|
34598
|
-
const attachments = props[attachmentField];
|
|
35456
|
+
const attachments = res.Type === "AWS::IAM::Policy" ? props[attachmentField] : [props[standaloneType.field]];
|
|
34599
35457
|
if (!Array.isArray(attachments)) continue;
|
|
34600
35458
|
if (!attachments.some((a) => isRefTo(a, capturedLogicalId) || a === capturedPhysicalId)) continue;
|
|
34601
35459
|
let policyName = props["PolicyName"];
|
|
@@ -34808,9 +35666,9 @@ function deepEqualValue(a, b) {
|
|
|
34808
35666
|
function diffLogMasker(diffSecrets, template, parameterValues, resources) {
|
|
34809
35667
|
const inherited = this.options.inheritedSecrets;
|
|
34810
35668
|
const noEchoValues = /* @__PURE__ */ new Map();
|
|
34811
|
-
const noEchoNames = new Set(Object.entries(template.Parameters ?? {}).filter(([, definition]) => definition
|
|
35669
|
+
const noEchoNames = new Set(Object.entries(template.Parameters ?? {}).filter(([, definition]) => declaresNoEcho(definition)).map(([name]) => name));
|
|
34812
35670
|
const splitDelimiters = literalSplitDelimitersOf(template, noEchoNames);
|
|
34813
|
-
for (const [name, definition] of Object.entries(template.Parameters ?? {})) if (definition
|
|
35671
|
+
for (const [name, definition] of Object.entries(template.Parameters ?? {})) if (declaresNoEcho(definition) && Object.hasOwn(parameterValues, name)) recordLogOnlyParameterValue(noEchoValues, parameterValues[name], splitDelimiters);
|
|
34814
35672
|
const stateNames = /* @__PURE__ */ new Map();
|
|
34815
35673
|
const union = createUnionSecretMasker([
|
|
34816
35674
|
diffSecrets,
|
|
@@ -34907,7 +35765,7 @@ function refuseRedactedAttributeReads(logicalId, resourceType, context) {
|
|
|
34907
35765
|
const producers = [...new Set(reads.map((read) => read.logicalId).filter((id) => !!id))];
|
|
34908
35766
|
throw new ProvisioningError(`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: ${producers.map((id) => displayIdent(id)).join(", ")} declared ${reads.length === 1 ? "that attribute" : "those attributes"} NoEcho, so cdkd's recorded state holds only the redaction mask for ${reads.length === 1 ? "it" : "them"}, and cdkd does not re-run a producer to recover a value. Remedy: deploy a change to the producer in the SAME run as ${logicalId} (for a custom resource, change one of its properties, e.g. a nonce / version property, so its handler runs again and supplies the value), or stop declaring the value NoEcho.`, resourceType, logicalId);
|
|
34909
35767
|
}
|
|
34910
|
-
throw new ProvisioningError(`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: cdkd's recorded state holds only the redaction mask there, and the value is not recoverable from state. There are three ways a record comes to hold the mask. (1) A custom resource handler declared its response NoEcho: true — the value is generated by the handler, so cdkd has nothing to re-derive it from and must not write the literal mask to AWS. Remedies: force that custom resource to update (change one of its properties, e.g. a nonce / version property) so its handler runs again and supplies the value in this same run; or stop setting NoEcho on that response. If the value comes from ANOTHER stack, the producer and this stack must deploy in ONE run (cdkd deploy --all, or cdkd deploy '**' when either is inside a CDK Stage) with the producer's custom resource actually running — re-deploying the producer by itself does not help, because it re-masks the value on the way into its own state. (2) The value holds the Fn::Base64 encoding of a secret value (a {{resolve:...}} dynamic reference under Fn::Base64, such as EC2 UserData), which cdkd never records — so a deploy that leaves the resource or output holding it unchanged reads the mask again, and a re-import does not recover it. Remedy: have this resource build the value itself from the SECRET's own reference (the {{resolve:secretsmanager:...}} or {{resolve:ssm-secure:...}} reference, or a {{resolve:ssm:...}} of a SecureString parameter, that the encoding was made from) under its own Fn::Base64, instead of reading it from another resource's attribute or another stack's output — not by a {{resolve:ssm:...}} read of a String parameter holding the encoding, which cdkd treats as public and would record in state in the clear. (3) The resource
|
|
35768
|
+
throw new ProvisioningError(`Cannot resolve ${reads.map((read) => read.display).join(", ")} for ${logicalId}: cdkd's recorded state holds only the redaction mask there, and the value is not recoverable from state. There are three ways a record comes to hold the mask. (1) A custom resource handler declared its response NoEcho: true — the value is generated by the handler, so cdkd has nothing to re-derive it from and must not write the literal mask to AWS. Remedies: force that custom resource to update (change one of its properties, e.g. a nonce / version property) so its handler runs again and supplies the value in this same run; or stop setting NoEcho on that response. If the value comes from ANOTHER stack, the producer and this stack must deploy in ONE run (cdkd deploy --all, or cdkd deploy '**' when either is inside a CDK Stage) with the producer's custom resource actually running — re-deploying the producer by itself does not help, because it re-masks the value on the way into its own state. (2) The value holds the Fn::Base64 encoding of a secret value (a {{resolve:...}} dynamic reference under Fn::Base64, such as EC2 UserData), which cdkd never records — so a deploy that leaves the resource or output holding it unchanged reads the mask again, and a re-import does not recover it. Remedy: have this resource build the value itself from the SECRET's own reference (the {{resolve:secretsmanager:...}} or {{resolve:ssm-secure:...}} reference, or a {{resolve:ssm:...}} of a SecureString parameter, that the encoding was made from) under its own Fn::Base64, instead of reading it from another resource's attribute or another stack's output — not by a {{resolve:ssm:...}} read of a String parameter holding the encoding, which cdkd treats as public and would record in state in the clear. (3) The resource is recorded through the Cloud Control fallback (by a deploy or by 'cdkd import'), which keeps in the clear only the Fn::GetAtt attributes it can vouch for and masks the rest. If the name above is not an Fn::GetAtt attribute CloudFormation accepts for that resource type, no record will ever hold it: stop reading it. If it is one, 'cdkd import' masked it because it could not vouch for the value, or could not read the schema and warned about it when it happened (if that warning named a missing cloudformation:DescribeType permission, grant it first); a deploy that creates or updates the resource records it, unless its value came from a secret. See https://github.com/go-to-k/cdkd/issues/2449. ${DeployEngine.maskedRecordRemedyFor(reads, context.resources, true)}`, resourceType, logicalId);
|
|
34911
35769
|
}
|
|
34912
35770
|
function allRecordedSecrets() {
|
|
34913
35771
|
const all = /* @__PURE__ */ new Map();
|
|
@@ -35216,6 +36074,7 @@ async function createFirstThenDeleteOld(input) {
|
|
|
35216
36074
|
async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentResource, deleteProvider, deleteProperties, finalSnapshotIdentifier, updateReplacePolicy, secrets, deleteProvisionedBy, noEchoDeleteValues) {
|
|
35217
36075
|
let deleteResult = void 0;
|
|
35218
36076
|
let deleteFailed = false;
|
|
36077
|
+
const inlinePolicyClaimed = isStandaloneInlinePolicyType(oldResourceType) ? this.inlinePolicyClaimedFor(oldResourceType, logicalId, this.deployStateResources) : void 0;
|
|
35219
36078
|
try {
|
|
35220
36079
|
deleteResult = await deleteProvider.delete(logicalId, currentResource.physicalId, oldResourceType, deleteProperties, {
|
|
35221
36080
|
expectedRegion: this.stackRegion,
|
|
@@ -35224,7 +36083,8 @@ async function deleteReplacedAfterCreate(logicalId, oldResourceType, currentReso
|
|
|
35224
36083
|
...this.replacementDeleteContext(updateReplacePolicy),
|
|
35225
36084
|
recordedAttributes: currentResource.attributes,
|
|
35226
36085
|
recordedNoEchoLeaves: currentResource.noEchoLeaves,
|
|
35227
|
-
...noEchoDeleteValues !== void 0 && { noEchoDeleteValues }
|
|
36086
|
+
...noEchoDeleteValues !== void 0 && { noEchoDeleteValues },
|
|
36087
|
+
...inlinePolicyClaimed && { inlinePolicyClaimed }
|
|
35228
36088
|
});
|
|
35229
36089
|
} catch (deleteError) {
|
|
35230
36090
|
const deleteMsg = maskSecretsInText(deleteError instanceof Error ? deleteError.message : String(deleteError), secrets);
|
|
@@ -35504,9 +36364,13 @@ function buildResolverContext(base, stackName) {
|
|
|
35504
36364
|
recordedOutputReads: this.recordedOutputReads,
|
|
35505
36365
|
attributeHealer: (logicalId, resource) => this.healStaleAttributes(logicalId, resource, stackName),
|
|
35506
36366
|
...this.options.inheritedSecrets && hasMaskableValues(this.options.inheritedSecrets) && { inheritedSecrets: this.options.inheritedSecrets },
|
|
36367
|
+
...this.options.inheritedPhysicalNameCopies && { inheritedPhysicalNameCopies: this.options.inheritedPhysicalNameCopies },
|
|
35507
36368
|
recordedSecretValues,
|
|
35508
36369
|
noEchoAttributeResources: this.noEchoAttributeResources,
|
|
35509
36370
|
secretNameNeedles: (logicalId) => this.noteSecretNamedRecord(logicalId, Object.hasOwn(base.resources, logicalId) ? base.resources[logicalId] : void 0),
|
|
36371
|
+
producerSecrets: (logicalId) => this.perResourceSecrets.get(logicalId),
|
|
36372
|
+
secretRegionEvidence: () => this.runProducerRegionEvidence?.(),
|
|
36373
|
+
producerPreRunPhysicalId: (logicalId) => Object.hasOwn(this.healBaseline, logicalId) ? this.healBaseline[logicalId]?.physicalId : void 0,
|
|
35510
36374
|
...base.redactedAttributeReads && { redactedAttributeReads: base.redactedAttributeReads }
|
|
35511
36375
|
};
|
|
35512
36376
|
}
|
|
@@ -38606,10 +39470,7 @@ function noEchoParameterNamesOf(template) {
|
|
|
38606
39470
|
const names = /* @__PURE__ */ new Set();
|
|
38607
39471
|
const declared = template?.Parameters;
|
|
38608
39472
|
if (declared === null || typeof declared !== "object") return names;
|
|
38609
|
-
for (const [name, definition] of Object.entries(declared))
|
|
38610
|
-
const noEcho = definition?.NoEcho;
|
|
38611
|
-
if (noEcho === true || noEcho === "true") names.add(name);
|
|
38612
|
-
}
|
|
39473
|
+
for (const [name, definition] of Object.entries(declared)) if (declaresNoEcho(definition)) names.add(name);
|
|
38613
39474
|
return names;
|
|
38614
39475
|
}
|
|
38615
39476
|
function noEchoAttributeNamesOf(record) {
|
|
@@ -38634,7 +39495,10 @@ function noEchoPositionSources(resources = {}, template = this.constructPathTemp
|
|
|
38634
39495
|
function noEchoLeavesFor(logicalId, record, templateProps, sources) {
|
|
38635
39496
|
if (templateProps !== void 0 && isWrittenFromDeployedTemplate(record.properties)) return canonicalCoordinates(noEchoCoordinatesOf(templateProps, record.properties, sources));
|
|
38636
39497
|
const existing = noEchoLeavesOf(record);
|
|
38637
|
-
if (existing !== void 0)
|
|
39498
|
+
if (existing !== void 0) {
|
|
39499
|
+
const confirmed = this.witnessConfirmedLeaves.get(logicalId) ?? [];
|
|
39500
|
+
return canonicalCoordinates([...existing, ...confirmed]);
|
|
39501
|
+
}
|
|
38638
39502
|
const resolvedAsSame = this.perResourceResolvedType.get(logicalId) === record.resourceType;
|
|
38639
39503
|
const source = (templateProps !== void 0 && resolvedAsSame ? templateProps : void 0) ?? templatePropertiesFor(this, logicalId, record.resourceType);
|
|
38640
39504
|
if (source === void 0) return void 0;
|
|
@@ -38846,6 +39710,1140 @@ function noEchoComparisonForTemplate(template, knownConditions, values, resource
|
|
|
38846
39710
|
return (input) => compare(input);
|
|
38847
39711
|
}
|
|
38848
39712
|
|
|
39713
|
+
//#endregion
|
|
39714
|
+
//#region src/analyzer/security-changes.ts
|
|
39715
|
+
const RESOURCE_SCRUTINY = {
|
|
39716
|
+
"AWS::Bedrock::KnowledgeBasePolicy": "ResourcePolicyResource",
|
|
39717
|
+
"AWS::Bedrock::ResourcePolicy": "ResourcePolicyResource",
|
|
39718
|
+
"AWS::CloudTrail::ResourcePolicy": "ResourcePolicyResource",
|
|
39719
|
+
"AWS::EC2::SecurityGroupEgress": "EgressRuleResource",
|
|
39720
|
+
"AWS::EC2::SecurityGroupIngress": "IngressRuleResource",
|
|
39721
|
+
"AWS::ECR::RegistryPolicy": "ResourcePolicyResource",
|
|
39722
|
+
"AWS::EventSchemas::RegistryPolicy": "ResourcePolicyResource",
|
|
39723
|
+
"AWS::EventsV2::ResourcePolicy": "ResourcePolicyResource",
|
|
39724
|
+
"AWS::IAM::GroupPolicy": "IdentityPolicyResource",
|
|
39725
|
+
"AWS::IAM::ManagedPolicy": "IdentityPolicyResource",
|
|
39726
|
+
"AWS::IAM::Policy": "IdentityPolicyResource",
|
|
39727
|
+
"AWS::IAM::RolePolicy": "IdentityPolicyResource",
|
|
39728
|
+
"AWS::IAM::UserPolicy": "IdentityPolicyResource",
|
|
39729
|
+
"AWS::IoT::Policy": "ResourcePolicyResource",
|
|
39730
|
+
"AWS::Kinesis::ResourcePolicy": "ResourcePolicyResource",
|
|
39731
|
+
"AWS::Lambda::Permission": "LambdaPermission",
|
|
39732
|
+
"AWS::Lambda::ResourcePolicy": "ResourcePolicyResource",
|
|
39733
|
+
"AWS::Lex::ResourcePolicy": "ResourcePolicyResource",
|
|
39734
|
+
"AWS::Logs::ResourcePolicy": "ResourcePolicyResource",
|
|
39735
|
+
"AWS::MSK::ClusterPolicy": "ResourcePolicyResource",
|
|
39736
|
+
"AWS::MediaPackageV2::ChannelPolicy": "ResourcePolicyResource",
|
|
39737
|
+
"AWS::MediaPackageV2::OriginEndpointPolicy": "ResourcePolicyResource",
|
|
39738
|
+
"AWS::MediaTailor::ChannelPolicy": "ResourcePolicyResource",
|
|
39739
|
+
"AWS::S3::BucketPolicy": "ResourcePolicyResource",
|
|
39740
|
+
"AWS::S3::MultiRegionAccessPointPolicy": "ResourcePolicyResource",
|
|
39741
|
+
"AWS::S3Express::BucketPolicy": "ResourcePolicyResource",
|
|
39742
|
+
"AWS::S3Files::FileSystemPolicy": "ResourcePolicyResource",
|
|
39743
|
+
"AWS::S3ObjectLambda::AccessPointPolicy": "ResourcePolicyResource",
|
|
39744
|
+
"AWS::S3Outposts::BucketPolicy": "ResourcePolicyResource",
|
|
39745
|
+
"AWS::S3Tables::TableBucketPolicy": "ResourcePolicyResource",
|
|
39746
|
+
"AWS::S3Tables::TablePolicy": "ResourcePolicyResource",
|
|
39747
|
+
"AWS::S3Vectors::VectorBucketPolicy": "ResourcePolicyResource",
|
|
39748
|
+
"AWS::SMSVOICE::ResourcePolicy": "ResourcePolicyResource",
|
|
39749
|
+
"AWS::SNS::TopicInlinePolicy": "ResourcePolicyResource",
|
|
39750
|
+
"AWS::SNS::TopicPolicy": "ResourcePolicyResource",
|
|
39751
|
+
"AWS::SQS::QueueInlinePolicy": "ResourcePolicyResource",
|
|
39752
|
+
"AWS::SQS::QueuePolicy": "ResourcePolicyResource",
|
|
39753
|
+
"AWS::SSM::ResourcePolicy": "ResourcePolicyResource",
|
|
39754
|
+
"AWS::SSO::Assignment": "SsoAssignmentResource",
|
|
39755
|
+
"AWS::SSO::InstanceAccessControlAttributeConfiguration": "SsoInstanceACAConfigResource",
|
|
39756
|
+
"AWS::SSO::PermissionSet": "SsoPermissionSet",
|
|
39757
|
+
"AWS::SecretsManager::ResourcePolicy": "ResourcePolicyResource",
|
|
39758
|
+
"AWS::VpcLattice::AuthPolicy": "ResourcePolicyResource",
|
|
39759
|
+
"AWS::VpcLattice::ResourcePolicy": "ResourcePolicyResource"
|
|
39760
|
+
};
|
|
39761
|
+
const PROPERTY_SCRUTINY = {
|
|
39762
|
+
"AWS::ApiGateway::DomainNameV2": { Policy: "InlineResourcePolicy" },
|
|
39763
|
+
"AWS::ApiGateway::RestApi": { Policy: "InlineResourcePolicy" },
|
|
39764
|
+
"AWS::Backup::BackupVault": { AccessPolicy: "InlineResourcePolicy" },
|
|
39765
|
+
"AWS::Backup::LogicallyAirGappedBackupVault": { AccessPolicy: "InlineResourcePolicy" },
|
|
39766
|
+
"AWS::CodeArtifact::Domain": { PermissionsPolicyDocument: "InlineResourcePolicy" },
|
|
39767
|
+
"AWS::CodeArtifact::Repository": { PermissionsPolicyDocument: "InlineResourcePolicy" },
|
|
39768
|
+
"AWS::EC2::SecurityGroup": {
|
|
39769
|
+
SecurityGroupEgress: "EgressRules",
|
|
39770
|
+
SecurityGroupIngress: "IngressRules"
|
|
39771
|
+
},
|
|
39772
|
+
"AWS::EC2::VPCEndpoint": { PolicyDocument: "InlineResourcePolicy" },
|
|
39773
|
+
"AWS::ECR::PublicRepository": { RepositoryPolicyText: "InlineResourcePolicy" },
|
|
39774
|
+
"AWS::ECR::Repository": { RepositoryPolicyText: "InlineResourcePolicy" },
|
|
39775
|
+
"AWS::EFS::FileSystem": { FileSystemPolicy: "InlineResourcePolicy" },
|
|
39776
|
+
"AWS::Events::EventBus": { Policy: "InlineResourcePolicy" },
|
|
39777
|
+
"AWS::IAM::Group": {
|
|
39778
|
+
ManagedPolicyArns: "ManagedPolicies",
|
|
39779
|
+
Policies: "InlineIdentityPolicies"
|
|
39780
|
+
},
|
|
39781
|
+
"AWS::IAM::Role": {
|
|
39782
|
+
AssumeRolePolicyDocument: "InlineResourcePolicy",
|
|
39783
|
+
ManagedPolicyArns: "ManagedPolicies",
|
|
39784
|
+
Policies: "InlineIdentityPolicies"
|
|
39785
|
+
},
|
|
39786
|
+
"AWS::IAM::User": {
|
|
39787
|
+
ManagedPolicyArns: "ManagedPolicies",
|
|
39788
|
+
Policies: "InlineIdentityPolicies"
|
|
39789
|
+
},
|
|
39790
|
+
"AWS::KMS::Key": { KeyPolicy: "InlineResourcePolicy" },
|
|
39791
|
+
"AWS::KMS::ReplicaKey": { KeyPolicy: "InlineResourcePolicy" },
|
|
39792
|
+
"AWS::Logs::LogGroup": {
|
|
39793
|
+
DataProtectionPolicy: "InlineResourcePolicy",
|
|
39794
|
+
ResourcePolicyDocument: "InlineResourcePolicy"
|
|
39795
|
+
},
|
|
39796
|
+
"AWS::MPA::ApprovalTeam": { Policies: "InlineIdentityPolicies" },
|
|
39797
|
+
"AWS::NetworkManager::CoreNetwork": { PolicyDocument: "InlineResourcePolicy" },
|
|
39798
|
+
"AWS::Oam::Sink": { Policy: "InlineResourcePolicy" },
|
|
39799
|
+
"AWS::Omics::SequenceStore": { S3AccessPolicy: "InlineResourcePolicy" },
|
|
39800
|
+
"AWS::RAM::Permission": { PolicyTemplate: "InlineResourcePolicy" },
|
|
39801
|
+
"AWS::Redshift::Cluster": { NamespaceResourcePolicy: "InlineResourcePolicy" },
|
|
39802
|
+
"AWS::RedshiftServerless::Namespace": { NamespaceResourcePolicy: "InlineResourcePolicy" },
|
|
39803
|
+
"AWS::RolesAnywhere::Profile": { ManagedPolicyArns: "ManagedPolicies" },
|
|
39804
|
+
"AWS::S3::AccessPoint": { Policy: "InlineResourcePolicy" },
|
|
39805
|
+
"AWS::S3Express::AccessPoint": { Policy: "InlineResourcePolicy" },
|
|
39806
|
+
"AWS::S3Outposts::AccessPoint": { Policy: "InlineResourcePolicy" },
|
|
39807
|
+
"AWS::SNS::Subscription": {
|
|
39808
|
+
RedrivePolicy: "InlineResourcePolicy",
|
|
39809
|
+
ReplayPolicy: "InlineResourcePolicy"
|
|
39810
|
+
},
|
|
39811
|
+
"AWS::SNS::Topic": {
|
|
39812
|
+
DataProtectionPolicy: "InlineResourcePolicy",
|
|
39813
|
+
ArchivePolicy: "InlineResourcePolicy"
|
|
39814
|
+
},
|
|
39815
|
+
"AWS::SQS::Queue": { RedriveAllowPolicy: "InlineResourcePolicy" },
|
|
39816
|
+
"AWS::SSO::PermissionSet": {
|
|
39817
|
+
InlinePolicy: "InlineResourcePolicy",
|
|
39818
|
+
ManagedPolicies: "ManagedPolicies"
|
|
39819
|
+
},
|
|
39820
|
+
"AWS::SageMaker::ModelPackageGroup": { ModelPackageGroupPolicy: "InlineResourcePolicy" },
|
|
39821
|
+
"AWS::Serverless::Function": { AssumeRolePolicyDocument: "InlineResourcePolicy" }
|
|
39822
|
+
};
|
|
39823
|
+
function resourceScrutiny(type) {
|
|
39824
|
+
return Object.hasOwn(RESOURCE_SCRUTINY, type) ? RESOURCE_SCRUTINY[type] : void 0;
|
|
39825
|
+
}
|
|
39826
|
+
function propertyScrutinies(type) {
|
|
39827
|
+
return Object.hasOwn(PROPERTY_SCRUTINY, type) ? PROPERTY_SCRUTINY[type] ?? {} : {};
|
|
39828
|
+
}
|
|
39829
|
+
function isScrutinizedProperty(type, path) {
|
|
39830
|
+
return resourceScrutiny(type) !== void 0 || Object.hasOwn(propertyScrutinies(type), path);
|
|
39831
|
+
}
|
|
39832
|
+
function strictEqual(a, b) {
|
|
39833
|
+
if (a === b) return true;
|
|
39834
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return a !== a && b !== b;
|
|
39835
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
39836
|
+
if (Array.isArray(a)) {
|
|
39837
|
+
const bArr = b;
|
|
39838
|
+
return a.length === bArr.length && a.every((v, i) => strictEqual(v, bArr[i]));
|
|
39839
|
+
}
|
|
39840
|
+
const aKeys = Object.keys(a);
|
|
39841
|
+
if (aKeys.length !== Object.keys(b).length) return false;
|
|
39842
|
+
return aKeys.every((k) => Object.hasOwn(b, k) && strictEqual(a[k], b[k]));
|
|
39843
|
+
}
|
|
39844
|
+
function cfnEqual(lvalue, rvalue) {
|
|
39845
|
+
if (lvalue === rvalue) return true;
|
|
39846
|
+
if ((typeof lvalue === "string" && typeof rvalue === "boolean" || typeof lvalue === "boolean" && typeof rvalue === "string") && lvalue.toString() === rvalue.toString()) return true;
|
|
39847
|
+
if ((typeof lvalue === "string" || typeof rvalue === "string") && Number(lvalue) === Number(rvalue)) return true;
|
|
39848
|
+
if (typeof lvalue !== typeof rvalue) return false;
|
|
39849
|
+
if (Array.isArray(lvalue) !== Array.isArray(rvalue)) return false;
|
|
39850
|
+
if (Array.isArray(lvalue)) {
|
|
39851
|
+
if (lvalue.length !== rvalue.length) return false;
|
|
39852
|
+
for (let i = 0; i < lvalue.length; i++) if (!cfnEqual(lvalue[i], rvalue[i])) return false;
|
|
39853
|
+
return true;
|
|
39854
|
+
}
|
|
39855
|
+
if (typeof lvalue === "object") {
|
|
39856
|
+
if (lvalue === null || rvalue === null) return false;
|
|
39857
|
+
const keys = Object.keys(lvalue);
|
|
39858
|
+
if (keys.length !== Object.keys(rvalue).length) return false;
|
|
39859
|
+
for (const key of keys) {
|
|
39860
|
+
if (!Object.hasOwn(rvalue, key)) return false;
|
|
39861
|
+
if (key === "DependsOn") {
|
|
39862
|
+
if (!dependsOnEqual(lvalue[key], rvalue[key])) return false;
|
|
39863
|
+
continue;
|
|
39864
|
+
}
|
|
39865
|
+
if (!cfnEqual(lvalue[key], rvalue[key])) return false;
|
|
39866
|
+
}
|
|
39867
|
+
return true;
|
|
39868
|
+
}
|
|
39869
|
+
return false;
|
|
39870
|
+
}
|
|
39871
|
+
function dependsOnEqual(lvalue, rvalue) {
|
|
39872
|
+
if (Array.isArray(lvalue) !== Array.isArray(rvalue)) {
|
|
39873
|
+
const array = Array.isArray(lvalue) ? lvalue : rvalue;
|
|
39874
|
+
const nonArray = Array.isArray(lvalue) ? rvalue : lvalue;
|
|
39875
|
+
return array.length === 1 && cfnEqual(array[0], nonArray);
|
|
39876
|
+
}
|
|
39877
|
+
if (Array.isArray(lvalue) && Array.isArray(rvalue)) {
|
|
39878
|
+
if (lvalue.length !== rvalue.length) return false;
|
|
39879
|
+
for (let i = 0; i < lvalue.length; i++) if (!cfnEqual(lvalue[i], rvalue[0]) && lvalue.length === 1) return false;
|
|
39880
|
+
return true;
|
|
39881
|
+
}
|
|
39882
|
+
return false;
|
|
39883
|
+
}
|
|
39884
|
+
function normalize(template) {
|
|
39885
|
+
if (typeof template !== "object" || template === null) return;
|
|
39886
|
+
for (const key of Object.keys(template)) {
|
|
39887
|
+
if (key === "Fn::GetAtt" && typeof template[key] === "string") {
|
|
39888
|
+
template[key] = template[key].split(".");
|
|
39889
|
+
continue;
|
|
39890
|
+
} else if (key === "DependsOn") {
|
|
39891
|
+
if (typeof template[key] === "string") template[key] = [template[key]];
|
|
39892
|
+
else if (Array.isArray(template[key])) template[key] = template[key].sort((x, y) => String(x) < String(y) ? -1 : String(x) > String(y) ? 1 : 0);
|
|
39893
|
+
continue;
|
|
39894
|
+
}
|
|
39895
|
+
if (Array.isArray(template[key])) for (const element of template[key]) normalize(element);
|
|
39896
|
+
else normalize(template[key]);
|
|
39897
|
+
}
|
|
39898
|
+
}
|
|
39899
|
+
function getIntrinsic(x) {
|
|
39900
|
+
if (x === void 0 || x === null || Array.isArray(x) || typeof x !== "object") return void 0;
|
|
39901
|
+
const keys = Object.keys(x);
|
|
39902
|
+
return keys.length === 1 && (keys[0] === "Ref" || keys[0].startsWith("Fn::")) ? {
|
|
39903
|
+
fn: keys[0],
|
|
39904
|
+
args: x[keys[0]]
|
|
39905
|
+
} : void 0;
|
|
39906
|
+
}
|
|
39907
|
+
function isNoValue(x) {
|
|
39908
|
+
const intrinsic = getIntrinsic(x);
|
|
39909
|
+
return intrinsic !== void 0 && intrinsic.fn === "Ref" && intrinsic.args === "AWS::NoValue";
|
|
39910
|
+
}
|
|
39911
|
+
function renderIntrinsics(x) {
|
|
39912
|
+
if (Array.isArray(x)) return x.filter((el) => !isNoValue(el)).map(renderIntrinsics);
|
|
39913
|
+
if (isNoValue(x)) return void 0;
|
|
39914
|
+
const intrinsic = getIntrinsic(x);
|
|
39915
|
+
if (intrinsic !== void 0) {
|
|
39916
|
+
if (intrinsic.fn === "Ref") return "${" + intrinsic.args + "}";
|
|
39917
|
+
if (intrinsic.fn === "Fn::GetAtt") return "${" + intrinsic.args[0] + "." + intrinsic.args[1] + "}";
|
|
39918
|
+
if (intrinsic.fn === "Fn::Join") {
|
|
39919
|
+
const [separator, args] = intrinsic.args;
|
|
39920
|
+
if (Array.isArray(args)) return args.filter((el) => !isNoValue(el)).map(renderIntrinsics).join(separator);
|
|
39921
|
+
return JSON.stringify({ "Fn::Join": renderIntrinsics([separator, args]) });
|
|
39922
|
+
}
|
|
39923
|
+
return JSON.stringify({ [intrinsic.fn]: renderIntrinsics(intrinsic.args) });
|
|
39924
|
+
}
|
|
39925
|
+
if (typeof x === "object" && x !== null) {
|
|
39926
|
+
const ret = {};
|
|
39927
|
+
for (const [key, value] of Object.entries(x)) if (!isNoValue(value)) ret[key] = renderIntrinsics(value);
|
|
39928
|
+
return ret;
|
|
39929
|
+
}
|
|
39930
|
+
return x;
|
|
39931
|
+
}
|
|
39932
|
+
var Targets = class {
|
|
39933
|
+
values;
|
|
39934
|
+
not;
|
|
39935
|
+
constructor(statement, positiveKey, negativeKey) {
|
|
39936
|
+
if (negativeKey in statement) {
|
|
39937
|
+
this.values = forceListOfStrings(statement[negativeKey]);
|
|
39938
|
+
this.not = true;
|
|
39939
|
+
} else {
|
|
39940
|
+
this.values = forceListOfStrings(statement[positiveKey]);
|
|
39941
|
+
this.not = false;
|
|
39942
|
+
}
|
|
39943
|
+
this.values.sort();
|
|
39944
|
+
}
|
|
39945
|
+
get empty() {
|
|
39946
|
+
return this.values.length === 0;
|
|
39947
|
+
}
|
|
39948
|
+
equal(other) {
|
|
39949
|
+
return this.not === other.not && strictEqual(this.values.sort(), other.values.sort());
|
|
39950
|
+
}
|
|
39951
|
+
replaceEmpty(replacement) {
|
|
39952
|
+
if (this.empty) this.values.push(replacement);
|
|
39953
|
+
}
|
|
39954
|
+
replaceStar(replacement) {
|
|
39955
|
+
for (let i = 0; i < this.values.length; i++) if (this.values[i] === "*") this.values[i] = replacement;
|
|
39956
|
+
this.values.sort();
|
|
39957
|
+
}
|
|
39958
|
+
render() {
|
|
39959
|
+
return this.not ? this.values.map((s) => `NOT ${s}`).join("\n") : this.values.join("\n");
|
|
39960
|
+
}
|
|
39961
|
+
};
|
|
39962
|
+
function forceListOfStrings(x) {
|
|
39963
|
+
if (typeof x === "string") return [x];
|
|
39964
|
+
if (x === void 0 || x === null) return [];
|
|
39965
|
+
if (Array.isArray(x)) return x.map((e) => forceListOfStrings(e).join(","));
|
|
39966
|
+
if (typeof x === "object") {
|
|
39967
|
+
const ret = [];
|
|
39968
|
+
for (const [key, value] of Object.entries(x)) ret.push(...forceListOfStrings(value).map((s) => `${key}:${s}`));
|
|
39969
|
+
return ret;
|
|
39970
|
+
}
|
|
39971
|
+
return [`${x}`];
|
|
39972
|
+
}
|
|
39973
|
+
var Statement = class {
|
|
39974
|
+
sid;
|
|
39975
|
+
effect;
|
|
39976
|
+
resources;
|
|
39977
|
+
actions;
|
|
39978
|
+
principals;
|
|
39979
|
+
condition;
|
|
39980
|
+
serializedIntrinsic;
|
|
39981
|
+
constructor(statement) {
|
|
39982
|
+
if (typeof statement === "string") {
|
|
39983
|
+
this.sid = void 0;
|
|
39984
|
+
this.effect = "Unknown";
|
|
39985
|
+
this.resources = new Targets({}, "", "");
|
|
39986
|
+
this.actions = new Targets({}, "", "");
|
|
39987
|
+
this.principals = new Targets({}, "", "");
|
|
39988
|
+
this.condition = void 0;
|
|
39989
|
+
this.serializedIntrinsic = statement;
|
|
39990
|
+
} else {
|
|
39991
|
+
if (typeof statement !== "object" || statement === null) throw new Error("An IAM policy statement is neither an object nor a string");
|
|
39992
|
+
this.sid = typeof statement.Sid === "string" ? statement.Sid : void 0;
|
|
39993
|
+
this.effect = statement.Effect === "Allow" || statement.Effect === "Deny" ? statement.Effect : "Unknown";
|
|
39994
|
+
this.resources = new Targets(statement, "Resource", "NotResource");
|
|
39995
|
+
this.actions = new Targets(statement, "Action", "NotAction");
|
|
39996
|
+
this.principals = new Targets(statement, "Principal", "NotPrincipal");
|
|
39997
|
+
this.condition = statement.Condition;
|
|
39998
|
+
this.serializedIntrinsic = void 0;
|
|
39999
|
+
}
|
|
40000
|
+
}
|
|
40001
|
+
equal(other) {
|
|
40002
|
+
return this.sid === other.sid && this.effect === other.effect && this.serializedIntrinsic === other.serializedIntrinsic && this.resources.equal(other.resources) && this.actions.equal(other.actions) && this.principals.equal(other.principals) && strictEqual(this.condition, other.condition);
|
|
40003
|
+
}
|
|
40004
|
+
get isNegativeStatement() {
|
|
40005
|
+
const notTarget = this.actions.not || this.principals.not || this.resources.not;
|
|
40006
|
+
return this.effect === "Allow" ? notTarget : !notTarget;
|
|
40007
|
+
}
|
|
40008
|
+
render() {
|
|
40009
|
+
return this.serializedIntrinsic ? [
|
|
40010
|
+
this.serializedIntrinsic,
|
|
40011
|
+
"",
|
|
40012
|
+
"",
|
|
40013
|
+
this.principals.render(),
|
|
40014
|
+
""
|
|
40015
|
+
] : [
|
|
40016
|
+
this.resources.render(),
|
|
40017
|
+
this.effect,
|
|
40018
|
+
this.actions.render(),
|
|
40019
|
+
this.principals.render(),
|
|
40020
|
+
renderCondition(this.condition)
|
|
40021
|
+
];
|
|
40022
|
+
}
|
|
40023
|
+
};
|
|
40024
|
+
function parseStatements(x) {
|
|
40025
|
+
if (x === void 0) x = [];
|
|
40026
|
+
if (!Array.isArray(x)) x = [x];
|
|
40027
|
+
return x.map((s) => new Statement(s));
|
|
40028
|
+
}
|
|
40029
|
+
function parseLambdaPermission(x) {
|
|
40030
|
+
const statement = {
|
|
40031
|
+
Effect: "Allow",
|
|
40032
|
+
Action: x.Action,
|
|
40033
|
+
Resource: x.FunctionName
|
|
40034
|
+
};
|
|
40035
|
+
if (x.Principal !== void 0) {
|
|
40036
|
+
if (x.Principal === "*") statement.Principal = "*";
|
|
40037
|
+
else if (/^\d{12}$/.test(x.Principal)) statement.Principal = { AWS: `arn:aws:iam::${x.Principal}:root` };
|
|
40038
|
+
else statement.Principal = { Service: x.Principal };
|
|
40039
|
+
}
|
|
40040
|
+
if (x.SourceArn !== void 0) {
|
|
40041
|
+
statement.Condition ??= {};
|
|
40042
|
+
statement.Condition.ArnLike = { "AWS:SourceArn": x.SourceArn };
|
|
40043
|
+
}
|
|
40044
|
+
if (x.SourceAccount !== void 0) {
|
|
40045
|
+
statement.Condition ??= {};
|
|
40046
|
+
statement.Condition.StringEquals = { "AWS:SourceAccount": x.SourceAccount };
|
|
40047
|
+
}
|
|
40048
|
+
if (x.EventSourceToken !== void 0) {
|
|
40049
|
+
statement.Condition ??= {};
|
|
40050
|
+
statement.Condition.StringEquals = { "lambda:EventSourceToken": x.EventSourceToken };
|
|
40051
|
+
}
|
|
40052
|
+
return new Statement(statement);
|
|
40053
|
+
}
|
|
40054
|
+
function renderCondition(condition) {
|
|
40055
|
+
if (!condition || Object.keys(condition).length === 0) return "";
|
|
40056
|
+
const lines = JSON.stringify(condition, void 0, 2).split("\n");
|
|
40057
|
+
return lines.slice(1, lines.length - 1).map((s) => s.slice(2)).join("\n");
|
|
40058
|
+
}
|
|
40059
|
+
function defaultPrincipal(principal, statements) {
|
|
40060
|
+
statements.forEach((s) => s.principals.replaceEmpty(principal));
|
|
40061
|
+
statements.forEach((s) => s.principals.replaceStar(principal));
|
|
40062
|
+
return statements;
|
|
40063
|
+
}
|
|
40064
|
+
function defaultResource(resource, statements) {
|
|
40065
|
+
statements.forEach((s) => s.resources.replaceEmpty(resource));
|
|
40066
|
+
statements.forEach((s) => s.resources.replaceStar(resource));
|
|
40067
|
+
return statements;
|
|
40068
|
+
}
|
|
40069
|
+
var ManagedPolicyAttachment = class {
|
|
40070
|
+
identityArn;
|
|
40071
|
+
managedPolicyArn;
|
|
40072
|
+
constructor(identityArn, managedPolicyArn) {
|
|
40073
|
+
this.identityArn = identityArn;
|
|
40074
|
+
this.managedPolicyArn = managedPolicyArn;
|
|
40075
|
+
}
|
|
40076
|
+
equal(other) {
|
|
40077
|
+
return this.identityArn === other.identityArn && this.managedPolicyArn === other.managedPolicyArn;
|
|
40078
|
+
}
|
|
40079
|
+
};
|
|
40080
|
+
var SsoElement = class {
|
|
40081
|
+
fields;
|
|
40082
|
+
constructor(fields) {
|
|
40083
|
+
this.fields = fields;
|
|
40084
|
+
}
|
|
40085
|
+
equal(other) {
|
|
40086
|
+
return strictEqual(this.fields, other.fields);
|
|
40087
|
+
}
|
|
40088
|
+
};
|
|
40089
|
+
var SecurityGroupRule = class {
|
|
40090
|
+
ipProtocol;
|
|
40091
|
+
fromPort;
|
|
40092
|
+
toPort;
|
|
40093
|
+
groupId;
|
|
40094
|
+
peer;
|
|
40095
|
+
constructor(rule, groupRef) {
|
|
40096
|
+
this.ipProtocol = rule.IpProtocol?.toString() || "*unknown*";
|
|
40097
|
+
this.fromPort = rule.FromPort;
|
|
40098
|
+
this.toPort = rule.ToPort;
|
|
40099
|
+
this.groupId = rule.GroupId || groupRef || "*unknown*";
|
|
40100
|
+
this.peer = findFirst(rule, ["CidrIp", "CidrIpv6"], (ip) => ({
|
|
40101
|
+
kind: "cidr-ip",
|
|
40102
|
+
ip
|
|
40103
|
+
})) || findFirst(rule, ["DestinationSecurityGroupId", "SourceSecurityGroupId"], (id) => ({
|
|
40104
|
+
kind: "security-group",
|
|
40105
|
+
securityGroupId: id
|
|
40106
|
+
})) || findFirst(rule, ["DestinationPrefixListId", "SourcePrefixListId"], (id) => ({
|
|
40107
|
+
kind: "prefix-list",
|
|
40108
|
+
prefixListId: id
|
|
40109
|
+
}));
|
|
40110
|
+
}
|
|
40111
|
+
equal(other) {
|
|
40112
|
+
return this.ipProtocol === other.ipProtocol && this.fromPort === other.fromPort && this.toPort === other.toPort && peerEqual(this.peer, other.peer);
|
|
40113
|
+
}
|
|
40114
|
+
describeProtocol() {
|
|
40115
|
+
if (this.ipProtocol === "-1") return "Everything";
|
|
40116
|
+
const ipProtocol = this.ipProtocol.toUpperCase();
|
|
40117
|
+
if (this.fromPort === -1) return `All ${ipProtocol}`;
|
|
40118
|
+
if (this.fromPort === this.toPort) return `${ipProtocol} ${this.fromPort}`;
|
|
40119
|
+
return `${ipProtocol} ${this.fromPort}-${this.toPort}`;
|
|
40120
|
+
}
|
|
40121
|
+
describePeer() {
|
|
40122
|
+
switch (this.peer?.kind) {
|
|
40123
|
+
case "cidr-ip":
|
|
40124
|
+
if (this.peer.ip === "0.0.0.0/0") return "Everyone (IPv4)";
|
|
40125
|
+
if (this.peer.ip === "::/0") return "Everyone (IPv6)";
|
|
40126
|
+
return `${this.peer.ip}`;
|
|
40127
|
+
case "prefix-list": return `${this.peer.prefixListId}`;
|
|
40128
|
+
case "security-group": return `${this.peer.securityGroupId}`;
|
|
40129
|
+
default: return "?";
|
|
40130
|
+
}
|
|
40131
|
+
}
|
|
40132
|
+
};
|
|
40133
|
+
function peerEqual(a, b) {
|
|
40134
|
+
if (a === void 0 || b === void 0) return a === b;
|
|
40135
|
+
if (a.kind === "cidr-ip" && b.kind === "cidr-ip") return a.ip === b.ip;
|
|
40136
|
+
if (a.kind === "security-group" && b.kind === "security-group") return a.securityGroupId === b.securityGroupId;
|
|
40137
|
+
if (a.kind === "prefix-list" && b.kind === "prefix-list") return a.prefixListId === b.prefixListId;
|
|
40138
|
+
return false;
|
|
40139
|
+
}
|
|
40140
|
+
function findFirst(obj, keys, fn) {
|
|
40141
|
+
for (const key of keys) try {
|
|
40142
|
+
if (key in obj) return fn(obj[key]);
|
|
40143
|
+
} catch {}
|
|
40144
|
+
}
|
|
40145
|
+
var DiffableCollection = class {
|
|
40146
|
+
additions = [];
|
|
40147
|
+
removals = [];
|
|
40148
|
+
oldElements = [];
|
|
40149
|
+
newElements = [];
|
|
40150
|
+
addOld(...elements) {
|
|
40151
|
+
this.oldElements.push(...elements);
|
|
40152
|
+
}
|
|
40153
|
+
addNew(...elements) {
|
|
40154
|
+
this.newElements.push(...elements);
|
|
40155
|
+
}
|
|
40156
|
+
calculateDiff() {
|
|
40157
|
+
const contains = (x, xs) => xs.some((y) => y.equal(x));
|
|
40158
|
+
this.additions.push(...this.newElements.filter((x) => !contains(x, this.oldElements)));
|
|
40159
|
+
this.removals.push(...this.oldElements.filter((x) => !contains(x, this.newElements)));
|
|
40160
|
+
}
|
|
40161
|
+
get hasChanges() {
|
|
40162
|
+
return this.additions.length + this.removals.length > 0;
|
|
40163
|
+
}
|
|
40164
|
+
get hasAdditions() {
|
|
40165
|
+
return this.additions.length > 0;
|
|
40166
|
+
}
|
|
40167
|
+
};
|
|
40168
|
+
function resourceDiffers(oldValue, newValue) {
|
|
40169
|
+
if (oldValue === void 0 || newValue === void 0) return true;
|
|
40170
|
+
if (oldValue.Type !== newValue.Type) return true;
|
|
40171
|
+
const keyDiffers = (a, b, skip) => [.../* @__PURE__ */ new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})])].some((key) => {
|
|
40172
|
+
if (key === skip) return false;
|
|
40173
|
+
const x = a?.[key];
|
|
40174
|
+
const y = b?.[key];
|
|
40175
|
+
return !(x === void 0 && y === void 0) && !cfnEqual(x, y);
|
|
40176
|
+
});
|
|
40177
|
+
return keyDiffers(oldValue.Properties, newValue.Properties) || keyDiffers(oldValue, newValue, "Properties");
|
|
40178
|
+
}
|
|
40179
|
+
var SecurityChanges = class {
|
|
40180
|
+
statements = new DiffableCollection();
|
|
40181
|
+
managedPolicies = new DiffableCollection();
|
|
40182
|
+
ssoPermissionSets = new DiffableCollection();
|
|
40183
|
+
ssoAssignments = new DiffableCollection();
|
|
40184
|
+
ssoInstanceACAConfigs = new DiffableCollection();
|
|
40185
|
+
ingress = new DiffableCollection();
|
|
40186
|
+
egress = new DiffableCollection();
|
|
40187
|
+
constructor(oldTemplate, newTemplate) {
|
|
40188
|
+
normalize(oldTemplate);
|
|
40189
|
+
normalize(newTemplate);
|
|
40190
|
+
const oldResources = oldTemplate.Resources ?? {};
|
|
40191
|
+
const newResources = newTemplate.Resources ?? {};
|
|
40192
|
+
const changed = [];
|
|
40193
|
+
for (const id of /* @__PURE__ */ new Set([...Object.keys(oldResources), ...Object.keys(newResources)])) {
|
|
40194
|
+
const oldValue = Object.hasOwn(oldResources, id) ? oldResources[id] : void 0;
|
|
40195
|
+
const newValue = Object.hasOwn(newResources, id) ? newResources[id] : void 0;
|
|
40196
|
+
if (oldValue === void 0 && newValue === void 0) continue;
|
|
40197
|
+
if (resourceDiffers(oldValue, newValue)) changed.push([id, {
|
|
40198
|
+
oldValue,
|
|
40199
|
+
newValue
|
|
40200
|
+
}]);
|
|
40201
|
+
}
|
|
40202
|
+
for (const change of this.propertyChanges(changed)) this.readPropertyChange(change);
|
|
40203
|
+
for (const change of this.resourceChanges(changed)) this.readResourceChange(change);
|
|
40204
|
+
for (const collection of this.collections()) collection.calculateDiff();
|
|
40205
|
+
}
|
|
40206
|
+
collections() {
|
|
40207
|
+
return [
|
|
40208
|
+
this.statements,
|
|
40209
|
+
this.managedPolicies,
|
|
40210
|
+
this.ssoPermissionSets,
|
|
40211
|
+
this.ssoAssignments,
|
|
40212
|
+
this.ssoInstanceACAConfigs,
|
|
40213
|
+
this.ingress,
|
|
40214
|
+
this.egress
|
|
40215
|
+
];
|
|
40216
|
+
}
|
|
40217
|
+
propertyChanges(changed) {
|
|
40218
|
+
const ret = [];
|
|
40219
|
+
for (const [logicalId, { oldValue, newValue }] of changed) {
|
|
40220
|
+
const oldType = oldValue?.Type;
|
|
40221
|
+
const newType = newValue?.Type;
|
|
40222
|
+
if (oldType !== void 0 && newType !== void 0 && oldType !== newType) continue;
|
|
40223
|
+
const resourceType = oldType ?? newType;
|
|
40224
|
+
if (!resourceType) continue;
|
|
40225
|
+
for (const [propertyName, scrutiny] of Object.entries(propertyScrutinies(resourceType))) ret.push({
|
|
40226
|
+
logicalId,
|
|
40227
|
+
resourceType,
|
|
40228
|
+
scrutiny,
|
|
40229
|
+
oldValue: oldValue?.Properties?.[propertyName],
|
|
40230
|
+
newValue: newValue?.Properties?.[propertyName]
|
|
40231
|
+
});
|
|
40232
|
+
}
|
|
40233
|
+
return ret;
|
|
40234
|
+
}
|
|
40235
|
+
resourceChanges(changed) {
|
|
40236
|
+
const ret = [];
|
|
40237
|
+
for (const [logicalId, { oldValue, newValue }] of changed) {
|
|
40238
|
+
const oldType = oldValue?.Type;
|
|
40239
|
+
const newType = newValue?.Type;
|
|
40240
|
+
const common = {
|
|
40241
|
+
logicalId,
|
|
40242
|
+
oldProperties: oldValue?.Properties,
|
|
40243
|
+
newProperties: newValue?.Properties
|
|
40244
|
+
};
|
|
40245
|
+
if (oldType !== void 0 && newType !== void 0 && oldType !== newType) {
|
|
40246
|
+
const oldScrutiny = resourceScrutiny(oldType);
|
|
40247
|
+
if (oldScrutiny) ret.push({
|
|
40248
|
+
...common,
|
|
40249
|
+
newProperties: void 0,
|
|
40250
|
+
scrutiny: oldScrutiny
|
|
40251
|
+
});
|
|
40252
|
+
const newScrutiny = resourceScrutiny(newType);
|
|
40253
|
+
if (newScrutiny) ret.push({
|
|
40254
|
+
...common,
|
|
40255
|
+
oldProperties: void 0,
|
|
40256
|
+
scrutiny: newScrutiny
|
|
40257
|
+
});
|
|
40258
|
+
continue;
|
|
40259
|
+
}
|
|
40260
|
+
const type = oldType ?? newType;
|
|
40261
|
+
const scrutiny = type ? resourceScrutiny(type) : void 0;
|
|
40262
|
+
if (scrutiny) ret.push({
|
|
40263
|
+
...common,
|
|
40264
|
+
scrutiny
|
|
40265
|
+
});
|
|
40266
|
+
}
|
|
40267
|
+
return ret;
|
|
40268
|
+
}
|
|
40269
|
+
get permissionsBroadened() {
|
|
40270
|
+
return this.statements.additions.some((s) => !s.isNegativeStatement) || this.statements.removals.some((s) => s.isNegativeStatement) || this.managedPolicies.hasAdditions || this.ssoPermissionSets.hasAdditions || this.ssoAssignments.hasAdditions || this.ssoInstanceACAConfigs.hasAdditions || this.ingress.hasAdditions || this.egress.hasAdditions;
|
|
40271
|
+
}
|
|
40272
|
+
get iamHasChanges() {
|
|
40273
|
+
return this.statements.hasChanges || this.managedPolicies.hasChanges || this.ssoPermissionSets.hasChanges || this.ssoAssignments.hasChanges || this.ssoInstanceACAConfigs.hasChanges;
|
|
40274
|
+
}
|
|
40275
|
+
get securityGroupsHaveChanges() {
|
|
40276
|
+
return this.ingress.hasChanges || this.egress.hasChanges;
|
|
40277
|
+
}
|
|
40278
|
+
get permissionsAnyChanges() {
|
|
40279
|
+
return this.iamHasChanges || this.securityGroupsHaveChanges;
|
|
40280
|
+
}
|
|
40281
|
+
readPropertyChange(change) {
|
|
40282
|
+
switch (change.scrutiny) {
|
|
40283
|
+
case "InlineIdentityPolicies":
|
|
40284
|
+
this.statements.addOld(...readIdentityPolicies(change.oldValue, change.logicalId));
|
|
40285
|
+
this.statements.addNew(...readIdentityPolicies(change.newValue, change.logicalId));
|
|
40286
|
+
break;
|
|
40287
|
+
case "InlineResourcePolicy":
|
|
40288
|
+
if (change.resourceType === "AWS::SSO::PermissionSet") {
|
|
40289
|
+
this.statements.addOld(...readPermissionSetInlinePolicy(change.oldValue, change.logicalId));
|
|
40290
|
+
this.statements.addNew(...readPermissionSetInlinePolicy(change.newValue, change.logicalId));
|
|
40291
|
+
} else {
|
|
40292
|
+
this.statements.addOld(...readResourceStatements(change.oldValue, change.logicalId));
|
|
40293
|
+
this.statements.addNew(...readResourceStatements(change.newValue, change.logicalId));
|
|
40294
|
+
}
|
|
40295
|
+
break;
|
|
40296
|
+
case "ManagedPolicies":
|
|
40297
|
+
this.managedPolicies.addOld(...readManagedPolicies(change.oldValue, change.logicalId));
|
|
40298
|
+
this.managedPolicies.addNew(...readManagedPolicies(change.newValue, change.logicalId));
|
|
40299
|
+
break;
|
|
40300
|
+
case "IngressRules":
|
|
40301
|
+
this.ingress.addOld(...readInlineRules(change.oldValue, change.logicalId));
|
|
40302
|
+
this.ingress.addNew(...readInlineRules(change.newValue, change.logicalId));
|
|
40303
|
+
break;
|
|
40304
|
+
case "EgressRules":
|
|
40305
|
+
this.egress.addOld(...readInlineRules(change.oldValue, change.logicalId));
|
|
40306
|
+
this.egress.addNew(...readInlineRules(change.newValue, change.logicalId));
|
|
40307
|
+
}
|
|
40308
|
+
}
|
|
40309
|
+
readResourceChange(change) {
|
|
40310
|
+
const id = change.logicalId;
|
|
40311
|
+
switch (change.scrutiny) {
|
|
40312
|
+
case "IdentityPolicyResource":
|
|
40313
|
+
this.statements.addOld(...readIdentityPolicyResource(change.oldProperties));
|
|
40314
|
+
this.statements.addNew(...readIdentityPolicyResource(change.newProperties));
|
|
40315
|
+
break;
|
|
40316
|
+
case "ResourcePolicyResource":
|
|
40317
|
+
this.statements.addOld(...readResourcePolicyResource(change.oldProperties));
|
|
40318
|
+
this.statements.addNew(...readResourcePolicyResource(change.newProperties));
|
|
40319
|
+
break;
|
|
40320
|
+
case "LambdaPermission":
|
|
40321
|
+
this.statements.addOld(...readLambdaStatements(change.oldProperties));
|
|
40322
|
+
this.statements.addNew(...readLambdaStatements(change.newProperties));
|
|
40323
|
+
break;
|
|
40324
|
+
case "SsoPermissionSet":
|
|
40325
|
+
this.ssoPermissionSets.addOld(...readSso(change.oldProperties, id, permissionSetFields));
|
|
40326
|
+
this.ssoPermissionSets.addNew(...readSso(change.newProperties, id, permissionSetFields));
|
|
40327
|
+
break;
|
|
40328
|
+
case "SsoAssignmentResource":
|
|
40329
|
+
this.ssoAssignments.addOld(...readSso(change.oldProperties, id, assignmentFields));
|
|
40330
|
+
this.ssoAssignments.addNew(...readSso(change.newProperties, id, assignmentFields));
|
|
40331
|
+
break;
|
|
40332
|
+
case "SsoInstanceACAConfigResource":
|
|
40333
|
+
this.ssoInstanceACAConfigs.addOld(...readSso(change.oldProperties, id, acaConfigFields));
|
|
40334
|
+
this.ssoInstanceACAConfigs.addNew(...readSso(change.newProperties, id, acaConfigFields));
|
|
40335
|
+
break;
|
|
40336
|
+
case "IngressRuleResource":
|
|
40337
|
+
this.ingress.addOld(...readRuleResource(change.oldProperties));
|
|
40338
|
+
this.ingress.addNew(...readRuleResource(change.newProperties));
|
|
40339
|
+
break;
|
|
40340
|
+
case "EgressRuleResource":
|
|
40341
|
+
this.egress.addOld(...readRuleResource(change.oldProperties));
|
|
40342
|
+
this.egress.addNew(...readRuleResource(change.newProperties));
|
|
40343
|
+
}
|
|
40344
|
+
}
|
|
40345
|
+
};
|
|
40346
|
+
function readIdentityPolicies(policies, logicalId) {
|
|
40347
|
+
if (policies === void 0 || !Array.isArray(policies)) return [];
|
|
40348
|
+
const appliesToPrincipal = "AWS:${" + logicalId + "}";
|
|
40349
|
+
return policies.flatMap((policy) => {
|
|
40350
|
+
const unparsed = policy.PolicyDocument?.Statement ? policy.PolicyDocument.Statement : policy;
|
|
40351
|
+
return defaultPrincipal(appliesToPrincipal, parseStatements(renderIntrinsics(unparsed)));
|
|
40352
|
+
});
|
|
40353
|
+
}
|
|
40354
|
+
function readIdentityPolicyResource(properties) {
|
|
40355
|
+
if (properties === void 0) return [];
|
|
40356
|
+
properties = renderIntrinsics(properties);
|
|
40357
|
+
return (properties.Groups || []).concat(properties.Users || []).concat(properties.Roles || []).flatMap((principal) => defaultPrincipal("AWS:" + principal, parseStatements(properties.PolicyDocument.Statement)));
|
|
40358
|
+
}
|
|
40359
|
+
function readPermissionSetInlinePolicy(policy, logicalId) {
|
|
40360
|
+
if (policy === void 0) return [];
|
|
40361
|
+
const statements = parseStatements(renderIntrinsics(policy.Statement));
|
|
40362
|
+
defaultResource("${" + logicalId + ".Arn}", statements);
|
|
40363
|
+
defaultPrincipal("AWS:${" + logicalId + "}", statements);
|
|
40364
|
+
return statements;
|
|
40365
|
+
}
|
|
40366
|
+
function readResourceStatements(policy, logicalId) {
|
|
40367
|
+
if (policy === void 0) return [];
|
|
40368
|
+
return defaultResource("${" + logicalId + ".Arn}", parseStatements(renderIntrinsics(policy.Statement)));
|
|
40369
|
+
}
|
|
40370
|
+
function readResourcePolicyResource(properties) {
|
|
40371
|
+
if (properties === void 0) return [];
|
|
40372
|
+
properties = renderIntrinsics(properties);
|
|
40373
|
+
const policyKeys = Object.keys(properties).filter((key) => key.indexOf("Policy") > -1);
|
|
40374
|
+
const resourceKeys = Object.keys(properties).filter((key) => !policyKeys.includes(key) && !key.endsWith("Name"));
|
|
40375
|
+
let resources = resourceKeys.length === 1 ? properties[resourceKeys[0]] : ["???"];
|
|
40376
|
+
if (!Array.isArray(resources)) resources = [resources];
|
|
40377
|
+
return resources.flatMap((resource) => defaultResource(resource, parseStatements(properties[policyKeys[0]].Statement)));
|
|
40378
|
+
}
|
|
40379
|
+
function readManagedPolicies(policyArns, logicalId) {
|
|
40380
|
+
if (!policyArns) return [];
|
|
40381
|
+
const identity = "${" + logicalId + "}";
|
|
40382
|
+
const arns = renderIntrinsics(policyArns);
|
|
40383
|
+
return typeof arns === "string" ? [new ManagedPolicyAttachment(identity, arns)] : arns.map((arn) => new ManagedPolicyAttachment(identity, arn));
|
|
40384
|
+
}
|
|
40385
|
+
function readLambdaStatements(properties) {
|
|
40386
|
+
if (!properties) return [];
|
|
40387
|
+
return [parseLambdaPermission(renderIntrinsics(properties))];
|
|
40388
|
+
}
|
|
40389
|
+
function readInlineRules(rules, logicalId) {
|
|
40390
|
+
if (!rules || !Array.isArray(rules)) return [];
|
|
40391
|
+
const ref = "${" + logicalId + ".GroupId}";
|
|
40392
|
+
return rules.flatMap((rule) => {
|
|
40393
|
+
const rendered = renderIntrinsics(rule);
|
|
40394
|
+
return typeof rendered === "object" ? [new SecurityGroupRule(rendered, ref)] : [];
|
|
40395
|
+
});
|
|
40396
|
+
}
|
|
40397
|
+
function readRuleResource(resource) {
|
|
40398
|
+
if (!resource) return [];
|
|
40399
|
+
return [new SecurityGroupRule(renderIntrinsics(resource))];
|
|
40400
|
+
}
|
|
40401
|
+
const permissionSetFields = (p) => ({
|
|
40402
|
+
name: p.Name,
|
|
40403
|
+
ssoInstanceArn: p.InstanceArn,
|
|
40404
|
+
ssoCustomerManagedPolicyReferences: p.CustomerManagedPolicyReferences,
|
|
40405
|
+
ssoPermissionsBoundary: p.PermissionsBoundary
|
|
40406
|
+
});
|
|
40407
|
+
const assignmentFields = (p) => ({
|
|
40408
|
+
ssoInstanceArn: p.InstanceArn,
|
|
40409
|
+
permissionSetArn: p.PermissionSetArn,
|
|
40410
|
+
principalId: p.PrincipalId,
|
|
40411
|
+
principalType: p.PrincipalType,
|
|
40412
|
+
targetId: p.TargetId,
|
|
40413
|
+
targetType: p.TargetType
|
|
40414
|
+
});
|
|
40415
|
+
const acaConfigFields = (p) => ({
|
|
40416
|
+
ssoInstanceArn: p.InstanceArn,
|
|
40417
|
+
accessControlAttributes: p.AccessControlAttributes
|
|
40418
|
+
});
|
|
40419
|
+
function readSso(properties, logicalId, fields) {
|
|
40420
|
+
if (properties === void 0) return [];
|
|
40421
|
+
const values = Object.fromEntries(Object.entries({
|
|
40422
|
+
cfnLogicalId: "${" + logicalId + "}",
|
|
40423
|
+
...fields(renderIntrinsics(properties))
|
|
40424
|
+
}).filter(([, v]) => v !== void 0));
|
|
40425
|
+
return [new SsoElement(values)];
|
|
40426
|
+
}
|
|
40427
|
+
function withHeader(color, header, rows, then = () => 0) {
|
|
40428
|
+
rows.sort((a, b) => {
|
|
40429
|
+
const keyA = sortKey(a, color);
|
|
40430
|
+
const keyB = sortKey(b, color);
|
|
40431
|
+
if (keyA < keyB) return -1;
|
|
40432
|
+
if (keyB < keyA) return 1;
|
|
40433
|
+
return then(a) - then(b);
|
|
40434
|
+
});
|
|
40435
|
+
return [header, ...rows];
|
|
40436
|
+
}
|
|
40437
|
+
function sortKey(row, color) {
|
|
40438
|
+
const open = !color ? "" : row[0] === "-" ? "\x1B[31m" : row[0] === "+" ? "\x1B[32m" : "";
|
|
40439
|
+
if (open === "" || row[1] === "") return row[1];
|
|
40440
|
+
const close = "\x1B[39m";
|
|
40441
|
+
return open + row[1].replace(/\r?\n/g, (m) => close + m + open) + close;
|
|
40442
|
+
}
|
|
40443
|
+
function summarizeStatements(changes, color) {
|
|
40444
|
+
return withHeader(color, [
|
|
40445
|
+
"",
|
|
40446
|
+
"Resource",
|
|
40447
|
+
"Effect",
|
|
40448
|
+
"Action",
|
|
40449
|
+
"Principal",
|
|
40450
|
+
"Condition"
|
|
40451
|
+
], [...changes.statements.additions.map((s) => ["+", ...s.render()]), ...changes.statements.removals.map((s) => ["-", ...s.render()])]);
|
|
40452
|
+
}
|
|
40453
|
+
function summarizeManagedPolicies(changes, color) {
|
|
40454
|
+
return withHeader(color, [
|
|
40455
|
+
"",
|
|
40456
|
+
"Resource",
|
|
40457
|
+
"Managed Policy ARN"
|
|
40458
|
+
], [...changes.managedPolicies.additions.map((a) => [
|
|
40459
|
+
"+",
|
|
40460
|
+
a.identityArn,
|
|
40461
|
+
a.managedPolicyArn
|
|
40462
|
+
]), ...changes.managedPolicies.removals.map((a) => [
|
|
40463
|
+
"-",
|
|
40464
|
+
a.identityArn,
|
|
40465
|
+
a.managedPolicyArn
|
|
40466
|
+
])]);
|
|
40467
|
+
}
|
|
40468
|
+
function ssoRows(collection, cells) {
|
|
40469
|
+
return [...collection.additions.map((e) => ["+", ...cells(e.fields)]), ...collection.removals.map((e) => ["-", ...cells(e.fields)])];
|
|
40470
|
+
}
|
|
40471
|
+
function formatManagedPolicyRef(s) {
|
|
40472
|
+
return `Name: ${s?.Name || ""}, Path: ${s?.Path || ""}`;
|
|
40473
|
+
}
|
|
40474
|
+
function summarizeSsoPermissionSets(changes, color) {
|
|
40475
|
+
const boundary = (pb) => {
|
|
40476
|
+
if (pb?.ManagedPolicyArn !== void 0) return `ManagedPolicyArn: ${pb?.ManagedPolicyArn || ""}`;
|
|
40477
|
+
if (pb?.CustomerManagedPolicyReference !== void 0) return `CustomerManagedPolicyReference: {\n ${formatManagedPolicyRef(pb?.CustomerManagedPolicyReference)}\n}`;
|
|
40478
|
+
return "";
|
|
40479
|
+
};
|
|
40480
|
+
return withHeader(color, [
|
|
40481
|
+
"",
|
|
40482
|
+
"Resource",
|
|
40483
|
+
"InstanceArn",
|
|
40484
|
+
"PermissionSet name",
|
|
40485
|
+
"PermissionsBoundary",
|
|
40486
|
+
"CustomerManagedPolicyReferences"
|
|
40487
|
+
], ssoRows(changes.ssoPermissionSets, (f) => [
|
|
40488
|
+
f.cfnLogicalId || "",
|
|
40489
|
+
f.ssoInstanceArn || "",
|
|
40490
|
+
f.name || "",
|
|
40491
|
+
boundary(f.ssoPermissionsBoundary),
|
|
40492
|
+
f.ssoCustomerManagedPolicyReferences?.map(formatManagedPolicyRef).join("\n") || ""
|
|
40493
|
+
]));
|
|
40494
|
+
}
|
|
40495
|
+
function summarizeSsoInstanceACAConfigs(changes, color) {
|
|
40496
|
+
const attribute = (aca) => `Key: ${aca?.Key}, Values: [${aca?.Value?.Source.join(", ")}]`;
|
|
40497
|
+
return withHeader(color, [
|
|
40498
|
+
"",
|
|
40499
|
+
"Resource",
|
|
40500
|
+
"InstanceArn",
|
|
40501
|
+
"AccessControlAttributes"
|
|
40502
|
+
], ssoRows(changes.ssoInstanceACAConfigs, (f) => [
|
|
40503
|
+
f.cfnLogicalId || "",
|
|
40504
|
+
f.ssoInstanceArn || "",
|
|
40505
|
+
f.accessControlAttributes?.map(attribute).join("\n") || ""
|
|
40506
|
+
]));
|
|
40507
|
+
}
|
|
40508
|
+
function summarizeSsoAssignments(changes, color) {
|
|
40509
|
+
return withHeader(color, [
|
|
40510
|
+
"",
|
|
40511
|
+
"Resource",
|
|
40512
|
+
"InstanceArn",
|
|
40513
|
+
"PermissionSetArn",
|
|
40514
|
+
"PrincipalId",
|
|
40515
|
+
"PrincipalType",
|
|
40516
|
+
"TargetId",
|
|
40517
|
+
"TargetType"
|
|
40518
|
+
], ssoRows(changes.ssoAssignments, (f) => [
|
|
40519
|
+
f.cfnLogicalId || "",
|
|
40520
|
+
f.ssoInstanceArn || "",
|
|
40521
|
+
f.permissionSetArn || "",
|
|
40522
|
+
f.principalId || "",
|
|
40523
|
+
f.principalType || "",
|
|
40524
|
+
f.targetId || "",
|
|
40525
|
+
f.targetType || ""
|
|
40526
|
+
]));
|
|
40527
|
+
}
|
|
40528
|
+
function summarizeSecurityGroups(changes, color) {
|
|
40529
|
+
const render = (sign, dir) => (rule) => [
|
|
40530
|
+
sign,
|
|
40531
|
+
`${rule.groupId}`,
|
|
40532
|
+
dir,
|
|
40533
|
+
rule.describeProtocol(),
|
|
40534
|
+
rule.describePeer()
|
|
40535
|
+
];
|
|
40536
|
+
return withHeader(color, [
|
|
40537
|
+
"",
|
|
40538
|
+
"Group",
|
|
40539
|
+
"Dir",
|
|
40540
|
+
"Protocol",
|
|
40541
|
+
"Peer"
|
|
40542
|
+
], [
|
|
40543
|
+
...changes.ingress.additions.map(render("+", "In")),
|
|
40544
|
+
...changes.egress.additions.map(render("+", "Out")),
|
|
40545
|
+
...changes.ingress.removals.map(render("-", "In")),
|
|
40546
|
+
...changes.egress.removals.map(render("-", "Out"))
|
|
40547
|
+
], (row) => row[2].indexOf("In") > -1 ? 0 : 1);
|
|
40548
|
+
}
|
|
40549
|
+
function displayWidth(text) {
|
|
40550
|
+
let width = 0;
|
|
40551
|
+
for (const ch of text.replace(/(?:\p{Regional_Indicator}{2}|\p{Emoji_Presentation}|\p{Extended_Pictographic}\uFE0F)\p{Emoji_Modifier}?(?:\u200D(?:\p{Emoji_Presentation}|\p{Extended_Pictographic}\uFE0F?)\p{Emoji_Modifier}?)*/gu, " ")) {
|
|
40552
|
+
const code = ch.codePointAt(0);
|
|
40553
|
+
if (code <= 31 || code >= 127 && code <= 159) continue;
|
|
40554
|
+
if (code >= 768 && code <= 879) continue;
|
|
40555
|
+
width += isFullwidth(code) ? 2 : 1;
|
|
40556
|
+
}
|
|
40557
|
+
return width;
|
|
40558
|
+
}
|
|
40559
|
+
function isFullwidth(c) {
|
|
40560
|
+
return c >= 4352 && (c <= 4447 || c === 9001 || c === 9002 || c >= 11904 && c <= 12871 && c !== 12351 || c >= 12880 && c <= 19903 || c >= 19968 && c <= 42182 || c >= 43360 && c <= 43388 || c >= 44032 && c <= 55203 || c >= 63744 && c <= 64255 || c >= 65040 && c <= 65049 || c >= 65072 && c <= 65131 || c >= 65281 && c <= 65376 || c >= 65504 && c <= 65510 || c >= 110592 && c <= 110593 || c >= 127488 && c <= 127569 || c >= 131072 && c <= 262141);
|
|
40561
|
+
}
|
|
40562
|
+
function formatTable(cells, color) {
|
|
40563
|
+
const paint = (fn) => color ? fn : (text) => text;
|
|
40564
|
+
const lines = cells.map((row) => row.map((cell) => String(cell).split("\n")));
|
|
40565
|
+
const widths = cells[0].map((_, i) => Math.max(...lines.map((row) => Math.max(...row[i].map(displayWidth)))));
|
|
40566
|
+
const rule = (left, join, right) => paint(gray)(left + widths.map((w) => "─".repeat(w + 2)).join(join) + right);
|
|
40567
|
+
const bar = paint(gray)("│");
|
|
40568
|
+
const out = [rule("┌", "┬", "┐")];
|
|
40569
|
+
lines.forEach((row, r) => {
|
|
40570
|
+
if (r > 0 && (r === 1 || sortKey(cells[r - 1], color) !== sortKey(cells[r], color))) out.push(rule("├", "┼", "┤"));
|
|
40571
|
+
const sign = r === 0 ? "" : cells[r][0];
|
|
40572
|
+
const tint = paint(sign === "+" ? green : sign === "-" ? red : (text) => text);
|
|
40573
|
+
const height = Math.max(...row.map((cell) => cell.length));
|
|
40574
|
+
for (let l = 0; l < height; l++) {
|
|
40575
|
+
const cellsOut = row.map((cell, i) => {
|
|
40576
|
+
const text = cell[l] ?? "";
|
|
40577
|
+
return " " + (text === "" ? "" : tint(text)) + " ".repeat(widths[i] - displayWidth(text)) + " ";
|
|
40578
|
+
});
|
|
40579
|
+
out.push(bar + cellsOut.join(bar) + bar);
|
|
40580
|
+
}
|
|
40581
|
+
});
|
|
40582
|
+
out.push(rule("└", "┴", "┘"));
|
|
40583
|
+
return out.join("\n");
|
|
40584
|
+
}
|
|
40585
|
+
function formatSecurityChanges(changes, logicalToPath = {}, color = stdoutSupportsColor()) {
|
|
40586
|
+
if (!changes.permissionsAnyChanges) return "";
|
|
40587
|
+
const paint = (fn) => color ? fn : (text) => text;
|
|
40588
|
+
const substitute = (source) => source.replace(/\$\{([^.}]+)(.[^}]+)?\}/gi, (_m, logId, suffix) => {
|
|
40589
|
+
const path = Object.hasOwn(logicalToPath, logId) ? logicalToPath[logId] : void 0;
|
|
40590
|
+
return "${" + (path && normalizePath(path) || logId) + (suffix || "") + "}";
|
|
40591
|
+
});
|
|
40592
|
+
let out = "";
|
|
40593
|
+
const section = (title) => {
|
|
40594
|
+
out += `${paint(bold)(title)}\n`;
|
|
40595
|
+
};
|
|
40596
|
+
const table = (rows) => {
|
|
40597
|
+
out += formatTable(rows.map((row) => row.map(substitute)), color) + "\n";
|
|
40598
|
+
};
|
|
40599
|
+
if (changes.statements.hasChanges) {
|
|
40600
|
+
section("IAM Statement Changes");
|
|
40601
|
+
table(summarizeStatements(changes, color));
|
|
40602
|
+
}
|
|
40603
|
+
if (changes.managedPolicies.hasChanges) {
|
|
40604
|
+
section("IAM Policy Changes");
|
|
40605
|
+
table(summarizeManagedPolicies(changes, color));
|
|
40606
|
+
}
|
|
40607
|
+
if (changes.ssoPermissionSets.hasChanges || changes.ssoInstanceACAConfigs.hasChanges || changes.ssoAssignments.hasChanges) {
|
|
40608
|
+
section("IAM Identity Center Changes");
|
|
40609
|
+
if (changes.ssoPermissionSets.hasChanges) table(summarizeSsoPermissionSets(changes, color));
|
|
40610
|
+
if (changes.ssoInstanceACAConfigs.hasChanges) table(summarizeSsoInstanceACAConfigs(changes, color));
|
|
40611
|
+
if (changes.ssoAssignments.hasChanges) table(summarizeSsoAssignments(changes, color));
|
|
40612
|
+
}
|
|
40613
|
+
if (changes.securityGroupsHaveChanges) {
|
|
40614
|
+
section("Security Group Changes");
|
|
40615
|
+
table(summarizeSecurityGroups(changes, color));
|
|
40616
|
+
}
|
|
40617
|
+
out += `${paint(yellow)("(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)")}\n`;
|
|
40618
|
+
out += "\n";
|
|
40619
|
+
return out;
|
|
40620
|
+
}
|
|
40621
|
+
function normalizePath(p) {
|
|
40622
|
+
if (p.startsWith("/")) p = p.slice(1);
|
|
40623
|
+
let parts = p.split("/");
|
|
40624
|
+
if (parts.length > 1) {
|
|
40625
|
+
parts = parts.slice(1);
|
|
40626
|
+
if (parts.length > 1) {
|
|
40627
|
+
const last = parts[parts.length - 1];
|
|
40628
|
+
if (last === "Resource" || last === "Default") parts = parts.slice(0, parts.length - 1);
|
|
40629
|
+
}
|
|
40630
|
+
p = parts.join("/");
|
|
40631
|
+
}
|
|
40632
|
+
return p;
|
|
40633
|
+
}
|
|
40634
|
+
function stdoutSupportsColor(env = process.env, argv = process.argv, isTTY = process.stdout.isTTY === true, platform = process.platform) {
|
|
40635
|
+
const terminator = argv.indexOf("--");
|
|
40636
|
+
const hasFlag = (flag) => {
|
|
40637
|
+
const position = argv.indexOf(`--${flag}`);
|
|
40638
|
+
return position !== -1 && (terminator === -1 || position < terminator);
|
|
40639
|
+
};
|
|
40640
|
+
let force;
|
|
40641
|
+
if ([
|
|
40642
|
+
"no-color",
|
|
40643
|
+
"no-colors",
|
|
40644
|
+
"color=false",
|
|
40645
|
+
"color=never"
|
|
40646
|
+
].some(hasFlag)) force = 0;
|
|
40647
|
+
else if ([
|
|
40648
|
+
"color",
|
|
40649
|
+
"colors",
|
|
40650
|
+
"color=true",
|
|
40651
|
+
"color=always"
|
|
40652
|
+
].some(hasFlag)) force = 1;
|
|
40653
|
+
const forceEnv = env["FORCE_COLOR"];
|
|
40654
|
+
if (forceEnv !== void 0) {
|
|
40655
|
+
if (forceEnv === "true") force = 1;
|
|
40656
|
+
else if (forceEnv === "false") force = 0;
|
|
40657
|
+
else force = forceEnv.length === 0 ? 1 : Math.min(parseInt(forceEnv, 10), 3);
|
|
40658
|
+
}
|
|
40659
|
+
if (force === 0) return false;
|
|
40660
|
+
if ([
|
|
40661
|
+
"color=16m",
|
|
40662
|
+
"color=full",
|
|
40663
|
+
"color=truecolor",
|
|
40664
|
+
"color=256"
|
|
40665
|
+
].some(hasFlag)) return true;
|
|
40666
|
+
if (!isTTY && force === void 0) return false;
|
|
40667
|
+
const min = force || 0;
|
|
40668
|
+
if (env["TERM"] === "dumb") return min > 0;
|
|
40669
|
+
if (platform === "win32") return true;
|
|
40670
|
+
if ("CI" in env) return [
|
|
40671
|
+
"TRAVIS",
|
|
40672
|
+
"CIRCLECI",
|
|
40673
|
+
"APPVEYOR",
|
|
40674
|
+
"GITLAB_CI",
|
|
40675
|
+
"GITHUB_ACTIONS",
|
|
40676
|
+
"BUILDKITE"
|
|
40677
|
+
].some((sign) => sign in env) || env["CI_NAME"] === "codeship" || min > 0;
|
|
40678
|
+
if ("TEAMCITY_VERSION" in env) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env["TEAMCITY_VERSION"] ?? "");
|
|
40679
|
+
if (env["COLORTERM"] === "truecolor") return true;
|
|
40680
|
+
if (env["TERM_PROGRAM"] === "iTerm.app" || env["TERM_PROGRAM"] === "Apple_Terminal") return true;
|
|
40681
|
+
const term = env["TERM"] ?? "";
|
|
40682
|
+
if (/-256(color)?$/i.test(term)) return true;
|
|
40683
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(term)) return true;
|
|
40684
|
+
if ("COLORTERM" in env) return true;
|
|
40685
|
+
return min > 0;
|
|
40686
|
+
}
|
|
40687
|
+
|
|
40688
|
+
//#endregion
|
|
40689
|
+
//#region src/analyzer/security-diff.ts
|
|
40690
|
+
function isSyntheticChange(pc) {
|
|
40691
|
+
return pc.replacementPropagated === true || pc.inPlacePropagated === true || pc.noEchoPromoted === true;
|
|
40692
|
+
}
|
|
40693
|
+
function withChanges(base, changes, side) {
|
|
40694
|
+
const props = { ...base ?? {} };
|
|
40695
|
+
for (const pc of changes) {
|
|
40696
|
+
const value = pc[side];
|
|
40697
|
+
if (value === void 0) delete props[pc.path];
|
|
40698
|
+
else props[pc.path] = value;
|
|
40699
|
+
}
|
|
40700
|
+
return props;
|
|
40701
|
+
}
|
|
40702
|
+
function securityDiffTemplates(changes, records) {
|
|
40703
|
+
const oldResources = {};
|
|
40704
|
+
const newResources = {};
|
|
40705
|
+
const maskedChanges = [];
|
|
40706
|
+
for (const change of changes) {
|
|
40707
|
+
const id = change.logicalId;
|
|
40708
|
+
const record = Object.hasOwn(records, id) ? records[id] : void 0;
|
|
40709
|
+
switch (change.changeType) {
|
|
40710
|
+
case "CREATE":
|
|
40711
|
+
newResources[id] = {
|
|
40712
|
+
Type: change.resourceType,
|
|
40713
|
+
Properties: { ...change.desiredProperties ?? {} }
|
|
40714
|
+
};
|
|
40715
|
+
break;
|
|
40716
|
+
case "DELETE":
|
|
40717
|
+
oldResources[id] = {
|
|
40718
|
+
Type: record?.resourceType ?? change.resourceType,
|
|
40719
|
+
Properties: { ...change.currentProperties ?? record?.properties ?? {} }
|
|
40720
|
+
};
|
|
40721
|
+
break;
|
|
40722
|
+
case "UPDATE": {
|
|
40723
|
+
const pcs = change.propertyChanges ?? [];
|
|
40724
|
+
const typeChange = pcs.find((pc) => pc.path === "Type");
|
|
40725
|
+
const oldType = record?.resourceType ?? change.resourceType;
|
|
40726
|
+
if (typeChange !== void 0 || oldType !== change.resourceType) {
|
|
40727
|
+
oldResources[id] = {
|
|
40728
|
+
Type: typeof typeChange?.oldValue === "string" ? typeChange.oldValue : oldType,
|
|
40729
|
+
Properties: { ...change.currentProperties ?? record?.properties ?? {} }
|
|
40730
|
+
};
|
|
40731
|
+
newResources[id] = {
|
|
40732
|
+
Type: change.resourceType,
|
|
40733
|
+
Properties: { ...change.desiredProperties ?? {} }
|
|
40734
|
+
};
|
|
40735
|
+
break;
|
|
40736
|
+
}
|
|
40737
|
+
for (const pc of pcs) if (pc.maskedExpressionChanged === true && !isSyntheticChange(pc)) maskedChanges.push({
|
|
40738
|
+
logicalId: id,
|
|
40739
|
+
resourceType: change.resourceType,
|
|
40740
|
+
path: pc.path
|
|
40741
|
+
});
|
|
40742
|
+
const real = pcs.filter((pc) => !isSyntheticChange(pc) && pc.maskedExpressionChanged !== true);
|
|
40743
|
+
if (real.length === 0) break;
|
|
40744
|
+
const base = change.currentProperties ?? record?.properties;
|
|
40745
|
+
oldResources[id] = {
|
|
40746
|
+
Type: oldType,
|
|
40747
|
+
Properties: withChanges(base, real, "oldValue")
|
|
40748
|
+
};
|
|
40749
|
+
newResources[id] = {
|
|
40750
|
+
Type: change.resourceType,
|
|
40751
|
+
Properties: withChanges(base, real, "newValue")
|
|
40752
|
+
};
|
|
40753
|
+
break;
|
|
40754
|
+
}
|
|
40755
|
+
}
|
|
40756
|
+
}
|
|
40757
|
+
return {
|
|
40758
|
+
oldTemplate: { Resources: oldResources },
|
|
40759
|
+
newTemplate: { Resources: newResources },
|
|
40760
|
+
maskedChanges
|
|
40761
|
+
};
|
|
40762
|
+
}
|
|
40763
|
+
async function diffSecurity(args) {
|
|
40764
|
+
const templates = securityDiffTemplates(args.changes, args.records);
|
|
40765
|
+
const { oldTemplate, newTemplate } = templates;
|
|
40766
|
+
if (Object.keys(oldTemplate.Resources).length === 0 && Object.keys(newTemplate.Resources).length === 0 && templates.maskedChanges.length === 0) return {
|
|
40767
|
+
broadening: false,
|
|
40768
|
+
rendered: ""
|
|
40769
|
+
};
|
|
40770
|
+
try {
|
|
40771
|
+
const unjudged = templates.maskedChanges.filter((c) => isScrutinizedProperty(c.resourceType, c.path));
|
|
40772
|
+
const diff = new SecurityChanges(structuredClone(oldTemplate), structuredClone(newTemplate));
|
|
40773
|
+
const broadening = diff.permissionsBroadened || unjudged.length > 0;
|
|
40774
|
+
const unjudgedNote = unjudged.length === 0 ? "" : "These changed values are masked, so whether they broaden permissions could not be evaluated:\n" + unjudged.map((c) => ` ${c.logicalId} (${c.resourceType}): ${c.path}\n`).join("");
|
|
40775
|
+
if (!diff.permissionsBroadened && !diff.permissionsAnyChanges) return {
|
|
40776
|
+
broadening,
|
|
40777
|
+
rendered: terminalSafe(unjudgedNote)
|
|
40778
|
+
};
|
|
40779
|
+
let table;
|
|
40780
|
+
try {
|
|
40781
|
+
const shown = args.secretMask === void 0 ? void 0 : withholdSecrets(templates, args.secretMask());
|
|
40782
|
+
const shownDiff = shown === void 0 || shown.masked === 0 ? diff : new SecurityChanges(shown.templates.oldTemplate, shown.templates.newTemplate);
|
|
40783
|
+
table = formatSecurityChanges(shownDiff, logicalIdToPath(args.records, args.template));
|
|
40784
|
+
if (shown !== void 0 && shown.masked > 0) table += "(Values that hold a secret are shown as ***.)\n";
|
|
40785
|
+
} catch {
|
|
40786
|
+
table = "The security changes are not shown: they could not be checked for secrets.\n";
|
|
40787
|
+
}
|
|
40788
|
+
return {
|
|
40789
|
+
broadening,
|
|
40790
|
+
rendered: terminalSafe(table + unjudgedNote)
|
|
40791
|
+
};
|
|
40792
|
+
} catch (error) {
|
|
40793
|
+
throw new CdkdError(safeMsg`Could not compute the security diff of stack ${args.stackName}, so whether its changes broaden permissions is unknown: ${error instanceof Error ? error.message : String(error)}`, "SECURITY_DIFF_FAILED");
|
|
40794
|
+
}
|
|
40795
|
+
}
|
|
40796
|
+
function holdsSecret(value, mask) {
|
|
40797
|
+
if (typeof value === "string") return mask(value) !== value;
|
|
40798
|
+
if (typeof value === "number" || typeof value === "boolean") return mask(String(value)) !== String(value);
|
|
40799
|
+
if (Array.isArray(value)) return value.some((v) => holdsSecret(v, mask));
|
|
40800
|
+
if (value !== null && typeof value === "object") return Object.entries(value).some(([k, v]) => mask(k) !== k || holdsSecret(v, mask));
|
|
40801
|
+
return false;
|
|
40802
|
+
}
|
|
40803
|
+
function maskLeaves(value, mask, keys = true) {
|
|
40804
|
+
if (Array.isArray(value)) return value.map((v) => maskLeaves(v, mask, keys));
|
|
40805
|
+
if (value !== null && typeof value === "object") {
|
|
40806
|
+
const entries = Object.entries(value).map(([k, v]) => [keys && mask(k) !== k ? "***" : k, maskLeaves(v, mask, keys)]);
|
|
40807
|
+
if (new Set(entries.map(([k]) => k)).size < entries.length) return "***";
|
|
40808
|
+
return Object.fromEntries(entries);
|
|
40809
|
+
}
|
|
40810
|
+
return holdsSecret(value, mask) ? "***" : value;
|
|
40811
|
+
}
|
|
40812
|
+
function withholdSecrets(templates, mask) {
|
|
40813
|
+
const copy = structuredClone(templates);
|
|
40814
|
+
let masked = 0;
|
|
40815
|
+
const ids = /* @__PURE__ */ new Set([...Object.keys(copy.oldTemplate.Resources), ...Object.keys(copy.newTemplate.Resources)]);
|
|
40816
|
+
for (const id of ids) {
|
|
40817
|
+
const oldProps = copy.oldTemplate.Resources[id]?.Properties;
|
|
40818
|
+
const newProps = copy.newTemplate.Resources[id]?.Properties;
|
|
40819
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(oldProps ?? {}), ...Object.keys(newProps ?? {})]);
|
|
40820
|
+
for (const key of keys) {
|
|
40821
|
+
const oldValue = oldProps?.[key];
|
|
40822
|
+
const newValue = newProps?.[key];
|
|
40823
|
+
const newHolds = holdsSecret(newValue, mask);
|
|
40824
|
+
if (!newHolds && !holdsSecret(oldValue, mask)) continue;
|
|
40825
|
+
masked++;
|
|
40826
|
+
if (newProps !== void 0 && newValue !== void 0) newProps[key] = maskLeaves(newValue, mask);
|
|
40827
|
+
if (oldProps === void 0 || oldValue === void 0) continue;
|
|
40828
|
+
if (newHolds && JSON.stringify(oldValue) !== JSON.stringify(newValue)) oldProps[key] = maskLeaves(oldValue, () => "***", false);
|
|
40829
|
+
else oldProps[key] = maskLeaves(oldValue, mask);
|
|
40830
|
+
}
|
|
40831
|
+
}
|
|
40832
|
+
return {
|
|
40833
|
+
templates: copy,
|
|
40834
|
+
masked
|
|
40835
|
+
};
|
|
40836
|
+
}
|
|
40837
|
+
function logicalIdToPath(records, template) {
|
|
40838
|
+
const map = {};
|
|
40839
|
+
for (const [id, record] of Object.entries(records)) if (typeof record?.constructPath === "string") map[id] = record.constructPath;
|
|
40840
|
+
for (const [id, resource] of Object.entries(template?.Resources ?? {})) {
|
|
40841
|
+
const path = (resource?.Metadata)?.["aws:cdk:path"];
|
|
40842
|
+
if (typeof path === "string") map[id] = path;
|
|
40843
|
+
}
|
|
40844
|
+
return map;
|
|
40845
|
+
}
|
|
40846
|
+
|
|
38849
40847
|
//#endregion
|
|
38850
40848
|
//#region src/deployment/resource-deadline.ts
|
|
38851
40849
|
var InvalidResourceDeadlineError = class extends Error {
|
|
@@ -38953,7 +40951,16 @@ async function requireDeploymentApproval(args) {
|
|
|
38953
40951
|
const changes = [...args.changes].filter((c) => c.changeType !== "NO_CHANGE" && !isNoEchoPromotionOnly(c));
|
|
38954
40952
|
const destructiveChanges = findDestructiveChanges(args.stackName, changes, args.records, args.template, new Set(args.recreateTargetIds ?? []));
|
|
38955
40953
|
const onlyNestedUpdates = changes.every((c) => c.changeType === "UPDATE" && c.resourceType === NESTED_STACK_TYPE$1);
|
|
38956
|
-
|
|
40954
|
+
const security = level === "broadening" ? await diffSecurity({
|
|
40955
|
+
stackName: args.stackName,
|
|
40956
|
+
changes,
|
|
40957
|
+
records: args.records,
|
|
40958
|
+
template: args.template,
|
|
40959
|
+
secretMask: args.secretMask
|
|
40960
|
+
}).catch((error) => {
|
|
40961
|
+
throw error instanceof Error ? markNonRetryable(error) : error;
|
|
40962
|
+
}) : void 0;
|
|
40963
|
+
if (!(level === "destructive" ? destructiveChanges.length > 0 : level === "broadening" ? security?.broadening === true : changes.length > 0 && !onlyNestedUpdates)) return false;
|
|
38957
40964
|
const count = (type) => changes.filter((c) => c.changeType === type).length;
|
|
38958
40965
|
if (enclosingDeadlineExpired()) throw approvalAfterTimeout(args.stackName);
|
|
38959
40966
|
let approved;
|
|
@@ -38966,7 +40973,8 @@ async function requireDeploymentApproval(args) {
|
|
|
38966
40973
|
update: count("UPDATE"),
|
|
38967
40974
|
delete: count("DELETE")
|
|
38968
40975
|
},
|
|
38969
|
-
destructiveChanges
|
|
40976
|
+
destructiveChanges,
|
|
40977
|
+
...security !== void 0 && { securityChanges: security.rendered }
|
|
38970
40978
|
}));
|
|
38971
40979
|
} catch (error) {
|
|
38972
40980
|
throw error instanceof Error ? markNonRetryable(error) : error;
|
|
@@ -38986,7 +40994,7 @@ async function checkDestructivePlan(args) {
|
|
|
38986
40994
|
async function approveLateReplacement(args) {
|
|
38987
40995
|
const level = args.options.requireApproval ?? "never";
|
|
38988
40996
|
const approve = args.options.approveDeployment;
|
|
38989
|
-
if (level === "never" || approve === void 0) return true;
|
|
40997
|
+
if (level === "never" || level === "broadening" || approve === void 0) return true;
|
|
38990
40998
|
if (enclosingDeadlineExpired()) return false;
|
|
38991
40999
|
try {
|
|
38992
41000
|
const approved = await whileEnclosingDeadlinesPaused(() => approve({
|
|
@@ -39245,15 +41253,35 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39245
41253
|
if (resourceType === "AWS::CloudFormation::Stack") recordPassedNoEchoParameters(updateSecrets, desiredProps["Parameters"], this.noEchoPositionSources(stateResources));
|
|
39246
41254
|
if (fingerprintSources !== void 0 && resourceType === "AWS::CloudFormation::Stack") recordPassedParameterClasses(updateSecrets, await classifyPassedParameters(desiredProps["Parameters"], fingerprintSources));
|
|
39247
41255
|
const desiredForSkipCheck = maskAtCoordinates(redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), updateSecrets, desiredProps), comparisonCoordinates);
|
|
41256
|
+
const legacyDesired = withoutPhysicalNameCopies(updateSecrets, () => maskAtCoordinates(redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), updateSecrets, desiredProps), comparisonCoordinates));
|
|
41257
|
+
const copies = physicalNameCopiesOf.get(updateSecrets);
|
|
41258
|
+
const regionEvidence = getCurrentProducerRegions()?.();
|
|
41259
|
+
const recordOwnSecrets = copies !== void 0 && copies.size > 0 && regionEvidence?.complete === true && recordHoldsEmbeddedReference(currentResource) ? await resolveRecordSecrets({
|
|
41260
|
+
properties: currentResource.properties,
|
|
41261
|
+
attributes: currentResource.attributes
|
|
41262
|
+
}, (token, own) => this.resolver.resolveDynamicReferences(token, persistedTokenResolverContext(own, regionEvidence.regions))) : void 0;
|
|
41263
|
+
const embeddedRewrites = [...embeddedPhysicalNameRewrites(updateSecrets), ...recordOwnSecrets === void 0 || recordOwnSecrets.size === 0 ? [] : embeddedPhysicalNameRewrites(updateSecrets, recordOwnSecrets)];
|
|
41264
|
+
const repairable = [currentProps, currentResource.properties].filter((bag) => bag !== null && typeof bag === "object");
|
|
41265
|
+
for (const bag of new Set(repairable)) for (const key of Object.keys(bag)) {
|
|
41266
|
+
const repaired = repairEmbeddedPhysicalNamesTowards(repairPhysicalNameCopyLeaves(bag[key], legacyDesired[key], desiredForSkipCheck[key]), desiredForSkipCheck[key], embeddedRewrites);
|
|
41267
|
+
if (repaired !== bag[key]) bag[key] = repaired;
|
|
41268
|
+
}
|
|
41269
|
+
const attributes = currentResource.attributes;
|
|
41270
|
+
if (attributes !== void 0 && attributes !== null && embeddedRewrites.length > 0) for (const key of Object.keys(attributes)) {
|
|
41271
|
+
const repaired = replaceEmbeddedPhysicalNameRewrites(attributes[key], embeddedRewrites);
|
|
41272
|
+
if (repaired !== attributes[key]) attributes[key] = repaired;
|
|
41273
|
+
}
|
|
39248
41274
|
const allowedSilentDrops = this.providerRegistry.getAllowedUnsupportedProperties?.();
|
|
39249
41275
|
const desiredForSkipCheckAsWritten = currentResource.provisionedBy !== "cc-api" && allowedSilentDrops ? withoutAcceptedSilentDropProperties(resourceType, desiredForSkipCheck, allowedSilentDrops, currentResource.properties) : desiredForSkipCheck;
|
|
39250
41276
|
const allowedForRecord = allowedSilentDrops ?? /* @__PURE__ */ new Set();
|
|
39251
41277
|
const createOnlyEvidence = acceptedCreateOnlyDropsOf(currentResource);
|
|
39252
41278
|
const recordedAsWritten = currentResource.provisionedBy === "cc-api" ? currentProps : withoutUnwrittenSilentDropProperties(resourceType, currentProps, desiredForSkipCheck, allowedForRecord, createOnlyEvidence);
|
|
39253
41279
|
const unmarkedRecord = noEchoLeavesOf(currentResource) === void 0;
|
|
39254
|
-
const todayAsWritten = unmarkedRecord ? redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), withoutNoEchoParameterEntries(updateSecrets), desiredProps) : void 0;
|
|
41280
|
+
const todayAsWritten = unmarkedRecord || witnessNormalize(recordedAsWritten, void 0, desiredForSkipCheckAsWritten).differing.length > 0 ? redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), withoutNoEchoParameterEntries(updateSecrets), desiredProps) : void 0;
|
|
39255
41281
|
const witness = todayAsWritten === void 0 ? void 0 : witnessNormalize(recordedAsWritten, todayAsWritten, desiredForSkipCheckAsWritten);
|
|
39256
41282
|
const currentPropsAsWritten = witness === void 0 ? recordedAsWritten : witness.current;
|
|
41283
|
+
const witnessMigrates = unmarkedRecord || (witness?.confirmed.length ?? 0) > 0;
|
|
41284
|
+
if (!unmarkedRecord && witness !== void 0 && witness.confirmed.length > 0) this.witnessConfirmedLeaves.set(logicalId, witness.confirmed.map((coordinate) => [...coordinate]));
|
|
39257
41285
|
for (const coordinate of witness?.differing ?? []) {
|
|
39258
41286
|
const desiredAt = valueAtCoordinate(desiredForSkipCheckAsWritten, coordinate);
|
|
39259
41287
|
recordPreviousNoEchoLeaves(this.secretNameBagFor(logicalId), valueAtCoordinate(recordedAsWritten, coordinate), scalarLeavesOf(desiredAt), updateSecrets, desiredAt !== "***");
|
|
@@ -39310,7 +41338,8 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39310
41338
|
this.logger.warn(cause === "parameter" ? safeMsg`${logicalId}.${key} is a create-only property, and a NoEcho parameter's value changed since the last deploy: ${logicalId} is replaced.` : safeMsg`${logicalId}.${key} is a create-only property, and the value at its NoEcho position changed since the last deploy: ${logicalId} is replaced.`);
|
|
39311
41339
|
};
|
|
39312
41340
|
const suppliesFreshMaskOnlyValue = pendingParameterLeaves.size > 0 || Object.keys(resolvedProps).some((key) => otherFreshAt(key).length > 0);
|
|
39313
|
-
const
|
|
41341
|
+
const rewrittenPaths = readsProducerReplacedThisRun.call(this, template, logicalId, stateResources) ? redactionRewrittenPaths(resolvedProps, desiredForSkipCheck, comparisonCoordinates) : /* @__PURE__ */ new Set();
|
|
41342
|
+
const recordMatchesDesired = movedMasked.size === 0 && rewrittenPaths.size === 0 && keyOrderFreeJson(desiredForSkipCheckAsWritten) === keyOrderFreeJson(currentPropsAsWritten);
|
|
39314
41343
|
const applyAttributeOnlyUpdate = (attributeChanges) => {
|
|
39315
41344
|
const attrSummary = attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
|
|
39316
41345
|
this.logger.info(safeMsg` ↻ ${logicalId} (${resourceType}) attribute update: ${attrSummary}`);
|
|
@@ -39326,7 +41355,7 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39326
41355
|
};
|
|
39327
41356
|
const schemaCreateOnly = pendingParameterLeaves.size === 0 && parameterCoordinates.length === 0 ? [] : await getCreateOnlyPropertyPaths(resourceType).catch(() => []);
|
|
39328
41357
|
const echoCandidates = echoFidelityCandidates(parameterCoordinates, resolvedProps, schemaCreateOnly);
|
|
39329
|
-
const readbackRecord =
|
|
41358
|
+
const readbackRecord = witnessMigrates && parameterCoordinates.length > 0 ? {
|
|
39330
41359
|
...currentResource,
|
|
39331
41360
|
properties: maskAtCoordinates(currentResource.properties, parameterCoordinates)
|
|
39332
41361
|
} : currentResource;
|
|
@@ -39383,7 +41412,7 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39383
41412
|
};
|
|
39384
41413
|
const lateReplacementDeclined = /* @__PURE__ */ new Set();
|
|
39385
41414
|
const differsWhy = (key) => !lateReplacementDeclined.has(key) ? "differs; the provider is not known to report this property exactly, so the difference may be its normalization" : lateCrossPrefixRefused ? "differs; the replacement was refused: see the state-prefix warning above" : `differs; the replacement was not approved (--require-approval=${this.options.requireApproval ?? "never"})`;
|
|
39386
|
-
if (
|
|
41415
|
+
if (witnessMigrates && !typeChanged && echoCandidates.length > 0 && hasAddressablePhysicalId(currentResource)) await readOnce();
|
|
39387
41416
|
if (!typeChanged && !suppliesFreshMaskOnlyValue && lostChild === void 0 && this.recreateDirectionFor(stackName, logicalId) === void 0 && recordMatchesDesired) {
|
|
39388
41417
|
if (change.attributeChanges && change.attributeChanges.length > 0) {
|
|
39389
41418
|
applyAttributeOnlyUpdate(change.attributeChanges);
|
|
@@ -39414,7 +41443,7 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39414
41443
|
lowered.push(pc);
|
|
39415
41444
|
continue;
|
|
39416
41445
|
}
|
|
39417
|
-
const moved = movedMasked.has(pc.path) || keyOrderFreeJson(desiredForSkipCheckAsWritten[pc.path]) !== keyOrderFreeJson(currentPropsAsWritten[pc.path]);
|
|
41446
|
+
const moved = movedMasked.has(pc.path) || rewrittenPaths.has(pc.path) || keyOrderFreeJson(desiredForSkipCheckAsWritten[pc.path]) !== keyOrderFreeJson(currentPropsAsWritten[pc.path]);
|
|
39418
41447
|
const conditionalVerdict = moved && !typeChanged && isReplacementCeiling(pc) ? this.diffCalculator.conditionalReplacementVerdict?.(resourceType, pc.path, currentPropsAsWritten[pc.path], desiredForSkipCheckAsWritten[pc.path]) : void 0;
|
|
39419
41448
|
if (moved && conditionalVerdict !== false) {
|
|
39420
41449
|
warnWitnessReplacement(pc.path);
|
|
@@ -39468,7 +41497,7 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39468
41497
|
return liveHoldsFreshLeaves(read.live[key], pendingParameterLeaves.get(key) ?? []) ? "held" : "differs";
|
|
39469
41498
|
};
|
|
39470
41499
|
const lowered = [];
|
|
39471
|
-
const movedAt = (path) => movedMasked.has(path) || keyOrderFreeJson(desiredForSkipCheckAsWritten[path]) !== keyOrderFreeJson(currentPropsAsWritten[path]);
|
|
41500
|
+
const movedAt = (path) => movedMasked.has(path) || rewrittenPaths.has(path) || keyOrderFreeJson(desiredForSkipCheckAsWritten[path]) !== keyOrderFreeJson(currentPropsAsWritten[path]);
|
|
39472
41501
|
replacedAnyway = this.recreateDirectionFor(stackName, logicalId) !== void 0 || lostWithParent !== void 0 || (change.propertyChanges ?? []).some((other) => other.requiresReplacement && (!parameterCreateOnlyPaths.has(other.path) || movedAt(other.path)));
|
|
39473
41502
|
for (const pc of change.propertyChanges ?? []) {
|
|
39474
41503
|
if (!parameterCreateOnlyPaths.has(pc.path)) {
|
|
@@ -39618,11 +41647,16 @@ async function provisionUpdate(logicalId, change, stateResources, stackName, tem
|
|
|
39618
41647
|
diffSawTokenChange: diffMovedServiceToken(change)
|
|
39619
41648
|
});
|
|
39620
41649
|
if (serviceTokenRefusal !== void 0) throw markRefusedBeforeApplying(markNonRetryable(new CdkdError(renderServiceTokenRefusal([serviceTokenRefusal], stackName, createSecretMasker(updateSecrets)), SERVICE_TOKEN_CHANGE_REFUSED)));
|
|
41650
|
+
let previousForProvider = currentPropsAsWritten;
|
|
41651
|
+
for (const coordinate of witness?.confirmed ?? []) {
|
|
41652
|
+
const value = valueAtCoordinate(resolvedProps, coordinate);
|
|
41653
|
+
if (value !== void 0) previousForProvider = setAtCoordinate(previousForProvider, coordinate, value);
|
|
41654
|
+
}
|
|
39621
41655
|
return markRestored(await this.updateInPlace({
|
|
39622
41656
|
conditions,
|
|
39623
41657
|
counts,
|
|
39624
41658
|
currentProps,
|
|
39625
|
-
currentPropsAsWritten,
|
|
41659
|
+
currentPropsAsWritten: previousForProvider,
|
|
39626
41660
|
currentResource,
|
|
39627
41661
|
dependencies,
|
|
39628
41662
|
desiredForSkipCheckAsWritten,
|
|
@@ -39666,6 +41700,26 @@ function recordPreviousNoEchoLeaves(registry, stored, desiredLeaves, resolution,
|
|
|
39666
41700
|
if (partlyMasked !== leaf && partlyMasked !== "***") recordLogOnlyValue(registry, partlyMasked);
|
|
39667
41701
|
}
|
|
39668
41702
|
}
|
|
41703
|
+
function recordHoldsEmbeddedReference(record) {
|
|
41704
|
+
const walk = (node) => {
|
|
41705
|
+
if (typeof node === "string") return node.includes("{{resolve:") && !isSingleDynamicReferenceToken(node);
|
|
41706
|
+
if (node === null || typeof node !== "object") return false;
|
|
41707
|
+
return Object.values(node).some(walk);
|
|
41708
|
+
};
|
|
41709
|
+
return walk(record.properties) || walk(record.attributes);
|
|
41710
|
+
}
|
|
41711
|
+
function redactionRewrittenPaths(resolvedProps, desiredForSkipCheck, comparisonCoordinates) {
|
|
41712
|
+
const masked = maskAtCoordinates({ ...resolvedProps }, comparisonCoordinates);
|
|
41713
|
+
return new Set(Object.keys(masked).filter((key) => keyOrderFreeJson(masked[key]) !== keyOrderFreeJson(desiredForSkipCheck[key])));
|
|
41714
|
+
}
|
|
41715
|
+
function readsProducerReplacedThisRun(template, logicalId, stateResources) {
|
|
41716
|
+
return (this.extractAllDependencies(template, logicalId) ?? []).some((id) => {
|
|
41717
|
+
const loaded = Object.hasOwn(this.healBaseline, id) ? this.healBaseline[id] : void 0;
|
|
41718
|
+
if (loaded === void 0) return false;
|
|
41719
|
+
const now = Object.hasOwn(stateResources, id) ? stateResources[id] : void 0;
|
|
41720
|
+
return now !== void 0 && now.physicalId !== loaded.physicalId;
|
|
41721
|
+
});
|
|
41722
|
+
}
|
|
39669
41723
|
|
|
39670
41724
|
//#endregion
|
|
39671
41725
|
//#region src/deployment/deploy-engine/update-replace.ts
|
|
@@ -40699,6 +42753,7 @@ async function executeDeployment(template, currentState, changes, dag, execution
|
|
|
40699
42753
|
const concurrency = this.options.concurrency;
|
|
40700
42754
|
this.deployChanges = changes;
|
|
40701
42755
|
const newResources = { ...currentState.resources };
|
|
42756
|
+
this.deployStateResources = newResources;
|
|
40702
42757
|
const actualCounts = {
|
|
40703
42758
|
created: 0,
|
|
40704
42759
|
updated: 0,
|
|
@@ -42077,7 +44132,7 @@ function conditionFingerprint(template, name, inputOf) {
|
|
|
42077
44132
|
inputs[parameter] = { token: input.expression };
|
|
42078
44133
|
hasToken = true;
|
|
42079
44134
|
} else {
|
|
42080
|
-
if (
|
|
44135
|
+
if (declaresNoEcho(definition)) return void 0;
|
|
42081
44136
|
if (typeof input.value !== "string") return void 0;
|
|
42082
44137
|
if (carriesDynamicReference(input.value)) return void 0;
|
|
42083
44138
|
if (coerceParameterTypedValue(input.value, type) !== input.value) return void 0;
|
|
@@ -42460,6 +44515,7 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
|
|
|
42460
44515
|
};
|
|
42461
44516
|
const currentEtag = currentStateData?.etag;
|
|
42462
44517
|
this.healBaseline = currentState.resources ?? {};
|
|
44518
|
+
this.runProducerRegionEvidence = () => this.producerRegionEvidence(currentState);
|
|
42463
44519
|
refuseMalformedOutputs(currentState, stackName, this.stackRegion, this.options.refusalRecovery);
|
|
42464
44520
|
refuseMalformedResourcesForDeploy(currentState, stackName, this.stackRegion, this.options.refusalRecovery);
|
|
42465
44521
|
refuseMalformedResourceEntriesForDeploy(currentState, stackName, this.stackRegion, this.options.refusalRecovery);
|
|
@@ -42760,7 +44816,8 @@ async function doDeployWithPrefetch(stackName, template, createOnlyPrefetch) {
|
|
|
42760
44816
|
changes: changes.values(),
|
|
42761
44817
|
records: currentState.resources,
|
|
42762
44818
|
template: effectiveTemplate,
|
|
42763
|
-
recreateTargetIds: recreateTargetIdsFor(this.options.recreateTargets, stackName)
|
|
44819
|
+
recreateTargetIds: recreateTargetIdsFor(this.options.recreateTargets, stackName),
|
|
44820
|
+
secretMask: () => this.diffLogMasker(diffResolverContext.recordedSecretValues, effectiveTemplate, parameterValues, currentState.resources)
|
|
42764
44821
|
})) this.generatedNameGuard?.noteApprovalPrompted();
|
|
42765
44822
|
this.generatedNameGuard?.recordPlannedIntents();
|
|
42766
44823
|
this.resolver.resetPhysicalIdFallbackCount();
|
|
@@ -43070,6 +45127,7 @@ var DeployEngine = class {
|
|
|
43070
45127
|
secretNameNeedles = /* @__PURE__ */ new Map();
|
|
43071
45128
|
perResourceTemplateProps = /* @__PURE__ */ new Map();
|
|
43072
45129
|
perResourceResolvedType = /* @__PURE__ */ new Map();
|
|
45130
|
+
witnessConfirmedLeaves = /* @__PURE__ */ new Map();
|
|
43073
45131
|
fingerprintNoEchoValues = void 0;
|
|
43074
45132
|
preDeploySecretNamedRecords = void 0;
|
|
43075
45133
|
fingerprintParameters = void 0;
|
|
@@ -43093,7 +45151,9 @@ var DeployEngine = class {
|
|
|
43093
45151
|
updateWasReplaced = /* @__PURE__ */ new Map();
|
|
43094
45152
|
oldDeletedBeforeCreate = /* @__PURE__ */ new Set();
|
|
43095
45153
|
healBaseline = {};
|
|
45154
|
+
runProducerRegionEvidence = void 0;
|
|
43096
45155
|
deployChanges = /* @__PURE__ */ new Map();
|
|
45156
|
+
deployStateResources = {};
|
|
43097
45157
|
stackRecordsView = void 0;
|
|
43098
45158
|
inlinePolicyWriters = /* @__PURE__ */ new Map();
|
|
43099
45159
|
attributeHeals = /* @__PURE__ */ new Map();
|
|
@@ -43110,7 +45170,9 @@ var DeployEngine = class {
|
|
|
43110
45170
|
this.exportIndexStore = exportIndexStore;
|
|
43111
45171
|
this.resolver = new IntrinsicFunctionResolver(stackRegion, {
|
|
43112
45172
|
strictGetAtt: options.strictGetAtt ?? false,
|
|
43113
|
-
cfnFallback: options.cfnFallback ?? true
|
|
45173
|
+
cfnFallback: options.cfnFallback ?? true,
|
|
45174
|
+
...options.producerLookup && { producerLookup: options.producerLookup },
|
|
45175
|
+
...options.consumerAccount && { consumerAccount: options.consumerAccount }
|
|
43114
45176
|
});
|
|
43115
45177
|
this.options.concurrency = options.concurrency ?? 10;
|
|
43116
45178
|
this.options.dryRun = options.dryRun ?? false;
|
|
@@ -43137,6 +45199,7 @@ var DeployEngine = class {
|
|
|
43137
45199
|
this.perResourceTemplateProps = /* @__PURE__ */ new Map();
|
|
43138
45200
|
this.constructPathTemplate = void 0;
|
|
43139
45201
|
this.perResourceResolvedType = /* @__PURE__ */ new Map();
|
|
45202
|
+
this.witnessConfirmedLeaves = /* @__PURE__ */ new Map();
|
|
43140
45203
|
this.fingerprintNoEchoValues = void 0;
|
|
43141
45204
|
this.preDeploySecretNamedRecords = void 0;
|
|
43142
45205
|
this.fingerprintParameters = void 0;
|
|
@@ -43157,7 +45220,9 @@ var DeployEngine = class {
|
|
|
43157
45220
|
this.updateWasReplaced = /* @__PURE__ */ new Map();
|
|
43158
45221
|
this.oldDeletedBeforeCreate = /* @__PURE__ */ new Set();
|
|
43159
45222
|
this.healBaseline = {};
|
|
45223
|
+
this.runProducerRegionEvidence = void 0;
|
|
43160
45224
|
this.deployChanges = /* @__PURE__ */ new Map();
|
|
45225
|
+
this.deployStateResources = {};
|
|
43161
45226
|
this.inlinePolicyWriters = /* @__PURE__ */ new Map();
|
|
43162
45227
|
this.attributeHeals = /* @__PURE__ */ new Map();
|
|
43163
45228
|
this.healedAttributes = /* @__PURE__ */ new Map();
|
|
@@ -43227,7 +45292,7 @@ var DeployEngine = class {
|
|
|
43227
45292
|
};
|
|
43228
45293
|
}
|
|
43229
45294
|
inlinePolicyClaimedFor(resourceType, logicalId, stateResources) {
|
|
43230
|
-
if (resourceType !== "AWS::IAM::Policy" && !isInlinePolicyPrincipalType(resourceType)) return;
|
|
45295
|
+
if (resourceType !== "AWS::IAM::Policy" && !isInlinePolicyPrincipalType(resourceType) && !isStandaloneInlinePolicyType(resourceType)) return;
|
|
43231
45296
|
const args = {
|
|
43232
45297
|
selfLogicalId: logicalId,
|
|
43233
45298
|
writers: this.inlinePolicyWriters,
|
|
@@ -43374,5 +45439,5 @@ DeployEngine.prototype.replacementNameOrigin = replacementNameOrigin;
|
|
|
43374
45439
|
DeployEngine.prototype.orphanedNameCollisionAdvice = orphanedNameCollisionAdvice;
|
|
43375
45440
|
|
|
43376
45441
|
//#endregion
|
|
43377
|
-
export { getPriorAttempts as $, isWarmThroughputDecrease as $a, derivePartitionAndUrlSuffix as $c, malformedResourceEntriesWarning as $i, reserveStackCreateToken as $n, isUncertifiedBaselineMaskPosition as $o, AWS_CREDENTIAL_ENV_KEYS as $r, ensureAssetStorage as $s, orphanDeleteNeedsIdentity as $t, noEchoExactEchoLeavesOf as A, repairMalformedOrphansForReadOnly as Aa, getDefaultStateBucketName as Ac, UNREADABLE_RESOURCES_MAP_ROW as Ai, maskEventTextWithBoundBags as An, passedNoEchoParametersOf as Ao, deleteSkipReason as Ar, acceptedCreateOnlyDropsOf as As, isHandledOrphan as At, beginDeleteWait as B, findSilentDropProperties as Ba, stateBucketExistenceConfirmed as Bc, malformedExportNamesWarning as Bi, ccRoutedFinalSnapshotError as Bn, printingCorpusOf as Bo, DiffCalculator as Br, orphansCarriedFrom as Bs, withStackRecords as Bt, recordRetainedForReadoption as C, refuseMalformedResourcePropertiesForExport as Ca, warnFinchArgvExposure as Cc, withSharedDrainBudget as Ci, collectPublishedOutputNames as Cn, maskAtCoordinates as Co, customResourceResponseExpirationWarning as Cr, CrossPrefixReadError as Cs, revertedNestedRowIds as Ct, withResourceDeadline as D, refuseMalformedResourcesForExport as Da, getDockerImageBySourceHash as Dc, STATE_REGION_DIVERGED as Di, DEFAULT_RESOURCE_WARN_AFTER_MS as Dn, noEchoCoordinatesOf as Do, UNSPECIFIED_SKIP_REASON as Dr, isAccessDenied$1 as Ds, withNestedStackContext as Dt, serviceTokenBlockingReason as E, refuseMalformedResourcesForDestroy as Ea, AssetManifestLoader as Ec, JSON_LISTING_HOLE_VALUE as Ei, DEFAULT_RESOURCE_TIMEOUT_MS as En, maskedLeafCoordinatesOf as Eo, unchangedBehindSecretReference as Er, crossPrefixDeniedWarning as Es, getCurrentNestedStackContext as Et, isProtectionValueActive as F, unpreviewableOrphanRecords as Fa, resolveCaptureObservedState as Fc, hasReadableOutputs as Fi, storedSecretNameNeedles as Fn, carryLogOnlyValues as Fo, ec2InstanceProtectionSite as Fr, hasUnverifiableParameterRefusal as Fs, replayFailedOperations as Ft, DELETE_INDEX_WAIT_PROCEED_NOTE as G, findReplacedReadersOfRecreateTargets as Ga, MIGRATE_TMP_PREFIX as Gc, malformedOrphanRecordsRefusalMessage as Gi, unsupportedFinalSnapshotError as Gn, errorCauseChain as Go, producerRegionsFromState as Gr, WorkGraph as Gs, isReplacementOrphan as Gt, deleteBudgetKey as H, withoutSilentDropProperties as Ha, ssmResolvedValueType as Hc, malformedLocalOutputsWarning as Hi, effectiveDeletionPolicy as Hn, recordLogOnlyValue as Ho, IntrinsicFunctionResolver as Hr, AssetPublisher as Hs, recordAfterRollbackUpdate as Ht, perType as I, unreadableOrphanRecords as Ia, resolveSkipPrefix as Ic, hasReadableResources as Ii, extractDeploymentEventError as In, createUnionSecretMasker as Io, isTerminationProtectionPropagationError as Ir, importableOutputKeys as Is, replayRollback as It, waitForIndexesSettled as J, isStatefulRecreateTargetForReplace as Ja, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Jc, malformedOrphansRefusalMessage as Ji, findDestructiveChanges as Jn, markSameGenerationBag as Jo, assertFlagRoleArn as Jr, loadPublishableAssetManifest as Js, recheckFailedPlan as Jt, INDEX_SETTLE_POLL_INTERVAL_MS as K, shownType as Ka, findLargeInlineResources as Kc, malformedOrphanRecordsWarning as Ki, maskingRetryLogger as Kn, maskSecretsInError as Ko, regionLessSecretName as Kr, buildAssetRedirectMap as Ks, planFailedOps as Kt, readProtection as L, unreadableResourceEntries as La, resolveStateBucketWithDefault as Lc, isReadableOrphanRecord as Li, ATOMIC_FINAL_SNAPSHOT_TYPES as Ln, hasMaskableValues as Lo, observeThenDisableInstanceApiTermination as Lr, importableOutputs as Ls, awaitInFlightSibling as Lt, recordedProtectionEvidence as M, repairMalformedResourceEntriesForReadOnly as Ma, loadCdkJson as Mc, deployRefusesOrphanRowsReason as Mi, secretNamePrintingBag as Mn, readsNoEchoSource as Mo, isWaitAbandonedError as Mr, exportNamesCarriedFrom as Ms, loadJournaledOrphans as Mt, recordedProtectionNote as N, repairMalformedResourcePropertiesForReadOnly as Na, resolveApp as Nc, displayLogicalId as Ni, secretNamedRecordNeedles as Nn, valueAtCoordinate as No, markWaitAbandoned as Nr, hasReadableExportSet as Ns, makeForeignHolderScan as Nt, noEchoAttributeNamesOf as O, refuseMalformedState as Oa, Synthesizer as Oc, STATE_RESOURCES_MALFORMED as Oi, completedReplayEntries as On, noEchoLeavesOf as Oo, deleteIndeterminateGuards as Or, isNotImplemented as Os, deleteJournaledOrphans as Ot, PROTECTION_PROPERTY_BY_TYPE as P, repairMalformedResourcesForReadOnly as Pa, resolveAutoAssetStorage as Pc, hasReadableOrphans as Pi, stateSecretNameNeedles as Pn, liveMatchesUnresolvedTokenFrame as Po, disableInstanceApiTermination as Pr, hasReasonlessBaselineRefusal as Ps, sameJournaledOrphans as Pt, isTruthyCfnBoolean as Q, coerceWarmThroughput as Qa, canonicalizeRegion as Qc, malformedRenderedContainersWarning as Qi, ledgerForStack as Qn, dynamicReferenceTokens as Qo, sendableAssumeRoleCommand as Qr, assertAssetBucketRegion as Qs, seedsDeleteFirstGuard as Qt, DynamoDBGlobalTableProvider as R, withheldAccountClause as Ra, resolveStateBucketWithDefaultAndSource as Rc, isReadableResourceEntry as Ri, PRE_DELETE_SNAPSHOT_TYPES as Rn, literalSplitDelimitersOf as Ro, reDisableInstanceApiTermination as Rr, isReadableBag as Rs, destroyStackRecordsView as Rt, keptForReadoption as S, refuseMalformedResourcePropertiesForDrift as Sa, runDockerStreaming as Sc, parseWebACLArn as Si, collectDeclaredOutputNames as Sn, isMarkedCoordinate as So, applyCustomResourceResponseExpiration as Sr, rebuildClientForBucketRegion as Ss, revertNestedChildFromJournal as St, findServiceTokenRefusals as T, refuseMalformedResourcesForDeploy as Ta, stripControlChars as Tc, passedParameterClassesOf as Ti, bindingSkippedOutputs as Tn, maskWholeValue as To, slowCcOperationTimeoutMs as Tr, applyCrossPrefixScan as Ts, collectNestedChildUnaddressed as Tt, resolveDynamoDbDeleteBudgetClock as U, NO_CC_HANDLERS_REASON as Ua, CFN_TEMPLATE_BODY_LIMIT as Uc, malformedLocalResourceEntriesWarning as Ui, isFinalSnapshotError as Un, shareLogOnlyValues as Uo, poisonRenderedSpellingsCollidingIn as Ur, isSensitiveAttributeName as Us, demoteSupersededOrphans as Ut, compensateRemovedDeletionProtection as V, unwrittenCreateOnlyReplacement as Va, warnDeprecatedNoPrefixCliFlag as Vc, malformedExportSourceWarning as Vi, createPreDeleteFinalSnapshot as Vn, recordLogOnlyParameterValue as Vo, INTRINSIC_KEYS as Vr, shouldRetainResource as Vs, removeProtectionTypeList as Vt, resolveDynamoDbDeleteBudgetMs as W, hasNoCloudControlHandlers as Wa, CFN_TEMPLATE_URL_LIMIT as Wc, malformedLocalResourcesWarning as Wi, refusesFinalSnapshot as Wn, createSecretMasker as Wo, classifyReplaySecretRegion as Wr, stringifyValue as Ws, isJournaledOrphan as Wt, S3_AUTO_DELETE_OBJECTS_TAG as X, renderStatefulReason as Xa, expectedOwnerParam as Xc, malformedOutputsRefusalMessage as Xi, RollbackInlinePolicyWriters as Xn, scrubResourceRecord as Xo, explicitRoleArnOrThrow as Xr, AssetModeResolver as Xs, replacementNeverSwapped as Xt, ECR_AUTO_DELETE_IMAGES_TAG as Y, isStatefulRecreateTargetSync as Ya, decodeListingKey as Yc, malformedOrphansWarning as Yi, formatDestructiveChange as Yn, redactSecretsForState as Yo, assertSendableRoleArn as Yr, rewriteTemplateAssetReferences as Ys, recordUnderIdIsNotOwn as Yt, hasCdkAutoDeleteTag as Z, WARM_THROUGHPUT_MEMBERS as Za, PARTITION_TABLE as Zc, malformedOutputsWarning as Zi, earliestDefined as Zn, DYNAMIC_REFERENCE_TOKEN_SCAN as Zo, isIamRoleArn as Zr, BOOTSTRAP_MARKER_PREFIX as Zs, resolveReplacementOldType as Zt, makeCanonicalizePropertiesFn as _, refuseMalformedResourceEntriesForDestroy as _a, isMalformedEnvKey as _c, keepsSecretReferenceToken as _i, carriedExportAliasExposure as _n, lambdaFunctionNameForMask as _o, readsNoEchoDeleteValues as _r, WHOLE_DYNAMIC_REFERENCE_PATTERN as _s, displacedPhysicalIdShown as _t, findNestedTemplateTreeDefect as a, refuseDivergentRecordRegionForDestroy as aa, validateContainerRepoName as ac, s3BucketDomainName as ai, hasPlainPrototype$1 as al, redactedDeleteAddressFields as an, configIntegerRefusal as ao, readTagList as ar, carriesSecretMask as as, gray as at, lookupEachName as b, refuseMalformedResourceEntriesForOrphan as ba, redactedDockerCause as bc, isStalePlaceholderArnAttribute as bi, isWholeDynamicReferenceValue as bn, TemplateParser as bo, withPrintingSecrets as br, isLockInfoExpired as bs, nestedChildStackName as bt, renderNestedTemplateTreeDefect as c, refuseMalformedOrphanRecordsForDestroy as ca, resolveDockerContextDirectory as cc, s3BucketWebsiteUrl as ci, absoluteAssemblyPathEscape as cl, updatePartialReason as cn, replayWarn as co, tagPlanWarning as cr, recordMaskOnlyValuesIn as cs, yellow as ct, conditionInputsFrom as d, refuseMalformedOrphansForOrphan as da, describeDockerFailure as dc, parameterTypeMayLoseSecretIdentity as di, renderAssemblyPathEscape as dl, WITHHELD_NAME_DISPLAY as dn, requireConfigString as do, CC_BROKEN_REASON as dr, recordProvenPublicExpression as ds, reachableDivergentParameters as dt, malformedResourcePropertiesWarning as ea, getBootstrapMarkerKey as ec, applyCallerIdentityCredentials as ei, AssemblyReader as el, findNestedStackTypeChanges as en, toCfnInteger as eo, withCreateTokenLedger as er, pathCrossesDottedKey as es, markRefusedBeforeApplying as et, parentSuppliedValues as f, refuseMalformedOutputs as fa, dockerSpawnEnvWithSensitive as fc, getAccountInfo as fi, resolveAssemblyPath as fl, displayTextOrWithheld as fn, prefetchCreateOnlyPropertyPaths as fo, ProviderRegistry as fr, wholeStringLeavesOf as fs, resourcesNamingDeclaredParameter as ft, mergeNoChangeOutputs as g, refuseMalformedResourceEntriesForDeploy as ga, isDockerClientEnvKey as gc, isNamelessDynamicReferenceError as gi, secretSafeKeyDisplay as gn, canonicalLambdaFunctionName as go, TemplateNoEchoReresolver as gr, TEMPLATE_SOURCED_RULES as gs, displacedOpClause as gt, keptWholeReasonText as h, refuseMalformedResourceEntries as ha, getDockerCmd as hc, carriesFetchableDynamicReference as hi, secretBearingStateKeyWarning as hn, withRetry as ho, wouldReturnToSdkProvider as hr, STATE_SOURCED_READBACK_RULES as hs, NESTED_PENDING_PARENT_REASON as ht, childTemplateLoader as i, previewableOrphanRecords as ia, validateAssetBucketName as ic, s3BucketArn as ii, hasOwnKey as il, isRedactedRecordedValue as in, configBooleanRefusal as io, planTagDiff as ir, recoverMaskedOutput as is, cyan as it, noEchoParameterNamesOf as j, repairMalformedOutputsForReadOnly as ja, getLegacyStateBucketName as jc, accountArgs as ji, orphanRecordsPrintingBag as jn, readbackPathFor as jo, withIndeterminateGuard as jr, describeRegionValueKind as js, journaledOrphanLines as jt, noEchoComparisonForTemplate as k, repairMalformedOrphanRecordsForReadOnly as ka, synthesisStatusMessage as kc, UNREADABLE_ORPHANS_CONTAINER_ROW as ki, journaledOrphanPrintingBag as kn, noEchoOutputsComparison as ko, deleteLeftInPlace as kr, splitImportedOps as ks, dropFailedHint as kt, templateIdentity as l, refuseMalformedOrphans as la, describeDockerCapturedOutput as lc, coerceParameterTypedValue as li, describeFileReadFailure as ll, DeploymentEventsReader as ln, requireConfigArray as lo, definedAttributes as lr, recordNoEchoAttributeValues as ls, computeParameterTaint as lt, isSecretBearingReferenceString as m, refuseMalformedResourceAttributesForOrphan as ma, formatDockerLoginError as mc, carriesDynamicReference as mi, resolveBucketRegion as ml, secretBearing as mn, describeTypeWithThrottleRetry as mo, isCustomResource as mr, STATE_SOURCED_CROSS_GENERATION_RULES as ms, planOrphanAdoption as mt, IMPLICIT_DELETE_DEPENDENCIES as n, malformedScrubResourceEntriesRefusalMessage as na, parseBootstrapMarker as nc, envCredentialsAreAssumedRole as ni, processStackMessages as nl, inheritProducerRegions as nn, coerceCfnBoolean as no, DBPROXY_TAGS_WHAT as nr, inheritNestedStackParameterAssociations as ns, createReadOnlyAttributeHealerFactory as nt, isAbsoluteAssetPath as o, refuseMalformedNestedChildOutputs as oa, buildDenyExternalAccessPolicy as oc, s3BucketDualStackDomainName as oi, nullPrototypeRecord as ol, redactedDeleteAddressSkip as on, configStringRefusal as oo, refuseMalformedDesiredTags as or, provenPublicValue as os, green as ot, readRecordedConditionVerdicts as p, refuseMalformedOutputsForDestroy as pa, finchSecretArgvRefusal as pc, isImpossibleEmptyStoredAttribute as pi, clearBucketRegionCache as pl, exportAliasCollisionScrubWarning as pn, templateResourceTypes as po, ccBrokenReason as pr, STATE_SOURCED_BASELINE_RULES as ps, makeSiblingClaimReader as pt, deleteTableWithIndexBusyRetry as q, MULTI_REGION_RECREATE_BLOCKED_TYPES as qa, uploadCfnTemplate as qc, malformedOrphanRowsKeptWarning as qi, constructPathOf as qn, maskSecretsInText as qo, applyRoleArnIfSet as qr, createAssetRedirectResolver as qs, planRollback as qt, computeImplicitDeleteEdges as r, malformedStateRefusalMessage as ra, readBootstrapMarkerBody as rc, isSettledInstanceState as ri, defineOwnKey as rl, REDACTED_DELETE_ADDRESS_SKIP_REASON as rn, coerceCfnInteger as ro, DBPROXY_TAG_OPTIONS as rr, recordNestedStackParameterExpressions as rs, bold as rt, listNestedTemplateRows as s, refuseMalformedOrphanRecords as sa, buildDockerImage as sc, s3BucketRegionalDomainName as si, ownValue as sl, updatePartialMessage as sn, readConfigString as so, tagMapAsList as sr, recordMaskOnlyValue as ss, red as st, DeployEngine as t, malformedResourcesWarning as ta, isCrossRegionRedirect as tc, callerEnvCredentials as ti, StageLoadError as tl, getCurrentProducerRegions as tn, toFiniteNumber as to, acquireIdempotencyToken as tr, identityKeyFor as ts, formatResourceLine as tt, conditionFingerprint as u, refuseMalformedOrphansForDestroy as ua, describeDockerExecFailure as uc, isUnboundTemplateParameter as ui, displayAssemblyPath as ul, DeploymentEventsStore as un, requireConfigObject as uo, stringifyIfAssigned as ur, recordNoEchoParameterFreshValue as us, namesAnyDeclaredParameter as ut, chunks as v, refuseMalformedResourceEntriesForImport as va, partitionSensitiveEnv as vc, AWS_NO_VALUE as vi, exportNameNoEchoParameters as vn, sameLambdaFunctionAddress as vo, isCustomResourceType as vr, isSingleDynamicReferenceToken as vs, dropSettledNestedJournals as vt, deferredServiceTokenWarning as w, refuseMalformedResourcePropertiesForOrphan as wa, escapeRegExp$3 as wc, parameterInputsFor as wi, isExportAliasCollision as wn, maskReadbackAtCoordinates as wo, CloudControlProvider as wr, CrossPrefixScanCache as ws, withNestedRevertRun as wt, withApiLimit as x, refuseMalformedResourcePropertiesForDestroy as xa, runDockerForeground as xc, refStateLookupFromResource as xi, noEchoParameterValueSeed as xn, canonicalCoordinates as xo, CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID as xr, S3StateBackend as xs, recordDisplacedSkips as xt, isAccessDeniedError as y, refuseMalformedResourceEntriesForImportSave as ya, redactDockerArgvValues as yc, cfnRefValueFromPhysicalId as yi, exportNameSecretExposure as yn, DagBuilder as yo, getCurrentResourceSecrets as yr, LockManager as ys, getNestedRevertRun as yt, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as z, findActionableSilentDrops as za, resolveUseCdkBootstrapAssets as zc, malformedDriftResourcePropertiesWarning as zi, buildFinalSnapshotIdentifier as zn, logOnlyValueCount as zo, reEnableInstanceApiTermination as zr, orphansAfterRollback as zs, getStackRecords as zt };
|
|
43378
|
-
//# sourceMappingURL=deploy-engine-
|
|
45442
|
+
export { isTruthyCfnBoolean as $, isStatefulRecreateTargetForReplace as $a, CFN_TEMPLATE_BODY_LIMIT as $c, malformedOrphansRefusalMessage as $i, ledgerForStack as $n, markSameGenerationBag as $o, sendableAssumeRoleCommand as $r, isSensitiveAttributeName as $s, seedsDeleteFirstGuard as $t, noEchoComparisonForTemplate as A, refuseMalformedResourcesForDeploy as Aa, redactedDockerCause as Ac, declaresNoEcho as Ai, journaledOrphanPrintingBag as An, maskWholeValue as Ao, deleteIndeterminateGuards as Ar, isLockInfoExpired as As, dropFailedHint as At, DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS as B, unpreviewableOrphanRecords as Ba, getDefaultStateBucketName as Bc, hasReadableOutputs as Bi, PRE_DELETE_SNAPSHOT_TYPES as Bn, carryLogOnlyValues as Bo, reDisableInstanceApiTermination as Br, acceptedCreateOnlyDropsOf as Bs, getStackRecords as Bt, recordRetainedForReadoption as C, refuseMalformedResourceEntriesForImport as Ca, finchSecretArgvRefusal as Cc, cfnRefValueFromPhysicalId as Ci, clearBucketRegionCache as Cl, collectDeclaredOutputNames as Cn, sameLambdaFunctionAddress as Co, applyCustomResourceResponseExpiration as Cr, STATE_SOURCED_BASELINE_RULES as Cs, revertNestedChildFromJournal as Ct, withResourceDeadline as D, refuseMalformedResourcePropertiesForDrift as Da, isMalformedEnvKey as Dc, withSharedDrainBudget as Di, DEFAULT_RESOURCE_TIMEOUT_MS as Dn, isMarkedCoordinate as Do, unchangedBehindSecretReference as Dr, WHOLE_DYNAMIC_REFERENCE_PATTERN as Ds, getCurrentNestedStackContext as Dt, serviceTokenBlockingReason as E, refuseMalformedResourcePropertiesForDestroy as Ea, isDockerClientEnvKey as Ec, parseWebACLArn as Ei, bindingSkippedOutputs as En, canonicalCoordinates as Eo, slowCcOperationTimeoutMs as Er, TEMPLATE_SOURCED_RULES as Es, collectNestedChildUnaddressed as Et, PROTECTION_PROPERTY_BY_TYPE as F, repairMalformedOrphansForReadOnly as Fa, stripControlChars as Fc, UNREADABLE_RESOURCES_MAP_ROW as Fi, secretNamedRecordNeedles as Fn, passedNoEchoParametersOf as Fo, markWaitAbandoned as Fr, applyCrossPrefixScan as Fs, sameJournaledOrphans as Ft, resolveDynamoDbDeleteBudgetMs as G, findSilentDropProperties as Ga, resolveCaptureObservedState as Gc, malformedExportNamesWarning as Gi, isFinalSnapshotError as Gn, printingCorpusOf as Go, poisonRenderedSpellingsCollidingIn as Gr, hasUnverifiableParameterRefusal as Gs, isJournaledOrphan as Gt, compensateRemovedDeletionProtection as H, unreadableResourceEntries as Ha, loadCdkJson as Hc, isReadableOrphanRecord as Hi, ccRoutedFinalSnapshotError as Hn, hasMaskableValues as Ho, DiffCalculator as Hr, exportNamesCarriedFrom as Hs, removeProtectionTypeList as Ht, isProtectionValueActive as I, repairMalformedOutputsForReadOnly as Ia, AssetManifestLoader as Ic, accountArgs as Ii, stateSecretNameNeedles as In, readbackPathFor as Io, disableInstanceApiTermination as Ir, crossPrefixDeniedWarning as Is, replayFailedOperations as It, deleteTableWithIndexBusyRetry as J, NO_CC_HANDLERS_REASON as Ja, resolveStateBucketWithDefaultAndSource as Jc, malformedLocalResourceEntriesWarning as Ji, maskingRetryLogger as Jn, shareLogOnlyValues as Jo, applyRoleArnIfSet as Jr, isReadableBag as Js, planRollback as Jt, DELETE_INDEX_WAIT_PROCEED_NOTE as K, unwrittenCreateOnlyReplacement as Ka, resolveSkipPrefix as Kc, malformedExportSourceWarning as Ki, refusesFinalSnapshot as Kn, recordLogOnlyParameterValue as Ko, producerLookupOver as Kr, importableOutputKeys as Ks, isReplacementOrphan as Kt, perType as L, repairMalformedResourceEntriesForReadOnly as La, getDockerImageBySourceHash as Lc, deployRefusesOrphanRowsReason as Li, storedSecretNameNeedles as Ln, readsNoEchoSource as Lo, ec2InstanceProtectionSite as Lr, isAccessDenied$1 as Ls, replayRollback as Lt, noEchoParameterNamesOf as M, refuseMalformedResourcesForExport as Ma, runDockerStreaming as Mc, STATE_REGION_DIVERGED as Mi, orphanRecordsPrintingBag as Mn, noEchoCoordinatesOf as Mo, deleteSkipReason as Mr, rebuildClientForBucketRegion as Ms, journaledOrphanLines as Mt, recordedProtectionEvidence as N, refuseMalformedState as Na, warnFinchArgvExposure as Nc, STATE_RESOURCES_MALFORMED as Ni, secretNamePrintingBag as Nn, noEchoLeavesOf as No, withIndeterminateGuard as Nr, CrossPrefixReadError as Ns, loadJournaledOrphans as Nt, diffSecurity as O, refuseMalformedResourcePropertiesForExport as Oa, partitionSensitiveEnv as Oc, parameterInputsFor as Oi, DEFAULT_RESOURCE_WARN_AFTER_MS as On, maskAtCoordinates as Oo, RollbackInlinePolicyWriters as Or, isSingleDynamicReferenceToken as Os, withNestedStackContext as Ot, recordedProtectionNote as P, repairMalformedOrphanRecordsForReadOnly as Pa, escapeRegExp$3 as Pc, UNREADABLE_ORPHANS_CONTAINER_ROW as Pi, secretNamePrintingBags as Pn, noEchoOutputsComparison as Po, isWaitAbandonedError as Pr, CrossPrefixScanCache as Ps, makeForeignHolderScan as Pt, hasCdkAutoDeleteTag as Q, MULTI_REGION_RECREATE_BLOCKED_TYPES as Qa, ssmResolvedValueType as Qc, malformedOrphanRowsKeptWarning as Qi, earliestDefined as Qn, maskSecretsInText as Qo, isIamRoleArn as Qr, AssetPublisher as Qs, resolveReplacementOldType as Qt, readProtection as R, repairMalformedResourcePropertiesForReadOnly as Ra, Synthesizer as Rc, displayLogicalId as Ri, extractDeploymentEventError as Rn, valueAtCoordinate as Ro, isTerminationProtectionPropagationError as Rr, isNotImplemented as Rs, awaitInFlightSibling as Rt, keptForReadoption as S, refuseMalformedResourceEntriesForDestroy as Sa, dockerSpawnEnvWithSensitive as Sc, AWS_NO_VALUE as Si, resolveAssemblyPath as Sl, noEchoParameterValueSeed as Sn, lambdaFunctionNameForMask as So, CUSTOM_RESOURCE_RESPONSE_LIFECYCLE_RULE_ID as Sr, wholeStringLeavesOf as Ss, recordDisplacedSkips as St, findServiceTokenRefusals as T, refuseMalformedResourceEntriesForOrphan as Ta, getDockerCmd as Tc, refStateLookupFromResource as Ti, isExportAliasCollision as Tn, TemplateParser as To, CloudControlProvider as Tr, STATE_SOURCED_READBACK_RULES as Ts, withNestedRevertRun as Tt, deleteBudgetKey as U, withheldAccountClause as Ua, resolveApp as Uc, isReadableResourceEntry as Ui, createPreDeleteFinalSnapshot as Un, literalSplitDelimitersOf as Uo, INTRINSIC_KEYS as Ur, hasReadableExportSet as Us, recordAfterRollbackUpdate as Ut, beginDeleteWait as V, unreadableOrphanRecords as Va, getLegacyStateBucketName as Vc, hasReadableResources as Vi, buildFinalSnapshotIdentifier as Vn, createUnionSecretMasker as Vo, reEnableInstanceApiTermination as Vr, describeRegionValueKind as Vs, withStackRecords as Vt, resolveDynamoDbDeleteBudgetClock as W, findActionableSilentDrops as Wa, resolveAutoAssetStorage as Wc, malformedDriftResourcePropertiesWarning as Wi, effectiveDeletionPolicy as Wn, logOnlyValueCount as Wo, IntrinsicFunctionResolver as Wr, hasReasonlessBaselineRefusal as Ws, demoteSupersededOrphans as Wt, ECR_AUTO_DELETE_IMAGES_TAG as X, findReplacedReadersOfRecreateTargets as Xa, stateBucketExistenceConfirmed as Xc, malformedOrphanRecordsRefusalMessage as Xi, findDestructiveChanges as Xn, errorCauseChain as Xo, assertSendableRoleArn as Xr, orphansCarriedFrom as Xs, recordUnderIdIsNotOwn as Xt, waitForIndexesSettled as Y, hasNoCloudControlHandlers as Ya, resolveUseCdkBootstrapAssets as Yc, malformedLocalResourcesWarning as Yi, constructPathOf as Yn, createSecretMasker as Yo, assertFlagRoleArn as Yr, orphansAfterRollback as Ys, recheckFailedPlan as Yt, S3_AUTO_DELETE_OBJECTS_TAG as Z, shownType as Za, warnDeprecatedNoPrefixCliFlag as Zc, malformedOrphanRecordsWarning as Zi, formatDestructiveChange as Zn, maskSecretsInError as Zo, explicitRoleArnOrThrow as Zr, shouldRetainResource as Zs, replacementNeverSwapped as Zt, makeCanonicalizePropertiesFn as _, refuseMalformedOutputs as _a, buildDockerImage as _c, isImpossibleEmptyStoredAttribute as _i, ownValue as _l, secretSafeKeyDisplay as _n, prefetchCreateOnlyPropertyPaths as _o, TemplateNoEchoReresolver as _r, recordMaskOnlyValue as _s, displacedOpClause as _t, findNestedTemplateTreeDefect as a, malformedResourcePropertiesWarning as aa, rewriteTemplateAssetReferences as ac, s3BucketArn as ai, decodeListingKey as al, isRedactedRecordedValue as an, toCfnInteger as ao, planTagDiff as ar, dynamicReferenceTokens as as, cyan as at, lookupEachName as b, refuseMalformedResourceEntries as ba, describeDockerExecFailure as bc, isNamelessDynamicReferenceError as bi, displayAssemblyPath as bl, exportNameSecretExposure as bn, withRetry as bo, getCurrentResourceSecrets as br, recordNoEchoParameterFreshValue as bs, getNestedRevertRun as bt, renderNestedTemplateTreeDefect as c, malformedStateRefusalMessage as ca, assertAssetBucketRegion as cc, s3BucketRegionalDomainName as ci, canonicalizeRegion as cl, updatePartialMessage as cn, coerceCfnInteger as co, tagMapAsList as cr, identityKeyFor as cs, red as ct, conditionInputsFrom as d, refuseMalformedNestedChildOutputs as da, isCrossRegionRedirect as dc, producerRegionsFromState as di, StageLoadError as dl, DeploymentEventsStore as dn, configStringRefusal as do, stringifyIfAssigned as dr, recoverMaskedOutput as ds, namesAnyDeclaredParameter as dt, malformedOrphansWarning as ea, stringifyValue as ec, AWS_CREDENTIAL_ENV_KEYS as ei, CFN_TEMPLATE_URL_LIMIT as el, orphanDeleteNeedsIdentity as en, isStatefulRecreateTargetSync as eo, reserveStackCreateToken as er, redactSecretsForState as es, getPriorAttempts as et, parentSuppliedValues as f, refuseMalformedOrphanRecords as fa, parseBootstrapMarker as fc, regionLessSecretName as fi, processStackMessages as fl, WITHHELD_NAME_DISPLAY as fn, readConfigString as fo, CC_BROKEN_REASON as fr, physicalNameCopiesOf as fs, reachableDivergentParameters as ft, mergeNoChangeOutputs as g, refuseMalformedOrphansForOrphan as ga, buildDenyExternalAccessPolicy as gc, getAccountInfo as gi, nullPrototypeRecord as gl, secretBearingStateKeyWarning as gn, requireConfigString as go, wouldReturnToSdkProvider as gr, provenPublicValue as gs, NESTED_PENDING_PARENT_REASON as gt, keptWholeReasonText as h, refuseMalformedOrphansForDestroy as ha, validateContainerRepoName as hc, parameterTypeMayLoseSecretIdentity as hi, hasPlainPrototype$1 as hl, secretBearing as hn, requireConfigObject as ho, isCustomResource as hr, carriesSecretMask as hs, planOrphanAdoption as ht, childTemplateLoader as i, malformedResourceEntriesWarning as ia, loadPublishableAssetManifest as ic, isSettledInstanceState as ii, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as il, REDACTED_DELETE_ADDRESS_SKIP_REASON as in, isWarmThroughputDecrease as io, DBPROXY_TAG_OPTIONS as ir, DYNAMIC_REFERENCE_TOKEN_SCAN as is, bold as it, noEchoExactEchoLeavesOf as j, refuseMalformedResourcesForDestroy as ja, runDockerForeground as jc, JSON_LISTING_HOLE_VALUE as ji, maskEventTextWithBoundBags as jn, maskedLeafCoordinatesOf as jo, deleteLeftInPlace as jr, S3StateBackend as js, isHandledOrphan as jt, noEchoAttributeNamesOf as k, refuseMalformedResourcePropertiesForOrphan as ka, redactDockerArgvValues as kc, passedParameterClassesOf as ki, completedReplayEntries as kn, maskReadbackAtCoordinates as ko, UNSPECIFIED_SKIP_REASON as kr, LockManager as ks, deleteJournaledOrphans as kt, templateIdentity as l, previewableOrphanRecords as la, ensureAssetStorage as lc, s3BucketWebsiteUrl as li, derivePartitionAndUrlSuffix as ll, updatePartialReason as ln, configBooleanRefusal as lo, tagPlanWarning as lr, inheritNestedStackParameterAssociations as ls, yellow as lt, isSecretBearingReferenceString as m, refuseMalformedOrphans as ma, validateAssetBucketName as mc, isUnboundTemplateParameter as mi, hasOwnKey as ml, exportAliasCollisionScrubWarning as mn, requireConfigArray as mo, ccBrokenReason as mr, splitGetAttStringForm as ms, makeSiblingClaimReader as mt, IMPLICIT_DELETE_DEPENDENCIES as n, malformedOutputsWarning as na, buildAssetRedirectMap as nc, callerEnvCredentials as ni, findLargeInlineResources as nl, getCurrentProducerRegions as nn, WARM_THROUGHPUT_MEMBERS as no, acquireIdempotencyToken as nr, withPhysicalNameCopies as ns, formatResourceLine as nt, isAbsoluteAssetPath as o, malformedResourcesWarning as oa, AssetModeResolver as oc, s3BucketDomainName as oi, expectedOwnerParam as ol, redactedDeleteAddressFields as on, toFiniteNumber as oo, readTagList as or, isUncertifiedBaselineMaskPosition as os, gray as ot, readRecordedConditionVerdicts as p, refuseMalformedOrphanRecordsForDestroy as pa, readBootstrapMarkerBody as pc, coerceParameterTypedValue as pi, defineOwnKey as pl, displayTextOrWithheld as pn, replayWarn as po, ProviderRegistry as pr, recordPhysicalNameCopy as ps, resourcesNamingDeclaredParameter as pt, INDEX_SETTLE_POLL_INTERVAL_MS as q, withoutSilentDropProperties as qa, resolveStateBucketWithDefault as qc, malformedLocalOutputsWarning as qi, unsupportedFinalSnapshotError as qn, recordLogOnlyValue as qo, refuseUnreadableCdkCrossAccountRefs as qr, importableOutputs as qs, planFailedOps as qt, computeImplicitDeleteEdges as r, malformedRenderedContainersWarning as ra, createAssetRedirectResolver as rc, envCredentialsAreAssumedRole as ri, uploadCfnTemplate as rl, inheritProducerRegions as rn, coerceWarmThroughput as ro, DBPROXY_TAGS_WHAT as rr, withoutPhysicalNameCopies as rs, createReadOnlyAttributeHealerFactory as rt, listNestedTemplateRows as s, malformedScrubResourceEntriesRefusalMessage as sa, BOOTSTRAP_MARKER_PREFIX as sc, s3BucketDualStackDomainName as si, PARTITION_TABLE as sl, redactedDeleteAddressSkip as sn, coerceCfnBoolean as so, refuseMalformedDesiredTags as sr, pathCrossesDottedKey as ss, green as st, DeployEngine as t, malformedOutputsRefusalMessage as ta, WorkGraph as tc, applyCallerIdentityCredentials as ti, MIGRATE_TMP_PREFIX as tl, findNestedStackTypeChanges as tn, renderStatefulReason as to, withCreateTokenLedger as tr, scrubResourceRecord as ts, markRefusedBeforeApplying as tt, conditionFingerprint as u, refuseDivergentRecordRegionForDestroy as ua, getBootstrapMarkerKey as uc, classifyReplaySecretRegion as ui, AssemblyReader as ul, DeploymentEventsReader as un, configIntegerRefusal as uo, definedAttributes as ur, recordNestedStackParameterExpressions as us, computeParameterTaint as ut, chunks as v, refuseMalformedOutputsForDestroy as va, resolveDockerContextDirectory as vc, carriesDynamicReference as vi, absoluteAssemblyPathEscape as vl, carriedExportAliasExposure as vn, templateResourceTypes as vo, readsNoEchoDeleteValues as vr, recordMaskOnlyValuesIn as vs, displacedPhysicalIdShown as vt, deferredServiceTokenWarning as w, refuseMalformedResourceEntriesForImportSave as wa, formatDockerLoginError as wc, isStalePlaceholderArnAttribute as wi, resolveBucketRegion as wl, collectPublishedOutputNames as wn, DagBuilder as wo, customResourceResponseExpirationWarning as wr, STATE_SOURCED_CROSS_GENERATION_RULES as ws, revertedNestedRowIds as wt, withApiLimit as x, refuseMalformedResourceEntriesForDeploy as xa, describeDockerFailure as xc, keepsSecretReferenceToken as xi, renderAssemblyPathEscape as xl, isWholeDynamicReferenceValue as xn, canonicalLambdaFunctionName as xo, withPrintingSecrets as xr, recordProvenPublicExpression as xs, nestedChildStackName as xt, isAccessDeniedError as y, refuseMalformedResourceAttributesForOrphan as ya, describeDockerCapturedOutput as yc, carriesFetchableDynamicReference as yi, describeFileReadFailure as yl, exportNameNoEchoParameters as yn, describeTypeWithThrottleRetry as yo, isCustomResourceType as yr, recordNoEchoAttributeValues as ys, dropSettledNestedJournals as yt, DynamoDBGlobalTableProvider as z, repairMalformedResourcesForReadOnly as za, synthesisStatusMessage as zc, hasReadableOrphans as zi, ATOMIC_FINAL_SNAPSHOT_TYPES as zn, liveMatchesUnresolvedTokenFrame as zo, observeThenDisableInstanceApiTermination as zr, splitImportedOps as zs, destroyStackRecordsView as zt };
|
|
45443
|
+
//# sourceMappingURL=deploy-engine-A-Ys_mhE.js.map
|