@fjall/deploy-core 12.4.0 → 13.1.0
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/README.md +8 -0
- package/dist/.build-source-hash +20 -16
- package/dist/.minified +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +1 -1
- package/dist/src/orchestration/application/destructionGate.js +1 -1
- package/dist/src/orchestration/application/plan/classify.js +1 -1
- package/dist/src/orchestration/domain/WorkerDomainDeployProvider.d.ts +77 -0
- package/dist/src/orchestration/domain/WorkerDomainDeployProvider.js +1 -0
- package/dist/src/orchestration/domain/domainTakeoverGate.d.ts +71 -0
- package/dist/src/orchestration/domain/domainTakeoverGate.js +2 -0
- package/dist/src/orchestration/domain/index.d.ts +4 -0
- package/dist/src/orchestration/domain/index.js +1 -1
- package/dist/src/orchestration/domain/recordConsentSpelling.d.ts +41 -0
- package/dist/src/orchestration/domain/recordConsentSpelling.js +1 -0
- package/dist/src/orchestration/domain/route53Release.d.ts +37 -0
- package/dist/src/orchestration/domain/route53Release.js +1 -0
- package/dist/src/orchestration/domainInterface.d.ts +34 -0
- package/dist/src/orchestration/index.d.ts +1 -1
- package/dist/src/orchestration/organisation/cascadeHelpers.d.ts +17 -6
- package/dist/src/orchestration/organisation/cascadeHelpers.js +1 -1
- package/dist/src/orchestration/organisationDeploy/cascadeExecution.d.ts +10 -0
- package/dist/src/orchestration/organisationDeploy/cascadeExecution.js +1 -1
- package/dist/src/orchestration/organisationDeploy/orgCascadeDeploy.js +4 -4
- package/dist/src/orchestration/remediation/removalUpdate.d.ts +4 -4
- package/dist/src/types/params.d.ts +12 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -20,6 +20,14 @@ import { StepRegistry } from "@fjall/deploy-core/steps";
|
|
|
20
20
|
|
|
21
21
|
See [docs.fjall.io](https://docs.fjall.io) for full usage.
|
|
22
22
|
|
|
23
|
+
## Breaking changes
|
|
24
|
+
|
|
25
|
+
Majors are documented in [docs/release-notes](../docs/release-notes/) at the
|
|
26
|
+
repository root. From 13.0.0 the destruction gate's stateful-resource oracle
|
|
27
|
+
also covers log groups, secrets, KMS keys, hosted zones and Cognito user
|
|
28
|
+
pools — deletes and replacements of those types stop at the gate (exit 4)
|
|
29
|
+
until consented with `--remediate`.
|
|
30
|
+
|
|
23
31
|
## Licence
|
|
24
32
|
|
|
25
33
|
Proprietary — see [LICENSE](./LICENSE).
|
package/dist/.build-source-hash
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"package.json",
|
|
10
10
|
"tsconfig.json"
|
|
11
11
|
],
|
|
12
|
-
"hash": "
|
|
12
|
+
"hash": "bed82535df82cb45f19dd90a2fb43c721be20ac573faf86b444c55e18c4304fe",
|
|
13
13
|
"files": {
|
|
14
14
|
"src/__test-utils__/awsMockHelpers.ts": "fea371c1b1869678",
|
|
15
15
|
"src/__test-utils__/index.ts": "e03cf35821157dc4",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"src/aws/utils/regions.ts": "3a5191f4d2242a60",
|
|
53
53
|
"src/aws/utils/stackStatus.ts": "55fb23ba5514bc13",
|
|
54
54
|
"src/events/index.ts": "e55c022f0d9013e6",
|
|
55
|
-
"src/index.ts": "
|
|
55
|
+
"src/index.ts": "e1c8cfdfd80e015f",
|
|
56
56
|
"src/orchestration/activeDeploymentGuard.ts": "e8dde742c00ea728",
|
|
57
57
|
"src/orchestration/application/applicationDeploy.ts": "867232cbc981906c",
|
|
58
58
|
"src/orchestration/application/applicationDeployHelpers.ts": "bca833cc04f0b4c5",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"src/orchestration/application/databaseEndpointReconcile.ts": "27b14ee41524c632",
|
|
69
69
|
"src/orchestration/application/deploySessionPolicy.ts": "8052c64ce050c2b8",
|
|
70
70
|
"src/orchestration/application/destroyPreFlight.ts": "cc4978dec60b033e",
|
|
71
|
-
"src/orchestration/application/destructionGate.ts": "
|
|
71
|
+
"src/orchestration/application/destructionGate.ts": "5fbaa6ef69eb3ae1",
|
|
72
72
|
"src/orchestration/application/detectionPipeline.ts": "69b7dfcedf22fe01",
|
|
73
73
|
"src/orchestration/application/dockerBuildHelper.ts": "e7a7259e987d93be",
|
|
74
74
|
"src/orchestration/application/ecrCacheRepository.ts": "d7a5602ccabde493",
|
|
@@ -81,13 +81,13 @@
|
|
|
81
81
|
"src/orchestration/application/plan/assemblyDigest.ts": "4c77451ced199188",
|
|
82
82
|
"src/orchestration/application/plan/buildDeployPlan.ts": "4cb0b57b60712404",
|
|
83
83
|
"src/orchestration/application/plan/changeSetEscalation.ts": "d9ad7a5a65283dc4",
|
|
84
|
-
"src/orchestration/application/plan/classify.ts": "
|
|
84
|
+
"src/orchestration/application/plan/classify.ts": "d9fc8d78d281b69a",
|
|
85
85
|
"src/orchestration/application/plan/computeDeployPlan.ts": "62d47d2d620895b6",
|
|
86
86
|
"src/orchestration/application/plan/index.ts": "a2292dca615dd021",
|
|
87
87
|
"src/orchestration/application/plan/loadDeployPlan.ts": "f0d4414fd34f68c3",
|
|
88
88
|
"src/orchestration/application/plan/pinnedNames.ts": "d6a90c96c88f13e0",
|
|
89
89
|
"src/orchestration/application/plan/registryOverlay.ts": "920be845c7f4aea2",
|
|
90
|
-
"src/orchestration/application/plan/renameDetection.ts": "
|
|
90
|
+
"src/orchestration/application/plan/renameDetection.ts": "7242d45be616625f",
|
|
91
91
|
"src/orchestration/application/plan/renderDeployPlan.ts": "7fa4fc332accdc00",
|
|
92
92
|
"src/orchestration/application/plan/types.ts": "191929198672081c",
|
|
93
93
|
"src/orchestration/application/schemaGateImage.ts": "587a115432c6678e",
|
|
@@ -106,15 +106,19 @@
|
|
|
106
106
|
"src/orchestration/destroy.ts": "b6da154984e63a8d",
|
|
107
107
|
"src/orchestration/dockerBuildParamsKeys.ts": "ac3d6ecd24d68792",
|
|
108
108
|
"src/orchestration/dockerInterface.ts": "f2efc8a98d3b3d65",
|
|
109
|
+
"src/orchestration/domain/WorkerDomainDeployProvider.ts": "fa34993b4f96451a",
|
|
109
110
|
"src/orchestration/domain/caaPreflight.ts": "4a9ab5bd9567fb41",
|
|
110
111
|
"src/orchestration/domain/delegatedDomainDeploy.ts": "b5e5c2db59250b8a",
|
|
111
112
|
"src/orchestration/domain/delegationDestroyMirror.ts": "939f6c3cc3293d8b",
|
|
112
|
-
"src/orchestration/domain/
|
|
113
|
+
"src/orchestration/domain/domainTakeoverGate.ts": "70c77f8eb61b1e3d",
|
|
114
|
+
"src/orchestration/domain/index.ts": "e3c35fd95d88567e",
|
|
113
115
|
"src/orchestration/domain/nsPropagationGate.ts": "c7a443e7048d4430",
|
|
116
|
+
"src/orchestration/domain/recordConsentSpelling.ts": "9869eadf39e75d98",
|
|
114
117
|
"src/orchestration/domain/route53Delegation.ts": "a7149a0542e4d185",
|
|
118
|
+
"src/orchestration/domain/route53Release.ts": "558363b79172ec40",
|
|
115
119
|
"src/orchestration/domain/types.ts": "132972b0e1113ac1",
|
|
116
120
|
"src/orchestration/domain/zoneClassifier.ts": "f9908f0b4635709e",
|
|
117
|
-
"src/orchestration/domainInterface.ts": "
|
|
121
|
+
"src/orchestration/domainInterface.ts": "2887751e0ded2282",
|
|
118
122
|
"src/orchestration/drift/classifyDriftFailure.ts": "4426ecc6545b0472",
|
|
119
123
|
"src/orchestration/drift/detectStackDrift.ts": "cc38b12162e08fac",
|
|
120
124
|
"src/orchestration/drift/driftPreFlight.ts": "87c6176636655ad7",
|
|
@@ -125,19 +129,19 @@
|
|
|
125
129
|
"src/orchestration/drift/route53RecordPreflight.ts": "f4db16a6c0e69ac9",
|
|
126
130
|
"src/orchestration/failure/classifyFailure.ts": "bfb80731bc7d6b95",
|
|
127
131
|
"src/orchestration/failure/deploymentFailureAttachment.ts": "358d9e4d88390cfd",
|
|
128
|
-
"src/orchestration/index.ts": "
|
|
132
|
+
"src/orchestration/index.ts": "405fae4d6e7ac57d",
|
|
129
133
|
"src/orchestration/manifestSecretParser.ts": "c5576bd88a3652f8",
|
|
130
134
|
"src/orchestration/organisation/accountsConfig.ts": "a55a3306564e7b2f",
|
|
131
135
|
"src/orchestration/organisation/cascadeDestroyHelpers.ts": "7f1927a00ed24767",
|
|
132
|
-
"src/orchestration/organisation/cascadeHelpers.ts": "
|
|
136
|
+
"src/orchestration/organisation/cascadeHelpers.ts": "dd36d26f3694bdfd",
|
|
133
137
|
"src/orchestration/organisation/cascadeSummary.ts": "335be9649cea0626",
|
|
134
138
|
"src/orchestration/organisation/organisationDeploy.ts": "f3fad626230d8a16",
|
|
135
139
|
"src/orchestration/organisation/organisationDestroy.ts": "06076a7e76345854",
|
|
136
140
|
"src/orchestration/organisation/organisationSetup.ts": "3f3415b762a83a47",
|
|
137
141
|
"src/orchestration/organisation/reconcileProviderAccounts.ts": "91920b2ed61dd811",
|
|
138
|
-
"src/orchestration/organisationDeploy/cascadeExecution.ts": "
|
|
142
|
+
"src/orchestration/organisationDeploy/cascadeExecution.ts": "67fbdbff425f6794",
|
|
139
143
|
"src/orchestration/organisationDeploy/infraSteps.ts": "53880cef5020dd04",
|
|
140
|
-
"src/orchestration/organisationDeploy/orgCascadeDeploy.ts": "
|
|
144
|
+
"src/orchestration/organisationDeploy/orgCascadeDeploy.ts": "3968db08ab9568ac",
|
|
141
145
|
"src/orchestration/organisationDeploy/orgContext.ts": "635f429a7cbb7c32",
|
|
142
146
|
"src/orchestration/organisationDeploy/resolveCascadeAccounts.ts": "9882c235a302cbf9",
|
|
143
147
|
"src/orchestration/organisationDeploy/singleComponentDeploy.ts": "3e35f43f3a59097c",
|
|
@@ -153,7 +157,7 @@
|
|
|
153
157
|
"src/orchestration/remediation/recreatePreFlight.ts": "654ef18cabe97777",
|
|
154
158
|
"src/orchestration/remediation/recreateResource.ts": "a9d97c47e0af68a7",
|
|
155
159
|
"src/orchestration/remediation/remediationJournal.ts": "5ebb14e618fde1c1",
|
|
156
|
-
"src/orchestration/remediation/removalUpdate.ts": "
|
|
160
|
+
"src/orchestration/remediation/removalUpdate.ts": "5e318c32562e01f2",
|
|
157
161
|
"src/orchestration/remediation/retainFlip.ts": "80e7b47e87251db5",
|
|
158
162
|
"src/orchestration/resolveOperation.ts": "84a9f425939fad63",
|
|
159
163
|
"src/orchestration/restart/restartApplication.ts": "3320b6aef19da793",
|
|
@@ -252,7 +256,7 @@
|
|
|
252
256
|
"src/types/frameworkBuilder.ts": "41198a0b446f60b6",
|
|
253
257
|
"src/types/index.ts": "eb45188ded4c08b4",
|
|
254
258
|
"src/types/operations.ts": "57a6c9e22a3f37ca",
|
|
255
|
-
"src/types/params.ts": "
|
|
259
|
+
"src/types/params.ts": "8d7e40c0e526d75e",
|
|
256
260
|
"src/types/remediation.ts": "0e1138f0c8fdc6bf",
|
|
257
261
|
"src/types/stepDefinitions.ts": "a5e2aa03b15011b4",
|
|
258
262
|
"src/types/validation.ts": "44aa473ec0e25dc4",
|
|
@@ -263,9 +267,9 @@
|
|
|
263
267
|
"src/util/sleepAbortable.ts": "f9cac3bf8a79a476",
|
|
264
268
|
"src/version.ts": "1811a4475823b27e",
|
|
265
269
|
"../scripts/minify-dist.mjs": "6b2e4b0df8aec601",
|
|
266
|
-
"package.json": "
|
|
270
|
+
"package.json": "b236e6ca44f111d1",
|
|
267
271
|
"tsconfig.json": "1929cf3f99fe9b1e"
|
|
268
272
|
},
|
|
269
|
-
"outputHash": "
|
|
270
|
-
"outputFileCount":
|
|
273
|
+
"outputHash": "8aeca5061a5ccd5357c2a97b2031ff0dab91f97444ffb4c2bf08a078b894d796",
|
|
274
|
+
"outputFileCount": 503
|
|
271
275
|
}
|
package/dist/.minified
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
251 files minified at 2026-08-16T10:00:13.306Z
|
package/dist/src/index.d.ts
CHANGED
|
@@ -83,7 +83,9 @@ export { parseAccountsConfiguration, flattenAccountsToEnvironments, extractAllAc
|
|
|
83
83
|
export type { AccountsConfig } from "./orchestration/index.js";
|
|
84
84
|
export { runOpenNextBuild } from "./orchestration/index.js";
|
|
85
85
|
export { runOrganisationSetup, ORG_SETUP_PHASES } from "./orchestration/index.js";
|
|
86
|
-
export type { OrgSetupPhase, OrgSetupCallbacks, OrgSetupConfig, OrgSetupResult, DockerProvider, DockerProgressCallback, DockerBuildParams, DockerBuildResult, ResolvedBuildSecret, ResolvedBuildSecrets, ECRInitParams, ECRInitResult, TagImagesParams, TagImagesResult, TagByDigestParams, DomainDeployProvider, DomainConfig, DomainDeployResult, DeployServices } from "./orchestration/index.js";
|
|
86
|
+
export type { OrgSetupPhase, OrgSetupCallbacks, OrgSetupConfig, OrgSetupResult, DockerProvider, DockerProgressCallback, DockerBuildParams, DockerBuildResult, ResolvedBuildSecret, ResolvedBuildSecrets, ECRInitParams, ECRInitResult, TagImagesParams, TagImagesResult, TagByDigestParams, DomainDeployProvider, DomainConfig, DomainDeployResult, DomainTakeoverSynth, DeployServices } from "./orchestration/index.js";
|
|
87
|
+
export { recordPhysicalName, parseRecordPhysicalName, recordSetKey, deleteRecordSetsByKey, cascadeTakeoverDigestSeed, buildCascadeTakeoverTicket, runCascadeTakeoverGate, WorkerDomainDeployProvider, createWorkerDomainDeployProvider } from "./orchestration/index.js";
|
|
88
|
+
export type { RecordConsentIdentity, DeletedRecordSet, DomainsTakeoverContext, DomainsTakeoverWithheld, DomainsTakeoverGateOutcome, WorkerDomainDeployProviderParams } from "./orchestration/index.js";
|
|
87
89
|
export { DOMAIN_DELEGATION_ERROR_TYPES, DomainDelegationError, DEFAULT_PUBLIC_RESOLVER_ADDRESSES, PUBLIC_DNS_QUERY_TIMEOUT_MS, createPublicResolvers, NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS, NS_PROPAGATION_DEFAULT_INTERVAL_MS, waitForNsPropagation, ACM_CAA_ISSUERS, runCaaPreflight, deployDelegatedDomain, CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE, templateOwnsDelegationRecord, deleteChildNsFromParent, nsDelegationPhysicalName, runDelegatedDomainDestroy } from "./orchestration/index.js";
|
|
88
90
|
export type { DomainDeployPhase, DomainDelegationErrorType, PublicCaaRecord, PublicDnsResolver, NsPropagationGateParams, NsPropagationVerdict, CaaPreflightParams, CaaPreflightVerdict, DelegatedDomainDeployer, DelegatedZonePhaseState, DeployDelegatedDomainParams, DelegatedDomainDeployOutcome, NsDeleteOutcome, DeleteChildNsParams, DelegationDestroyNsOutcome, DelegatedDomainDestroyOutcome, DelegatedDomainDestroyParams } from "./orchestration/index.js";
|
|
89
91
|
export { classifyZoneRecords, buildSatelliteRecordIndex, createSystemDnsNameProbe, systemDnsNameProbe, normaliseRecordName, isRoute53NameServer, isDelegatedToRoute53 } from "./orchestration/index.js";
|
package/dist/src/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEPLOY_CORE_VERSION_GLOBAL as t}from"./version.js";import{DeploymentEventSchema as i,DEPLOYMENT_EVENT_TYPES as a,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as n,DEPLOYMENT_EVENT_STATUS_REASON_MAX as s,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as E,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as c,DEPLOYMENT_ERROR_MESSAGE_MAX as S,CASCADE_PHASES as l,CASCADE_ACCOUNT_STATUSES as _,clampDeploymentEventStrings as p,truncateUtf16Safe as A}from"./types/index.js";import{DeployEventSchema as R,StepProgressSchema as m,DeployResourceSchema as d,PlanChangeSchema as u,PlanPropertyChangeSchema as D,ChangeCountsSchema as P,DEPLOY_EVENT_CONTRACT as O,DEPLOY_EVENT_CONTRACT_MAJOR as f,DEPLOY_EVENT_CONTRACT_MINOR as N,SUPPORTED_CONTRACT_MARKERS as C,DEPLOY_EVENT_ID_MAX as I,DEPLOY_EVENT_NAME_MAX as L,DEPLOY_EVENT_MESSAGE_MAX as g,DEPLOY_EVENT_STATUS_REASON_MAX as y,DEPLOY_EVENT_ERROR_MESSAGE_MAX as x,DEPLOY_EVENT_TRAIL_DETAIL_MAX as F,DEPLOY_EVENT_OUTPUT_MAX as h,DEPLOY_EVENT_ARN_MAX as M,DEPLOY_EVENT_URL_MAX as v,STEP_COMPLETE_STATUSES as U,LOG_LEVELS as b,STACK_CLEANUP_PHASES as k,CASCADE_ACCOUNT_PHASES as Y,DEPLOY_RESULTS as V,DETECTION_PHASES as G,PHASE_STATUSES as B,BUILDERS as K,CASCADE_OUTCOME_RESULTS as X,PLAN_ACTIONS as H,REPLACEMENT_MODES as w,APPROVAL_KINDS as J,APPROVAL_DECISIONS as W,ALL_PROGRESS_KINDS as Q,createDeployEmitter as j,parseDeployEvent as Z,parseDeployContractVersion as q}from"./types/index.js";import{SimpleAwsProvider as $}from"./aws/index.js";import{checkTargetReadiness as re,describeTargetReadinessReason as te,buildTargetUnreadyAdvisory as oe,buildTargetSetUnreadyAdvisory as ie,probeAccountStackExists as ae}from"./aws/index.js";import{checkRegionEnabled as se,regionDisabledMessage as Ee}from"./aws/index.js";import{ensureOrganisationExists as Se,describeOrganisation as le,enablePolicyTypes as _e,enableServiceAccess as pe,SERVICE_PRINCIPALS as Ae,enableRamSharing as Te,activateTrustedAccess as Re,enableIpamDelegatedAdmin as me,updateBackupGlobalSettings as de,listAccounts as ue,findAccount as De,createAccount as Pe,ensureOrganisationalUnitsExist as Oe,placeAccountsInOUs as fe,buildAccountToOUMap as Ne,findDevelopmentOuId as Ce,activateCostAllocationTags as Ie,checkIdentityCentreStatus as Le,snapshotIdentityCentre as ge,composeSdkAbortSignal as ye,extractErrorName as xe,isAborted as Fe,DEFAULT_MAX_PAGES as he,IDENTITY_STORE_PAGE_SIZE as Me,drainPages as ve,isOULeaf as Ue,registerSecurityDelegates as be,SECURITY_SERVICE_PRINCIPALS as ke,enableCentralisedRootAccess as Ye,ROOT_ACCESS_FEATURES as Ve,RootAccessEnablementError as Ge}from"./aws/index.js";import{STEP_IDS as Ke,STEP_NAMES as Xe,INFRASTRUCTURE_STEP_NAMES as He,INFRA_STEP_NAME as we}from"./types/index.js";import{RemediationVerbSchema as We,REMEDIATION_VERB_GLOSS as Qe,IDENTITY_PIN_SLOT_SWAP_GLOSS as je,DestructionFindingSchema as Ze,DestructionTicketResourceSchema as qe,DestructionTicketSchema as ze,DestructionConsentSchema as $e,DestructionOutcomeSchema as er,DESTRUCTION_FINDINGS as rr,CONSENT_VERDICTS as tr,TICKET_VERDICT_SOURCES as or,TicketVerdictSourceSchema as ir}from"./types/index.js";import{DRIFT_VERDICTS as nr,DriftVerdictSchema as sr,DriftSuspectSchema as Er,DriftFindingSchema as cr,DriftJournalRecordSchema as Sr,verbsForDriftVerdict as lr}from"./types/index.js";import{REMEDIATION_PHASES as pr,RemediationPhaseSchema as Ar,RemediationTargetSchema as Tr,RemediationFlipProofSchema as Rr,RemediationJournalRecordSchema as mr,RemediationVerbWithSurgerySchema as dr,remediationPhaseRank as ur,remediationPlaceholderPhysicalId as Dr,isRemediationPlaceholderPhysicalId as Pr}from"./types/index.js";import{ProgressReporter as fr,APPLICATION_STACKS as Nr,ORGANISATION_TYPES as Cr,APPLICATION_DEPLOY_ORDER as Ir,APPLICATION_DESTROY_ORDER as Lr,OPENNEXT_DEPLOY_ORDER as gr,OPENNEXT_DESTROY_ORDER as yr,PARALLEL_DEPLOY_GROUPS as xr,PARALLEL_DESTROY_GROUPS as Fr,OPENNEXT_PARALLEL_GROUPS as hr,PARALLEL_OPERATION_TYPES as Mr,isApplicationOperation as vr,isOrganisationOperation as Ur,getParallelDeployGroups as br,getParallelDestroyGroups as kr,getApplicationDeployOrder as Yr,getApplicationDestroyOrder as Vr,getApplicationStackName as Gr,getOrganisationStackName as Br,isApplicationStack as Kr,isQuarantineDetail as Xr,isRetainedBucketsDetail as Hr,getApplicationStepName as wr,getApplicationStepId as Jr,toPascalCase as Wr,isOpenNextPattern as Qr,OPENNEXT_PATTERNS as jr,STACK_NOT_FOUND_PATTERN as Zr,STACK_FAILED_STATE_PATTERN as qr,CDK_NO_STACKS_MATCH as zr,INFRASTRUCTURE_FILENAME as $r,ApplicationError as et,wrapApplicationError as rt,stubCallerIdentity as tt}from"./types/index.js";import{deriveResourcesFromManifestStacks as it}from"./types/detection/patternDetection.js";import{FjallStateFileSchema as nt,readStateFile as st,writeStateFile as Et,createEmptyState as ct,deleteStateFile as St,updateTemplateHash as lt,getStateFilePath as _t,regionSuffix as pt}from"./types/config/FjallState.js";import{readDomainState as Tt,writeDomainState as Rt,recordDomainDeployState as mt,deleteDomainState as dt,hashDomainDirectory as ut,LEGACY_DOMAIN_STATE_FILENAME as Dt}from"./types/config/DomainState.js";import{CloudFormationEventMonitor as Ot}from"./aws/index.js";import{CdkService as Nt,CdkArgumentBuilder as Ct,CdkProcessManager as It,ensureDependencyIntegrity as Lt,clearDependencyIntegrityCache as gt,DEPENDENCY_SYNC_TIMEOUT_MS as yt,CdkEventMonitor as xt,startStackMonitoring as Ft,DEFAULT_DEPLOY_TIMEOUT_MS as ht,isCdkError as Mt,formatInfrastructureError as vt,getStructuralHint as Ut,getSourceContext as bt,hasCdkDifferences as kt,parseDiffOutput as Yt,CloudFormationService as Vt,CloudFormationError as Gt,EcsService as Bt,EcsError as Kt,EcsServiceResolver as Xt,TemplateHashService as Ht,TemplateHashError as wt,CdkContextBuilder as Jt,emitProgress as Wt,PROGRESS_MESSAGES as Qt,parseBuildPhase as jt,buildStepContextBuildConfig as Zt,convertCloudFormationOutputsToRecord as qt,ApplicationStackService as zt}from"./services/index.js";import{CdkError as eo}from"./types/errors/index.js";import{BaseServiceError as to,ValidationError as oo,AuthError as io,AwsError as ao,DeploymentError as no,NetworkError as so,FileSystemError as Eo,ConfigError as co,toServiceError as So}from"./types/errors/index.js";import{filterDangerousEnvVars as _o,maskSensitiveOutput as po,parseShellArgs as Ao,sleep as To}from"@fjall/util";import{artefactOutputKey as mo,DeployModeSchema as uo,ServiceArtefactSchema as Do,ServiceArtefactsSchema as Po}from"@fjall/util";import{hasDockerfile as fo}from"./util/dockerfileDetection.js";import{sleepAbortable as Co}from"./util/sleepAbortable.js";import{createSequencedCallbacks as Lo}from"./util/sequencedCallbacks.js";import{fileExists as yo}from"@fjall/util/fsHelpers";import{success as Fo,failure as ho,isSuccess as Mo,isFailure as vo}from"@fjall/generator";import{deploy as bo}from"./orchestration/index.js";import{destroy as Yo}from"./orchestration/index.js";import{buildParamsContext as Go}from"./orchestration/contextHelpers.js";import{emitStepWarnings as Ko,emitWarningEvent as Xo}from"./orchestration/contextHelpers.js";import{ENGINE_DIAGNOSTIC_SCOPE as wo}from"./util/diagnosticScopes.js";import{restart as Wo,probeSecretsDrift as Qo,probeServiceDeploymentStatus as jo,computeSecretsDrift as Zo,deriveStaleParameters as qo,extractConsumedSsmParameters as zo}from"./orchestration/index.js";import{partitionAccounts as ei}from"./orchestration/index.js";import{buildRegionList as ti,buildAccountRegionPairs as oi,cascadeHomeRegion as ii,cascadeOperationKey as ai}from"./orchestration/index.js";import{projectScalarSummary as si,projectAccountRows as Ei}from"./orchestration/index.js";import{reconcileProviderAccounts as Si,mergeReconciledProviderAccounts as li}from"./orchestration/index.js";import{decideNextTransition as pi,reconcileTrailMigration as Ai,decommissionMemberTrailStorage as Ti,ORG_TRAIL_BUCKET_OUTPUT_KEY as Ri,TRAIL_BUCKET_OUTPUT_KEY as mi,TRAIL_KEY_ARN_OUTPUT_KEY as di}from"./orchestration/index.js";import{classifyDriftFailure as Di,fetchLastOperationEvents as Pi,DriftProbe as Oi,clearDriftSuspects as fi,defaultDriftJournalDir as Ni,readDriftSuspects as Ci,recordDriftSuspects as Ii,detectStackDrift as Li,runDriftPreFlight as gi,formatDriftPreFlightBlock as yi,DRIFT_PREFLIGHT_TRIGGER_STATUSES as xi,DRIFT_PREFLIGHT_BUDGET_MS as Fi,runRoute53RecordPreflight as hi}from"./orchestration/index.js";import{archiveCompletedRemediationJournal as vi,computeRemediationOpId as Ui,defaultRemediationJournalDir as bi,findRemediationJournalByOpId as ki,listActiveRemediationOps as Yi,listActiveRemediationOpsForContext as Vi,readRemediationJournal as Gi,sweepExpiredRemediationJournals as Bi,writeRemediationJournal as Ki,REMEDIATION_JOURNAL_RETENTION_DAYS as Xi,captureRemediationForensics as Hi,defaultRemediationForensicsDir as wi,applyRetainFlip as Ji,composeFlipCapabilities as Wi,computeTemplateDigest as Qi,deriveRetainFlipTemplate as ji,findMarkedResourcesByOpId as Zi,proveFlipMetadataOnly as qi,readRetainFlipState as zi,verifyRetainFlipDiff as $i,FORGET_MARKER_KEY as ea,FORGET_FLIP_SPEC as ra,RECREATE_MARKER_KEY as ta,assessForgetResumability as oa,completeForgetAfterConverge as ia,completeForgetAfterDeploy as aa,formatRecreateInFlightCures as na,partitionPreFlightByRemediation as sa,runForgetSurgery as Ea,synthTemplateDeclaresResource as ca,runRecreateSurgery as Sa,snapshotPolicyForType as la,SNAPSHOT_CAPABLE_RESOURCE_TYPES as _a,runRecreatePreFlight as pa,deriveRemovalTemplate as Aa,findRemovalDeletionFailures as Ta,findResourcesPresent as Ra,proveRemovalTargetsOnly as ma,advertisableDriftVerbs as da,buildDriftRepairTicket as ua,runDriftRepairGate as Da,formatPinOutcomeDetail as Pa,pinProbeCoverage as Oa,renderPinReportLines as fa,runPinRemediation as Na,captureLegacySurfaces as Ca,decodeLegacyAnchor as Ia,runIdentitySurfaceGate as La,collectIdentityPinCandidates as ga,degradedIdentityPinOutcomes as ya,renderIdentityPinReportLines as xa,runIdentityPinMigration as Fa,composePostFailureRepairOffer as ha,formatDriftRepairOffer as Ma,DriftRepairAvailableError as va,checkDeployPathStackAvailability as Ua,isDeployPathBlockingStatus as ba,StackUnavailableError as ka,assertLeaseBeforeStack as Ya,LeaseDeniedError as Va}from"./orchestration/index.js";import{unlockBucket as Ba,unlockQueue as Ka}from"./orchestration/index.js";import{triageBucketPolicy as Ha,isEnforceSslStatement as wa,toResourcePolicyStatements as Ja,restoreBucketPolicy as Wa,synthesiseEnforceSslDocument as Qa,ensureEnforceSsl as ja,restoreAndReconcileQuarantinedBucket as Za}from"./orchestration/index.js";import{verifyOrgTrailDelivery as za}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as en,isRootTaskPolicyArn as rn,ROOT_TASK_POLICY_ARNS as tn,MAX_ROOT_SESSION_SECONDS as on}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as nn,flattenAccountsToEnvironments as sn,extractAllAccountNames as En,accountsConfigToOUTree as cn,isStringArray as Sn,isAccountsConfig as ln,isOuOnlyAccountBucket as _n,OU_ONLY_ACCOUNT_BUCKETS as pn}from"./orchestration/index.js";import{runOpenNextBuild as Tn}from"./orchestration/index.js";import{runOrganisationSetup as mn,ORG_SETUP_PHASES as dn}from"./orchestration/index.js";import{DOMAIN_DELEGATION_ERROR_TYPES as Dn,DomainDelegationError as Pn,DEFAULT_PUBLIC_RESOLVER_ADDRESSES as On,PUBLIC_DNS_QUERY_TIMEOUT_MS as fn,createPublicResolvers as Nn,NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS as Cn,NS_PROPAGATION_DEFAULT_INTERVAL_MS as In,waitForNsPropagation as Ln,ACM_CAA_ISSUERS as gn,runCaaPreflight as yn,deployDelegatedDomain as xn,CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE as Fn,templateOwnsDelegationRecord as hn,deleteChildNsFromParent as Mn,nsDelegationPhysicalName as vn,runDelegatedDomainDestroy as Un}from"./orchestration/index.js";import{classifyZoneRecords as kn,buildSatelliteRecordIndex as Yn,createSystemDnsNameProbe as Vn,systemDnsNameProbe as Gn,normaliseRecordName as Bn,isRoute53NameServer as Kn,isDelegatedToRoute53 as Xn}from"./orchestration/index.js";import{resolveBuildSecrets as wn,resolveSecretRefValue as Jn,resolveBuildSecretSessionProvider as Wn,sourcedRefsFromBuildArgs as Qn,resolveBuildArgs as jn,buildBuildSecretSessionPolicy as Zn,buildDeploySessionPolicy as qn,partitionForRegion as zn,validateBuildGroup as $n}from"./orchestration/index.js";import{FrameworkRegistry as rs}from"./orchestration/index.js";import{openNextBuilder as os,staticSiteBuilder as is,dockerBuilder as as}from"./orchestration/index.js";import{StepRegistry as ss,getDestroyStepId as Es}from"./steps/index.js";import{buildDeployPlan as Ss,computeDeployPlan as ls,computeAssemblyDigest as _s,digestHead as ps,classifyImpact as As,derivePropertyChanges as Ts,isDataLoss as Rs,isStatefulResourceType as ms,renderPlanSummary as ds,renderPlanLines as us,toWirePlanChanges as Ds,signApprovalToken as Ps,verifyApprovalToken as Os,DEFAULT_APPROVAL_TTL_MS as fs,APPROVAL_TOKEN_PATTERN as Ns,runApprovalGate as Cs,approvalRefusalReason as Is}from"./orchestration/index.js";import{runDestructionGate as gs,buildDestructionTicket as ys,evaluateDestructionConsents as xs,computeTicketDigest as Fs,legalRemediationVerbs as hs,executableRemediationVerbs as Ms,advertisableRemediationVerbs as vs,renderDestructionTicketLines as Us,renderConsentVerdictLines as bs,loadDeployPlan as ks,createMemoisedPlanLoader as Ys}from"./orchestration/index.js";import{DEPLOYMENT_FAILURE_CLASSIFIER_VERSION as Gs,classifyDeployFailure as Bs,classifyFromEcsCompletion as Ks,classifyFromFailureAnalysis as Xs,classifyUnclassified as Hs}from"./orchestration/failure/classifyFailure.js";import{attachDeploymentFailure as Js,getDeploymentFailure as Ws}from"./orchestration/failure/deploymentFailureAttachment.js";export{gn as ACM_CAA_ISSUERS,Q as ALL_PROGRESS_KINDS,Ir as APPLICATION_DEPLOY_ORDER,Lr as APPLICATION_DESTROY_ORDER,Nr as APPLICATION_STACKS,W as APPROVAL_DECISIONS,J as APPROVAL_KINDS,Ns as APPROVAL_TOKEN_PATTERN,et as ApplicationError,zt as ApplicationStackService,io as AuthError,ao as AwsError,K as BUILDERS,to as BaseServiceError,Y as CASCADE_ACCOUNT_PHASES,_ as CASCADE_ACCOUNT_STATUSES,X as CASCADE_OUTCOME_RESULTS,l as CASCADE_PHASES,zr as CDK_NO_STACKS_MATCH,tr as CONSENT_VERDICTS,Fn as CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE,Ct as CdkArgumentBuilder,Jt as CdkContextBuilder,eo as CdkError,xt as CdkEventMonitor,It as CdkProcessManager,Nt as CdkService,P as ChangeCountsSchema,Gt as CloudFormationError,Ot as CloudFormationEventMonitor,Vt as CloudFormationService,co as ConfigError,fs as DEFAULT_APPROVAL_TTL_MS,ht as DEFAULT_DEPLOY_TIMEOUT_MS,he as DEFAULT_MAX_PAGES,On as DEFAULT_PUBLIC_RESOLVER_ADDRESSES,yt as DEPENDENCY_SYNC_TIMEOUT_MS,S as DEPLOYMENT_ERROR_MESSAGE_MAX,E as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,n as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,s as DEPLOYMENT_EVENT_STATUS_REASON_MAX,c as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,a as DEPLOYMENT_EVENT_TYPES,Gs as DEPLOYMENT_FAILURE_CLASSIFIER_VERSION,t as DEPLOY_CORE_VERSION_GLOBAL,M as DEPLOY_EVENT_ARN_MAX,O as DEPLOY_EVENT_CONTRACT,f as DEPLOY_EVENT_CONTRACT_MAJOR,N as DEPLOY_EVENT_CONTRACT_MINOR,x as DEPLOY_EVENT_ERROR_MESSAGE_MAX,I as DEPLOY_EVENT_ID_MAX,g as DEPLOY_EVENT_MESSAGE_MAX,L as DEPLOY_EVENT_NAME_MAX,h as DEPLOY_EVENT_OUTPUT_MAX,y as DEPLOY_EVENT_STATUS_REASON_MAX,F as DEPLOY_EVENT_TRAIL_DETAIL_MAX,v as DEPLOY_EVENT_URL_MAX,V as DEPLOY_RESULTS,rr as DESTRUCTION_FINDINGS,G as DETECTION_PHASES,Dn as DOMAIN_DELEGATION_ERROR_TYPES,Fi as DRIFT_PREFLIGHT_BUDGET_MS,xi as DRIFT_PREFLIGHT_TRIGGER_STATUSES,nr as DRIFT_VERDICTS,R as DeployEventSchema,uo as DeployModeSchema,d as DeployResourceSchema,no as DeploymentError,i as DeploymentEventSchema,$e as DestructionConsentSchema,Ze as DestructionFindingSchema,er as DestructionOutcomeSchema,qe as DestructionTicketResourceSchema,ze as DestructionTicketSchema,Pn as DomainDelegationError,cr as DriftFindingSchema,Sr as DriftJournalRecordSchema,Oi as DriftProbe,va as DriftRepairAvailableError,Er as DriftSuspectSchema,sr as DriftVerdictSchema,wo as ENGINE_DIAGNOSTIC_SCOPE,Kt as EcsError,Bt as EcsService,Xt as EcsServiceResolver,ra as FORGET_FLIP_SPEC,ea as FORGET_MARKER_KEY,Eo as FileSystemError,nt as FjallStateFileSchema,rs as FrameworkRegistry,je as IDENTITY_PIN_SLOT_SWAP_GLOSS,Me as IDENTITY_STORE_PAGE_SIZE,$r as INFRASTRUCTURE_FILENAME,He as INFRASTRUCTURE_STEP_NAMES,we as INFRA_STEP_NAME,Dt as LEGACY_DOMAIN_STATE_FILENAME,b as LOG_LEVELS,Va as LeaseDeniedError,on as MAX_ROOT_SESSION_SECONDS,In as NS_PROPAGATION_DEFAULT_INTERVAL_MS,Cn as NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS,so as NetworkError,gr as OPENNEXT_DEPLOY_ORDER,yr as OPENNEXT_DESTROY_ORDER,hr as OPENNEXT_PARALLEL_GROUPS,jr as OPENNEXT_PATTERNS,Cr as ORGANISATION_TYPES,dn as ORG_SETUP_PHASES,Ri as ORG_TRAIL_BUCKET_OUTPUT_KEY,pn as OU_ONLY_ACCOUNT_BUCKETS,xr as PARALLEL_DEPLOY_GROUPS,Fr as PARALLEL_DESTROY_GROUPS,Mr as PARALLEL_OPERATION_TYPES,B as PHASE_STATUSES,H as PLAN_ACTIONS,Qt as PROGRESS_MESSAGES,fn as PUBLIC_DNS_QUERY_TIMEOUT_MS,u as PlanChangeSchema,D as PlanPropertyChangeSchema,fr as ProgressReporter,ta as RECREATE_MARKER_KEY,Xi as REMEDIATION_JOURNAL_RETENTION_DAYS,pr as REMEDIATION_PHASES,Qe as REMEDIATION_VERB_GLOSS,w as REPLACEMENT_MODES,Ve as ROOT_ACCESS_FEATURES,tn as ROOT_TASK_POLICY_ARNS,Rr as RemediationFlipProofSchema,mr as RemediationJournalRecordSchema,Ar as RemediationPhaseSchema,Tr as RemediationTargetSchema,We as RemediationVerbSchema,dr as RemediationVerbWithSurgerySchema,Ge as RootAccessEnablementError,ke as SECURITY_SERVICE_PRINCIPALS,Ae as SERVICE_PRINCIPALS,_a as SNAPSHOT_CAPABLE_RESOURCE_TYPES,k as STACK_CLEANUP_PHASES,qr as STACK_FAILED_STATE_PATTERN,Zr as STACK_NOT_FOUND_PATTERN,U as STEP_COMPLETE_STATUSES,Ke as STEP_IDS,Xe as STEP_NAMES,C as SUPPORTED_CONTRACT_MARKERS,Do as ServiceArtefactSchema,Po as ServiceArtefactsSchema,$ as SimpleAwsProvider,ka as StackUnavailableError,m as StepProgressSchema,ss as StepRegistry,or as TICKET_VERDICT_SOURCES,mi as TRAIL_BUCKET_OUTPUT_KEY,di as TRAIL_KEY_ARN_OUTPUT_KEY,wt as TemplateHashError,Ht as TemplateHashService,ir as TicketVerdictSourceSchema,oo as ValidationError,cn as accountsConfigToOUTree,Ie as activateCostAllocationTags,Re as activateTrustedAccess,da as advertisableDriftVerbs,vs as advertisableRemediationVerbs,Ji as applyRetainFlip,Is as approvalRefusalReason,vi as archiveCompletedRemediationJournal,mo as artefactOutputKey,Ya as assertLeaseBeforeStack,oa as assessForgetResumability,en as assumeRootForTask,Js as attachDeploymentFailure,oi as buildAccountRegionPairs,Ne as buildAccountToOUMap,Zn as buildBuildSecretSessionPolicy,Ss as buildDeployPlan,qn as buildDeploySessionPolicy,ys as buildDestructionTicket,ua as buildDriftRepairTicket,Go as buildParamsContext,ti as buildRegionList,Yn as buildSatelliteRecordIndex,Zt as buildStepContextBuildConfig,ie as buildTargetSetUnreadyAdvisory,oe as buildTargetUnreadyAdvisory,Ca as captureLegacySurfaces,Hi as captureRemediationForensics,ii as cascadeHomeRegion,ai as cascadeOperationKey,Ua as checkDeployPathStackAvailability,Le as checkIdentityCentreStatus,se as checkRegionEnabled,re as checkTargetReadiness,p as clampDeploymentEventStrings,Bs as classifyDeployFailure,Di as classifyDriftFailure,Ks as classifyFromEcsCompletion,Xs as classifyFromFailureAnalysis,As as classifyImpact,Hs as classifyUnclassified,kn as classifyZoneRecords,gt as clearDependencyIntegrityCache,fi as clearDriftSuspects,ga as collectIdentityPinCandidates,ia as completeForgetAfterConverge,aa as completeForgetAfterDeploy,Wi as composeFlipCapabilities,ha as composePostFailureRepairOffer,ye as composeSdkAbortSignal,_s as computeAssemblyDigest,ls as computeDeployPlan,Ui as computeRemediationOpId,Zo as computeSecretsDrift,Qi as computeTemplateDigest,Fs as computeTicketDigest,qt as convertCloudFormationOutputsToRecord,Pe as createAccount,j as createDeployEmitter,ct as createEmptyState,Ys as createMemoisedPlanLoader,Nn as createPublicResolvers,Lo as createSequencedCallbacks,Vn as createSystemDnsNameProbe,pi as decideNextTransition,Ia as decodeLegacyAnchor,Ti as decommissionMemberTrailStorage,Ni as defaultDriftJournalDir,wi as defaultRemediationForensicsDir,bi as defaultRemediationJournalDir,ya as degradedIdentityPinOutcomes,Mn as deleteChildNsFromParent,dt as deleteDomainState,St as deleteStateFile,bo as deploy,xn as deployDelegatedDomain,Ts as derivePropertyChanges,Aa as deriveRemovalTemplate,it as deriveResourcesFromManifestStacks,ji as deriveRetainFlipTemplate,qo as deriveStaleParameters,le as describeOrganisation,te as describeTargetReadinessReason,Yo as destroy,Li as detectStackDrift,ps as digestHead,as as dockerBuilder,ve as drainPages,Wt as emitProgress,Ko as emitStepWarnings,Xo as emitWarningEvent,Ye as enableCentralisedRootAccess,me as enableIpamDelegatedAdmin,_e as enablePolicyTypes,Te as enableRamSharing,pe as enableServiceAccess,Lt as ensureDependencyIntegrity,ja as ensureEnforceSsl,Se as ensureOrganisationExists,Oe as ensureOrganisationalUnitsExist,xs as evaluateDestructionConsents,Ms as executableRemediationVerbs,En as extractAllAccountNames,zo as extractConsumedSsmParameters,xe as extractErrorName,ho as failure,Pi as fetchLastOperationEvents,yo as fileExists,_o as filterDangerousEnvVars,De as findAccount,Ce as findDevelopmentOuId,Zi as findMarkedResourcesByOpId,ki as findRemediationJournalByOpId,Ta as findRemovalDeletionFailures,Ra as findResourcesPresent,sn as flattenAccountsToEnvironments,yi as formatDriftPreFlightBlock,Ma as formatDriftRepairOffer,vt as formatInfrastructureError,Pa as formatPinOutcomeDetail,na as formatRecreateInFlightCures,Yr as getApplicationDeployOrder,Vr as getApplicationDestroyOrder,Gr as getApplicationStackName,Jr as getApplicationStepId,wr as getApplicationStepName,Ws as getDeploymentFailure,Es as getDestroyStepId,Br as getOrganisationStackName,br as getParallelDeployGroups,kr as getParallelDestroyGroups,bt as getSourceContext,_t as getStateFilePath,Ut as getStructuralHint,kt as hasCdkDifferences,fo as hasDockerfile,ut as hashDomainDirectory,Fe as isAborted,ln as isAccountsConfig,vr as isApplicationOperation,Kr as isApplicationStack,Mt as isCdkError,Rs as isDataLoss,Xn as isDelegatedToRoute53,ba as isDeployPathBlockingStatus,wa as isEnforceSslStatement,vo as isFailure,Ue as isOULeaf,Qr as isOpenNextPattern,Ur as isOrganisationOperation,_n as isOuOnlyAccountBucket,Xr as isQuarantineDetail,Pr as isRemediationPlaceholderPhysicalId,Hr as isRetainedBucketsDetail,rn as isRootTaskPolicyArn,Kn as isRoute53NameServer,ms as isStatefulResourceType,Sn as isStringArray,Mo as isSuccess,hs as legalRemediationVerbs,ue as listAccounts,Yi as listActiveRemediationOps,Vi as listActiveRemediationOpsForContext,ks as loadDeployPlan,po as maskSensitiveOutput,li as mergeReconciledProviderAccounts,Bn as normaliseRecordName,vn as nsDelegationPhysicalName,os as openNextBuilder,nn as parseAccountsConfiguration,jt as parseBuildPhase,q as parseDeployContractVersion,Z as parseDeployEvent,Yt as parseDiffOutput,Ao as parseShellArgs,ei as partitionAccounts,zn as partitionForRegion,sa as partitionPreFlightByRemediation,Oa as pinProbeCoverage,fe as placeAccountsInOUs,ae as probeAccountStackExists,Qo as probeSecretsDrift,jo as probeServiceDeploymentStatus,Ei as projectAccountRows,si as projectScalarSummary,qi as proveFlipMetadataOnly,ma as proveRemovalTargetsOnly,Tt as readDomainState,Ci as readDriftSuspects,Gi as readRemediationJournal,zi as readRetainFlipState,st as readStateFile,Si as reconcileProviderAccounts,Ai as reconcileTrailMigration,mt as recordDomainDeployState,Ii as recordDriftSuspects,Ee as regionDisabledMessage,pt as regionSuffix,be as registerSecurityDelegates,ur as remediationPhaseRank,Dr as remediationPlaceholderPhysicalId,bs as renderConsentVerdictLines,Us as renderDestructionTicketLines,xa as renderIdentityPinReportLines,fa as renderPinReportLines,us as renderPlanLines,ds as renderPlanSummary,jn as resolveBuildArgs,Wn as resolveBuildSecretSessionProvider,wn as resolveBuildSecrets,Jn as resolveSecretRefValue,Wo as restart,Za as restoreAndReconcileQuarantinedBucket,Wa as restoreBucketPolicy,Cs as runApprovalGate,yn as runCaaPreflight,Un as runDelegatedDomainDestroy,gs as runDestructionGate,gi as runDriftPreFlight,Da as runDriftRepairGate,Ea as runForgetSurgery,Fa as runIdentityPinMigration,La as runIdentitySurfaceGate,Tn as runOpenNextBuild,mn as runOrganisationSetup,Na as runPinRemediation,pa as runRecreatePreFlight,Sa as runRecreateSurgery,hi as runRoute53RecordPreflight,Ps as signApprovalToken,To as sleep,Co as sleepAbortable,ge as snapshotIdentityCentre,la as snapshotPolicyForType,Qn as sourcedRefsFromBuildArgs,Ft as startStackMonitoring,is as staticSiteBuilder,tt as stubCallerIdentity,Fo as success,Bi as sweepExpiredRemediationJournals,ca as synthTemplateDeclaresResource,Qa as synthesiseEnforceSslDocument,Gn as systemDnsNameProbe,hn as templateOwnsDelegationRecord,Wr as toPascalCase,Ja as toResourcePolicyStatements,So as toServiceError,Ds as toWirePlanChanges,Ha as triageBucketPolicy,A as truncateUtf16Safe,Ba as unlockBucket,Ka as unlockQueue,de as updateBackupGlobalSettings,lt as updateTemplateHash,$n as validateBuildGroup,lr as verbsForDriftVerdict,Os as verifyApprovalToken,za as verifyOrgTrailDelivery,$i as verifyRetainFlipDiff,Ln as waitForNsPropagation,rt as wrapApplicationError,Rt as writeDomainState,Ki as writeRemediationJournal,Et as writeStateFile};
|
|
1
|
+
import{DEPLOY_CORE_VERSION_GLOBAL as t}from"./version.js";import{DeploymentEventSchema as i,DEPLOYMENT_EVENT_TYPES as a,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as n,DEPLOYMENT_EVENT_STATUS_REASON_MAX as s,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as c,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as E,DEPLOYMENT_ERROR_MESSAGE_MAX as S,CASCADE_PHASES as l,CASCADE_ACCOUNT_STATUSES as p,clampDeploymentEventStrings as T,truncateUtf16Safe as _}from"./types/index.js";import{DeployEventSchema as R,StepProgressSchema as m,DeployResourceSchema as d,PlanChangeSchema as u,PlanPropertyChangeSchema as D,ChangeCountsSchema as P,DEPLOY_EVENT_CONTRACT as O,DEPLOY_EVENT_CONTRACT_MAJOR as f,DEPLOY_EVENT_CONTRACT_MINOR as N,SUPPORTED_CONTRACT_MARKERS as C,DEPLOY_EVENT_ID_MAX as I,DEPLOY_EVENT_NAME_MAX as g,DEPLOY_EVENT_MESSAGE_MAX as y,DEPLOY_EVENT_STATUS_REASON_MAX as L,DEPLOY_EVENT_ERROR_MESSAGE_MAX as h,DEPLOY_EVENT_TRAIL_DETAIL_MAX as x,DEPLOY_EVENT_OUTPUT_MAX as v,DEPLOY_EVENT_ARN_MAX as F,DEPLOY_EVENT_URL_MAX as M,STEP_COMPLETE_STATUSES as U,LOG_LEVELS as k,STACK_CLEANUP_PHASES as b,CASCADE_ACCOUNT_PHASES as Y,DEPLOY_RESULTS as V,DETECTION_PHASES as G,PHASE_STATUSES as B,BUILDERS as K,CASCADE_OUTCOME_RESULTS as X,PLAN_ACTIONS as H,REPLACEMENT_MODES as w,APPROVAL_KINDS as J,APPROVAL_DECISIONS as W,ALL_PROGRESS_KINDS as Q,createDeployEmitter as j,parseDeployEvent as Z,parseDeployContractVersion as q}from"./types/index.js";import{SimpleAwsProvider as $}from"./aws/index.js";import{checkTargetReadiness as re,describeTargetReadinessReason as te,buildTargetUnreadyAdvisory as oe,buildTargetSetUnreadyAdvisory as ie,probeAccountStackExists as ae}from"./aws/index.js";import{checkRegionEnabled as se,regionDisabledMessage as ce}from"./aws/index.js";import{ensureOrganisationExists as Se,describeOrganisation as le,enablePolicyTypes as pe,enableServiceAccess as Te,SERVICE_PRINCIPALS as _e,enableRamSharing as Ae,activateTrustedAccess as Re,enableIpamDelegatedAdmin as me,updateBackupGlobalSettings as de,listAccounts as ue,findAccount as De,createAccount as Pe,ensureOrganisationalUnitsExist as Oe,placeAccountsInOUs as fe,buildAccountToOUMap as Ne,findDevelopmentOuId as Ce,activateCostAllocationTags as Ie,checkIdentityCentreStatus as ge,snapshotIdentityCentre as ye,composeSdkAbortSignal as Le,extractErrorName as he,isAborted as xe,DEFAULT_MAX_PAGES as ve,IDENTITY_STORE_PAGE_SIZE as Fe,drainPages as Me,isOULeaf as Ue,registerSecurityDelegates as ke,SECURITY_SERVICE_PRINCIPALS as be,enableCentralisedRootAccess as Ye,ROOT_ACCESS_FEATURES as Ve,RootAccessEnablementError as Ge}from"./aws/index.js";import{STEP_IDS as Ke,STEP_NAMES as Xe,INFRASTRUCTURE_STEP_NAMES as He,INFRA_STEP_NAME as we}from"./types/index.js";import{RemediationVerbSchema as We,REMEDIATION_VERB_GLOSS as Qe,IDENTITY_PIN_SLOT_SWAP_GLOSS as je,DestructionFindingSchema as Ze,DestructionTicketResourceSchema as qe,DestructionTicketSchema as ze,DestructionConsentSchema as $e,DestructionOutcomeSchema as er,DESTRUCTION_FINDINGS as rr,CONSENT_VERDICTS as tr,TICKET_VERDICT_SOURCES as or,TicketVerdictSourceSchema as ir}from"./types/index.js";import{DRIFT_VERDICTS as nr,DriftVerdictSchema as sr,DriftSuspectSchema as cr,DriftFindingSchema as Er,DriftJournalRecordSchema as Sr,verbsForDriftVerdict as lr}from"./types/index.js";import{REMEDIATION_PHASES as Tr,RemediationPhaseSchema as _r,RemediationTargetSchema as Ar,RemediationFlipProofSchema as Rr,RemediationJournalRecordSchema as mr,RemediationVerbWithSurgerySchema as dr,remediationPhaseRank as ur,remediationPlaceholderPhysicalId as Dr,isRemediationPlaceholderPhysicalId as Pr}from"./types/index.js";import{ProgressReporter as fr,APPLICATION_STACKS as Nr,ORGANISATION_TYPES as Cr,APPLICATION_DEPLOY_ORDER as Ir,APPLICATION_DESTROY_ORDER as gr,OPENNEXT_DEPLOY_ORDER as yr,OPENNEXT_DESTROY_ORDER as Lr,PARALLEL_DEPLOY_GROUPS as hr,PARALLEL_DESTROY_GROUPS as xr,OPENNEXT_PARALLEL_GROUPS as vr,PARALLEL_OPERATION_TYPES as Fr,isApplicationOperation as Mr,isOrganisationOperation as Ur,getParallelDeployGroups as kr,getParallelDestroyGroups as br,getApplicationDeployOrder as Yr,getApplicationDestroyOrder as Vr,getApplicationStackName as Gr,getOrganisationStackName as Br,isApplicationStack as Kr,isQuarantineDetail as Xr,isRetainedBucketsDetail as Hr,getApplicationStepName as wr,getApplicationStepId as Jr,toPascalCase as Wr,isOpenNextPattern as Qr,OPENNEXT_PATTERNS as jr,STACK_NOT_FOUND_PATTERN as Zr,STACK_FAILED_STATE_PATTERN as qr,CDK_NO_STACKS_MATCH as zr,INFRASTRUCTURE_FILENAME as $r,ApplicationError as et,wrapApplicationError as rt,stubCallerIdentity as tt}from"./types/index.js";import{deriveResourcesFromManifestStacks as it}from"./types/detection/patternDetection.js";import{FjallStateFileSchema as nt,readStateFile as st,writeStateFile as ct,createEmptyState as Et,deleteStateFile as St,updateTemplateHash as lt,getStateFilePath as pt,regionSuffix as Tt}from"./types/config/FjallState.js";import{readDomainState as At,writeDomainState as Rt,recordDomainDeployState as mt,deleteDomainState as dt,hashDomainDirectory as ut,LEGACY_DOMAIN_STATE_FILENAME as Dt}from"./types/config/DomainState.js";import{CloudFormationEventMonitor as Ot}from"./aws/index.js";import{CdkService as Nt,CdkArgumentBuilder as Ct,CdkProcessManager as It,ensureDependencyIntegrity as gt,clearDependencyIntegrityCache as yt,DEPENDENCY_SYNC_TIMEOUT_MS as Lt,CdkEventMonitor as ht,startStackMonitoring as xt,DEFAULT_DEPLOY_TIMEOUT_MS as vt,isCdkError as Ft,formatInfrastructureError as Mt,getStructuralHint as Ut,getSourceContext as kt,hasCdkDifferences as bt,parseDiffOutput as Yt,CloudFormationService as Vt,CloudFormationError as Gt,EcsService as Bt,EcsError as Kt,EcsServiceResolver as Xt,TemplateHashService as Ht,TemplateHashError as wt,CdkContextBuilder as Jt,emitProgress as Wt,PROGRESS_MESSAGES as Qt,parseBuildPhase as jt,buildStepContextBuildConfig as Zt,convertCloudFormationOutputsToRecord as qt,ApplicationStackService as zt}from"./services/index.js";import{CdkError as eo}from"./types/errors/index.js";import{BaseServiceError as to,ValidationError as oo,AuthError as io,AwsError as ao,DeploymentError as no,NetworkError as so,FileSystemError as co,ConfigError as Eo,toServiceError as So}from"./types/errors/index.js";import{filterDangerousEnvVars as po,maskSensitiveOutput as To,parseShellArgs as _o,sleep as Ao}from"@fjall/util";import{artefactOutputKey as mo,DeployModeSchema as uo,ServiceArtefactSchema as Do,ServiceArtefactsSchema as Po}from"@fjall/util";import{hasDockerfile as fo}from"./util/dockerfileDetection.js";import{sleepAbortable as Co}from"./util/sleepAbortable.js";import{createSequencedCallbacks as go}from"./util/sequencedCallbacks.js";import{fileExists as Lo}from"@fjall/util/fsHelpers";import{success as xo,failure as vo,isSuccess as Fo,isFailure as Mo}from"@fjall/generator";import{deploy as ko}from"./orchestration/index.js";import{destroy as Yo}from"./orchestration/index.js";import{buildParamsContext as Go}from"./orchestration/contextHelpers.js";import{emitStepWarnings as Ko,emitWarningEvent as Xo}from"./orchestration/contextHelpers.js";import{ENGINE_DIAGNOSTIC_SCOPE as wo}from"./util/diagnosticScopes.js";import{restart as Wo,probeSecretsDrift as Qo,probeServiceDeploymentStatus as jo,computeSecretsDrift as Zo,deriveStaleParameters as qo,extractConsumedSsmParameters as zo}from"./orchestration/index.js";import{partitionAccounts as ei}from"./orchestration/index.js";import{buildRegionList as ti,buildAccountRegionPairs as oi,cascadeHomeRegion as ii,cascadeOperationKey as ai}from"./orchestration/index.js";import{projectScalarSummary as si,projectAccountRows as ci}from"./orchestration/index.js";import{reconcileProviderAccounts as Si,mergeReconciledProviderAccounts as li}from"./orchestration/index.js";import{decideNextTransition as Ti,reconcileTrailMigration as _i,decommissionMemberTrailStorage as Ai,ORG_TRAIL_BUCKET_OUTPUT_KEY as Ri,TRAIL_BUCKET_OUTPUT_KEY as mi,TRAIL_KEY_ARN_OUTPUT_KEY as di}from"./orchestration/index.js";import{classifyDriftFailure as Di,fetchLastOperationEvents as Pi,DriftProbe as Oi,clearDriftSuspects as fi,defaultDriftJournalDir as Ni,readDriftSuspects as Ci,recordDriftSuspects as Ii,detectStackDrift as gi,runDriftPreFlight as yi,formatDriftPreFlightBlock as Li,DRIFT_PREFLIGHT_TRIGGER_STATUSES as hi,DRIFT_PREFLIGHT_BUDGET_MS as xi,runRoute53RecordPreflight as vi}from"./orchestration/index.js";import{archiveCompletedRemediationJournal as Mi,computeRemediationOpId as Ui,defaultRemediationJournalDir as ki,findRemediationJournalByOpId as bi,listActiveRemediationOps as Yi,listActiveRemediationOpsForContext as Vi,readRemediationJournal as Gi,sweepExpiredRemediationJournals as Bi,writeRemediationJournal as Ki,REMEDIATION_JOURNAL_RETENTION_DAYS as Xi,captureRemediationForensics as Hi,defaultRemediationForensicsDir as wi,applyRetainFlip as Ji,composeFlipCapabilities as Wi,computeTemplateDigest as Qi,deriveRetainFlipTemplate as ji,findMarkedResourcesByOpId as Zi,proveFlipMetadataOnly as qi,readRetainFlipState as zi,verifyRetainFlipDiff as $i,FORGET_MARKER_KEY as ea,FORGET_FLIP_SPEC as ra,RECREATE_MARKER_KEY as ta,assessForgetResumability as oa,completeForgetAfterConverge as ia,completeForgetAfterDeploy as aa,formatRecreateInFlightCures as na,partitionPreFlightByRemediation as sa,runForgetSurgery as ca,synthTemplateDeclaresResource as Ea,runRecreateSurgery as Sa,snapshotPolicyForType as la,SNAPSHOT_CAPABLE_RESOURCE_TYPES as pa,runRecreatePreFlight as Ta,deriveRemovalTemplate as _a,findRemovalDeletionFailures as Aa,findResourcesPresent as Ra,proveRemovalTargetsOnly as ma,advertisableDriftVerbs as da,buildDriftRepairTicket as ua,runDriftRepairGate as Da,formatPinOutcomeDetail as Pa,pinProbeCoverage as Oa,renderPinReportLines as fa,runPinRemediation as Na,captureLegacySurfaces as Ca,decodeLegacyAnchor as Ia,runIdentitySurfaceGate as ga,collectIdentityPinCandidates as ya,degradedIdentityPinOutcomes as La,renderIdentityPinReportLines as ha,runIdentityPinMigration as xa,composePostFailureRepairOffer as va,formatDriftRepairOffer as Fa,DriftRepairAvailableError as Ma,checkDeployPathStackAvailability as Ua,isDeployPathBlockingStatus as ka,StackUnavailableError as ba,assertLeaseBeforeStack as Ya,LeaseDeniedError as Va}from"./orchestration/index.js";import{unlockBucket as Ba,unlockQueue as Ka}from"./orchestration/index.js";import{triageBucketPolicy as Ha,isEnforceSslStatement as wa,toResourcePolicyStatements as Ja,restoreBucketPolicy as Wa,synthesiseEnforceSslDocument as Qa,ensureEnforceSsl as ja,restoreAndReconcileQuarantinedBucket as Za}from"./orchestration/index.js";import{verifyOrgTrailDelivery as za}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as en,isRootTaskPolicyArn as rn,ROOT_TASK_POLICY_ARNS as tn,MAX_ROOT_SESSION_SECONDS as on}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as nn,flattenAccountsToEnvironments as sn,extractAllAccountNames as cn,accountsConfigToOUTree as En,isStringArray as Sn,isAccountsConfig as ln,isOuOnlyAccountBucket as pn,OU_ONLY_ACCOUNT_BUCKETS as Tn}from"./orchestration/index.js";import{runOpenNextBuild as An}from"./orchestration/index.js";import{runOrganisationSetup as mn,ORG_SETUP_PHASES as dn}from"./orchestration/index.js";import{recordPhysicalName as Dn,parseRecordPhysicalName as Pn,recordSetKey as On,deleteRecordSetsByKey as fn,cascadeTakeoverDigestSeed as Nn,buildCascadeTakeoverTicket as Cn,runCascadeTakeoverGate as In,WorkerDomainDeployProvider as gn,createWorkerDomainDeployProvider as yn}from"./orchestration/index.js";import{DOMAIN_DELEGATION_ERROR_TYPES as hn,DomainDelegationError as xn,DEFAULT_PUBLIC_RESOLVER_ADDRESSES as vn,PUBLIC_DNS_QUERY_TIMEOUT_MS as Fn,createPublicResolvers as Mn,NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS as Un,NS_PROPAGATION_DEFAULT_INTERVAL_MS as kn,waitForNsPropagation as bn,ACM_CAA_ISSUERS as Yn,runCaaPreflight as Vn,deployDelegatedDomain as Gn,CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE as Bn,templateOwnsDelegationRecord as Kn,deleteChildNsFromParent as Xn,nsDelegationPhysicalName as Hn,runDelegatedDomainDestroy as wn}from"./orchestration/index.js";import{classifyZoneRecords as Wn,buildSatelliteRecordIndex as Qn,createSystemDnsNameProbe as jn,systemDnsNameProbe as Zn,normaliseRecordName as qn,isRoute53NameServer as zn,isDelegatedToRoute53 as $n}from"./orchestration/index.js";import{resolveBuildSecrets as rs,resolveSecretRefValue as ts,resolveBuildSecretSessionProvider as os,sourcedRefsFromBuildArgs as is,resolveBuildArgs as as,buildBuildSecretSessionPolicy as ns,buildDeploySessionPolicy as ss,partitionForRegion as cs,validateBuildGroup as Es}from"./orchestration/index.js";import{FrameworkRegistry as ls}from"./orchestration/index.js";import{openNextBuilder as Ts,staticSiteBuilder as _s,dockerBuilder as As}from"./orchestration/index.js";import{StepRegistry as ms,getDestroyStepId as ds}from"./steps/index.js";import{buildDeployPlan as Ds,computeDeployPlan as Ps,computeAssemblyDigest as Os,digestHead as fs,classifyImpact as Ns,derivePropertyChanges as Cs,isDataLoss as Is,isStatefulResourceType as gs,renderPlanSummary as ys,renderPlanLines as Ls,toWirePlanChanges as hs,signApprovalToken as xs,verifyApprovalToken as vs,DEFAULT_APPROVAL_TTL_MS as Fs,APPROVAL_TOKEN_PATTERN as Ms,runApprovalGate as Us,approvalRefusalReason as ks}from"./orchestration/index.js";import{runDestructionGate as Ys,buildDestructionTicket as Vs,evaluateDestructionConsents as Gs,computeTicketDigest as Bs,legalRemediationVerbs as Ks,executableRemediationVerbs as Xs,advertisableRemediationVerbs as Hs,renderDestructionTicketLines as ws,renderConsentVerdictLines as Js,loadDeployPlan as Ws,createMemoisedPlanLoader as Qs}from"./orchestration/index.js";import{DEPLOYMENT_FAILURE_CLASSIFIER_VERSION as Zs,classifyDeployFailure as qs,classifyFromEcsCompletion as zs,classifyFromFailureAnalysis as $s,classifyUnclassified as ec}from"./orchestration/failure/classifyFailure.js";import{attachDeploymentFailure as tc,getDeploymentFailure as oc}from"./orchestration/failure/deploymentFailureAttachment.js";export{Yn as ACM_CAA_ISSUERS,Q as ALL_PROGRESS_KINDS,Ir as APPLICATION_DEPLOY_ORDER,gr as APPLICATION_DESTROY_ORDER,Nr as APPLICATION_STACKS,W as APPROVAL_DECISIONS,J as APPROVAL_KINDS,Ms as APPROVAL_TOKEN_PATTERN,et as ApplicationError,zt as ApplicationStackService,io as AuthError,ao as AwsError,K as BUILDERS,to as BaseServiceError,Y as CASCADE_ACCOUNT_PHASES,p as CASCADE_ACCOUNT_STATUSES,X as CASCADE_OUTCOME_RESULTS,l as CASCADE_PHASES,zr as CDK_NO_STACKS_MATCH,tr as CONSENT_VERDICTS,Bn as CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE,Ct as CdkArgumentBuilder,Jt as CdkContextBuilder,eo as CdkError,ht as CdkEventMonitor,It as CdkProcessManager,Nt as CdkService,P as ChangeCountsSchema,Gt as CloudFormationError,Ot as CloudFormationEventMonitor,Vt as CloudFormationService,Eo as ConfigError,Fs as DEFAULT_APPROVAL_TTL_MS,vt as DEFAULT_DEPLOY_TIMEOUT_MS,ve as DEFAULT_MAX_PAGES,vn as DEFAULT_PUBLIC_RESOLVER_ADDRESSES,Lt as DEPENDENCY_SYNC_TIMEOUT_MS,S as DEPLOYMENT_ERROR_MESSAGE_MAX,c as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,n as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,s as DEPLOYMENT_EVENT_STATUS_REASON_MAX,E as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,a as DEPLOYMENT_EVENT_TYPES,Zs as DEPLOYMENT_FAILURE_CLASSIFIER_VERSION,t as DEPLOY_CORE_VERSION_GLOBAL,F as DEPLOY_EVENT_ARN_MAX,O as DEPLOY_EVENT_CONTRACT,f as DEPLOY_EVENT_CONTRACT_MAJOR,N as DEPLOY_EVENT_CONTRACT_MINOR,h as DEPLOY_EVENT_ERROR_MESSAGE_MAX,I as DEPLOY_EVENT_ID_MAX,y as DEPLOY_EVENT_MESSAGE_MAX,g as DEPLOY_EVENT_NAME_MAX,v as DEPLOY_EVENT_OUTPUT_MAX,L as DEPLOY_EVENT_STATUS_REASON_MAX,x as DEPLOY_EVENT_TRAIL_DETAIL_MAX,M as DEPLOY_EVENT_URL_MAX,V as DEPLOY_RESULTS,rr as DESTRUCTION_FINDINGS,G as DETECTION_PHASES,hn as DOMAIN_DELEGATION_ERROR_TYPES,xi as DRIFT_PREFLIGHT_BUDGET_MS,hi as DRIFT_PREFLIGHT_TRIGGER_STATUSES,nr as DRIFT_VERDICTS,R as DeployEventSchema,uo as DeployModeSchema,d as DeployResourceSchema,no as DeploymentError,i as DeploymentEventSchema,$e as DestructionConsentSchema,Ze as DestructionFindingSchema,er as DestructionOutcomeSchema,qe as DestructionTicketResourceSchema,ze as DestructionTicketSchema,xn as DomainDelegationError,Er as DriftFindingSchema,Sr as DriftJournalRecordSchema,Oi as DriftProbe,Ma as DriftRepairAvailableError,cr as DriftSuspectSchema,sr as DriftVerdictSchema,wo as ENGINE_DIAGNOSTIC_SCOPE,Kt as EcsError,Bt as EcsService,Xt as EcsServiceResolver,ra as FORGET_FLIP_SPEC,ea as FORGET_MARKER_KEY,co as FileSystemError,nt as FjallStateFileSchema,ls as FrameworkRegistry,je as IDENTITY_PIN_SLOT_SWAP_GLOSS,Fe as IDENTITY_STORE_PAGE_SIZE,$r as INFRASTRUCTURE_FILENAME,He as INFRASTRUCTURE_STEP_NAMES,we as INFRA_STEP_NAME,Dt as LEGACY_DOMAIN_STATE_FILENAME,k as LOG_LEVELS,Va as LeaseDeniedError,on as MAX_ROOT_SESSION_SECONDS,kn as NS_PROPAGATION_DEFAULT_INTERVAL_MS,Un as NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS,so as NetworkError,yr as OPENNEXT_DEPLOY_ORDER,Lr as OPENNEXT_DESTROY_ORDER,vr as OPENNEXT_PARALLEL_GROUPS,jr as OPENNEXT_PATTERNS,Cr as ORGANISATION_TYPES,dn as ORG_SETUP_PHASES,Ri as ORG_TRAIL_BUCKET_OUTPUT_KEY,Tn as OU_ONLY_ACCOUNT_BUCKETS,hr as PARALLEL_DEPLOY_GROUPS,xr as PARALLEL_DESTROY_GROUPS,Fr as PARALLEL_OPERATION_TYPES,B as PHASE_STATUSES,H as PLAN_ACTIONS,Qt as PROGRESS_MESSAGES,Fn as PUBLIC_DNS_QUERY_TIMEOUT_MS,u as PlanChangeSchema,D as PlanPropertyChangeSchema,fr as ProgressReporter,ta as RECREATE_MARKER_KEY,Xi as REMEDIATION_JOURNAL_RETENTION_DAYS,Tr as REMEDIATION_PHASES,Qe as REMEDIATION_VERB_GLOSS,w as REPLACEMENT_MODES,Ve as ROOT_ACCESS_FEATURES,tn as ROOT_TASK_POLICY_ARNS,Rr as RemediationFlipProofSchema,mr as RemediationJournalRecordSchema,_r as RemediationPhaseSchema,Ar as RemediationTargetSchema,We as RemediationVerbSchema,dr as RemediationVerbWithSurgerySchema,Ge as RootAccessEnablementError,be as SECURITY_SERVICE_PRINCIPALS,_e as SERVICE_PRINCIPALS,pa as SNAPSHOT_CAPABLE_RESOURCE_TYPES,b as STACK_CLEANUP_PHASES,qr as STACK_FAILED_STATE_PATTERN,Zr as STACK_NOT_FOUND_PATTERN,U as STEP_COMPLETE_STATUSES,Ke as STEP_IDS,Xe as STEP_NAMES,C as SUPPORTED_CONTRACT_MARKERS,Do as ServiceArtefactSchema,Po as ServiceArtefactsSchema,$ as SimpleAwsProvider,ba as StackUnavailableError,m as StepProgressSchema,ms as StepRegistry,or as TICKET_VERDICT_SOURCES,mi as TRAIL_BUCKET_OUTPUT_KEY,di as TRAIL_KEY_ARN_OUTPUT_KEY,wt as TemplateHashError,Ht as TemplateHashService,ir as TicketVerdictSourceSchema,oo as ValidationError,gn as WorkerDomainDeployProvider,En as accountsConfigToOUTree,Ie as activateCostAllocationTags,Re as activateTrustedAccess,da as advertisableDriftVerbs,Hs as advertisableRemediationVerbs,Ji as applyRetainFlip,ks as approvalRefusalReason,Mi as archiveCompletedRemediationJournal,mo as artefactOutputKey,Ya as assertLeaseBeforeStack,oa as assessForgetResumability,en as assumeRootForTask,tc as attachDeploymentFailure,oi as buildAccountRegionPairs,Ne as buildAccountToOUMap,ns as buildBuildSecretSessionPolicy,Cn as buildCascadeTakeoverTicket,Ds as buildDeployPlan,ss as buildDeploySessionPolicy,Vs as buildDestructionTicket,ua as buildDriftRepairTicket,Go as buildParamsContext,ti as buildRegionList,Qn as buildSatelliteRecordIndex,Zt as buildStepContextBuildConfig,ie as buildTargetSetUnreadyAdvisory,oe as buildTargetUnreadyAdvisory,Ca as captureLegacySurfaces,Hi as captureRemediationForensics,ii as cascadeHomeRegion,ai as cascadeOperationKey,Nn as cascadeTakeoverDigestSeed,Ua as checkDeployPathStackAvailability,ge as checkIdentityCentreStatus,se as checkRegionEnabled,re as checkTargetReadiness,T as clampDeploymentEventStrings,qs as classifyDeployFailure,Di as classifyDriftFailure,zs as classifyFromEcsCompletion,$s as classifyFromFailureAnalysis,Ns as classifyImpact,ec as classifyUnclassified,Wn as classifyZoneRecords,yt as clearDependencyIntegrityCache,fi as clearDriftSuspects,ya as collectIdentityPinCandidates,ia as completeForgetAfterConverge,aa as completeForgetAfterDeploy,Wi as composeFlipCapabilities,va as composePostFailureRepairOffer,Le as composeSdkAbortSignal,Os as computeAssemblyDigest,Ps as computeDeployPlan,Ui as computeRemediationOpId,Zo as computeSecretsDrift,Qi as computeTemplateDigest,Bs as computeTicketDigest,qt as convertCloudFormationOutputsToRecord,Pe as createAccount,j as createDeployEmitter,Et as createEmptyState,Qs as createMemoisedPlanLoader,Mn as createPublicResolvers,go as createSequencedCallbacks,jn as createSystemDnsNameProbe,yn as createWorkerDomainDeployProvider,Ti as decideNextTransition,Ia as decodeLegacyAnchor,Ai as decommissionMemberTrailStorage,Ni as defaultDriftJournalDir,wi as defaultRemediationForensicsDir,ki as defaultRemediationJournalDir,La as degradedIdentityPinOutcomes,Xn as deleteChildNsFromParent,dt as deleteDomainState,fn as deleteRecordSetsByKey,St as deleteStateFile,ko as deploy,Gn as deployDelegatedDomain,Cs as derivePropertyChanges,_a as deriveRemovalTemplate,it as deriveResourcesFromManifestStacks,ji as deriveRetainFlipTemplate,qo as deriveStaleParameters,le as describeOrganisation,te as describeTargetReadinessReason,Yo as destroy,gi as detectStackDrift,fs as digestHead,As as dockerBuilder,Me as drainPages,Wt as emitProgress,Ko as emitStepWarnings,Xo as emitWarningEvent,Ye as enableCentralisedRootAccess,me as enableIpamDelegatedAdmin,pe as enablePolicyTypes,Ae as enableRamSharing,Te as enableServiceAccess,gt as ensureDependencyIntegrity,ja as ensureEnforceSsl,Se as ensureOrganisationExists,Oe as ensureOrganisationalUnitsExist,Gs as evaluateDestructionConsents,Xs as executableRemediationVerbs,cn as extractAllAccountNames,zo as extractConsumedSsmParameters,he as extractErrorName,vo as failure,Pi as fetchLastOperationEvents,Lo as fileExists,po as filterDangerousEnvVars,De as findAccount,Ce as findDevelopmentOuId,Zi as findMarkedResourcesByOpId,bi as findRemediationJournalByOpId,Aa as findRemovalDeletionFailures,Ra as findResourcesPresent,sn as flattenAccountsToEnvironments,Li as formatDriftPreFlightBlock,Fa as formatDriftRepairOffer,Mt as formatInfrastructureError,Pa as formatPinOutcomeDetail,na as formatRecreateInFlightCures,Yr as getApplicationDeployOrder,Vr as getApplicationDestroyOrder,Gr as getApplicationStackName,Jr as getApplicationStepId,wr as getApplicationStepName,oc as getDeploymentFailure,ds as getDestroyStepId,Br as getOrganisationStackName,kr as getParallelDeployGroups,br as getParallelDestroyGroups,kt as getSourceContext,pt as getStateFilePath,Ut as getStructuralHint,bt as hasCdkDifferences,fo as hasDockerfile,ut as hashDomainDirectory,xe as isAborted,ln as isAccountsConfig,Mr as isApplicationOperation,Kr as isApplicationStack,Ft as isCdkError,Is as isDataLoss,$n as isDelegatedToRoute53,ka as isDeployPathBlockingStatus,wa as isEnforceSslStatement,Mo as isFailure,Ue as isOULeaf,Qr as isOpenNextPattern,Ur as isOrganisationOperation,pn as isOuOnlyAccountBucket,Xr as isQuarantineDetail,Pr as isRemediationPlaceholderPhysicalId,Hr as isRetainedBucketsDetail,rn as isRootTaskPolicyArn,zn as isRoute53NameServer,gs as isStatefulResourceType,Sn as isStringArray,Fo as isSuccess,Ks as legalRemediationVerbs,ue as listAccounts,Yi as listActiveRemediationOps,Vi as listActiveRemediationOpsForContext,Ws as loadDeployPlan,To as maskSensitiveOutput,li as mergeReconciledProviderAccounts,qn as normaliseRecordName,Hn as nsDelegationPhysicalName,Ts as openNextBuilder,nn as parseAccountsConfiguration,jt as parseBuildPhase,q as parseDeployContractVersion,Z as parseDeployEvent,Yt as parseDiffOutput,Pn as parseRecordPhysicalName,_o as parseShellArgs,ei as partitionAccounts,cs as partitionForRegion,sa as partitionPreFlightByRemediation,Oa as pinProbeCoverage,fe as placeAccountsInOUs,ae as probeAccountStackExists,Qo as probeSecretsDrift,jo as probeServiceDeploymentStatus,ci as projectAccountRows,si as projectScalarSummary,qi as proveFlipMetadataOnly,ma as proveRemovalTargetsOnly,At as readDomainState,Ci as readDriftSuspects,Gi as readRemediationJournal,zi as readRetainFlipState,st as readStateFile,Si as reconcileProviderAccounts,_i as reconcileTrailMigration,mt as recordDomainDeployState,Ii as recordDriftSuspects,Dn as recordPhysicalName,On as recordSetKey,ce as regionDisabledMessage,Tt as regionSuffix,ke as registerSecurityDelegates,ur as remediationPhaseRank,Dr as remediationPlaceholderPhysicalId,Js as renderConsentVerdictLines,ws as renderDestructionTicketLines,ha as renderIdentityPinReportLines,fa as renderPinReportLines,Ls as renderPlanLines,ys as renderPlanSummary,as as resolveBuildArgs,os as resolveBuildSecretSessionProvider,rs as resolveBuildSecrets,ts as resolveSecretRefValue,Wo as restart,Za as restoreAndReconcileQuarantinedBucket,Wa as restoreBucketPolicy,Us as runApprovalGate,Vn as runCaaPreflight,In as runCascadeTakeoverGate,wn as runDelegatedDomainDestroy,Ys as runDestructionGate,yi as runDriftPreFlight,Da as runDriftRepairGate,ca as runForgetSurgery,xa as runIdentityPinMigration,ga as runIdentitySurfaceGate,An as runOpenNextBuild,mn as runOrganisationSetup,Na as runPinRemediation,Ta as runRecreatePreFlight,Sa as runRecreateSurgery,vi as runRoute53RecordPreflight,xs as signApprovalToken,Ao as sleep,Co as sleepAbortable,ye as snapshotIdentityCentre,la as snapshotPolicyForType,is as sourcedRefsFromBuildArgs,xt as startStackMonitoring,_s as staticSiteBuilder,tt as stubCallerIdentity,xo as success,Bi as sweepExpiredRemediationJournals,Ea as synthTemplateDeclaresResource,Qa as synthesiseEnforceSslDocument,Zn as systemDnsNameProbe,Kn as templateOwnsDelegationRecord,Wr as toPascalCase,Ja as toResourcePolicyStatements,So as toServiceError,hs as toWirePlanChanges,Ha as triageBucketPolicy,_ as truncateUtf16Safe,Ba as unlockBucket,Ka as unlockQueue,de as updateBackupGlobalSettings,lt as updateTemplateHash,Es as validateBuildGroup,lr as verbsForDriftVerdict,vs as verifyApprovalToken,za as verifyOrgTrailDelivery,$i as verifyRetainFlipDiff,bn as waitForNsPropagation,rt as wrapApplicationError,Rt as writeDomainState,Ki as writeRemediationJournal,ct as writeStateFile};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var N=Object.defineProperty;var d=(e,i)=>N(e,"name",{value:i,configurable:!0});import{createHash as D}from"node:crypto";import{success as g,failure as x}from"@fjall/generator";import{maskSensitiveOutput as C}from"@fjall/util";import{remediationPlaceholderPhysicalId as L}from"../../types/remediation.js";import{pinProbeCoverage as P}from"../remediation/pinRemediation.js";const v={"replacement-required":["abort","pin","recreate"],"pinned-name-replacement":["abort","pin","recreate"],"data-loss-delete":["abort","forget","recreate"],"resource-deleted":["abort","repair","forget","recreate"],"stack-deleted":["abort","repair","recreate"],"rename-detected":["abort","pin","recreate"],"rename-ambiguous":["abort","recreate"]};function G(e){return v[e]}d(G,"legalRemediationVerbs");const h={"replacement-required":["pin","recreate"],"pinned-name-replacement":["pin","recreate"],"data-loss-delete":["recreate"],"resource-deleted":["forget"],"stack-deleted":[],"rename-detected":["pin"],"rename-ambiguous":[]};function S(e){return h[e]}d(S,"executableRemediationVerbs");function b(e){const i=S(e.finding);return e.verbs.filter(n=>n==="abort"||i.includes(n)&&(n!=="pin"||y(e).covered))}d(b,"advertisableRemediationVerbs");function y(e){if(e.finding==="rename-detected")return e.pinSlotHint!==void 0?{covered:!0}:{covered:!1,detail:"no capacity-identity alias names this rename, so the identity-pin remediation cannot derive the {app, slot} to pin \u2014 hand-author the capacityIdentity entry in fjall-config.json and validate it with 'fjall migrate identity'"};const i=P(e.resourceType,e.offendingProperties);return i.covered?{covered:!0}:{covered:!1,detail:`verb 'pin' has no live-value probe for ${i.unsupportedPairs.join(", ")} in this release \u2014 pin cannot capture the live value(s) into the config for this resource`}}d(y,"pinVerbCoverage");function j(e){if(e.renameFinding!==void 0)return e.renameFinding;if(e.action==="replace")return e.pinnedPhysicalName!==void 0?"pinned-name-replacement":e.dataLoss?"replacement-required":void 0;if(e.action==="delete"&&e.dataLoss&&!e.retained)return"data-loss-delete"}d(j,"findingForChange");function R(e,i,n){if(i==="rename-detected"||i==="rename-ambiguous")return e.renameCause??"logical identity rename detected";if(i==="data-loss-delete")return"removed from the synthesised template \u2014 CloudFormation will delete the live resource and its data";const o=n.length>0?`${n.join(", ")} forces replacement`:"replacement required (no property-level detail available)",t=e.replacementMode==="may"||e.replacementMode==="conditional"?" (conditional verdict \u2014 worst-cased towards ceremony)":"";return i==="pinned-name-replacement"?`${o}${t}; CloudFormation refuses in-stack replacement of custom-named resources`:`${o}${t}`}d(R,"causeForChange");function E(e,i){const n=D("sha256");n.update(e),n.update(`
|
|
1
|
+
var N=Object.defineProperty;var d=(e,i)=>N(e,"name",{value:i,configurable:!0});import{createHash as D}from"node:crypto";import{success as g,failure as x}from"@fjall/generator";import{maskSensitiveOutput as C}from"@fjall/util";import{remediationPlaceholderPhysicalId as L}from"../../types/remediation.js";import{pinProbeCoverage as P}from"../remediation/pinRemediation.js";const v={"replacement-required":["abort","pin","recreate"],"pinned-name-replacement":["abort","pin","recreate"],"data-loss-delete":["abort","forget","recreate"],"resource-deleted":["abort","repair","forget","recreate"],"stack-deleted":["abort","repair","recreate"],"rename-detected":["abort","pin","recreate"],"rename-ambiguous":["abort","recreate"]};function G(e){return v[e]}d(G,"legalRemediationVerbs");const h={"replacement-required":["pin","recreate"],"pinned-name-replacement":["pin","recreate"],"data-loss-delete":["recreate"],"resource-deleted":["forget"],"stack-deleted":[],"rename-detected":["pin"],"rename-ambiguous":["recreate"]};function S(e){return h[e]}d(S,"executableRemediationVerbs");function b(e){const i=S(e.finding);return e.verbs.filter(n=>n==="abort"||i.includes(n)&&(n!=="pin"||y(e).covered))}d(b,"advertisableRemediationVerbs");function y(e){if(e.finding==="rename-detected")return e.pinSlotHint!==void 0?{covered:!0}:{covered:!1,detail:"no capacity-identity alias names this rename, so the identity-pin remediation cannot derive the {app, slot} to pin \u2014 hand-author the capacityIdentity entry in fjall-config.json and validate it with 'fjall migrate identity'"};const i=P(e.resourceType,e.offendingProperties);return i.covered?{covered:!0}:{covered:!1,detail:`verb 'pin' has no live-value probe for ${i.unsupportedPairs.join(", ")} in this release \u2014 pin cannot capture the live value(s) into the config for this resource`}}d(y,"pinVerbCoverage");function j(e){if(e.renameFinding!==void 0)return e.renameFinding;if(e.action==="replace")return e.pinnedPhysicalName!==void 0?"pinned-name-replacement":e.dataLoss?"replacement-required":void 0;if(e.action==="delete"&&e.dataLoss&&!e.retained)return"data-loss-delete"}d(j,"findingForChange");function R(e,i,n){if(i==="rename-detected"||i==="rename-ambiguous")return e.renameCause??"logical identity rename detected";if(i==="data-loss-delete")return"removed from the synthesised template \u2014 CloudFormation will delete the live resource and its data";const o=n.length>0?`${n.join(", ")} forces replacement`:"replacement required (no property-level detail available)",t=e.replacementMode==="may"||e.replacementMode==="conditional"?" (conditional verdict \u2014 worst-cased towards ceremony)":"";return i==="pinned-name-replacement"?`${o}${t}; CloudFormation refuses in-stack replacement of custom-named resources`:`${o}${t}`}d(R,"causeForChange");function E(e,i){const n=D("sha256");n.update(e),n.update(`
|
|
2
2
|
`);const o=i.map(t=>`${t.stack}|${t.logicalId}|${t.resourceType}|${t.physicalName}|${t.finding}`).sort();for(const t of o)n.update(t),n.update(`
|
|
3
3
|
`);return n.digest("hex")}d(E,"computeTicketDigest");function T(e,i){const n=new Set((i??[]).map(t=>`${t.stackName}
|
|
4
4
|
${t.logicalId}`)),o=[];for(const t of e.changes){if(t.action==="delete"&&n.has(`${t.stack}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var o=Object.defineProperty;var a=(e,t)=>o(e,"name",{value:t,configurable:!0});import{ResourceImpact as n}from"@aws-cdk/cloudformation-diff";function S(e){switch(e){case n.WILL_CREATE:return{action:"create",replacementMode:"none",destructive:!1,retained:!1};case n.WILL_UPDATE:return{action:"update",replacementMode:"none",destructive:!1,retained:!1};case n.WILL_REPLACE:return{action:"replace",replacementMode:"will",destructive:!0,retained:!1};case n.MAY_REPLACE:return{action:"replace",replacementMode:"may",destructive:!0,retained:!1};case n.WILL_DESTROY:return{action:"delete",replacementMode:"none",destructive:!0,retained:!1};case n.WILL_ORPHAN:return{action:"delete",replacementMode:"none",destructive:!1,retained:!0};case n.WILL_IMPORT:return{action:"read",replacementMode:"none",destructive:!1,retained:!1};case n.NO_CHANGE:return{action:"no-op",replacementMode:"none",destructive:!1,retained:!1};default:{const t=e;return{action:"replace",replacementMode:"conditional",destructive:!0,retained:!1}}}}a(S,"classifyImpact");const i=["AWS::RDS::","AWS::DynamoDB::Table","AWS::DynamoDB::GlobalTable","AWS::S3::Bucket","AWS::EFS::FileSystem","AWS::ElastiCache::","AWS::Redshift::","AWS::DocDB::","AWS::Neptune::","AWS::OpenSearchService::Domain","AWS::Elasticsearch::Domain","AWS::MSK::Cluster","AWS::QLDB::Ledger","AWS::Timestream::","AWS::EC2::Volume","AWS::FSx::","AWS::Logs::LogGroup","AWS::SecretsManager::Secret","AWS::KMS::Key","AWS::Route53::HostedZone","AWS::Cognito::UserPool"];function s(e){return i.some(t=>t.endsWith("::")?e.startsWith(t):e===t)}a(s,"isStatefulResourceType");function f(e){return e.retained||e.action!=="replace"&&e.action!=="delete"?!1:s(e.resourceType)}a(f,"isDataLoss");const l=new Set([n.WILL_REPLACE,n.MAY_REPLACE]);function A(e){if(e===void 0)return[];const t=[];for(const[c,r]of Object.entries(e))if(r.isDifferent!==!1&&(t.push({path:c,forcesReplacement:r.changeImpact!==void 0&&l.has(r.changeImpact)}),t.length>=100))break;return t}a(A,"derivePropertyChanges");export{S as classifyImpact,A as derivePropertyChanges,f as isDataLoss,s as isStatefulResourceType};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type Result } from "@fjall/generator";
|
|
2
|
+
import type { DeployCallbacks } from "../../types/callbacks.js";
|
|
3
|
+
import type { AwsCredentials } from "../../types/credentials.js";
|
|
4
|
+
import type { DomainConfig, DomainDeployProvider, DomainTakeoverSynth } from "../domainInterface.js";
|
|
5
|
+
/**
|
|
6
|
+
* The deployment worker's `DomainDeployProvider` (P6): the cascade's domains
|
|
7
|
+
* phase finally runs on webapp org deploys. Built on deploy-core's own
|
|
8
|
+
* primitives — `CdkService` with EXPLICIT job credentials, never the CLI's
|
|
9
|
+
* cwd-bound `Config.loadConfig` or ambient `AwsContext` — and parameterised
|
|
10
|
+
* by the job's `workingDirectory` + resolved `boundaryDir` (the CLI's path
|
|
11
|
+
* helpers are cwd-relative literals and its config walk goes UP, so a
|
|
12
|
+
* containered boundary like `infra/fjall` is unresolvable from
|
|
13
|
+
* workingDirectory alone; the job payload carries it instead).
|
|
14
|
+
*
|
|
15
|
+
* `delegatedDeployer` is deliberately not implemented in this release: the
|
|
16
|
+
* engine's documented single-shot `deployDomain` fallback handles delegated
|
|
17
|
+
* entries (waves still order parents first). The D8 two-phase parity
|
|
18
|
+
* (propagation gate + CAA preflight on FIRST deploys of delegated children)
|
|
19
|
+
* is a recorded follow-on in the domains-completion As-built.
|
|
20
|
+
*/
|
|
21
|
+
export interface WorkerDomainDeployProviderParams {
|
|
22
|
+
/** Absolute path of the checked-out repository the job deploys from. */
|
|
23
|
+
workingDirectory: string;
|
|
24
|
+
/**
|
|
25
|
+
* Repo-relative boundary directory (e.g. `fjall`, `infra/fjall`) from the
|
|
26
|
+
* organisation's tier pointer — resolved webapp-side and carried on the
|
|
27
|
+
* job payload.
|
|
28
|
+
*/
|
|
29
|
+
boundaryDir: string;
|
|
30
|
+
/** The job's explicit OIDC-minted credentials. */
|
|
31
|
+
credentials: AwsCredentials;
|
|
32
|
+
/**
|
|
33
|
+
* Serialised org config (`OrgConfigClient.serialise` shape) the worker
|
|
34
|
+
* already fetched for the deploy — threaded into CDK context exactly as
|
|
35
|
+
* the CLI's `assembleSynthContext` threads its own fetch.
|
|
36
|
+
*/
|
|
37
|
+
orgConfigSerialised?: string;
|
|
38
|
+
abortSignal?: AbortSignal;
|
|
39
|
+
}
|
|
40
|
+
export declare class WorkerDomainDeployProvider implements DomainDeployProvider {
|
|
41
|
+
private readonly domains;
|
|
42
|
+
private readonly workingDirectory;
|
|
43
|
+
private readonly boundaryDir;
|
|
44
|
+
private readonly credentials;
|
|
45
|
+
private readonly orgConfigSerialised;
|
|
46
|
+
private readonly abortSignal;
|
|
47
|
+
private readonly aws;
|
|
48
|
+
/** Memoised org lookup — one Organizations call per job, not per domain. */
|
|
49
|
+
private orgDetailsPromise;
|
|
50
|
+
private constructor();
|
|
51
|
+
/**
|
|
52
|
+
* Read + validate the domain registry once, fail-closed on malformed
|
|
53
|
+
* config. A missing config yields a provider with zero domains — the
|
|
54
|
+
* cascade's domains phase returns early, which is correct topology.
|
|
55
|
+
*/
|
|
56
|
+
static create(params: WorkerDomainDeployProviderParams): Promise<Result<WorkerDomainDeployProvider>>;
|
|
57
|
+
getDomains(): DomainConfig[];
|
|
58
|
+
private componentPath;
|
|
59
|
+
/**
|
|
60
|
+
* Worker mirror of the CLI's `assembleSynthContext`: same context keys, no
|
|
61
|
+
* ambient state. The org lookup degrades with a warning (CLI parity — the
|
|
62
|
+
* generated infrastructure drops the DelegationRole without org context,
|
|
63
|
+
* it does not fail), but accountId/region always come from the job's
|
|
64
|
+
* explicit credentials.
|
|
65
|
+
*/
|
|
66
|
+
private assembleContext;
|
|
67
|
+
private cdkCredentials;
|
|
68
|
+
private componentPreconditionError;
|
|
69
|
+
synthForTakeover(domainName: string, callbacks: DeployCallbacks): Promise<Result<DomainTakeoverSynth>>;
|
|
70
|
+
deployDomain(domainName: string, callbacks: DeployCallbacks): Promise<Result<void>>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The provider's public entry point: reads + validates the boundary's domain
|
|
74
|
+
* registry up front so a malformed config fails the JOB, closed, before the
|
|
75
|
+
* cascade ever consults `getDomains()`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createWorkerDomainDeployProvider(params: WorkerDomainDeployProviderParams): Promise<Result<WorkerDomainDeployProvider>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var D=Object.defineProperty;var u=(c,e)=>D(c,"name",{value:e,configurable:!0});import{existsSync as m}from"node:fs";import{readFile as k}from"node:fs/promises";import{join as h,resolve as S}from"node:path";import{OrganizationsClient as C}from"@aws-sdk/client-organizations";import{success as l,failure as o}from"@fjall/generator";import{getDomainStackName as P,getErrorMessage as f,maskSensitiveOutput as s}from"@fjall/util";import{RootConfigReadSchema as x}from"@fjall/util/config";import{logger as y}from"@fjall/util/logger";import{SimpleAwsProvider as v}from"../../aws/SimpleAwsProvider.js";import{describeOrganisationAsMember as E}from"../../aws/organisations/organisation.js";import{CdkService as w}from"../../services/infrastructure/CdkService.js";const b="WorkerDomainDeployProvider";async function $(c,e){const n=[h(c,e,"fjall-config.json"),h(c,"fjall-config.json")].find(r=>m(r));if(n===void 0)return l([]);let a;try{a=await k(n,"utf8")}catch(r){return o(new Error(`domains phase refused: ${n} exists but could not be read (${s(f(r))}) \u2014 deploying with an unreadable domain registry is not an option.`))}let d;try{d=JSON.parse(a)}catch(r){return o(new Error(`domains phase refused: ${n} is not valid JSON (${s(f(r))}). Cure: fix the file by hand \u2014 do not regenerate it, which would discard capacity-identity pins.`))}const i=x.safeParse(d);return i.success?l((i.data.domains??[]).map(r=>({name:r.name,type:r.type,...r.parentDomain!==void 0?{parentDomain:r.parentDomain}:{},...r.account!==void 0?{account:r.account}:{},...r.region!==void 0?{region:r.region}:{}}))):o(new Error(`domains phase refused: ${n} has a malformed domains/activeTarget/capacityIdentity value \u2014 deploying from a registry that cannot be parsed is not an option. Cure: fix the file by hand.`))}u($,"readDomainsConfig");class p{static{u(this,"WorkerDomainDeployProvider")}domains;workingDirectory;boundaryDir;credentials;orgConfigSerialised;abortSignal;aws;orgDetailsPromise;constructor(e,t){this.domains=t,this.workingDirectory=e.workingDirectory,this.boundaryDir=e.boundaryDir,this.credentials=e.credentials,this.orgConfigSerialised=e.orgConfigSerialised,this.abortSignal=e.abortSignal,this.aws=new v(e.credentials)}static async create(e){const t=await $(e.workingDirectory,e.boundaryDir);return t.success?l(new p(e,t.data)):o(t.error)}getDomains(){return this.domains}componentPath(e){return h(this.workingDirectory,this.boundaryDir,"domains",e)}async assembleContext(){this.orgDetailsPromise??=(async()=>{try{const t=await E(this.aws.getClient(C),this.abortSignal);if(!t.success){y.warn(b,"Organisation lookup failed \u2014 domain deploy proceeds without org context",{error:s(t.error.message)});return}return t.data===null?void 0:{orgId:t.data.orgId,managementAccountId:t.data.managementAccountId}}catch(t){y.warn(b,"Organisation lookup failed \u2014 domain deploy proceeds without org context",{error:s(f(t))});return}})();const e=await this.orgDetailsPromise;return{accountId:this.credentials.accountId,region:this.credentials.region,...e!==void 0?e:{},...this.orgConfigSerialised!==void 0?{orgConfig:this.orgConfigSerialised}:{}}}cdkCredentials(){return{accessKeyId:this.credentials.accessKeyId,secretAccessKey:this.credentials.secretAccessKey,...this.credentials.sessionToken!==void 0?{sessionToken:this.credentials.sessionToken}:{}}}componentPreconditionError(e){const t=this.componentPath(e);if(!m(t))return new Error(`Domain '${e}' is registered in fjall-config.json but ${t} does not exist in this checkout \u2014 merge the scaffold PR that creates it, or remove the registry entry.`);if(!m(h(t,"infrastructure.ts")))return new Error(`Domain '${e}' has no infrastructure.ts at ${t} \u2014 merge the scaffold/import PR that creates it.`)}async synthForTakeover(e,t){const n=this.componentPreconditionError(e);if(n!==void 0)return o(n);const a=this.componentPath(e),d=await this.assembleContext(),i=new w({...this.abortSignal!==void 0?{abortSignal:this.abortSignal}:{}});try{const r=await i.synth(a,{outputCallback:u(g=>{t.onProgress?.({type:"info",message:s(g)})},"outputCallback"),context:d,credentials:this.cdkCredentials()});if(!r.success)return o(new Error(`CDK synth failed: ${s(f(r.error))}`))}finally{i.dispose()}return l({stackNames:[P(e)],cdkOutPath:S(a,"cdk.out")})}async deployDomain(e,t){const n=this.componentPreconditionError(e);if(n!==void 0)return o(n);const a=this.componentPath(e),d=await this.assembleContext(),i=new w({...this.abortSignal!==void 0?{abortSignal:this.abortSignal}:{}});try{const r=await i.deploy(a,void 0,{outputCallback:u(g=>{t.onProgress?.({type:"info",message:s(g)})},"outputCallback"),context:d,credentials:this.cdkCredentials()});if(!r.success)return o(new Error(`CDK deploy failed: ${s(f(r.error))}`))}finally{i.dispose()}return l(void 0)}}async function z(c){return p.create(c)}u(z,"createWorkerDomainDeployProvider");export{p as WorkerDomainDeployProvider,z as createWorkerDomainDeployProvider};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Route53Client } from "@aws-sdk/client-route-53";
|
|
2
|
+
import { type Result } from "@fjall/generator";
|
|
3
|
+
import type { AwsProvider } from "../../aws/AwsProvider.js";
|
|
4
|
+
import type { CloudFormationService } from "../../services/infrastructure/CloudFormationService.js";
|
|
5
|
+
import type { DeployCallbacks } from "../../types/callbacks.js";
|
|
6
|
+
import type { DestructionConsent, DestructionConsentGate, DestructionConsentReport, DestructionOutcome, DestructionTicket } from "../../types/destruction.js";
|
|
7
|
+
import { type Route53RecordCollision } from "../drift/route53RecordPreflight.js";
|
|
8
|
+
import type { DomainConfig, DomainDeployProvider } from "../domainInterface.js";
|
|
9
|
+
import { type DeletedRecordSet } from "./route53Release.js";
|
|
10
|
+
/**
|
|
11
|
+
* The cascade's [G2]×D5 record-takeover gate (P6): the engine-side floor of
|
|
12
|
+
* the ceremony the standalone `fjall domain deploy` command already runs.
|
|
13
|
+
* Promoted here because review established the gate existed ONLY on that one
|
|
14
|
+
* CLI command path — the cascade (`provider.deployDomain` → raw CDK deploy)
|
|
15
|
+
* had no collision preflight on ANY surface, so an imported zone merged and
|
|
16
|
+
* org-deployed would hit raw CloudFormation "record set already exists" with
|
|
17
|
+
* no consent ceremony (the H5 incident class D5 exists to prevent).
|
|
18
|
+
*
|
|
19
|
+
* Shape: assess EVERY eligible domain first (synth → live-record preflight),
|
|
20
|
+
* union the verified collisions into ONE cascade-scoped ticket, evaluate
|
|
21
|
+
* consents ONCE (the strict evaluator's surplus rule stays intact — a
|
|
22
|
+
* consent naming no ticket row fails the whole set), and only then release +
|
|
23
|
+
* deploy. Withheld ⇒ the phase mutates NOTHING. The standalone CLI command
|
|
24
|
+
* keeps its richer per-domain interactive ceremony; this gate is the floor,
|
|
25
|
+
* not a replacement.
|
|
26
|
+
*/
|
|
27
|
+
/** Everything the gate needs from the cascade's execution context. */
|
|
28
|
+
export interface DomainsTakeoverContext {
|
|
29
|
+
aws: AwsProvider;
|
|
30
|
+
cfnService: Pick<CloudFormationService, "getTemplate">;
|
|
31
|
+
/** Flag-supplied consents (worker re-queue / CLI `--remediate`). */
|
|
32
|
+
consents?: readonly DestructionConsent[];
|
|
33
|
+
/** Digest the consents were minted against (TOCTOU binding). */
|
|
34
|
+
consentDigest?: string;
|
|
35
|
+
/** Interactive resolver — consulted only when no flag consents came. */
|
|
36
|
+
consentGate?: DestructionConsentGate;
|
|
37
|
+
/** Injectable Route53 client for the release arm (tests). */
|
|
38
|
+
route53Client?: Pick<Route53Client, "send">;
|
|
39
|
+
abortSignal?: AbortSignal;
|
|
40
|
+
}
|
|
41
|
+
export interface DomainsTakeoverWithheld {
|
|
42
|
+
readonly ticket: DestructionTicket;
|
|
43
|
+
readonly outcome: DestructionOutcome;
|
|
44
|
+
readonly report?: DestructionConsentReport;
|
|
45
|
+
readonly reasons: readonly string[];
|
|
46
|
+
}
|
|
47
|
+
export type DomainsTakeoverGateOutcome = {
|
|
48
|
+
readonly kind: "clear";
|
|
49
|
+
readonly released: readonly DeletedRecordSet[];
|
|
50
|
+
} | {
|
|
51
|
+
readonly kind: "withheld";
|
|
52
|
+
readonly withheld: DomainsTakeoverWithheld;
|
|
53
|
+
};
|
|
54
|
+
/** Digest seed: deterministic across the mint run and the consent re-run. */
|
|
55
|
+
export declare function cascadeTakeoverDigestSeed(zoneNames: readonly string[]): string;
|
|
56
|
+
/**
|
|
57
|
+
* Mint one ticket resource per verified collision — the SAME spelling and
|
|
58
|
+
* verb vocabulary as the standalone CLI ticket (`recordConsentSpelling`), so
|
|
59
|
+
* the operator copies consents verbatim between surfaces.
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildCascadeTakeoverTicket(zoneNames: readonly string[], collisions: readonly Route53RecordCollision[]): DestructionTicket;
|
|
62
|
+
/**
|
|
63
|
+
* Run the full gate: assess → (on verified, all-consentable collisions)
|
|
64
|
+
* consent ceremony → consented release. Mirrors the CLI's
|
|
65
|
+
* `runDomainConsentCeremony` semantics exactly: flag consents evaluated
|
|
66
|
+
* engine-side, the interactive gate consulted ONLY when no flags came, an
|
|
67
|
+
* `abort` verb is an operator withhold, no blanket flag exists, and every
|
|
68
|
+
* withheld path renders the full ticket + verdict table through the warning
|
|
69
|
+
* seam so non-interactive runs stop naming the exact consent spelling.
|
|
70
|
+
*/
|
|
71
|
+
export declare function runCascadeTakeoverGate(provider: DomainDeployProvider, domains: readonly DomainConfig[], callbacks: DeployCallbacks, context: DomainsTakeoverContext): Promise<Result<DomainsTakeoverGateOutcome>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var E=Object.defineProperty;var p=(s,l)=>E(s,"name",{value:l,configurable:!0});import{Route53Client as N}from"@aws-sdk/client-route-53";import{success as y,failure as g}from"@fjall/generator";import{maskSensitiveOutput as b}from"@fjall/util";import{computeTicketDigest as R,evaluateDestructionConsents as C,renderConsentVerdictLines as I,renderDestructionTicketLines as P}from"../application/destructionGate.js";import{emitWarningEvent as m}from"../contextHelpers.js";import{runRoute53RecordPreflight as z}from"../drift/route53RecordPreflight.js";import{recordPhysicalName as S}from"./recordConsentSpelling.js";import{deleteRecordSetsByKey as L,recordSetKey as F}from"./route53Release.js";function M(s){return`domain-deploy-takeover:${[...s].sort().join(",")}`}p(M,"cascadeTakeoverDigestSeed");function j(s,l){const o=l.map(e=>{const r=S(e.canonicalName,e.type,e.liveSetIdentifier);return{stack:`zone/${e.zoneId}`,logicalId:`Takeover ${r}`,resourceType:"AWS::Route53::RecordSet",physicalName:r,finding:"data-loss-delete",cause:b(`live record in zone ${e.zoneId} (${e.liveDescription}) is not owned by this stack's previous template \u2014 consenting RELEASES it: the live record is deleted so this deploy's CloudFormation stack recreates '${e.declaredName}' (${e.type}) from the declaration, a short DNS gap bounded by the deploy; consent with --remediate '${r}'=recreate`),offendingProperties:[],verdictSource:"drift-probe",dataLossRisk:!0,verbs:["abort","recreate"]}});return{ticketDigest:R(M(s),o),resources:o}}p(j,"buildCascadeTakeoverTicket");async function G(s,l,o,e){if(s.synthForTakeover===void 0)return g(new Error("domains phase refused: this DomainDeployProvider does not implement synthForTakeover, so the record-takeover gate cannot assess collisions \u2014 deploying ungated is not an option. Cure: implement synthForTakeover on the provider (CliDomainDeployProvider and WorkerDomainDeployProvider both do)."));const r=[];for(const c of l){const f=await s.synthForTakeover(c.name,o);if(!f.success)return g(new Error(`[${c.name}] takeover assessment synth failed: ${b(f.error.message)}`));const u=await z(e.aws,{stackNames:f.data.stackNames,cdkOutPath:f.data.cdkOutPath,cfnService:e.cfnService,onLog:p(n=>m(o,n),"onLog"),onUnreadableSynthTemplate:"block",...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(u.kind==="proceed")continue;const i=u.collisions,h=(i??[]).filter(n=>!n.consentable);if(i===void 0||h.length>0){const n=h.map(a=>` - ${S(a.canonicalName,a.type,a.liveSetIdentifier)}: ${a.nonConsentableReason??"not consentable"}`);return g(new Error([`[${c.name}] ${u.message}`,...n].join(`
|
|
2
|
+
`)))}r.push({domain:c,collisions:i})}return y(r)}p(G,"assessEligibleDomains");async function q(s,l,o,e){const r=await G(s,l,o,e);if(!r.success)return g(r.error);const c=r.data;if(c.length===0)return e.consents!==void 0&&e.consents.length>0&&m(o,"no record collisions \u2014 supplied consents were not needed"),y({kind:"clear",released:[]});const f=c.map(t=>t.domain.name),u=c.flatMap(t=>t.collisions),i=j(f,u),h=e.consents??[];let n=C({ticket:i,consents:h,...e.consentDigest!==void 0?{consentDigest:e.consentDigest}:{}});const a=[];if(!n.satisfied&&e.consentGate!==void 0&&h.length===0&&e.consentDigest===void 0){const t=await e.consentGate.resolve({target:`${f.join(", ")} record takeover`,ticket:i});t.kind==="abort"?a.push("declined at the interactive destruction ceremony \u2014 nothing was deleted, nothing was deployed"):n=C({ticket:i,consents:t.consents,consentDigest:t.ticketDigest})}const D=n.satisfied&&n.rows.some(t=>t.verdict==="matched"&&t.verb==="abort");if(!n.satisfied||D||a.length>0){const t=a.length>0||D?"declined":n.rows.length>0||n.digestMismatch?"consents-invalid":"awaiting-consent";for(const d of P(i))m(o,d);for(const d of I(n))m(o,d);for(const d of a)m(o,d);return t!=="declined"&&m(o,`Consent with --remediate '<name>/<TYPE>[@<setIdentifier>]'=recreate for EVERY row on the ticket (e.g. --remediate '${i.resources[0]?.physicalName??"<name>/<TYPE>"}'=recreate) (exact, case-sensitive). No blanket flag exists: --auto-approve, --skip-confirmation and approval tokens never satisfy this gate.`),y({kind:"withheld",withheld:{ticket:i,outcome:t,...n.rows.length>0||n.digestMismatch?{report:n}:{},reasons:a}})}const T=e.route53Client??e.aws.getClient(N),k=new Map;for(const t of u){const d=k.get(t.zoneId)??new Set;d.add(F(t.canonicalName,t.type,t.liveSetIdentifier)),k.set(t.zoneId,d)}const $=[];for(const[t,d]of k){const v=await L(T,t,d,e.abortSignal);if(!v.success)return g(v.error);for(const w of v.data)m(o,`Released live record ${S(w.name,w.type,w.setIdentifier)} from zone ${t} \u2014 this deploy's stack recreates it from the declaration`);$.push(...v.data)}return y({kind:"clear",released:$})}p(q,"runCascadeTakeoverGate");export{j as buildCascadeTakeoverTicket,M as cascadeTakeoverDigestSeed,q as runCascadeTakeoverGate};
|
|
@@ -10,3 +10,7 @@ export { deployDelegatedDomain, type DelegatedDomainDeployer, type DelegatedZone
|
|
|
10
10
|
export { CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE, templateOwnsDelegationRecord, deleteChildNsFromParent, nsDelegationPhysicalName, runDelegatedDomainDestroy, type NsDeleteOutcome, type DeleteChildNsParams, type DelegationDestroyNsOutcome, type DelegatedDomainDestroyOutcome, type DelegatedDomainDestroyParams } from "./delegationDestroyMirror.js";
|
|
11
11
|
export { classifyZoneRecords, buildSatelliteRecordIndex, createSystemDnsNameProbe, systemDnsNameProbe, normaliseRecordName, type RecordClassification, type ClassifiedRecord, type ZoneClassificationReport, type ZoneClassifierClients, type ZoneClassifierPhase, type ClassifyZoneOptions, type SatelliteRecordIndex, type DelegatedChildDomain, type ChildAccountClients, type ChildAccountClientFactory, type AwsSdkClientLike, type DnsProbeVerdict, type DnsNameProbe } from "./zoneClassifier.js";
|
|
12
12
|
export { isRoute53NameServer, isDelegatedToRoute53 } from "./route53Delegation.js";
|
|
13
|
+
export { recordPhysicalName, parseRecordPhysicalName, type RecordConsentIdentity } from "./recordConsentSpelling.js";
|
|
14
|
+
export { recordSetKey, deleteRecordSetsByKey, type DeletedRecordSet } from "./route53Release.js";
|
|
15
|
+
export { cascadeTakeoverDigestSeed, buildCascadeTakeoverTicket, runCascadeTakeoverGate, type DomainsTakeoverContext, type DomainsTakeoverWithheld, type DomainsTakeoverGateOutcome } from "./domainTakeoverGate.js";
|
|
16
|
+
export { WorkerDomainDeployProvider, createWorkerDomainDeployProvider, type WorkerDomainDeployProviderParams } from "./WorkerDomainDeployProvider.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DOMAIN_DELEGATION_ERROR_TYPES as
|
|
1
|
+
import{DOMAIN_DELEGATION_ERROR_TYPES as o,DomainDelegationError as a,DEFAULT_PUBLIC_RESOLVER_ADDRESSES as t,PUBLIC_DNS_QUERY_TIMEOUT_MS as s,createPublicResolvers as m,normaliseDnsName as i,isDnsEmptyAnswer as D}from"./types.js";import{NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS as n,NS_PROPAGATION_DEFAULT_INTERVAL_MS as d,waitForNsPropagation as c}from"./nsPropagationGate.js";import{ACM_CAA_ISSUERS as _,caaAncestorChain as E,formatCaaRecord as S,runCaaPreflight as T}from"./caaPreflight.js";import{deployDelegatedDomain as N}from"./delegatedDomainDeploy.js";import{CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE as p,templateOwnsDelegationRecord as f,deleteChildNsFromParent as y,nsDelegationPhysicalName as C,runDelegatedDomainDestroy as O}from"./delegationDestroyMirror.js";import{classifyZoneRecords as I,buildSatelliteRecordIndex as U,createSystemDnsNameProbe as g,systemDnsNameProbe as L,normaliseRecordName as u}from"./zoneClassifier.js";import{isRoute53NameServer as M,isDelegatedToRoute53 as h}from"./route53Delegation.js";import{recordPhysicalName as b,parseRecordPhysicalName as F}from"./recordConsentSpelling.js";import{recordSetKey as w,deleteRecordSetsByKey as B}from"./route53Release.js";import{cascadeTakeoverDigestSeed as K,buildCascadeTakeoverTicket as V,runCascadeTakeoverGate as W}from"./domainTakeoverGate.js";import{WorkerDomainDeployProvider as X,createWorkerDomainDeployProvider as Z}from"./WorkerDomainDeployProvider.js";export{_ as ACM_CAA_ISSUERS,p as CROSS_ACCOUNT_DELEGATION_RESOURCE_TYPE,t as DEFAULT_PUBLIC_RESOLVER_ADDRESSES,o as DOMAIN_DELEGATION_ERROR_TYPES,a as DomainDelegationError,d as NS_PROPAGATION_DEFAULT_INTERVAL_MS,n as NS_PROPAGATION_DEFAULT_MAX_ATTEMPTS,s as PUBLIC_DNS_QUERY_TIMEOUT_MS,X as WorkerDomainDeployProvider,V as buildCascadeTakeoverTicket,U as buildSatelliteRecordIndex,E as caaAncestorChain,K as cascadeTakeoverDigestSeed,I as classifyZoneRecords,m as createPublicResolvers,g as createSystemDnsNameProbe,Z as createWorkerDomainDeployProvider,y as deleteChildNsFromParent,B as deleteRecordSetsByKey,N as deployDelegatedDomain,S as formatCaaRecord,h as isDelegatedToRoute53,D as isDnsEmptyAnswer,M as isRoute53NameServer,i as normaliseDnsName,u as normaliseRecordName,C as nsDelegationPhysicalName,F as parseRecordPhysicalName,b as recordPhysicalName,w as recordSetKey,T as runCaaPreflight,W as runCascadeTakeoverGate,O as runDelegatedDomainDestroy,L as systemDnsNameProbe,f as templateOwnsDelegationRecord,c as waitForNsPropagation};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE consent spelling for a Route53 record set, shared by every release
|
|
3
|
+
* ceremony (the deploy takeover ticket — standalone CLI AND the cascade's
|
|
4
|
+
* engine gate — and the sync-remediation residue ticket): `<name>/<TYPE>`
|
|
5
|
+
* for simple records — byte-identical to the pre-variant convention, so
|
|
6
|
+
* existing docs and scripts keep working — and
|
|
7
|
+
* `<name>/<TYPE>@<setIdentifier>` for routing-policy variants. The name is
|
|
8
|
+
* normalised (lowercased, trailing dot stripped, Route53 octal escapes
|
|
9
|
+
* decoded) and the type uppercased, exactly the shape the rendered ticket
|
|
10
|
+
* shows, so the operator copies it verbatim between surfaces.
|
|
11
|
+
*
|
|
12
|
+
* Homed in deploy-core (P6): the cascade's engine takeover gate mints these
|
|
13
|
+
* names, so the grammar lives beside the gate; the CLI re-exports it —
|
|
14
|
+
* declared ONCE, never per-surface.
|
|
15
|
+
*
|
|
16
|
+
* The ceremony itself (`evaluateDestructionConsents`, `computeTicketDigest`,
|
|
17
|
+
* the Ink consent screen) treats the spelling as an opaque exact-match
|
|
18
|
+
* string — only the minting and release arms speak this grammar.
|
|
19
|
+
*/
|
|
20
|
+
/** Parsed identity of a consent spelling — the release arms' key material. */
|
|
21
|
+
export interface RecordConsentIdentity {
|
|
22
|
+
/** Normalised record name (lowercase, no trailing dot). */
|
|
23
|
+
readonly name: string;
|
|
24
|
+
/** Uppercase record type. */
|
|
25
|
+
readonly type: string;
|
|
26
|
+
/** Routing-policy variant; absent for simple records. */
|
|
27
|
+
readonly setIdentifier?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function recordPhysicalName(name: string, type: string, setIdentifier?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Inverse of {@link recordPhysicalName}. The grammar is anchored on the
|
|
32
|
+
* `/<TYPE>` boundary, NOT on the first `@` in the string: record names may
|
|
33
|
+
* contain `@` (the zone-apex spelling exists) and a SetIdentifier is free
|
|
34
|
+
* text that may itself contain `/` and `@`. Minted names are lowercased, so
|
|
35
|
+
* no uppercase type token can occur inside the name — the FIRST `/` followed
|
|
36
|
+
* by an uppercase type token that terminates at `@` or end-of-string is
|
|
37
|
+
* therefore the unambiguous split, and everything after that `@` (the first
|
|
38
|
+
* one following the type) is the identifier, verbatim. Returns `undefined`
|
|
39
|
+
* for strings that were never minted by `recordPhysicalName`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseRecordPhysicalName(physicalName: string): RecordConsentIdentity | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var i=Object.defineProperty;var s=(n,r)=>i(n,"name",{value:r,configurable:!0});import{normaliseRecordName as f}from"./zoneClassifier.js";const a=/^[A-Z][A-Z0-9]*$/;function u(n,r,e){const t=`${f(n)}/${r.toUpperCase()}`;return e===void 0?t:`${t}@${e}`}s(u,"recordPhysicalName");function m(n){let r=0;for(;;){const e=n.indexOf("/",r);if(e===-1)return;const t=n.slice(e+1),o=t.indexOf("@"),c=o===-1?t:t.slice(0,o);if(e>0&&a.test(c))return{name:n.slice(0,e),type:c,...o===-1?{}:{setIdentifier:t.slice(o+1)}};r=e+1}}s(m,"parseRecordPhysicalName");export{m as parseRecordPhysicalName,u as recordPhysicalName};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Route53Client } from "@aws-sdk/client-route-53";
|
|
2
|
+
import { type Result } from "@fjall/generator";
|
|
3
|
+
/**
|
|
4
|
+
* The EXECUTION ARM of the record-release ceremonies: the deploy takeover
|
|
5
|
+
* gate (standalone CLI and the cascade's engine gate, P6) and the sync
|
|
6
|
+
* remediation surface both delete consented record sets through this one
|
|
7
|
+
* helper. Homed in deploy-core so the cascade gate never re-implements the
|
|
8
|
+
* delete grammar the CLI already proved; the CLI re-exports it.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Normalised `name|TYPE|setIdentifier` key shared with the zone classifier's
|
|
12
|
+
* vocabulary. The third segment is empty for simple records, so a key names
|
|
13
|
+
* exactly ONE record set: either the simple record or one routing-policy
|
|
14
|
+
* variant — never a variant family.
|
|
15
|
+
*/
|
|
16
|
+
export declare function recordSetKey(name: string, type: string, setIdentifier?: string): string;
|
|
17
|
+
export interface DeletedRecordSet {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly type: string;
|
|
20
|
+
/** Present when the deleted record set was a routing-policy variant. */
|
|
21
|
+
readonly setIdentifier?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Delete the record sets matching the supplied normalised
|
|
25
|
+
* `name|TYPE|setIdentifier` keys — the execution arm of the release
|
|
26
|
+
* ceremonies (sync remediation and the deploy takeover). Callers reach this
|
|
27
|
+
* ONLY after `evaluateDestructionConsents` satisfied the ticket; the helper
|
|
28
|
+
* itself adds a structural guard: SOA and NS deletions are refused outright
|
|
29
|
+
* (the zone's own records ride the zone lifecycle; NS delegation removal has
|
|
30
|
+
* its own destroy-mirror machinery with its own ceremony).
|
|
31
|
+
*
|
|
32
|
+
* Each Route53 DELETE requires the record set's exact live shape, so the zone
|
|
33
|
+
* is re-listed here and matching is by the FULL key: one consented key
|
|
34
|
+
* deletes exactly one record set — a routing-policy sibling with a different
|
|
35
|
+
* SetIdentifier is never touched.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deleteRecordSetsByKey(route53: Pick<Route53Client, "send">, hostedZoneId: string, keys: ReadonlySet<string>, abortSignal?: AbortSignal): Promise<Result<DeletedRecordSet[], Error>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var g=Object.defineProperty;var l=(n,t)=>g(n,"name",{value:t,configurable:!0});import{ChangeResourceRecordSetsCommand as w,ListResourceRecordSetsCommand as N}from"@aws-sdk/client-route-53";import{success as I,failure as d}from"@fjall/generator";import{getErrorMessage as y,maskSensitiveOutput as S}from"@fjall/util";import{composeSdkAbortSignal as $,isAborted as h}from"../../aws/organisations/types.js";import{normaliseRecordName as u}from"./zoneClassifier.js";function E(n,t,i){return`${u(n)}|${t.toUpperCase()}|${i??""}`}l(E,"recordSetKey");async function v(n,t,i,s){for(const e of i){const r=e.split("|")[1]??"";if(r==="SOA"||r==="NS")return d(new Error(`record deletion: refusing to delete '${e}' \u2014 SOA and NS records never ride the sync-remediation path (NS delegation removal goes through the destroy mirror's own ceremony).`))}const p=[];let c,f,m;try{do{if(h(s))return d(new Error(`Aborted: record-set listing for zone ${t} cancelled by shutdown signal \u2014 nothing was deleted.`));const e=await n.send(new N({HostedZoneId:t,StartRecordName:c,StartRecordType:f,StartRecordIdentifier:m}),{abortSignal:$(s)});for(const r of e.ResourceRecordSets??[])r.Name===void 0||r.Type===void 0||i.has(E(r.Name,r.Type,r.SetIdentifier))&&p.push(r);e.IsTruncated?(c=e.NextRecordName,f=e.NextRecordType,m=e.NextRecordIdentifier):(c=void 0,f=void 0,m=void 0)}while(c)}catch(e){return d(new Error(`record deletion: could not list record sets for zone ${t}: ${S(y(e))} \u2014 nothing was deleted.`))}const o=[];for(const e of p){if(h(s))return d(new Error(`Aborted: record deletion for zone ${t} cancelled by shutdown signal. Deleted before the abort: ${o.length===0?"none":o.map(r=>`${r.name}/${r.type}`).join(", ")}. Re-run to resume \u2014 deletions are idempotent per record.`));try{await n.send(new w({HostedZoneId:t,ChangeBatch:{Comment:"fjall domain sync: consented residue-record deletion",Changes:[{Action:"DELETE",ResourceRecordSet:e}]}}),{abortSignal:$(s)}),o.push({name:u(e.Name??""),type:e.Type??"",...e.SetIdentifier!==void 0?{setIdentifier:e.SetIdentifier}:{}})}catch(r){const R=e.SetIdentifier!==void 0?`, setIdentifier '${e.SetIdentifier}'`:"";return d(new Error(`record deletion: deleting '${u(e.Name??"")}' (${e.Type??""}${R}) failed: ${S(y(r))}. Deleted before the failure: ${o.length===0?"none":o.map(a=>`${a.name}/${a.type}${a.setIdentifier!==void 0?`@${a.setIdentifier}`:""}`).join(", ")}. Re-run to resume \u2014 deletions are idempotent per record.`))}}return I(o)}l(v,"deleteRecordSetsByKey");export{v as deleteRecordSetsByKey,E as recordSetKey};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Result } from "@fjall/generator";
|
|
2
2
|
import type { DeployCallbacks } from "../types/callbacks.js";
|
|
3
3
|
import type { DelegatedDomainDeployer } from "./domain/delegatedDomainDeploy.js";
|
|
4
|
+
import type { DomainsTakeoverWithheld } from "./domain/domainTakeoverGate.js";
|
|
4
5
|
/**
|
|
5
6
|
* Configuration for a single domain to deploy.
|
|
6
7
|
*/
|
|
@@ -35,6 +36,20 @@ export interface DomainDeployResult {
|
|
|
35
36
|
* home. A skip is expected topology, never an entry in `errors`. */
|
|
36
37
|
domainsSkipped: number;
|
|
37
38
|
errors: string[];
|
|
39
|
+
/**
|
|
40
|
+
* Zone names that actually deployed this run (P6): the per-zone retirement
|
|
41
|
+
* signal for merged-not-deployed change rows. Skipped, withheld and failed
|
|
42
|
+
* zones never appear here — a blanket "org deploy succeeded" flip can
|
|
43
|
+
* never be honest for domain rows, only this list can.
|
|
44
|
+
*/
|
|
45
|
+
deployedZones: readonly string[];
|
|
46
|
+
/**
|
|
47
|
+
* Present when the [G2]×D5 record-takeover gate withheld consent: the
|
|
48
|
+
* phase deployed NOTHING (assess-first, mutate-never-before-consent) and
|
|
49
|
+
* the caller must surface the ticket through its own consent machinery
|
|
50
|
+
* (the worker's destructive_pending flow, the CLI's exit-4 ceremony).
|
|
51
|
+
*/
|
|
52
|
+
takeover?: DomainsTakeoverWithheld;
|
|
38
53
|
}
|
|
39
54
|
/**
|
|
40
55
|
* Provider interface for domain deployment operations.
|
|
@@ -65,4 +80,23 @@ export interface DomainDeployProvider {
|
|
|
65
80
|
* child-writes delegation — they keep the legacy single-shot path.
|
|
66
81
|
*/
|
|
67
82
|
delegatedDeployer?(domainName: string): DelegatedDomainDeployer | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Synthesise ONE domain's cloud assembly for the cascade's [G2]×D5
|
|
85
|
+
* record-takeover gate (P6): the returned stack names + assembly dir feed
|
|
86
|
+
* `runRoute53RecordPreflight` BEFORE the phase mutates anything.
|
|
87
|
+
*
|
|
88
|
+
* Optional for interface compatibility, but NOT optional in effect: the
|
|
89
|
+
* cascade FAILS the domains phase CLOSED when eligible domains exist and
|
|
90
|
+
* the provider lacks this seam — an implementation that cannot be
|
|
91
|
+
* collision-assessed never deploys ungated (the takeover ceremony must
|
|
92
|
+
* not silently evaporate into a raw deploy).
|
|
93
|
+
*/
|
|
94
|
+
synthForTakeover?(domainName: string, callbacks: DeployCallbacks): Promise<Result<DomainTakeoverSynth>>;
|
|
95
|
+
}
|
|
96
|
+
/** Assembly facts the takeover preflight reads for one domain. */
|
|
97
|
+
export interface DomainTakeoverSynth {
|
|
98
|
+
/** Stack artifact names whose templates claim Route53 record sets. */
|
|
99
|
+
readonly stackNames: readonly string[];
|
|
100
|
+
/** ABSOLUTE path to the synthesised cloud assembly (`cdk.out`). */
|
|
101
|
+
readonly cdkOutPath: string;
|
|
68
102
|
}
|
|
@@ -39,7 +39,7 @@ export { buildBuildSecretSessionPolicy, partitionForRegion, type BuildSecretRef,
|
|
|
39
39
|
export { buildDeploySessionPolicy, type DeploySessionContext } from "./application/deploySessionPolicy.js";
|
|
40
40
|
export { resolveBuildArgs, type ResolveBuildArgsContext, type ResolveBuildArgsResult, type SourcedBuildArgResolver } from "./application/buildArgResolver.js";
|
|
41
41
|
export { validateBuildGroup, type ValidateBuildGroupInput, type BuildGroupMemberInputs } from "./application/buildGroupValidator.js";
|
|
42
|
-
export type { DomainDeployProvider, DomainConfig, DomainDeployResult } from "./domainInterface.js";
|
|
42
|
+
export type { DomainDeployProvider, DomainConfig, DomainDeployResult, DomainTakeoverSynth } from "./domainInterface.js";
|
|
43
43
|
export * from "./domain/index.js";
|
|
44
44
|
export type { DeployServices } from "./serviceFactory.js";
|
|
45
45
|
export type { DetectionResult } from "./application/detectionPipeline.js";
|
|
@@ -4,7 +4,8 @@ import type { OrgConfig } from "../../types/config/orgConfig.js";
|
|
|
4
4
|
import type { DeployCallbacks } from "../../types/callbacks.js";
|
|
5
5
|
import type { OrganisationOperation } from "../../types/operations.js";
|
|
6
6
|
import type { DeployServices } from "../serviceFactory.js";
|
|
7
|
-
import type { DomainConfig, DomainDeployProvider } from "../domainInterface.js";
|
|
7
|
+
import type { DomainConfig, DomainDeployProvider, DomainDeployResult } from "../domainInterface.js";
|
|
8
|
+
import { type DomainsTakeoverContext } from "../domain/domainTakeoverGate.js";
|
|
8
9
|
import type { ProviderAccount } from "@fjall/util/config";
|
|
9
10
|
/**
|
|
10
11
|
* Max member accounts deployed/destroyed in parallel during a cascade. Each
|
|
@@ -147,6 +148,14 @@ export interface DeployDomainsOptions {
|
|
|
147
148
|
*/
|
|
148
149
|
executingAccountId?: string;
|
|
149
150
|
executingRegion?: string;
|
|
151
|
+
/**
|
|
152
|
+
* Execution context for the [G2]×D5 record-takeover gate (P6). NOT
|
|
153
|
+
* optional in effect: when eligible domains exist and this is absent, the
|
|
154
|
+
* phase FAILS CLOSED — the cascade must never deploy a domain whose
|
|
155
|
+
* record claims were not collision-assessed (the gate is the floor on
|
|
156
|
+
* every provider, CLI and worker alike).
|
|
157
|
+
*/
|
|
158
|
+
takeover?: DomainsTakeoverContext;
|
|
150
159
|
}
|
|
151
160
|
/**
|
|
152
161
|
* Order delegated domains into parent-first topological waves keyed on
|
|
@@ -165,9 +174,11 @@ export declare function planDelegatedDomainWaves(delegatedDomains: readonly Doma
|
|
|
165
174
|
* Deploy configured domains: apex domains sequentially, then delegated
|
|
166
175
|
* domains in parent-first topological waves (parallel within a wave).
|
|
167
176
|
* Delegates to the caller-provided DomainDeployProvider.
|
|
177
|
+
*
|
|
178
|
+
* P6: the [G2]×D5 record-takeover gate runs FIRST — every eligible domain is
|
|
179
|
+
* synthed and collision-assessed before ANY domain mutates, so a withheld
|
|
180
|
+
* ceremony deploys nothing (assess-first mirrors the application path's
|
|
181
|
+
* withhold-before-mutation semantics). `deployedZones` names exactly the
|
|
182
|
+
* zones that deployed — the only honest per-zone retirement signal.
|
|
168
183
|
*/
|
|
169
|
-
export declare function deployDomains(provider: DomainDeployProvider, callbacks: DeployCallbacks, options?: DeployDomainsOptions): Promise<
|
|
170
|
-
domainsDeployed: number;
|
|
171
|
-
domainsSkipped: number;
|
|
172
|
-
errors: string[];
|
|
173
|
-
}>;
|
|
184
|
+
export declare function deployDomains(provider: DomainDeployProvider, callbacks: DeployCallbacks, options?: DeployDomainsOptions): Promise<DomainDeployResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var Y=Object.defineProperty;var g=(e,n)=>Y(e,"name",{value:n,configurable:!0});import{join as H}from"path";import{success as I,failure as w}from"@fjall/generator";import{logger as A}from"@fjall/util/logger";import{maskSensitiveOutput as S,mapSettledWithConcurrency as X,resolveSynthEnvironment as q}from"@fjall/util";import{ORGANISATION_TYPES as P,getOrganisationStackName as V}from"../../types/operations.js";import{CdkContextBuilder as J}from"../../services/supporting/CdkContextBuilder.js";import{stubCallerIdentity as Q}from"../../types/deployment/index.js";import{CloudFormationService as W}from"../../services/infrastructure/CloudFormationService.js";import{getCascadeStateFilePath as Z,regionSuffix as ee}from"../../types/config/FjallState.js";import{BackupClient as te}from"@aws-sdk/client-backup";import{accountHasDisasterRecovery as ne,describeBackupVaultExists as oe}from"../../aws/organisations/backup.js";import{assertAssemblyEngineCompat as re,buildParamsContext as ae,collectStackOutputs as G,assumeCascadeRole as E,emitStepWarnings as se,emitWarningEvent as ie,forwardOutput as N,reconcileOidcProviderIfCarried as U}from"../contextHelpers.js";import{assertLeaseBeforeStack as ce}from"../application/leaseGate.js";import{deployDelegatedDomain as de}from"../domain/delegatedDomainDeploy.js";import{normaliseRecordName as j}from"../domain/zoneClassifier.js";import{runDriftPreFlightGate as ue}from"../drift/preFlightGate.js";import{accountTier as _}from"@fjall/util";import{buildBootstrapTagsIfResolved as fe}from"../bootstrapTags.js";import{hasOrganisationTierAccount as le}from"../../aws/organisations/accountGlobals.js";import{DEFAULT_REGION as K}from"../../aws/utils/regions.js";const pe=4;function Te(e){const n=e.find(o=>_(o)==="platform"),c=e.filter(o=>_(o)==="account");return{platformAccount:n,memberAccounts:c}}g(Te,"partitionAccounts");function me(e){const n=e?.primaryRegion??K,c=e?.secondaryRegions??[],o=new Set([n,...c]),i=e?.disasterRecoveryRegion;return i&&o.add(i),[...o]}g(me,"buildRegionList");function He(e){return me(e)[0]??K}g(He,"cascadeHomeRegion");function ge(e,n){return`${e} (${n})`}g(ge,"cascadeOperationKey");function Ve(e,n){const c=[];for(const o of n)for(const i of e)c.push({account:i,region:o});return c}g(Ve,"buildAccountRegionPairs");import{buildCascadeRoleArn as Ye}from"../contextHelpers.js";async function We(e,n,c,o){c.onLog?.(`Verifying cascade role access for ${n.length} account(s)\u2026`,"info");const i=await X(n,pe,async a=>E(e.awsProvider,a.id,a.region??e.awsProvider.getRegion(),`fjall-preflight-${a.name}`,o)),t=[];return i.forEach((a,s)=>{const r=n[s];if(r){if(a.status==="rejected"){t.push({accountId:r.id,accountName:r.name,error:a.reason instanceof Error?a.reason.message:String(a.reason)});return}a.value.success||t.push({accountId:r.id,accountName:r.name,error:a.value.error.message})}}),t.length===0&&c.onLog?.(`Cascade role access verified for ${n.length} account(s)`,"info"),t}g(We,"probeCascadeRoles");async function Ge(e,n,c,o,i,t,a){const s=a?.region??o.region??n.awsProvider.getRegion(),r=ge(o.name,s),u=a?.orgConfig??e.orgConfig,C=a?.ipamPoolId;t.onCascadeAccountStart?.(r,o.id,s,i);const p=await E(n.awsProvider,o.id,s,`fjall-cascade-${o.name}`,e.abortSignal);if(!p.success)return t.onCascadeAccountComplete?.(r,!1,S(p.error.message),s),w(new Error(`Failed to assume role for ${o.name}: ${S(p.error.message)}`));const{provider:d,credentials:l}=p.data,h=H(e.workingDirectory,"fjall",i==="platform"?P.PLATFORM:P.ACCOUNT),f=H(h,`cdk.out.${o.id}.${ee(s)}`),R=J.buildDeploymentContext({deployType:i,target:c.target,path:h,assemblyDir:f,environment:q(o),region:s,accountName:o.name,callerIdentity:Q(o.id),ipamPoolId:C,...ae({orgConfig:u,identity:e.identity,skipOidc:e.options?.skipOidc,region:s,primaryRegion:a?.primaryRegion,trailLifecycle:o.trailLifecycle})},{verbose:e.options?.verbose},u);if(ne(o.environment,u?.disasterRecoveryRegion)){const m=await oe(d.getClient(te),e.abortSignal);if(!m.success)return t.onCascadeAccountComplete?.(r,!1,S(m.error.message),s),w(new Error(`Backup vault probe failed for ${o.name}: ${S(m.error.message)}`));R.fjallAdoptBackupVault=m.data}t.onCascadeAccountPhaseChange?.(r,"synth",s);const $=await n.cdkService.runCdkSynth(R,N(t),l);if(!$.success)return t.onCascadeAccountComplete?.(r,!1,S(`Synth failed: ${$.error}`),s),w(new Error(`Synth failed for ${o.name}: ${S($.error)}`));se(t,$.data);const b=re(f,t);if(!b.success){const m=S(b.error.message);return t.onCascadeAccountComplete?.(r,!1,m,s),w(new Error(`Engine compatibility check failed for ${o.name}: ${m}`))}const y=V(i==="platform"?P.PLATFORM:P.ACCOUNT),F=Z(h,o.id,s),v=new W(d),{changed:z,currentHash:L}=await n.hashService.compareCascadeStack(f,y,F);if(!z&&e.options?.force!==!0&&await v.stackExists(y,void 0,e.abortSignal)){const m=await v.getStackOutputs(y,void 0,e.abortSignal);m.success||A.debug("cascadeHelpers","Failed to read outputs for skipped cascade account (non-critical)",{stackName:y,account:o.name});const T=G(m);return await U(R,d,t,e.abortSignal),t.onLog?.(`${o.name}: no infrastructure changes \u2014 skipping deploy`,"info"),t.onCascadeAccountComplete?.(r,!0,void 0,s,T,!0),I({outputs:T,skipped:!0})}const D=await ue(d,{stackNames:[y],cdkOutPath:f,cfnService:v,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(D.kind==="blocked")return t.onCascadeAccountComplete?.(r,!1,D.message,s),w(new Error(D.message));const O=await ce(e.assertLeaseForStack,y,e.abortSignal);if(O!==void 0)return t.onCascadeAccountComplete?.(r,!1,O.message,s),w(O);t.onCascadeAccountPhaseChange?.(r,"bootstrap",s);const x=await n.cdkService.runCdkBootstrap(R,N(t),l,void 0,fe({account:o,estate:le(u?.providerAccounts)?"org":"solo",...a?.orgId!==void 0?{orgId:a.orgId}:{}}));if(!x.success)return t.onCascadeAccountComplete?.(r,!1,S(`Bootstrap failed: ${x.error}`),s),w(new Error(`Bootstrap failed for ${o.name}: ${S(x.error)}`));t.onCascadeAccountPhaseChange?.(r,"deploy",s);const k=await n.cdkService.runCdkDeploy(R,y,N(t),m=>t.onCascadeAccountResourceProgress?.(r,m,s),d,l);if(!k.success)return t.onCascadeAccountComplete?.(r,!1,S(k.error),s),w(new Error(S(k.error)));const M=await v.getStackOutputs(y,void 0,e.abortSignal);M.success||A.debug("cascadeHelpers","Failed to read cascade account stack outputs (non-critical)",{stackName:y,account:o.name});const B=G(M);return await U(R,d,t,e.abortSignal),L!==void 0&&((await n.hashService.persistCascadeStack(F,y,L)).success||A.debug("cascadeHelpers","Failed to persist cascade hash state (non-critical)",{stackName:y,account:o.name})),t.onCascadeAccountComplete?.(r,!0,void 0,s,B,!1),I({outputs:B,skipped:!1})}g(Ge,"deployCascadeAccount");async function Ue(e,n,c,o){const i=new Map,t=e.awsProvider.getRegion(),a=await E(e.awsProvider,n.id,t,`fjall-ipam-read-${n.name}`,o);if(!a.success)return A.debug("organisationDeploy",`Cannot read Platform outputs: ${a.error.message}`),i;const s=new W(a.data.provider),r=V(P.PLATFORM),u=await s.getStackOutputs(r);if(!u.success)return A.debug("organisationDeploy",`Failed to read Platform stack outputs: ${u.error.message}`),i;const C=/^IpamPoolId(\d{12})(\w+)$/;for(const p of u.data){const d=p.OutputKey?.match(C);if(d&&p.OutputValue){const l=`${d[1]}-${d[2]}`;i.set(l,p.OutputValue)}}return i.size>0&&c.onLog?.(`Read ${i.size} IPAM pool ID(s) from Platform stack`,"info"),i}g(Ue,"readPlatformIpamPoolIds");function Ce(e,n){const c=e.account!==void 0&&n?.executingAccountId!==void 0&&e.account!==n.executingAccountId,o=e.region!==void 0&&n?.executingRegion!==void 0&&e.region!==n.executingRegion;if(c)return`[${e.name}] skipped: its fjall-config.json entry records account ${e.account} as its home, but this cascade runs in account ${n?.executingAccountId} - deploy it separately with 'fjall domain deploy ${e.name} -t <target in account ${e.account}>' or run the cascade under that account.`;if(o)return`[${e.name}] skipped: its fjall-config.json entry records region ${e.region} as its home, but this cascade runs in region ${n?.executingRegion} - deploy it separately with 'fjall domain deploy ${e.name} --region ${e.region}', or update the entry's "region" key if this move is intentional.`}g(Ce,"foreignDomainSkipReason");function he(e){const n=new Map;for(const t of e)n.set(j(t.name),t);const c=new Map,o=g((t,a)=>{const s=c.get(t);if(s!==void 0)return s;if(a.includes(t))return[...a.slice(a.indexOf(t)),t];const r=n.get(t);if(r===void 0)return-1;const u=r.parentDomain!==void 0?j(r.parentDomain):void 0,C=u===void 0?-1:o(u,[...a,t]);if(Array.isArray(C))return C;const p=C+1;return c.set(t,p),p},"resolveDepth"),i=[];for(const t of e){const a=o(j(t.name),[]);if(Array.isArray(a)){const s=a.map(r=>n.get(r)?.name??r).join(" -> ");return w(new Error(`Delegated domain ordering: fjall-config.json declares a parentDomain cycle (${s}) - no deploy order satisfies it. Nothing was deployed. Cure: correct the "parentDomain" of one entry in that cycle so parents form a chain, then re-run.`))}(i[a]??=[]).push(t)}return I(i.filter(t=>t.length>0))}g(he,"planDelegatedDomainWaves");async function _e(e,n,c){const o=e.getDomains();if(o.length===0)return{domainsDeployed:0,domainsSkipped:0,errors:[]};n.onCascadePhaseStart?.("domains");const i=[];let t=0;for(const d of o){const l=Ce(d,c);if(l!==void 0){t++,ie(n,l);continue}i.push(d)}const a=i.filter(d=>d.type==="apex"),s=i.filter(d=>d.type==="delegated");let r=0;const u=[],C=he(s);if(!C.success)return u.push(C.error.message),n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u};const p=C.data;for(const d of a){const l=await e.deployDomain(d.name,n);l.success?r++:u.push(`${d.name}: ${l.error.message}`)}for(const d of p){const l=await Promise.allSettled(d.map(h=>{const f=e.delegatedDeployer?.(h.name);return f!==void 0?de({deployer:f,callbacks:n,...c?.abortSignal!==void 0?{abortSignal:c.abortSignal}:{},...c?.skipCaaPreflight!==void 0?{skipCaaPreflight:c.skipCaaPreflight}:{}}):e.deployDomain(h.name,n)}));for(let h=0;h<l.length;h++){const f=l[h],R=d[h];if(!(!f||!R))if(f.status==="fulfilled")f.value.success?r++:u.push(`${R.name}: ${f.value.error.message}`);else{const $=f.reason instanceof Error?f.reason.message:String(f.reason);u.push(`${R.name}: ${$}`)}}}return n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u}}g(_e,"deployDomains");export{pe as CASCADE_MAX_CONCURRENCY,Ve as buildAccountRegionPairs,Ye as buildCascadeRoleArn,me as buildRegionList,He as cascadeHomeRegion,ge as cascadeOperationKey,Ge as deployCascadeAccount,_e as deployDomains,Te as partitionAccounts,he as planDelegatedDomainWaves,We as probeCascadeRoles,Ue as readPlatformIpamPoolIds};
|
|
1
|
+
var Y=Object.defineProperty;var g=(e,n)=>Y(e,"name",{value:n,configurable:!0});import{join as H}from"path";import{success as E,failure as $}from"@fjall/generator";import{logger as P}from"@fjall/util/logger";import{maskSensitiveOutput as S,mapSettledWithConcurrency as Z,resolveSynthEnvironment as X}from"@fjall/util";import{ORGANISATION_TYPES as A,getOrganisationStackName as G}from"../../types/operations.js";import{CdkContextBuilder as q}from"../../services/supporting/CdkContextBuilder.js";import{stubCallerIdentity as J}from"../../types/deployment/index.js";import{CloudFormationService as V}from"../../services/infrastructure/CloudFormationService.js";import{getCascadeStateFilePath as Q,regionSuffix as ee}from"../../types/config/FjallState.js";import{BackupClient as te}from"@aws-sdk/client-backup";import{accountHasDisasterRecovery as ne,describeBackupVaultExists as oe}from"../../aws/organisations/backup.js";import{assertAssemblyEngineCompat as re,buildParamsContext as ae,collectStackOutputs as W,assumeCascadeRole as N,emitStepWarnings as se,emitWarningEvent as ie,forwardOutput as j,reconcileOidcProviderIfCarried as U}from"../contextHelpers.js";import{assertLeaseBeforeStack as ce}from"../application/leaseGate.js";import{runCascadeTakeoverGate as de}from"../domain/domainTakeoverGate.js";import{deployDelegatedDomain as ue}from"../domain/delegatedDomainDeploy.js";import{normaliseRecordName as F}from"../domain/zoneClassifier.js";import{runDriftPreFlightGate as fe}from"../drift/preFlightGate.js";import{accountTier as _}from"@fjall/util";import{buildBootstrapTagsIfResolved as le}from"../bootstrapTags.js";import{hasOrganisationTierAccount as pe}from"../../aws/organisations/accountGlobals.js";import{DEFAULT_REGION as K}from"../../aws/utils/regions.js";const me=4;function Ge(e){const n=e.find(o=>_(o)==="platform"),c=e.filter(o=>_(o)==="account");return{platformAccount:n,memberAccounts:c}}g(Ge,"partitionAccounts");function ge(e){const n=e?.primaryRegion??K,c=e?.secondaryRegions??[],o=new Set([n,...c]),i=e?.disasterRecoveryRegion;return i&&o.add(i),[...o]}g(ge,"buildRegionList");function Ve(e){return ge(e)[0]??K}g(Ve,"cascadeHomeRegion");function he(e,n){return`${e} (${n})`}g(he,"cascadeOperationKey");function We(e,n){const c=[];for(const o of n)for(const i of e)c.push({account:i,region:o});return c}g(We,"buildAccountRegionPairs");import{buildCascadeRoleArn as Xe}from"../contextHelpers.js";async function Ue(e,n,c,o){c.onLog?.(`Verifying cascade role access for ${n.length} account(s)\u2026`,"info");const i=await Z(n,me,async a=>N(e.awsProvider,a.id,a.region??e.awsProvider.getRegion(),`fjall-preflight-${a.name}`,o)),t=[];return i.forEach((a,s)=>{const r=n[s];if(r){if(a.status==="rejected"){t.push({accountId:r.id,accountName:r.name,error:a.reason instanceof Error?a.reason.message:String(a.reason)});return}a.value.success||t.push({accountId:r.id,accountName:r.name,error:a.value.error.message})}}),t.length===0&&c.onLog?.(`Cascade role access verified for ${n.length} account(s)`,"info"),t}g(Ue,"probeCascadeRoles");async function _e(e,n,c,o,i,t,a){const s=a?.region??o.region??n.awsProvider.getRegion(),r=he(o.name,s),u=a?.orgConfig??e.orgConfig,l=a?.ipamPoolId;t.onCascadeAccountStart?.(r,o.id,s,i);const p=await N(n.awsProvider,o.id,s,`fjall-cascade-${o.name}`,e.abortSignal);if(!p.success)return t.onCascadeAccountComplete?.(r,!1,S(p.error.message),s),$(new Error(`Failed to assume role for ${o.name}: ${S(p.error.message)}`));const{provider:h,credentials:d}=p.data,C=H(e.workingDirectory,"fjall",i==="platform"?A.PLATFORM:A.ACCOUNT),y=H(C,`cdk.out.${o.id}.${ee(s)}`),f=q.buildDeploymentContext({deployType:i,target:c.target,path:C,assemblyDir:y,environment:X(o),region:s,accountName:o.name,callerIdentity:J(o.id),ipamPoolId:l,...ae({orgConfig:u,identity:e.identity,skipOidc:e.options?.skipOidc,region:s,primaryRegion:a?.primaryRegion,trailLifecycle:o.trailLifecycle})},{verbose:e.options?.verbose},u);if(ne(o.environment,u?.disasterRecoveryRegion)){const m=await oe(h.getClient(te),e.abortSignal);if(!m.success)return t.onCascadeAccountComplete?.(r,!1,S(m.error.message),s),$(new Error(`Backup vault probe failed for ${o.name}: ${S(m.error.message)}`));f.fjallAdoptBackupVault=m.data}t.onCascadeAccountPhaseChange?.(r,"synth",s);const R=await n.cdkService.runCdkSynth(f,j(t),d);if(!R.success)return t.onCascadeAccountComplete?.(r,!1,S(`Synth failed: ${R.error}`),s),$(new Error(`Synth failed for ${o.name}: ${S(R.error)}`));se(t,R.data);const v=re(y,t);if(!v.success){const m=S(v.error.message);return t.onCascadeAccountComplete?.(r,!1,m,s),$(new Error(`Engine compatibility check failed for ${o.name}: ${m}`))}const w=G(i==="platform"?A.PLATFORM:A.ACCOUNT),L=Q(C,o.id,s),D=new V(h),{changed:z,currentHash:b}=await n.hashService.compareCascadeStack(y,w,L);if(!z&&e.options?.force!==!0&&await D.stackExists(w,void 0,e.abortSignal)){const m=await D.getStackOutputs(w,void 0,e.abortSignal);m.success||P.debug("cascadeHelpers","Failed to read outputs for skipped cascade account (non-critical)",{stackName:w,account:o.name});const T=W(m);return await U(f,h,t,e.abortSignal),t.onLog?.(`${o.name}: no infrastructure changes \u2014 skipping deploy`,"info"),t.onCascadeAccountComplete?.(r,!0,void 0,s,T,!0),E({outputs:T,skipped:!0})}const x=await fe(h,{stackNames:[w],cdkOutPath:y,cfnService:D,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(x.kind==="blocked")return t.onCascadeAccountComplete?.(r,!1,x.message,s),$(new Error(x.message));const O=await ce(e.assertLeaseForStack,w,e.abortSignal);if(O!==void 0)return t.onCascadeAccountComplete?.(r,!1,O.message,s),$(O);t.onCascadeAccountPhaseChange?.(r,"bootstrap",s);const k=await n.cdkService.runCdkBootstrap(f,j(t),d,void 0,le({account:o,estate:pe(u?.providerAccounts)?"org":"solo",...a?.orgId!==void 0?{orgId:a.orgId}:{}}));if(!k.success)return t.onCascadeAccountComplete?.(r,!1,S(`Bootstrap failed: ${k.error}`),s),$(new Error(`Bootstrap failed for ${o.name}: ${S(k.error)}`));t.onCascadeAccountPhaseChange?.(r,"deploy",s);const I=await n.cdkService.runCdkDeploy(f,w,j(t),m=>t.onCascadeAccountResourceProgress?.(r,m,s),h,d);if(!I.success)return t.onCascadeAccountComplete?.(r,!1,S(I.error),s),$(new Error(S(I.error)));const M=await D.getStackOutputs(w,void 0,e.abortSignal);M.success||P.debug("cascadeHelpers","Failed to read cascade account stack outputs (non-critical)",{stackName:w,account:o.name});const B=W(M);return await U(f,h,t,e.abortSignal),b!==void 0&&((await n.hashService.persistCascadeStack(L,w,b)).success||P.debug("cascadeHelpers","Failed to persist cascade hash state (non-critical)",{stackName:w,account:o.name})),t.onCascadeAccountComplete?.(r,!0,void 0,s,B,!1),E({outputs:B,skipped:!1})}g(_e,"deployCascadeAccount");async function Ke(e,n,c,o){const i=new Map,t=e.awsProvider.getRegion(),a=await N(e.awsProvider,n.id,t,`fjall-ipam-read-${n.name}`,o);if(!a.success)return P.debug("organisationDeploy",`Cannot read Platform outputs: ${a.error.message}`),i;const s=new V(a.data.provider),r=G(A.PLATFORM),u=await s.getStackOutputs(r);if(!u.success)return P.debug("organisationDeploy",`Failed to read Platform stack outputs: ${u.error.message}`),i;const l=/^IpamPoolId(\d{12})(\w+)$/;for(const p of u.data){const h=p.OutputKey?.match(l);if(h&&p.OutputValue){const d=`${h[1]}-${h[2]}`;i.set(d,p.OutputValue)}}return i.size>0&&c.onLog?.(`Read ${i.size} IPAM pool ID(s) from Platform stack`,"info"),i}g(Ke,"readPlatformIpamPoolIds");function Ce(e,n){const c=e.account!==void 0&&n?.executingAccountId!==void 0&&e.account!==n.executingAccountId,o=e.region!==void 0&&n?.executingRegion!==void 0&&e.region!==n.executingRegion;if(c)return`[${e.name}] skipped: its fjall-config.json entry records account ${e.account} as its home, but this cascade runs in account ${n?.executingAccountId} - deploy it separately with 'fjall domain deploy ${e.name} -t <target in account ${e.account}>' or run the cascade under that account.`;if(o)return`[${e.name}] skipped: its fjall-config.json entry records region ${e.region} as its home, but this cascade runs in region ${n?.executingRegion} - deploy it separately with 'fjall domain deploy ${e.name} --region ${e.region}', or update the entry's "region" key if this move is intentional.`}g(Ce,"foreignDomainSkipReason");function ye(e){const n=new Map;for(const t of e)n.set(F(t.name),t);const c=new Map,o=g((t,a)=>{const s=c.get(t);if(s!==void 0)return s;if(a.includes(t))return[...a.slice(a.indexOf(t)),t];const r=n.get(t);if(r===void 0)return-1;const u=r.parentDomain!==void 0?F(r.parentDomain):void 0,l=u===void 0?-1:o(u,[...a,t]);if(Array.isArray(l))return l;const p=l+1;return c.set(t,p),p},"resolveDepth"),i=[];for(const t of e){const a=o(F(t.name),[]);if(Array.isArray(a)){const s=a.map(r=>n.get(r)?.name??r).join(" -> ");return $(new Error(`Delegated domain ordering: fjall-config.json declares a parentDomain cycle (${s}) - no deploy order satisfies it. Nothing was deployed. Cure: correct the "parentDomain" of one entry in that cycle so parents form a chain, then re-run.`))}(i[a]??=[]).push(t)}return E(i.filter(t=>t.length>0))}g(ye,"planDelegatedDomainWaves");async function ze(e,n,c){const o=e.getDomains();if(o.length===0)return{domainsDeployed:0,domainsSkipped:0,errors:[],deployedZones:[]};n.onCascadePhaseStart?.("domains");const i=[];let t=0;for(const d of o){const C=Ce(d,c);if(C!==void 0){t++,ie(n,C);continue}i.push(d)}const a=i.filter(d=>d.type==="apex"),s=i.filter(d=>d.type==="delegated");let r=0;const u=[],l=[],p=ye(s);if(!p.success)return u.push(p.error.message),n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u,deployedZones:l};const h=p.data;if(i.length>0){if(c?.takeover===void 0)return u.push("domains phase refused: the cascade executed without a takeover-gate context, so record collisions cannot be assessed \u2014 deploying ungated is not an option. This is a caller wiring defect (executeCascade threads services + consent inputs into DeployDomainsOptions.takeover)."),n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u,deployedZones:l};const d=await de(e,i,n,c.takeover);if(!d.success)return u.push(d.error.message),n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u,deployedZones:l};if(d.data.kind==="withheld")return n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u,deployedZones:l,takeover:d.data.withheld}}for(const d of a){const C=await e.deployDomain(d.name,n);C.success?(r++,l.push(d.name)):u.push(`${d.name}: ${C.error.message}`)}for(const d of h){const C=await Promise.allSettled(d.map(y=>{const f=e.delegatedDeployer?.(y.name);return f!==void 0?ue({deployer:f,callbacks:n,...c?.abortSignal!==void 0?{abortSignal:c.abortSignal}:{},...c?.skipCaaPreflight!==void 0?{skipCaaPreflight:c.skipCaaPreflight}:{}}):e.deployDomain(y.name,n)}));for(let y=0;y<C.length;y++){const f=C[y],R=d[y];if(!(!f||!R))if(f.status==="fulfilled")f.value.success?(r++,l.push(R.name)):u.push(`${R.name}: ${f.value.error.message}`);else{const v=f.reason instanceof Error?f.reason.message:String(f.reason);u.push(`${R.name}: ${v}`)}}}return n.onCascadePhaseComplete?.("domains"),{domainsDeployed:r,domainsSkipped:t,errors:u,deployedZones:l}}g(ze,"deployDomains");export{me as CASCADE_MAX_CONCURRENCY,We as buildAccountRegionPairs,Xe as buildCascadeRoleArn,ge as buildRegionList,Ve as cascadeHomeRegion,he as cascadeOperationKey,_e as deployCascadeAccount,ze as deployDomains,Ge as partitionAccounts,ye as planDelegatedDomainWaves,Ue as probeCascadeRoles,Ke as readPlatformIpamPoolIds};
|
|
@@ -2,6 +2,7 @@ import type { ProviderAccount } from "@fjall/util/config";
|
|
|
2
2
|
import type { DeployParams } from "../../types/params.js";
|
|
3
3
|
import type { OrgConfig } from "../../types/config/orgConfig.js";
|
|
4
4
|
import type { OrganisationOperation } from "../../types/operations.js";
|
|
5
|
+
import type { DomainsTakeoverWithheld } from "../domain/domainTakeoverGate.js";
|
|
5
6
|
import type { DeployServices } from "../serviceFactory.js";
|
|
6
7
|
/**
|
|
7
8
|
* Execute the cascade phases: platform deploy, IPAM pool read, domains, and
|
|
@@ -28,4 +29,13 @@ export declare function executeCascade(params: DeployParams, services: DeploySer
|
|
|
28
29
|
orgId?: string;
|
|
29
30
|
}): Promise<{
|
|
30
31
|
anyCascadeDeployHappened: boolean;
|
|
32
|
+
/** Zones the domains phase actually deployed (P6 per-zone retirement). */
|
|
33
|
+
deployedDomainZones: readonly string[];
|
|
34
|
+
/**
|
|
35
|
+
* Present when the domains-phase takeover gate withheld consent: the
|
|
36
|
+
* member fan-out was SKIPPED (members depend on domain DNS — certificate
|
|
37
|
+
* validation records above all) and the caller must surface the ticket as
|
|
38
|
+
* a destruction-pending result.
|
|
39
|
+
*/
|
|
40
|
+
domainsTakeover?: DomainsTakeoverWithheld;
|
|
31
41
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Z=Object.defineProperty;var E=(t,d)=>Z(t,"name",{value:d,configurable:!0});import{failure as $}from"@fjall/generator";import{regionSuffix as X}from"../../types/config/FjallState.js";import{partitionAccounts as Y,deployCascadeAccount as U,readPlatformIpamPoolIds as z,deployDomains as B,buildRegionList as J,buildAccountRegionPairs as K,cascadeHomeRegion as Q,CASCADE_MAX_CONCURRENCY as V}from"../organisation/cascadeHelpers.js";import{projectScalarSummary as M}from"../organisation/cascadeSummary.js";import{getErrorMessage as ee,maskSensitiveOutput as C,mapSettledWithConcurrency as te}from"@fjall/util";import{INFRA_STEPS as N}from"./infraSteps.js";async function ue(t,d,v,j){const{callbacks:e}=t,{providerAccounts:W,effectiveOrgConfig:O,totalSteps:p,cascadeErrors:f,allCascadeOutputs:L,orgId:x}=j;let S=!1;e.onCascadeStart?.();const _=Date.now();let u=2,P=!1,h,w=!1;const I=[],y=E(o=>({members:I,...h!==void 0?{platform:h}:{},domainsDeployed:w,errors:f,totalDurationMs:o}),"buildLedger"),{platformAccount:a,memberAccounts:k}=Y(W),F=Q(t.orgConfig);if(a){const{id:o,name:n}=N.CASCADE_PLATFORM;e.onStepStart?.(o,n,u,p),e.onCascadePhaseStart?.("platform");let c;const A=Date.now();try{c=await U(t,d,v,a,"platform",e,{orgConfig:O,primaryRegion:F,orgId:x})}catch(i){const r=C(ee(i));f.push({accountId:a.id,error:r}),e.onCascadePhaseComplete?.("platform"),e.onStepComplete?.(o,n,"error",u,p),c=$(new Error(r))}const R=Date.now()-A;if(c.success){P=!0;const i=c.data.skipped===!0;i||(S=!0),c.data.outputs&&L.push({accountId:a.id,outputs:c.data.outputs}),e.onCascadePhaseComplete?.("platform"),e.onStepComplete?.(o,n,i?"skipped":"completed",u,p),h={accountId:a.id,result:i?"skipped":"succeeded",durationMs:R}}else f.some(i=>i.accountId===a.id)||(f.push({accountId:a.id,error:C(c.error.message)}),e.onCascadePhaseComplete?.("platform"),e.onStepComplete?.(o,n,"error",u,p)),h={accountId:a.id,result:"failed",durationMs:R,error:C(c.error.message)};u++}let T=new Map;P&&a&&(T=await z(d,a,e,t.abortSignal));let b=[],H;if(t.domainProvider){const o=await B(t.domainProvider,e,{executingAccountId:d.awsProvider.getAccountId(),executingRegion:d.awsProvider.getRegion(),takeover:{aws:d.awsProvider,cfnService:d.cfnService,...t.options?.destructionConsents!==void 0?{consents:t.options.destructionConsents}:{},...t.options?.destructionConsentDigest!==void 0?{consentDigest:t.options.destructionConsentDigest}:{},...t.destructionConsentGate!==void 0?{consentGate:t.destructionConsentGate}:{},...t.abortSignal!==void 0?{abortSignal:t.abortSignal}:{}},...t.abortSignal!==void 0?{abortSignal:t.abortSignal}:{},...t.options?.skipCaaPreflight!==void 0?{skipCaaPreflight:t.options.skipCaaPreflight}:{}});w=o.domainsDeployed>0,w&&(S=!0),b=o.deployedZones;for(const n of o.errors)f.push({accountId:"domains",error:C(n)});if(o.takeover!==void 0){H=o.takeover,e.onLog?.("Member-account cascade skipped \u2014 domain record takeover consent is pending. Consent to the ticket and re-run; nothing was deployed in the domains phase.","warn");const n=y(Date.now()-_);return e.onCascadeComplete?.(M(n)),e.onCascadeLedger?.(n),{anyCascadeDeployHappened:S,deployedDomainZones:b,domainsTakeover:H}}}if(a!==void 0&&!P&&k.length>0){const{id:o,name:n}=N.CASCADE_ACCOUNTS;e.onStepStart?.(o,n,u,p),e.onStepComplete?.(o,n,"skipped",u,p),e.onLog?.("Skipping account cascade \u2014 platform deployment failed; platform is a prerequisite for member accounts.","warn")}else if(k.length>0){const{id:o,name:n}=N.CASCADE_ACCOUNTS;e.onStepStart?.(o,n,u,p),e.onCascadePhaseStart?.("accounts");const c=J(t.orgConfig),A=K(k,c);(await te(A,V,async({account:r,region:D})=>{const m=T.get(`${r.id}-${X(D)}`),s=Date.now();return{result:await U(t,d,v,r,"account",e,{ipamPoolId:m,orgConfig:O,region:D,primaryRegion:F,orgId:x}),durationMs:Date.now()-s}})).forEach((r,D)=>{const m=A[D];if(!m)return;const s=m.account;if(r.status==="rejected"){const l=C(r.reason instanceof Error?r.reason.message:String(r.reason));I.push({accountId:s.id,accountName:s.name,region:m.region,result:"failed",durationMs:0,error:l}),f.push({accountId:s.id,error:l});return}const{result:g,durationMs:G}=r.value;if(g.success){const l=g.data.skipped===!0;l||(S=!0),g.data.outputs&&L.push({accountId:s.id,outputs:g.data.outputs}),I.push({accountId:s.id,accountName:s.name,region:m.region,result:l?"skipped":"succeeded",durationMs:G})}else{const l=C(g.error.message);I.push({accountId:s.id,accountName:s.name,region:m.region,result:"failed",durationMs:G,error:l}),f.push({accountId:s.id,error:l})}});const i=M(y(0));e.onCascadePhaseComplete?.("accounts"),e.onStepComplete?.(o,n,i.accountsFailed>0?"error":i.accountsSkipped===k.length?"skipped":"completed",u,p)}const q=y(Date.now()-_);return e.onCascadeComplete?.(M(q)),e.onCascadeLedger?.(q),{anyCascadeDeployHappened:S,deployedDomainZones:b}}E(ue,"executeCascade");export{ue as executeCascade};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);
|
|
3
|
-
${r}`),"warn")}}if(u.length>0){const
|
|
1
|
+
var X=Object.defineProperty;var Z=(a,t)=>X(a,"name",{value:t,configurable:!0});import{join as z}from"node:path";import{OrganizationsClient as ee}from"@aws-sdk/client-organizations";import{success as K,failure as U}from"@fjall/generator";import{ORGANISATION_TYPES as R,getOrganisationStackName as A}from"../../types/operations.js";import{synthOrFail as te,bootstrapOrFail as oe,emitWarningEvent as ae,forwardOutput as re,forwardResourceProgress as ne}from"../contextHelpers.js";import{partitionAccounts as ie,probeCascadeRoles as ce,buildRegionList as se,buildAccountRegionPairs as de}from"../organisation/cascadeHelpers.js";import{assertLeaseBeforeStack as ue}from"../application/leaseGate.js";import{accountTier as le,maskSensitiveOutput as g}from"@fjall/util";import{findDevelopmentOuId as ge}from"../../aws/organisations/organisationalUnits.js";import{buildOrgContext as fe,resolveOrgDetails as pe}from"./orgContext.js";import{buildBootstrapTagsIfResolved as me}from"../bootstrapTags.js";import{INFRA_STEPS as q,emitOrgStackTargets as Se,maskAndFail as O,readStackOutputsBestEffort as J}from"./infraSteps.js";import{resolveCascadeAccounts as he}from"./resolveCascadeAccounts.js";import{executeCascade as Oe}from"./cascadeExecution.js";import{reconcileOrgTrailOutputs as we}from"./trailReconciliation.js";import{runDriftPreFlightGate as ke}from"../drift/preFlightGate.js";async function He(a,t,w,E){const{callbacks:e,options:L}=a,{providerAccounts:f,effectiveOrgConfig:Q,defaultRegion:V}=await he(a,t),p=await pe(t,a.abortSignal);if(!p.success)return O(e,p.error.message);const k=await ge(t.awsProvider.getClient(ee),p.data.rootId,a.abortSignal);if(!k.success)return O(e,k.error.message);const P={...p.data,...k.data!==void 0?{devOuId:k.data}:{}},F=f.find(o=>le(o)==="organisation"),d=fe(a,t,w,"organisation",P,void 0,F?.trailLifecycle),l=L?.cascade!==!1,{platformAccount:s,memberAccounts:T}=ie(f),v=l&&s!==void 0?1:0,x=l&&T.length>0?1:0,i=2+v+x,G=l?[...s!==void 0?[s]:[],...T]:[];if(G.length>0){const o=await ce(t,G,e,a.abortSignal),r=s!==void 0?o.find(n=>n.accountId===s.id):void 0;if(r!==void 0)return O(e,`Pre-flight cascade role check failed for the platform account ${r.accountName} (${r.accountId}): ${r.error}`);for(const n of o)ae(e,g(`Pre-flight cascade role check failed for ${n.accountName} (${n.accountId}) \u2014 its cascade deploy is expected to fail: ${n.error}`))}e.onCascadeAccountsReconciled?.({hasPlatformAccount:v>0,hasMemberAccounts:x>0});const{id:C,name:y}=q.PREPARE;e.onStepStart?.(C,y,0,i),e.onLog?.("Synthesising organisation infrastructure\u2026","info");const H=await te(t,d,e,"CDK synthesis failed");if(!H.success)return e.onStepComplete?.(C,y,"error",0,i),H;const M=t.awsProvider.getAccountId(),D=t.awsProvider.getRegion();Se(e,[{stackName:A(R.ORGANISATION),...M!==""?{accountId:M}:{},...D!==""?{region:D}:{}},...l&&s!==void 0?[{stackName:A(R.PLATFORM),accountId:s.id,region:s.region??D}]:[],...l?de(T,se(a.orgConfig)).map(({account:o,region:r})=>({stackName:A(R.ACCOUNT),accountId:o.id,region:r})):[]]);const W=await oe(t,d,e,me({account:F,estate:"org",orgId:P.orgId}));if(!W.success)return e.onStepComplete?.(C,y,"error",0,i),W;e.onStepComplete?.(C,y,"completed",0,i);const{id:m,name:S}=q.ORG_DEPLOY,c=A(R.ORGANISATION);let j=!0;const h=await t.hashService.getTemplateHashes(z(d.path,"cdk.out"));if(h.success){const o=await t.hashService.compareWithState(h.data,d.path);o.success?j=o.data.stackChanges.get(c)??!0:e.onLog?.(g(`Org root change detection failed \u2014 deploying to be safe: ${o.error.message}`),"warn")}else e.onLog?.(g(`Org root template hashing failed \u2014 deploying to be safe: ${h.error.message}`),"warn");const N=j||L?.force===!0||!await t.cfnService.stackExists(c,void 0,a.abortSignal);e.onOrgChangesDetected?.({hasOrgChanges:N});let b;if(N){e.onStepStart?.(m,S,1,i);const o=await ke(t.awsProvider,{stackNames:[c],cdkOutPath:z(d.path,"cdk.out"),cfnService:t.cfnService,callbacks:e,...a.abortSignal!==void 0?{abortSignal:a.abortSignal}:{}});if(o.kind==="blocked")return e.onStepComplete?.(m,S,"error",1,i),O(e,o.message);const r=await ue(a.assertLeaseForStack,c,a.abortSignal);if(r!==void 0)return e.onStepComplete?.(m,S,"error",1,i),e.onError?.(r),U(r);const n=await t.cdkService.runCdkDeploy(d,c,re(e),ne(e),t.awsProvider);if(!n.success)return e.onStepComplete?.(m,S,"error",1,i),O(e,n.error);b=await J(t,e,c,"Failed to read org stack outputs (non-critical)",a.abortSignal);const _=h.success?h.data.get(c):void 0;if(_!==void 0){const Y=await t.hashService.updateStateAfterDeploy(d.path,new Map([[c,_]]));Y.success||e.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy the org root: ${g(Y.error.message)}`,"warn")}e.onStepComplete?.(m,S,"completed",1,i)}else e.onLog?.("Organisation root: no infrastructure changes \u2014 skipping deploy","info"),b=await J(t,e,c,"Failed to read org stack outputs (non-critical)",a.abortSignal);const u=[],I=[];let B=N,$=[];if(l&&f.length>0){const o=await Oe(a,t,w,{providerAccounts:f,effectiveOrgConfig:Q,totalSteps:i,cascadeErrors:u,allCascadeOutputs:I,orgId:P.orgId});if(o.anyCascadeDeployHappened&&(B=!0),$=o.deployedDomainZones,o.domainsTakeover!==void 0)return K({target:w.target,deploymentType:"organisation",destructionPending:!0,destructionTicket:o.domainsTakeover.ticket,destructionOutcome:o.domainsTakeover.outcome,destructionHaltReasons:[...o.domainsTakeover.reasons],artefacts:[],durationMs:Date.now()-E});if(await we(a,t,{orgOutputs:b,allCascadeOutputs:I,orgDetails:p.data,providerAccounts:f,defaultRegion:V}),u.length>0){const r=u.map(n=>` ${n.accountId}: ${n.error}`).join(`
|
|
2
|
+
`);e.onLog?.(g(`Cascade failed for ${u.length} target(s):
|
|
3
|
+
${r}`),"warn")}}if(u.length>0){const o=u.map(n=>g(`${n.accountId}: ${n.error}`)).join(`
|
|
4
4
|
`),r=new Error(`Organisation root deployed, but the cascade failed for ${u.length} target(s):
|
|
5
|
-
${
|
|
5
|
+
${o}`);return e.onError?.(r),U(r)}return K({target:w.target,deploymentType:"organisation",outputs:b,artefacts:[],...I.length>0?{cascadeOutputs:I}:{},...$.length>0?{deployedDomainZones:$}:{},...B?{}:{noChanges:!0},durationMs:Date.now()-E})}Z(He,"deployOrgWithCascade");export{He as deployOrgWithCascade};
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
* alone, and `isStatefulResourceType` is a data-loss LABEL, not a
|
|
26
26
|
* deletion-authorisation gate: types it does not list (nested-stack
|
|
27
27
|
* containers with stateful children, EC2 instances with attached volumes,
|
|
28
|
-
* Custom:: providers whose Delete handlers run arbitrary code
|
|
29
|
-
*
|
|
28
|
+
* Custom:: providers whose Delete handlers run arbitrary code) can still
|
|
29
|
+
* destroy data or state. An allowlisted referrer
|
|
30
30
|
* carrying a retaining DeletionPolicy also fails closed: CloudFormation
|
|
31
31
|
* would DELETE_SKIPPED it, and the converge's re-create would collide with
|
|
32
32
|
* the orphaned physical resource. Co-removals are reported to the caller,
|
|
@@ -111,8 +111,8 @@ export interface StrippedExport {
|
|
|
111
111
|
* derivation closed — the ceremony consented to the TARGETS only, and
|
|
112
112
|
* `isStatefulResourceType` is a data-loss label, not a
|
|
113
113
|
* deletion-authorisation gate (it does not list nested-stack containers,
|
|
114
|
-
* EC2 instances
|
|
115
|
-
*
|
|
114
|
+
* EC2 instances or Custom:: providers, all of which can destroy data or run
|
|
115
|
+
* delete-time code).
|
|
116
116
|
*/
|
|
117
117
|
export declare const CO_REMOVABLE_RESOURCE_TYPES: readonly ["AWS::SecretsManager::SecretTargetAttachment", "AWS::SecretsManager::RotationSchedule"];
|
|
118
118
|
/** An allowlisted glue resource the derivation pulled into the removal
|
|
@@ -60,8 +60,9 @@ export interface DeployParams {
|
|
|
60
60
|
dockerProvider?: DockerProvider;
|
|
61
61
|
/**
|
|
62
62
|
* Optional domain deployment provider for organisation cascade.
|
|
63
|
-
* CLI provides an implementation backed by DomainService + zone files
|
|
64
|
-
*
|
|
63
|
+
* CLI provides an implementation backed by DomainService + zone files;
|
|
64
|
+
* the worker provides `WorkerDomainDeployProvider` (P6), parameterised by
|
|
65
|
+
* workingDirectory + boundaryDir + the job's explicit credentials.
|
|
65
66
|
* If omitted, the domains cascade phase is skipped.
|
|
66
67
|
*/
|
|
67
68
|
domainProvider?: DomainDeployProvider;
|
|
@@ -325,6 +326,15 @@ export interface DeployResult {
|
|
|
325
326
|
accountId: string;
|
|
326
327
|
outputs: Record<string, string>;
|
|
327
328
|
}>;
|
|
329
|
+
/**
|
|
330
|
+
* Zone names the cascade's domains phase actually deployed (P6). The
|
|
331
|
+
* per-zone retirement signal for merged-not-deployed domain change rows:
|
|
332
|
+
* skipped (foreign-pin), withheld and failed zones never appear, so a
|
|
333
|
+
* consumer flipping rows on this list is honest where any blanket
|
|
334
|
+
* org-deploy flip could not be. Absent when no domains phase ran or it
|
|
335
|
+
* deployed nothing.
|
|
336
|
+
*/
|
|
337
|
+
deployedDomainZones?: readonly string[];
|
|
328
338
|
/** Duration in milliseconds */
|
|
329
339
|
durationMs?: number;
|
|
330
340
|
/** Non-fatal warnings (e.g. cascade account failures) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/deploy-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.1.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/fjall-tech/fjall.git",
|
|
@@ -96,15 +96,15 @@
|
|
|
96
96
|
"@aws-sdk/client-ssm": "^3.1098.0",
|
|
97
97
|
"@aws-sdk/client-sso-admin": "^3.1098.0",
|
|
98
98
|
"@aws-sdk/client-sts": "^3.1098.0",
|
|
99
|
-
"@fjall/generator": "^
|
|
100
|
-
"@fjall/util": "^
|
|
99
|
+
"@fjall/generator": "^13.1.0",
|
|
100
|
+
"@fjall/util": "^13.1.0",
|
|
101
101
|
"@smithy/node-http-handler": "^4.9.13",
|
|
102
102
|
"aws-cdk": "^2.1134.0",
|
|
103
103
|
"tsx": "^4.23.1",
|
|
104
104
|
"zod": "^4.4.3"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@fjall/components-infrastructure": ">=
|
|
107
|
+
"@fjall/components-infrastructure": ">=13.0.0 <14.0.0"
|
|
108
108
|
},
|
|
109
109
|
"peerDependenciesMeta": {
|
|
110
110
|
"@fjall/components-infrastructure": {
|