@fjall/deploy-core 2.25.0 → 2.29.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/dist/.minified +1 -1
- package/dist/src/aws/index.d.ts +1 -1
- package/dist/src/aws/index.js +1 -1
- package/dist/src/aws/organisations/backup.d.ts +7 -2
- package/dist/src/aws/organisations/backup.js +2 -2
- package/dist/src/aws/organisations/index.d.ts +2 -2
- package/dist/src/aws/organisations/index.js +1 -1
- package/dist/src/aws/organisations/oidcProvider.d.ts +37 -0
- package/dist/src/aws/organisations/oidcProvider.js +1 -1
- package/dist/src/aws/organisations/organisation.d.ts +21 -0
- package/dist/src/aws/organisations/organisation.js +1 -1
- package/dist/src/aws/organisations/organisationalUnits.d.ts +15 -0
- package/dist/src/aws/organisations/organisationalUnits.js +1 -1
- package/dist/src/aws/utils/cloudformationEventHelpers.d.ts +45 -0
- package/dist/src/aws/utils/cloudformationEventHelpers.js +1 -1
- package/dist/src/aws/utils/cloudformationEventTypes.d.ts +1 -1
- package/dist/src/aws/utils/cloudformationEvents.d.ts +2 -1
- package/dist/src/aws/utils/cloudformationEvents.js +1 -1
- package/dist/src/aws/utils/stackStatus.js +1 -1
- package/dist/src/index.d.ts +13 -2
- package/dist/src/index.js +1 -1
- package/dist/src/orchestration/activeDeploymentGuard.d.ts +41 -0
- package/dist/src/orchestration/activeDeploymentGuard.js +8 -4
- package/dist/src/orchestration/application/applicationDeploy.d.ts +9 -0
- package/dist/src/orchestration/application/applicationDeploy.js +1 -1
- package/dist/src/orchestration/application/applicationDeployHelpers.d.ts +20 -3
- package/dist/src/orchestration/application/applicationDeployHelpers.js +3 -3
- package/dist/src/orchestration/application/applicationDestroy.js +1 -1
- package/dist/src/orchestration/application/approvalGate.d.ts +15 -1
- package/dist/src/orchestration/application/approvalGate.js +1 -1
- package/dist/src/orchestration/application/databaseEndpointReconcile.d.ts +77 -0
- package/dist/src/orchestration/application/databaseEndpointReconcile.js +1 -0
- package/dist/src/orchestration/application/deploySessionPolicy.d.ts +9 -1
- package/dist/src/orchestration/application/deploySessionPolicy.js +1 -1
- package/dist/src/orchestration/application/destructionGate.d.ts +164 -0
- package/dist/src/orchestration/application/destructionGate.js +5 -0
- package/dist/src/orchestration/application/dockerBuildHelper.js +1 -1
- package/dist/src/orchestration/application/ecrCacheRepository.d.ts +14 -0
- package/dist/src/orchestration/application/ecrCacheRepository.js +1 -0
- package/dist/src/orchestration/application/leaseGate.d.ts +30 -0
- package/dist/src/orchestration/application/leaseGate.js +1 -0
- package/dist/src/orchestration/application/plan/approvalToken.d.ts +15 -0
- package/dist/src/orchestration/application/plan/approvalToken.js +1 -1
- package/dist/src/orchestration/application/plan/changeSetEscalation.d.ts +46 -0
- package/dist/src/orchestration/application/plan/changeSetEscalation.js +1 -0
- package/dist/src/orchestration/application/plan/computeDeployPlan.d.ts +13 -0
- package/dist/src/orchestration/application/plan/computeDeployPlan.js +1 -1
- package/dist/src/orchestration/application/plan/index.d.ts +4 -1
- package/dist/src/orchestration/application/plan/index.js +1 -1
- package/dist/src/orchestration/application/plan/loadDeployPlan.d.ts +32 -0
- package/dist/src/orchestration/application/plan/loadDeployPlan.js +1 -0
- package/dist/src/orchestration/application/plan/pinnedNames.d.ts +31 -0
- package/dist/src/orchestration/application/plan/pinnedNames.js +1 -0
- package/dist/src/orchestration/application/plan/registryOverlay.d.ts +83 -0
- package/dist/src/orchestration/application/plan/registryOverlay.js +1 -0
- package/dist/src/orchestration/application/plan/renderDeployPlan.d.ts +4 -1
- package/dist/src/orchestration/application/plan/renderDeployPlan.js +1 -1
- package/dist/src/orchestration/application/plan/types.d.ts +31 -0
- package/dist/src/orchestration/application/plan/types.js +1 -0
- package/dist/src/orchestration/contextHelpers.d.ts +37 -1
- package/dist/src/orchestration/contextHelpers.js +1 -1
- package/dist/src/orchestration/drift/classifyDriftFailure.d.ts +31 -0
- package/dist/src/orchestration/drift/classifyDriftFailure.js +1 -0
- package/dist/src/orchestration/drift/detectStackDrift.d.ts +37 -0
- package/dist/src/orchestration/drift/detectStackDrift.js +1 -0
- package/dist/src/orchestration/drift/driftPreFlight.d.ts +73 -0
- package/dist/src/orchestration/drift/driftPreFlight.js +7 -0
- package/dist/src/orchestration/drift/driftProbe.d.ts +113 -0
- package/dist/src/orchestration/drift/driftProbe.js +1 -0
- package/dist/src/orchestration/drift/driftSuspectJournal.d.ts +40 -0
- package/dist/src/orchestration/drift/driftSuspectJournal.js +1 -0
- package/dist/src/orchestration/drift/preFlightGate.d.ts +44 -0
- package/dist/src/orchestration/drift/preFlightGate.js +2 -0
- package/dist/src/orchestration/index.d.ts +19 -0
- package/dist/src/orchestration/index.js +1 -1
- package/dist/src/orchestration/organisation/cascadeDestroyHelpers.d.ts +7 -0
- package/dist/src/orchestration/organisation/cascadeDestroyHelpers.js +1 -1
- package/dist/src/orchestration/organisation/cascadeHelpers.js +1 -1
- package/dist/src/orchestration/organisation/organisationDestroy.js +3 -3
- package/dist/src/orchestration/organisationDeploy/infraSteps.d.ts +8 -1
- package/dist/src/orchestration/organisationDeploy/infraSteps.js +1 -1
- package/dist/src/orchestration/organisationDeploy/orgCascadeDeploy.js +5 -5
- package/dist/src/orchestration/organisationDeploy/orgContext.d.ts +28 -2
- package/dist/src/orchestration/organisationDeploy/orgContext.js +1 -1
- package/dist/src/orchestration/organisationDeploy/singleComponentDeploy.js +1 -1
- package/dist/src/orchestration/remediation/driftRepairGate.d.ts +66 -0
- package/dist/src/orchestration/remediation/driftRepairGate.js +1 -0
- package/dist/src/orchestration/remediation/forensicsCapture.d.ts +49 -0
- package/dist/src/orchestration/remediation/forensicsCapture.js +1 -0
- package/dist/src/orchestration/remediation/forgetResource.d.ts +423 -0
- package/dist/src/orchestration/remediation/forgetResource.js +1 -0
- package/dist/src/orchestration/remediation/pinRemediation.d.ts +121 -0
- package/dist/src/orchestration/remediation/pinRemediation.js +1 -0
- package/dist/src/orchestration/remediation/postFailureRepairOffer.d.ts +77 -0
- package/dist/src/orchestration/remediation/postFailureRepairOffer.js +14 -0
- package/dist/src/orchestration/remediation/recreatePreFlight.d.ts +47 -0
- package/dist/src/orchestration/remediation/recreatePreFlight.js +1 -0
- package/dist/src/orchestration/remediation/recreateResource.d.ts +110 -0
- package/dist/src/orchestration/remediation/recreateResource.js +1 -0
- package/dist/src/orchestration/remediation/remediationJournal.d.ts +88 -0
- package/dist/src/orchestration/remediation/remediationJournal.js +2 -0
- package/dist/src/orchestration/remediation/removalUpdate.d.ts +135 -0
- package/dist/src/orchestration/remediation/removalUpdate.js +1 -0
- package/dist/src/orchestration/remediation/retainFlip.d.ts +294 -0
- package/dist/src/orchestration/remediation/retainFlip.js +1 -0
- package/dist/src/services/application/ApplicationStackService.d.ts +5 -3
- package/dist/src/services/application/ApplicationStackService.js +1 -1
- package/dist/src/services/application/applicationStackHelpers.d.ts +8 -6
- package/dist/src/services/application/applicationStackHelpers.js +3 -3
- package/dist/src/services/index.d.ts +2 -2
- package/dist/src/services/index.js +1 -1
- package/dist/src/services/infrastructure/CdkArgumentBuilder.js +1 -1
- package/dist/src/services/infrastructure/CdkEventMonitoring.d.ts +15 -0
- package/dist/src/services/infrastructure/CdkEventMonitoring.js +1 -1
- package/dist/src/services/infrastructure/CdkOutputAnalyser.d.ts +8 -0
- package/dist/src/services/infrastructure/CdkOutputAnalyser.js +2 -1
- package/dist/src/services/infrastructure/CdkService.js +3 -3
- package/dist/src/services/infrastructure/CdkServiceTypes.d.ts +7 -0
- package/dist/src/services/infrastructure/CfnRegistryService.d.ts +68 -0
- package/dist/src/services/infrastructure/CfnRegistryService.js +1 -0
- package/dist/src/services/infrastructure/CloudFormationService.d.ts +5 -2
- package/dist/src/services/infrastructure/CloudFormationService.js +1 -1
- package/dist/src/services/infrastructure/EcsServiceResolver.d.ts +23 -3
- package/dist/src/services/infrastructure/EcsServiceResolver.js +1 -1
- package/dist/src/services/infrastructure/cdkServiceHelpers.js +1 -1
- package/dist/src/services/infrastructure/cfnRegistrySeed.d.ts +10 -0
- package/dist/src/services/infrastructure/cfnRegistrySeed.js +1 -0
- package/dist/src/services/infrastructure/changeSetProbe.d.ts +88 -0
- package/dist/src/services/infrastructure/changeSetProbe.js +1 -0
- package/dist/src/services/infrastructure/index.d.ts +2 -0
- package/dist/src/services/infrastructure/index.js +1 -1
- package/dist/src/services/supporting/CdkContextBuilder.d.ts +1 -0
- package/dist/src/services/supporting/CdkContextBuilder.js +1 -1
- package/dist/src/types/callbackKeys.d.ts +1 -1
- package/dist/src/types/callbackKeys.js +1 -1
- package/dist/src/types/callbacks.d.ts +22 -0
- package/dist/src/types/config/entitlements.d.ts +9 -0
- package/dist/src/types/config/orgConfig.d.ts +6 -0
- package/dist/src/types/deployment/DeploymentTypes.d.ts +1 -0
- package/dist/src/types/deploymentEventSchema.d.ts +1 -0
- package/dist/src/types/deploymentEventSchema.js +1 -1
- package/dist/src/types/destruction.d.ts +212 -0
- package/dist/src/types/destruction.js +1 -0
- package/dist/src/types/drift.d.ts +72 -0
- package/dist/src/types/drift.js +1 -0
- package/dist/src/types/index.d.ts +8 -2
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/params.d.ts +161 -0
- package/dist/src/types/remediation.d.ts +126 -0
- package/dist/src/types/remediation.js +1 -0
- package/package.json +5 -4
package/dist/src/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DeploymentEventSchema as t,DEPLOYMENT_EVENT_TYPES as o,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as a,DEPLOYMENT_EVENT_STATUS_REASON_MAX as E,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as i,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as s,CASCADE_PHASES as S,CASCADE_ACCOUNT_STATUSES as n}from"./types/index.js";import{DeployEventSchema as A,StepProgressSchema as T,DeployResourceSchema as _,PlanChangeSchema as l,PlanPropertyChangeSchema as p,ChangeCountsSchema as O,DEPLOY_EVENT_CONTRACT as P,DEPLOY_EVENT_CONTRACT_MAJOR as R,DEPLOY_EVENT_CONTRACT_MINOR as u,SUPPORTED_CONTRACT_MARKERS as m,DEPLOY_EVENT_ID_MAX as d,DEPLOY_EVENT_NAME_MAX as C,DEPLOY_EVENT_MESSAGE_MAX as N,DEPLOY_EVENT_STATUS_REASON_MAX as D,DEPLOY_EVENT_ERROR_MESSAGE_MAX as L,DEPLOY_EVENT_TRAIL_DETAIL_MAX as f,DEPLOY_EVENT_OUTPUT_MAX as g,DEPLOY_EVENT_ARN_MAX as I,DEPLOY_EVENT_URL_MAX as x,STEP_COMPLETE_STATUSES as y,LOG_LEVELS as U,STACK_CLEANUP_PHASES as M,CASCADE_ACCOUNT_PHASES as v,DEPLOY_RESULTS as k,DETECTION_PHASES as Y,PHASE_STATUSES as h,BUILDERS as b,CASCADE_OUTCOME_RESULTS as V,PLAN_ACTIONS as F,REPLACEMENT_MODES as B,APPROVAL_KINDS as G,APPROVAL_DECISIONS as K,ALL_PROGRESS_KINDS as X,createDeployEmitter as H,parseDeployEvent as w,parseDeployContractVersion as j}from"./types/index.js";import{SimpleAwsProvider as q}from"./aws/index.js";import{checkTargetReadiness as W,describeTargetReadinessReason as Z,buildTargetUnreadyAdvisory as z,buildTargetSetUnreadyAdvisory as $,probeAccountStackExists as ee}from"./aws/index.js";import{checkRegionEnabled as te,regionDisabledMessage as oe}from"./aws/index.js";import{ensureOrganisationExists as Ee,describeOrganisation as ie,enablePolicyTypes as se,enableServiceAccess as Se,SERVICE_PRINCIPALS as ne,enableRamSharing as ce,activateTrustedAccess as Ae,enableIpamDelegatedAdmin as Te,updateBackupGlobalSettings as _e,listAccounts as le,findAccount as pe,createAccount as Oe,ensureOrganisationalUnitsExist as Pe,placeAccountsInOUs as Re,buildAccountToOUMap as ue,activateCostAllocationTags as me,checkIdentityCentreStatus as de,snapshotIdentityCentre as Ce,composeSdkAbortSignal as Ne,extractErrorName as De,isAborted as Le,DEFAULT_MAX_PAGES as fe,IDENTITY_STORE_PAGE_SIZE as ge,drainPages as Ie,isOULeaf as xe,registerSecurityDelegates as ye,SECURITY_SERVICE_PRINCIPALS as Ue,enableCentralisedRootAccess as Me,ROOT_ACCESS_FEATURES as ve,RootAccessEnablementError as ke}from"./aws/index.js";import{STEP_IDS as he,STEP_NAMES as be,INFRASTRUCTURE_STEP_NAMES as Ve,INFRA_STEP_NAME as Fe}from"./types/index.js";import{ProgressReporter as Ge,APPLICATION_STACKS as Ke,ORGANISATION_TYPES as Xe,APPLICATION_DEPLOY_ORDER as He,APPLICATION_DESTROY_ORDER as we,OPENNEXT_DEPLOY_ORDER as je,OPENNEXT_DESTROY_ORDER as Qe,PARALLEL_DEPLOY_GROUPS as qe,PARALLEL_DESTROY_GROUPS as Je,OPENNEXT_PARALLEL_GROUPS as We,PARALLEL_OPERATION_TYPES as Ze,isApplicationOperation as ze,isOrganisationOperation as $e,getParallelDeployGroups as er,getParallelDestroyGroups as rr,getApplicationDeployOrder as tr,getApplicationDestroyOrder as or,getApplicationStackName as ar,getOrganisationStackName as Er,isApplicationStack as ir,isQuarantineDetail as sr,isRetainedBucketsDetail as Sr,getApplicationStepName as nr,getApplicationStepId as cr,toPascalCase as Ar,isOpenNextPattern as Tr,OPENNEXT_PATTERNS as _r,deriveResourcesFromManifestStacks as lr,STACK_NOT_FOUND_PATTERN as pr,STACK_FAILED_STATE_PATTERN as Or,CDK_NO_STACKS_MATCH as Pr,INFRASTRUCTURE_FILENAME as Rr,ApplicationError as ur,wrapApplicationError as mr,FjallStateFileSchema as dr,readStateFile as Cr,writeStateFile as Nr,createEmptyState as Dr,deleteStateFile as Lr,updateTemplateHash as fr,getStateFilePath as gr,stubCallerIdentity as Ir}from"./types/index.js";import{CloudFormationEventMonitor as yr}from"./aws/index.js";import{CdkService as Mr,CdkArgumentBuilder as vr,CdkProcessManager as kr,CdkEventMonitor as Yr,startStackMonitoring as hr,DEFAULT_DEPLOY_TIMEOUT_MS as br,isCdkError as Vr,formatInfrastructureError as Fr,getStructuralHint as Br,getSourceContext as Gr,hasCdkDifferences as Kr,parseDiffOutput as Xr,CloudFormationService as Hr,CloudFormationError as wr,EcsService as jr,EcsError as Qr,EcsServiceResolver as qr,TemplateHashService as Jr,TemplateHashError as Wr,CdkContextBuilder as Zr,emitProgress as zr,PROGRESS_MESSAGES as $r,parseBuildPhase as et,buildStepContextBuildConfig as rt,convertCloudFormationOutputsToRecord as tt,ApplicationStackService as ot}from"./services/index.js";import{CdkError as Et}from"./types/errors/index.js";import{BaseServiceError as st,ValidationError as St,AuthError as nt,AwsError as ct,DeploymentError as At,NetworkError as Tt,FileSystemError as _t,ConfigError as lt,toServiceError as pt}from"./types/errors/index.js";import{filterDangerousEnvVars as Pt,maskSensitiveOutput as Rt,parseShellArgs as ut,sleep as mt}from"@fjall/util";import{artefactOutputKey as Ct,DeployModeSchema as Nt,ServiceArtefactSchema as Dt,ServiceArtefactsSchema as Lt}from"@fjall/util";import{hasDockerfile as gt}from"./util/dockerfileDetection.js";import{sleepAbortable as xt}from"./util/sleepAbortable.js";import{createSequencedCallbacks as Ut}from"./util/sequencedCallbacks.js";import{fileExists as vt}from"@fjall/util/fsHelpers";import{success as Yt,failure as ht,isSuccess as bt,isFailure as Vt}from"@fjall/generator";import{deploy as Bt}from"./orchestration/index.js";import{destroy as Kt}from"./orchestration/index.js";import{restart as Ht,probeSecretsDrift as wt,computeSecretsDrift as jt,deriveStaleParameters as Qt,extractConsumedSsmParameters as qt}from"./orchestration/index.js";import{partitionAccounts as Wt}from"./orchestration/index.js";import{buildRegionList as zt,buildAccountRegionPairs as $t,cascadeHomeRegion as eo,cascadeOperationKey as ro}from"./orchestration/index.js";import{projectScalarSummary as oo,projectAccountRows as ao}from"./orchestration/index.js";import{reconcileProviderAccounts as io,mergeReconciledProviderAccounts as so}from"./orchestration/index.js";import{decideNextTransition as no,reconcileTrailMigration as co,decommissionMemberTrailStorage as Ao,ORG_TRAIL_BUCKET_OUTPUT_KEY as To,TRAIL_BUCKET_OUTPUT_KEY as _o,TRAIL_KEY_ARN_OUTPUT_KEY as lo}from"./orchestration/index.js";import{unlockBucket as Oo,unlockQueue as Po}from"./orchestration/index.js";import{triageBucketPolicy as uo,isEnforceSslStatement as mo,toResourcePolicyStatements as Co,restoreBucketPolicy as No,synthesiseEnforceSslDocument as Do,ensureEnforceSsl as Lo,restoreAndReconcileQuarantinedBucket as fo}from"./orchestration/index.js";import{verifyOrgTrailDelivery as Io}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as yo,isRootTaskPolicyArn as Uo,ROOT_TASK_POLICY_ARNS as Mo,MAX_ROOT_SESSION_SECONDS as vo}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as Yo,flattenAccountsToEnvironments as ho,extractAllAccountNames as bo,accountsConfigToOUTree as Vo,isStringArray as Fo,isAccountsConfig as Bo,isOuOnlyAccountBucket as Go,OU_ONLY_ACCOUNT_BUCKETS as Ko}from"./orchestration/index.js";import{runOpenNextBuild as Ho}from"./orchestration/index.js";import{runOrganisationSetup as jo,ORG_SETUP_PHASES as Qo}from"./orchestration/index.js";import{resolveBuildSecrets as Jo,resolveSecretRefValue as Wo,resolveBuildSecretSessionProvider as Zo,sourcedRefsFromBuildArgs as zo,resolveBuildArgs as $o,buildBuildSecretSessionPolicy as ea,buildDeploySessionPolicy as ra,partitionForRegion as ta,validateBuildGroup as oa}from"./orchestration/index.js";import{FrameworkRegistry as Ea}from"./orchestration/index.js";import{openNextBuilder as sa,dockerBuilder as Sa}from"./orchestration/index.js";import{StepRegistry as ca,getDestroyStepId as Aa}from"./steps/index.js";import{buildDeployPlan as _a,computeDeployPlan as la,computeAssemblyDigest as pa,digestHead as Oa,classifyImpact as Pa,derivePropertyChanges as Ra,isDataLoss as ua,isStatefulResourceType as ma,renderPlanSummary as da,renderPlanLines as Ca,toWirePlanChanges as Na,signApprovalToken as Da,verifyApprovalToken as La,DEFAULT_APPROVAL_TTL_MS as fa,APPROVAL_TOKEN_PATTERN as ga,runApprovalGate as Ia}from"./orchestration/index.js";export{X as ALL_PROGRESS_KINDS,He as APPLICATION_DEPLOY_ORDER,we as APPLICATION_DESTROY_ORDER,Ke as APPLICATION_STACKS,K as APPROVAL_DECISIONS,G as APPROVAL_KINDS,ga as APPROVAL_TOKEN_PATTERN,ur as ApplicationError,ot as ApplicationStackService,nt as AuthError,ct as AwsError,b as BUILDERS,st as BaseServiceError,v as CASCADE_ACCOUNT_PHASES,n as CASCADE_ACCOUNT_STATUSES,V as CASCADE_OUTCOME_RESULTS,S as CASCADE_PHASES,Pr as CDK_NO_STACKS_MATCH,vr as CdkArgumentBuilder,Zr as CdkContextBuilder,Et as CdkError,Yr as CdkEventMonitor,kr as CdkProcessManager,Mr as CdkService,O as ChangeCountsSchema,wr as CloudFormationError,yr as CloudFormationEventMonitor,Hr as CloudFormationService,lt as ConfigError,fa as DEFAULT_APPROVAL_TTL_MS,br as DEFAULT_DEPLOY_TIMEOUT_MS,fe as DEFAULT_MAX_PAGES,i as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,a as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,E as DEPLOYMENT_EVENT_STATUS_REASON_MAX,s as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,o as DEPLOYMENT_EVENT_TYPES,I as DEPLOY_EVENT_ARN_MAX,P as DEPLOY_EVENT_CONTRACT,R as DEPLOY_EVENT_CONTRACT_MAJOR,u as DEPLOY_EVENT_CONTRACT_MINOR,L as DEPLOY_EVENT_ERROR_MESSAGE_MAX,d as DEPLOY_EVENT_ID_MAX,N as DEPLOY_EVENT_MESSAGE_MAX,C as DEPLOY_EVENT_NAME_MAX,g as DEPLOY_EVENT_OUTPUT_MAX,D as DEPLOY_EVENT_STATUS_REASON_MAX,f as DEPLOY_EVENT_TRAIL_DETAIL_MAX,x as DEPLOY_EVENT_URL_MAX,k as DEPLOY_RESULTS,Y as DETECTION_PHASES,A as DeployEventSchema,Nt as DeployModeSchema,_ as DeployResourceSchema,At as DeploymentError,t as DeploymentEventSchema,Qr as EcsError,jr as EcsService,qr as EcsServiceResolver,_t as FileSystemError,dr as FjallStateFileSchema,Ea as FrameworkRegistry,ge as IDENTITY_STORE_PAGE_SIZE,Rr as INFRASTRUCTURE_FILENAME,Ve as INFRASTRUCTURE_STEP_NAMES,Fe as INFRA_STEP_NAME,U as LOG_LEVELS,vo as MAX_ROOT_SESSION_SECONDS,Tt as NetworkError,je as OPENNEXT_DEPLOY_ORDER,Qe as OPENNEXT_DESTROY_ORDER,We as OPENNEXT_PARALLEL_GROUPS,_r as OPENNEXT_PATTERNS,Xe as ORGANISATION_TYPES,Qo as ORG_SETUP_PHASES,To as ORG_TRAIL_BUCKET_OUTPUT_KEY,Ko as OU_ONLY_ACCOUNT_BUCKETS,qe as PARALLEL_DEPLOY_GROUPS,Je as PARALLEL_DESTROY_GROUPS,Ze as PARALLEL_OPERATION_TYPES,h as PHASE_STATUSES,F as PLAN_ACTIONS,$r as PROGRESS_MESSAGES,l as PlanChangeSchema,p as PlanPropertyChangeSchema,Ge as ProgressReporter,B as REPLACEMENT_MODES,ve as ROOT_ACCESS_FEATURES,Mo as ROOT_TASK_POLICY_ARNS,ke as RootAccessEnablementError,Ue as SECURITY_SERVICE_PRINCIPALS,ne as SERVICE_PRINCIPALS,M as STACK_CLEANUP_PHASES,Or as STACK_FAILED_STATE_PATTERN,pr as STACK_NOT_FOUND_PATTERN,y as STEP_COMPLETE_STATUSES,he as STEP_IDS,be as STEP_NAMES,m as SUPPORTED_CONTRACT_MARKERS,Dt as ServiceArtefactSchema,Lt as ServiceArtefactsSchema,q as SimpleAwsProvider,T as StepProgressSchema,ca as StepRegistry,_o as TRAIL_BUCKET_OUTPUT_KEY,lo as TRAIL_KEY_ARN_OUTPUT_KEY,Wr as TemplateHashError,Jr as TemplateHashService,St as ValidationError,Vo as accountsConfigToOUTree,me as activateCostAllocationTags,Ae as activateTrustedAccess,Ct as artefactOutputKey,yo as assumeRootForTask,$t as buildAccountRegionPairs,ue as buildAccountToOUMap,ea as buildBuildSecretSessionPolicy,_a as buildDeployPlan,ra as buildDeploySessionPolicy,zt as buildRegionList,rt as buildStepContextBuildConfig,$ as buildTargetSetUnreadyAdvisory,z as buildTargetUnreadyAdvisory,eo as cascadeHomeRegion,ro as cascadeOperationKey,de as checkIdentityCentreStatus,te as checkRegionEnabled,W as checkTargetReadiness,Pa as classifyImpact,Ne as composeSdkAbortSignal,pa as computeAssemblyDigest,la as computeDeployPlan,jt as computeSecretsDrift,tt as convertCloudFormationOutputsToRecord,Oe as createAccount,H as createDeployEmitter,Dr as createEmptyState,Ut as createSequencedCallbacks,no as decideNextTransition,Ao as decommissionMemberTrailStorage,Lr as deleteStateFile,Bt as deploy,Ra as derivePropertyChanges,lr as deriveResourcesFromManifestStacks,Qt as deriveStaleParameters,ie as describeOrganisation,Z as describeTargetReadinessReason,Kt as destroy,Oa as digestHead,Sa as dockerBuilder,Ie as drainPages,zr as emitProgress,Me as enableCentralisedRootAccess,Te as enableIpamDelegatedAdmin,se as enablePolicyTypes,ce as enableRamSharing,Se as enableServiceAccess,Lo as ensureEnforceSsl,Ee as ensureOrganisationExists,Pe as ensureOrganisationalUnitsExist,bo as extractAllAccountNames,qt as extractConsumedSsmParameters,De as extractErrorName,ht as failure,vt as fileExists,Pt as filterDangerousEnvVars,pe as findAccount,ho as flattenAccountsToEnvironments,Fr as formatInfrastructureError,tr as getApplicationDeployOrder,or as getApplicationDestroyOrder,ar as getApplicationStackName,cr as getApplicationStepId,nr as getApplicationStepName,Aa as getDestroyStepId,Er as getOrganisationStackName,er as getParallelDeployGroups,rr as getParallelDestroyGroups,Gr as getSourceContext,gr as getStateFilePath,Br as getStructuralHint,Kr as hasCdkDifferences,gt as hasDockerfile,Le as isAborted,Bo as isAccountsConfig,ze as isApplicationOperation,ir as isApplicationStack,Vr as isCdkError,ua as isDataLoss,mo as isEnforceSslStatement,Vt as isFailure,xe as isOULeaf,Tr as isOpenNextPattern,$e as isOrganisationOperation,Go as isOuOnlyAccountBucket,sr as isQuarantineDetail,Sr as isRetainedBucketsDetail,Uo as isRootTaskPolicyArn,ma as isStatefulResourceType,Fo as isStringArray,bt as isSuccess,le as listAccounts,Rt as maskSensitiveOutput,so as mergeReconciledProviderAccounts,sa as openNextBuilder,Yo as parseAccountsConfiguration,et as parseBuildPhase,j as parseDeployContractVersion,w as parseDeployEvent,Xr as parseDiffOutput,ut as parseShellArgs,Wt as partitionAccounts,ta as partitionForRegion,Re as placeAccountsInOUs,ee as probeAccountStackExists,wt as probeSecretsDrift,ao as projectAccountRows,oo as projectScalarSummary,Cr as readStateFile,io as reconcileProviderAccounts,co as reconcileTrailMigration,oe as regionDisabledMessage,ye as registerSecurityDelegates,Ca as renderPlanLines,da as renderPlanSummary,$o as resolveBuildArgs,Zo as resolveBuildSecretSessionProvider,Jo as resolveBuildSecrets,Wo as resolveSecretRefValue,Ht as restart,fo as restoreAndReconcileQuarantinedBucket,No as restoreBucketPolicy,Ia as runApprovalGate,Ho as runOpenNextBuild,jo as runOrganisationSetup,Da as signApprovalToken,mt as sleep,xt as sleepAbortable,Ce as snapshotIdentityCentre,zo as sourcedRefsFromBuildArgs,hr as startStackMonitoring,Ir as stubCallerIdentity,Yt as success,Do as synthesiseEnforceSslDocument,Ar as toPascalCase,Co as toResourcePolicyStatements,pt as toServiceError,Na as toWirePlanChanges,uo as triageBucketPolicy,Oo as unlockBucket,Po as unlockQueue,_e as updateBackupGlobalSettings,fr as updateTemplateHash,oa as validateBuildGroup,La as verifyApprovalToken,Io as verifyOrgTrailDelivery,mr as wrapApplicationError,Nr as writeStateFile};
|
|
1
|
+
import{DeploymentEventSchema as t,DEPLOYMENT_EVENT_TYPES as o,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as i,DEPLOYMENT_EVENT_STATUS_REASON_MAX as a,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as s,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as n,CASCADE_PHASES as c,CASCADE_ACCOUNT_STATUSES as E}from"./types/index.js";import{DeployEventSchema as l,StepProgressSchema as T,DeployResourceSchema as p,PlanChangeSchema as A,PlanPropertyChangeSchema as R,ChangeCountsSchema as _,DEPLOY_EVENT_CONTRACT as m,DEPLOY_EVENT_CONTRACT_MAJOR as u,DEPLOY_EVENT_CONTRACT_MINOR as d,SUPPORTED_CONTRACT_MARKERS as P,DEPLOY_EVENT_ID_MAX as O,DEPLOY_EVENT_NAME_MAX as D,DEPLOY_EVENT_MESSAGE_MAX as f,DEPLOY_EVENT_STATUS_REASON_MAX as C,DEPLOY_EVENT_ERROR_MESSAGE_MAX as N,DEPLOY_EVENT_TRAIL_DETAIL_MAX as g,DEPLOY_EVENT_OUTPUT_MAX as L,DEPLOY_EVENT_ARN_MAX as I,DEPLOY_EVENT_URL_MAX as y,STEP_COMPLETE_STATUSES as h,LOG_LEVELS as v,STACK_CLEANUP_PHASES as x,CASCADE_ACCOUNT_PHASES as F,DEPLOY_RESULTS as M,DETECTION_PHASES as U,PHASE_STATUSES as k,BUILDERS as b,CASCADE_OUTCOME_RESULTS as V,PLAN_ACTIONS as Y,REPLACEMENT_MODES as B,APPROVAL_KINDS as G,APPROVAL_DECISIONS as K,ALL_PROGRESS_KINDS as X,createDeployEmitter as H,parseDeployEvent as J,parseDeployContractVersion as w}from"./types/index.js";import{SimpleAwsProvider as Q}from"./aws/index.js";import{checkTargetReadiness as q,describeTargetReadinessReason as Z,buildTargetUnreadyAdvisory as z,buildTargetSetUnreadyAdvisory as $,probeAccountStackExists as ee}from"./aws/index.js";import{checkRegionEnabled as te,regionDisabledMessage as oe}from"./aws/index.js";import{ensureOrganisationExists as ae,describeOrganisation as se,enablePolicyTypes as ne,enableServiceAccess as ce,SERVICE_PRINCIPALS as Ee,enableRamSharing as Se,activateTrustedAccess as le,enableIpamDelegatedAdmin as Te,updateBackupGlobalSettings as pe,listAccounts as Ae,findAccount as Re,createAccount as _e,ensureOrganisationalUnitsExist as me,placeAccountsInOUs as ue,buildAccountToOUMap as de,findDevelopmentOuId as Pe,activateCostAllocationTags as Oe,checkIdentityCentreStatus as De,snapshotIdentityCentre as fe,composeSdkAbortSignal as Ce,extractErrorName as Ne,isAborted as ge,DEFAULT_MAX_PAGES as Le,IDENTITY_STORE_PAGE_SIZE as Ie,drainPages as ye,isOULeaf as he,registerSecurityDelegates as ve,SECURITY_SERVICE_PRINCIPALS as xe,enableCentralisedRootAccess as Fe,ROOT_ACCESS_FEATURES as Me,RootAccessEnablementError as Ue}from"./aws/index.js";import{STEP_IDS as be,STEP_NAMES as Ve,INFRASTRUCTURE_STEP_NAMES as Ye,INFRA_STEP_NAME as Be}from"./types/index.js";import{RemediationVerbSchema as Ke,REMEDIATION_VERB_GLOSS as Xe,DestructionFindingSchema as He,DestructionTicketResourceSchema as Je,DestructionTicketSchema as we,DestructionConsentSchema as je,DestructionOutcomeSchema as Qe,DESTRUCTION_FINDINGS as We,CONSENT_VERDICTS as qe,TICKET_VERDICT_SOURCES as Ze,TicketVerdictSourceSchema as ze}from"./types/index.js";import{DRIFT_VERDICTS as er,DriftVerdictSchema as rr,DriftSuspectSchema as tr,DriftFindingSchema as or,DriftJournalRecordSchema as ir,verbsForDriftVerdict as ar}from"./types/index.js";import{REMEDIATION_PHASES as nr,RemediationPhaseSchema as cr,RemediationTargetSchema as Er,RemediationFlipProofSchema as Sr,RemediationJournalRecordSchema as lr,RemediationVerbWithSurgerySchema as Tr,remediationPhaseRank as pr,remediationPlaceholderPhysicalId as Ar,isRemediationPlaceholderPhysicalId as Rr}from"./types/index.js";import{ProgressReporter as mr,APPLICATION_STACKS as ur,ORGANISATION_TYPES as dr,APPLICATION_DEPLOY_ORDER as Pr,APPLICATION_DESTROY_ORDER as Or,OPENNEXT_DEPLOY_ORDER as Dr,OPENNEXT_DESTROY_ORDER as fr,PARALLEL_DEPLOY_GROUPS as Cr,PARALLEL_DESTROY_GROUPS as Nr,OPENNEXT_PARALLEL_GROUPS as gr,PARALLEL_OPERATION_TYPES as Lr,isApplicationOperation as Ir,isOrganisationOperation as yr,getParallelDeployGroups as hr,getParallelDestroyGroups as vr,getApplicationDeployOrder as xr,getApplicationDestroyOrder as Fr,getApplicationStackName as Mr,getOrganisationStackName as Ur,isApplicationStack as kr,isQuarantineDetail as br,isRetainedBucketsDetail as Vr,getApplicationStepName as Yr,getApplicationStepId as Br,toPascalCase as Gr,isOpenNextPattern as Kr,OPENNEXT_PATTERNS as Xr,deriveResourcesFromManifestStacks as Hr,STACK_NOT_FOUND_PATTERN as Jr,STACK_FAILED_STATE_PATTERN as wr,CDK_NO_STACKS_MATCH as jr,INFRASTRUCTURE_FILENAME as Qr,ApplicationError as Wr,wrapApplicationError as qr,FjallStateFileSchema as Zr,readStateFile as zr,writeStateFile as $r,createEmptyState as et,deleteStateFile as rt,updateTemplateHash as tt,getStateFilePath as ot,stubCallerIdentity as it}from"./types/index.js";import{CloudFormationEventMonitor as st}from"./aws/index.js";import{CdkService as ct,CdkArgumentBuilder as Et,CdkProcessManager as St,CdkEventMonitor as lt,startStackMonitoring as Tt,DEFAULT_DEPLOY_TIMEOUT_MS as pt,isCdkError as At,formatInfrastructureError as Rt,getStructuralHint as _t,getSourceContext as mt,hasCdkDifferences as ut,parseDiffOutput as dt,CloudFormationService as Pt,CloudFormationError as Ot,EcsService as Dt,EcsError as ft,EcsServiceResolver as Ct,TemplateHashService as Nt,TemplateHashError as gt,CdkContextBuilder as Lt,emitProgress as It,PROGRESS_MESSAGES as yt,parseBuildPhase as ht,buildStepContextBuildConfig as vt,convertCloudFormationOutputsToRecord as xt,ApplicationStackService as Ft}from"./services/index.js";import{CdkError as Ut}from"./types/errors/index.js";import{BaseServiceError as bt,ValidationError as Vt,AuthError as Yt,AwsError as Bt,DeploymentError as Gt,NetworkError as Kt,FileSystemError as Xt,ConfigError as Ht,toServiceError as Jt}from"./types/errors/index.js";import{filterDangerousEnvVars as jt,maskSensitiveOutput as Qt,parseShellArgs as Wt,sleep as qt}from"@fjall/util";import{artefactOutputKey as zt,DeployModeSchema as $t,ServiceArtefactSchema as eo,ServiceArtefactsSchema as ro}from"@fjall/util";import{hasDockerfile as oo}from"./util/dockerfileDetection.js";import{sleepAbortable as ao}from"./util/sleepAbortable.js";import{createSequencedCallbacks as no}from"./util/sequencedCallbacks.js";import{fileExists as Eo}from"@fjall/util/fsHelpers";import{success as lo,failure as To,isSuccess as po,isFailure as Ao}from"@fjall/generator";import{deploy as _o}from"./orchestration/index.js";import{destroy as uo}from"./orchestration/index.js";import{restart as Oo,probeSecretsDrift as Do,computeSecretsDrift as fo,deriveStaleParameters as Co,extractConsumedSsmParameters as No}from"./orchestration/index.js";import{partitionAccounts as Lo}from"./orchestration/index.js";import{buildRegionList as yo,buildAccountRegionPairs as ho,cascadeHomeRegion as vo,cascadeOperationKey as xo}from"./orchestration/index.js";import{projectScalarSummary as Mo,projectAccountRows as Uo}from"./orchestration/index.js";import{reconcileProviderAccounts as bo,mergeReconciledProviderAccounts as Vo}from"./orchestration/index.js";import{decideNextTransition as Bo,reconcileTrailMigration as Go,decommissionMemberTrailStorage as Ko,ORG_TRAIL_BUCKET_OUTPUT_KEY as Xo,TRAIL_BUCKET_OUTPUT_KEY as Ho,TRAIL_KEY_ARN_OUTPUT_KEY as Jo}from"./orchestration/index.js";import{classifyDriftFailure as jo,fetchLastOperationEvents as Qo,DriftProbe as Wo,clearDriftSuspects as qo,defaultDriftJournalDir as Zo,readDriftSuspects as zo,recordDriftSuspects as $o,detectStackDrift as ei,runDriftPreFlight as ri,formatDriftPreFlightBlock as ti,DRIFT_PREFLIGHT_TRIGGER_STATUSES as oi,DRIFT_PREFLIGHT_BUDGET_MS as ii}from"./orchestration/index.js";import{archiveCompletedRemediationJournal as si,computeRemediationOpId as ni,defaultRemediationJournalDir as ci,findRemediationJournalByOpId as Ei,listActiveRemediationOps as Si,listActiveRemediationOpsForContext as li,readRemediationJournal as Ti,sweepExpiredRemediationJournals as pi,writeRemediationJournal as Ai,REMEDIATION_JOURNAL_RETENTION_DAYS as Ri,captureRemediationForensics as _i,defaultRemediationForensicsDir as mi,applyRetainFlip as ui,composeFlipCapabilities as di,computeTemplateDigest as Pi,deriveRetainFlipTemplate as Oi,findMarkedResourcesByOpId as Di,proveFlipMetadataOnly as fi,readRetainFlipState as Ci,verifyRetainFlipDiff as Ni,FORGET_MARKER_KEY as gi,FORGET_FLIP_SPEC as Li,RECREATE_MARKER_KEY as Ii,assessForgetResumability as yi,completeForgetAfterConverge as hi,completeForgetAfterDeploy as vi,formatRecreateInFlightCures as xi,partitionPreFlightByRemediation as Fi,runForgetSurgery as Mi,synthTemplateDeclaresResource as Ui,runRecreateSurgery as ki,snapshotPolicyForType as bi,SNAPSHOT_CAPABLE_RESOURCE_TYPES as Vi,runRecreatePreFlight as Yi,deriveRemovalTemplate as Bi,findRemovalDeletionFailures as Gi,proveRemovalTargetsOnly as Ki,advertisableDriftVerbs as Xi,buildDriftRepairTicket as Hi,runDriftRepairGate as Ji,formatPinOutcomeDetail as wi,pinProbeCoverage as ji,renderPinReportLines as Qi,runPinRemediation as Wi,composePostFailureRepairOffer as qi,formatDriftRepairOffer as Zi,DriftRepairAvailableError as zi,checkDeployPathStackAvailability as $i,isDeployPathBlockingStatus as ea,StackUnavailableError as ra,assertLeaseBeforeStack as ta,LeaseDeniedError as oa}from"./orchestration/index.js";import{unlockBucket as aa,unlockQueue as sa}from"./orchestration/index.js";import{triageBucketPolicy as ca,isEnforceSslStatement as Ea,toResourcePolicyStatements as Sa,restoreBucketPolicy as la,synthesiseEnforceSslDocument as Ta,ensureEnforceSsl as pa,restoreAndReconcileQuarantinedBucket as Aa}from"./orchestration/index.js";import{verifyOrgTrailDelivery as _a}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as ua,isRootTaskPolicyArn as da,ROOT_TASK_POLICY_ARNS as Pa,MAX_ROOT_SESSION_SECONDS as Oa}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as fa,flattenAccountsToEnvironments as Ca,extractAllAccountNames as Na,accountsConfigToOUTree as ga,isStringArray as La,isAccountsConfig as Ia,isOuOnlyAccountBucket as ya,OU_ONLY_ACCOUNT_BUCKETS as ha}from"./orchestration/index.js";import{runOpenNextBuild as xa}from"./orchestration/index.js";import{runOrganisationSetup as Ma,ORG_SETUP_PHASES as Ua}from"./orchestration/index.js";import{resolveBuildSecrets as ba,resolveSecretRefValue as Va,resolveBuildSecretSessionProvider as Ya,sourcedRefsFromBuildArgs as Ba,resolveBuildArgs as Ga,buildBuildSecretSessionPolicy as Ka,buildDeploySessionPolicy as Xa,partitionForRegion as Ha,validateBuildGroup as Ja}from"./orchestration/index.js";import{FrameworkRegistry as ja}from"./orchestration/index.js";import{openNextBuilder as Wa,dockerBuilder as qa}from"./orchestration/index.js";import{StepRegistry as za,getDestroyStepId as $a}from"./steps/index.js";import{buildDeployPlan as rs,computeDeployPlan as ts,computeAssemblyDigest as os,digestHead as is,classifyImpact as as,derivePropertyChanges as ss,isDataLoss as ns,isStatefulResourceType as cs,renderPlanSummary as Es,renderPlanLines as Ss,toWirePlanChanges as ls,signApprovalToken as Ts,verifyApprovalToken as ps,DEFAULT_APPROVAL_TTL_MS as As,APPROVAL_TOKEN_PATTERN as Rs,runApprovalGate as _s}from"./orchestration/index.js";import{runDestructionGate as us,buildDestructionTicket as ds,evaluateDestructionConsents as Ps,computeTicketDigest as Os,legalRemediationVerbs as Ds,executableRemediationVerbs as fs,advertisableRemediationVerbs as Cs,renderDestructionTicketLines as Ns,renderConsentVerdictLines as gs,loadDeployPlan as Ls,createMemoisedPlanLoader as Is}from"./orchestration/index.js";export{X as ALL_PROGRESS_KINDS,Pr as APPLICATION_DEPLOY_ORDER,Or as APPLICATION_DESTROY_ORDER,ur as APPLICATION_STACKS,K as APPROVAL_DECISIONS,G as APPROVAL_KINDS,Rs as APPROVAL_TOKEN_PATTERN,Wr as ApplicationError,Ft as ApplicationStackService,Yt as AuthError,Bt as AwsError,b as BUILDERS,bt as BaseServiceError,F as CASCADE_ACCOUNT_PHASES,E as CASCADE_ACCOUNT_STATUSES,V as CASCADE_OUTCOME_RESULTS,c as CASCADE_PHASES,jr as CDK_NO_STACKS_MATCH,qe as CONSENT_VERDICTS,Et as CdkArgumentBuilder,Lt as CdkContextBuilder,Ut as CdkError,lt as CdkEventMonitor,St as CdkProcessManager,ct as CdkService,_ as ChangeCountsSchema,Ot as CloudFormationError,st as CloudFormationEventMonitor,Pt as CloudFormationService,Ht as ConfigError,As as DEFAULT_APPROVAL_TTL_MS,pt as DEFAULT_DEPLOY_TIMEOUT_MS,Le as DEFAULT_MAX_PAGES,s as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,i as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,a as DEPLOYMENT_EVENT_STATUS_REASON_MAX,n as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,o as DEPLOYMENT_EVENT_TYPES,I as DEPLOY_EVENT_ARN_MAX,m as DEPLOY_EVENT_CONTRACT,u as DEPLOY_EVENT_CONTRACT_MAJOR,d as DEPLOY_EVENT_CONTRACT_MINOR,N as DEPLOY_EVENT_ERROR_MESSAGE_MAX,O as DEPLOY_EVENT_ID_MAX,f as DEPLOY_EVENT_MESSAGE_MAX,D as DEPLOY_EVENT_NAME_MAX,L as DEPLOY_EVENT_OUTPUT_MAX,C as DEPLOY_EVENT_STATUS_REASON_MAX,g as DEPLOY_EVENT_TRAIL_DETAIL_MAX,y as DEPLOY_EVENT_URL_MAX,M as DEPLOY_RESULTS,We as DESTRUCTION_FINDINGS,U as DETECTION_PHASES,ii as DRIFT_PREFLIGHT_BUDGET_MS,oi as DRIFT_PREFLIGHT_TRIGGER_STATUSES,er as DRIFT_VERDICTS,l as DeployEventSchema,$t as DeployModeSchema,p as DeployResourceSchema,Gt as DeploymentError,t as DeploymentEventSchema,je as DestructionConsentSchema,He as DestructionFindingSchema,Qe as DestructionOutcomeSchema,Je as DestructionTicketResourceSchema,we as DestructionTicketSchema,or as DriftFindingSchema,ir as DriftJournalRecordSchema,Wo as DriftProbe,zi as DriftRepairAvailableError,tr as DriftSuspectSchema,rr as DriftVerdictSchema,ft as EcsError,Dt as EcsService,Ct as EcsServiceResolver,Li as FORGET_FLIP_SPEC,gi as FORGET_MARKER_KEY,Xt as FileSystemError,Zr as FjallStateFileSchema,ja as FrameworkRegistry,Ie as IDENTITY_STORE_PAGE_SIZE,Qr as INFRASTRUCTURE_FILENAME,Ye as INFRASTRUCTURE_STEP_NAMES,Be as INFRA_STEP_NAME,v as LOG_LEVELS,oa as LeaseDeniedError,Oa as MAX_ROOT_SESSION_SECONDS,Kt as NetworkError,Dr as OPENNEXT_DEPLOY_ORDER,fr as OPENNEXT_DESTROY_ORDER,gr as OPENNEXT_PARALLEL_GROUPS,Xr as OPENNEXT_PATTERNS,dr as ORGANISATION_TYPES,Ua as ORG_SETUP_PHASES,Xo as ORG_TRAIL_BUCKET_OUTPUT_KEY,ha as OU_ONLY_ACCOUNT_BUCKETS,Cr as PARALLEL_DEPLOY_GROUPS,Nr as PARALLEL_DESTROY_GROUPS,Lr as PARALLEL_OPERATION_TYPES,k as PHASE_STATUSES,Y as PLAN_ACTIONS,yt as PROGRESS_MESSAGES,A as PlanChangeSchema,R as PlanPropertyChangeSchema,mr as ProgressReporter,Ii as RECREATE_MARKER_KEY,Ri as REMEDIATION_JOURNAL_RETENTION_DAYS,nr as REMEDIATION_PHASES,Xe as REMEDIATION_VERB_GLOSS,B as REPLACEMENT_MODES,Me as ROOT_ACCESS_FEATURES,Pa as ROOT_TASK_POLICY_ARNS,Sr as RemediationFlipProofSchema,lr as RemediationJournalRecordSchema,cr as RemediationPhaseSchema,Er as RemediationTargetSchema,Ke as RemediationVerbSchema,Tr as RemediationVerbWithSurgerySchema,Ue as RootAccessEnablementError,xe as SECURITY_SERVICE_PRINCIPALS,Ee as SERVICE_PRINCIPALS,Vi as SNAPSHOT_CAPABLE_RESOURCE_TYPES,x as STACK_CLEANUP_PHASES,wr as STACK_FAILED_STATE_PATTERN,Jr as STACK_NOT_FOUND_PATTERN,h as STEP_COMPLETE_STATUSES,be as STEP_IDS,Ve as STEP_NAMES,P as SUPPORTED_CONTRACT_MARKERS,eo as ServiceArtefactSchema,ro as ServiceArtefactsSchema,Q as SimpleAwsProvider,ra as StackUnavailableError,T as StepProgressSchema,za as StepRegistry,Ze as TICKET_VERDICT_SOURCES,Ho as TRAIL_BUCKET_OUTPUT_KEY,Jo as TRAIL_KEY_ARN_OUTPUT_KEY,gt as TemplateHashError,Nt as TemplateHashService,ze as TicketVerdictSourceSchema,Vt as ValidationError,ga as accountsConfigToOUTree,Oe as activateCostAllocationTags,le as activateTrustedAccess,Xi as advertisableDriftVerbs,Cs as advertisableRemediationVerbs,ui as applyRetainFlip,si as archiveCompletedRemediationJournal,zt as artefactOutputKey,ta as assertLeaseBeforeStack,yi as assessForgetResumability,ua as assumeRootForTask,ho as buildAccountRegionPairs,de as buildAccountToOUMap,Ka as buildBuildSecretSessionPolicy,rs as buildDeployPlan,Xa as buildDeploySessionPolicy,ds as buildDestructionTicket,Hi as buildDriftRepairTicket,yo as buildRegionList,vt as buildStepContextBuildConfig,$ as buildTargetSetUnreadyAdvisory,z as buildTargetUnreadyAdvisory,_i as captureRemediationForensics,vo as cascadeHomeRegion,xo as cascadeOperationKey,$i as checkDeployPathStackAvailability,De as checkIdentityCentreStatus,te as checkRegionEnabled,q as checkTargetReadiness,jo as classifyDriftFailure,as as classifyImpact,qo as clearDriftSuspects,hi as completeForgetAfterConverge,vi as completeForgetAfterDeploy,di as composeFlipCapabilities,qi as composePostFailureRepairOffer,Ce as composeSdkAbortSignal,os as computeAssemblyDigest,ts as computeDeployPlan,ni as computeRemediationOpId,fo as computeSecretsDrift,Pi as computeTemplateDigest,Os as computeTicketDigest,xt as convertCloudFormationOutputsToRecord,_e as createAccount,H as createDeployEmitter,et as createEmptyState,Is as createMemoisedPlanLoader,no as createSequencedCallbacks,Bo as decideNextTransition,Ko as decommissionMemberTrailStorage,Zo as defaultDriftJournalDir,mi as defaultRemediationForensicsDir,ci as defaultRemediationJournalDir,rt as deleteStateFile,_o as deploy,ss as derivePropertyChanges,Bi as deriveRemovalTemplate,Hr as deriveResourcesFromManifestStacks,Oi as deriveRetainFlipTemplate,Co as deriveStaleParameters,se as describeOrganisation,Z as describeTargetReadinessReason,uo as destroy,ei as detectStackDrift,is as digestHead,qa as dockerBuilder,ye as drainPages,It as emitProgress,Fe as enableCentralisedRootAccess,Te as enableIpamDelegatedAdmin,ne as enablePolicyTypes,Se as enableRamSharing,ce as enableServiceAccess,pa as ensureEnforceSsl,ae as ensureOrganisationExists,me as ensureOrganisationalUnitsExist,Ps as evaluateDestructionConsents,fs as executableRemediationVerbs,Na as extractAllAccountNames,No as extractConsumedSsmParameters,Ne as extractErrorName,To as failure,Qo as fetchLastOperationEvents,Eo as fileExists,jt as filterDangerousEnvVars,Re as findAccount,Pe as findDevelopmentOuId,Di as findMarkedResourcesByOpId,Ei as findRemediationJournalByOpId,Gi as findRemovalDeletionFailures,Ca as flattenAccountsToEnvironments,ti as formatDriftPreFlightBlock,Zi as formatDriftRepairOffer,Rt as formatInfrastructureError,wi as formatPinOutcomeDetail,xi as formatRecreateInFlightCures,xr as getApplicationDeployOrder,Fr as getApplicationDestroyOrder,Mr as getApplicationStackName,Br as getApplicationStepId,Yr as getApplicationStepName,$a as getDestroyStepId,Ur as getOrganisationStackName,hr as getParallelDeployGroups,vr as getParallelDestroyGroups,mt as getSourceContext,ot as getStateFilePath,_t as getStructuralHint,ut as hasCdkDifferences,oo as hasDockerfile,ge as isAborted,Ia as isAccountsConfig,Ir as isApplicationOperation,kr as isApplicationStack,At as isCdkError,ns as isDataLoss,ea as isDeployPathBlockingStatus,Ea as isEnforceSslStatement,Ao as isFailure,he as isOULeaf,Kr as isOpenNextPattern,yr as isOrganisationOperation,ya as isOuOnlyAccountBucket,br as isQuarantineDetail,Rr as isRemediationPlaceholderPhysicalId,Vr as isRetainedBucketsDetail,da as isRootTaskPolicyArn,cs as isStatefulResourceType,La as isStringArray,po as isSuccess,Ds as legalRemediationVerbs,Ae as listAccounts,Si as listActiveRemediationOps,li as listActiveRemediationOpsForContext,Ls as loadDeployPlan,Qt as maskSensitiveOutput,Vo as mergeReconciledProviderAccounts,Wa as openNextBuilder,fa as parseAccountsConfiguration,ht as parseBuildPhase,w as parseDeployContractVersion,J as parseDeployEvent,dt as parseDiffOutput,Wt as parseShellArgs,Lo as partitionAccounts,Ha as partitionForRegion,Fi as partitionPreFlightByRemediation,ji as pinProbeCoverage,ue as placeAccountsInOUs,ee as probeAccountStackExists,Do as probeSecretsDrift,Uo as projectAccountRows,Mo as projectScalarSummary,fi as proveFlipMetadataOnly,Ki as proveRemovalTargetsOnly,zo as readDriftSuspects,Ti as readRemediationJournal,Ci as readRetainFlipState,zr as readStateFile,bo as reconcileProviderAccounts,Go as reconcileTrailMigration,$o as recordDriftSuspects,oe as regionDisabledMessage,ve as registerSecurityDelegates,pr as remediationPhaseRank,Ar as remediationPlaceholderPhysicalId,gs as renderConsentVerdictLines,Ns as renderDestructionTicketLines,Qi as renderPinReportLines,Ss as renderPlanLines,Es as renderPlanSummary,Ga as resolveBuildArgs,Ya as resolveBuildSecretSessionProvider,ba as resolveBuildSecrets,Va as resolveSecretRefValue,Oo as restart,Aa as restoreAndReconcileQuarantinedBucket,la as restoreBucketPolicy,_s as runApprovalGate,us as runDestructionGate,ri as runDriftPreFlight,Ji as runDriftRepairGate,Mi as runForgetSurgery,xa as runOpenNextBuild,Ma as runOrganisationSetup,Wi as runPinRemediation,Yi as runRecreatePreFlight,ki as runRecreateSurgery,Ts as signApprovalToken,qt as sleep,ao as sleepAbortable,fe as snapshotIdentityCentre,bi as snapshotPolicyForType,Ba as sourcedRefsFromBuildArgs,Tt as startStackMonitoring,it as stubCallerIdentity,lo as success,pi as sweepExpiredRemediationJournals,Ui as synthTemplateDeclaresResource,Ta as synthesiseEnforceSslDocument,Gr as toPascalCase,Sa as toResourcePolicyStatements,Jt as toServiceError,ls as toWirePlanChanges,ca as triageBucketPolicy,aa as unlockBucket,sa as unlockQueue,pe as updateBackupGlobalSettings,tt as updateTemplateHash,Ja as validateBuildGroup,ar as verbsForDriftVerdict,ps as verifyApprovalToken,_a as verifyOrgTrailDelivery,Ni as verifyRetainFlipDiff,qr as wrapApplicationError,Ai as writeRemediationJournal,$r as writeStateFile};
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import { type Result } from "@fjall/generator";
|
|
2
|
+
import { BaseServiceError } from "../types/errors/ServiceError.js";
|
|
2
3
|
import type { CloudFormationService } from "../services/infrastructure/CloudFormationService.js";
|
|
4
|
+
/**
|
|
5
|
+
* A deploy-path pre-flight found one or more target stacks mid-operation or
|
|
6
|
+
* otherwise unavailable. Carries the offending stacks so surfaces can render
|
|
7
|
+
* them; the message is surface-neutral (no CLI flags, no CLI commands) and
|
|
8
|
+
* pre-built from static literals + stack names/statuses — nothing to mask.
|
|
9
|
+
*/
|
|
10
|
+
export declare class StackUnavailableError extends BaseServiceError {
|
|
11
|
+
readonly stacks: ReadonlyArray<{
|
|
12
|
+
name: string;
|
|
13
|
+
status: string;
|
|
14
|
+
}>;
|
|
15
|
+
constructor(message: string, stacks: ReadonlyArray<{
|
|
16
|
+
name: string;
|
|
17
|
+
status: string;
|
|
18
|
+
}>);
|
|
19
|
+
}
|
|
3
20
|
/**
|
|
4
21
|
* Pre-flight check: query CloudFormation for each stack and reject
|
|
5
22
|
* if any are currently in an IN_PROGRESS or otherwise unsafe state.
|
|
@@ -8,3 +25,27 @@ import type { CloudFormationService } from "../services/infrastructure/CloudForm
|
|
|
8
25
|
* is blocking — specifically `safeToRedeploy === "No"`.
|
|
9
26
|
*/
|
|
10
27
|
export declare function checkActiveDeployments(stackNames: string[], cfnService: CloudFormationService): Promise<Result<void>>;
|
|
28
|
+
/**
|
|
29
|
+
* Deploy-path blocking classification (P0.5). Deliberately stricter than the
|
|
30
|
+
* destroy guard's `safeToRedeploy === "No"` check:
|
|
31
|
+
*
|
|
32
|
+
* - every `*_IN_PROGRESS` status blocks EXCEPT `REVIEW_IN_PROGRESS` (a
|
|
33
|
+
* change-set awaiting execution holds no stack lock)
|
|
34
|
+
* - `DELETE_FAILED` blocks (the map says "Maybe" for destroy's benefit, but a
|
|
35
|
+
* deploy into a half-deleted stack only wedges it further)
|
|
36
|
+
* - any status this build cannot classify blocks by DEFAULT — a new
|
|
37
|
+
* CloudFormation status is more likely a new in-progress state than a new
|
|
38
|
+
* terminal one, so fail closed rather than race it
|
|
39
|
+
*
|
|
40
|
+
* Known terminal states (complete, failed, rolled back) pass: CloudFormation
|
|
41
|
+
* accepts an update there, and deployability is the deploy's own problem.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isDeployPathBlockingStatus(status: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Deploy-path pre-flight (P0.5): reject the deploy BEFORE any image
|
|
46
|
+
* build/push when a target stack is mid-operation or in an unclassifiable
|
|
47
|
+
* state. Unlike `checkActiveDeployments` (the destroy guard) there is NO
|
|
48
|
+
* `--force` bypass — deploying over an in-flight operation cannot be a
|
|
49
|
+
* deliberate recovery action the way a forced destroy can.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkDeployPathStackAvailability(stackNames: string[], cfnService: CloudFormationService, abortSignal?: AbortSignal): Promise<Result<void>>;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import{success as
|
|
2
|
-
`);return
|
|
3
|
-
${
|
|
1
|
+
import{success as u,failure as c}from"@fjall/generator";import{stackStatusMap as l}from"../aws/utils/stackStatus.js";import{BaseServiceError as f}from"../types/errors/ServiceError.js";class p extends f{stacks;constructor(r,o){super("STACK_UNAVAILABLE",r),this.stacks=o}}async function E(t,r){if(t.length===0)return u(void 0);const o=await Promise.all(t.map(async n=>{const e=await r.getStackStatus(n);return{name:n,result:e}})),a=[];for(const{name:n,result:e}of o){if(!e.success)return c(e.error);const s=e.data;if(s===null||s.status==="DOES_NOT_EXIST")continue;l[s.status]?.safeToRedeploy==="No"&&a.push({name:n,status:s.status})}if(a.length>0){const n=a.map(e=>` ${e.name}: ${e.status}`).join(`
|
|
2
|
+
`);return c(new Error(`Cannot proceed while stacks are busy:
|
|
3
|
+
${n}
|
|
4
4
|
|
|
5
|
-
Wait for the in-progress operation to complete, or use --force to override.`))}return
|
|
5
|
+
Wait for the in-progress operation to complete, or use --force to override.`))}return u(void 0)}function d(t){return t==="REVIEW_IN_PROGRESS"?!1:t.endsWith("_IN_PROGRESS")||t==="DELETE_FAILED"?!0:l[t]===void 0||t==="UNKNOWN"}function S(t){const r=t.map(a=>` ${a.name}: ${a.status}`).join(`
|
|
6
|
+
`);return`Cannot start this deployment \u2014 ${t.length===1?"a CloudFormation stack is not available":"CloudFormation stacks are not available"}:
|
|
7
|
+
${r}
|
|
8
|
+
|
|
9
|
+
Another operation may be in progress or need attention. Wait for it to finish, then retry. Check progress in the Fjall dashboard.`}async function y(t,r,o){if(t.length===0)return u(void 0);const a=await Promise.all(t.map(async e=>{const s=await r.getStackStatus(e,void 0,o);return{name:e,result:s}})),n=[];for(const{name:e,result:s}of a){if(!s.success)return c(s.error);const i=s.data;i===null||i.status==="DOES_NOT_EXIST"||d(i.status)&&n.push({name:e,status:i.status})}return n.length>0?c(new p(S(n),n)):u(void 0)}export{p as StackUnavailableError,E as checkActiveDeployments,y as checkDeployPathStackAvailability,d as isDeployPathBlockingStatus};
|
|
@@ -2,6 +2,15 @@ import { type Result } from "@fjall/generator";
|
|
|
2
2
|
import type { DeployParams, DeployResult } from "../../types/params.js";
|
|
3
3
|
import type { ApplicationOperation } from "../../types/operations.js";
|
|
4
4
|
import type { DeployServices } from "../serviceFactory.js";
|
|
5
|
+
/**
|
|
6
|
+
* Surface the stacks this operation will mutate (§5.9 reconciler coordinates),
|
|
7
|
+
* post-plan and before the first mutating CFN op. A reconciler persists these
|
|
8
|
+
* so a crashed run's in-flight stacks can be located by name/account/region
|
|
9
|
+
* without waiting for failure output. No-ops when no consumer wired the
|
|
10
|
+
* callback or the operation touches no stacks (fully skipped re-run).
|
|
11
|
+
* Shared by the deploy and destroy legs (F-X7) — one emission contract.
|
|
12
|
+
*/
|
|
13
|
+
export declare function emitStackTargets(callbacks: DeployParams["callbacks"], services: DeployServices, stackNames: readonly string[]): void;
|
|
5
14
|
/**
|
|
6
15
|
* Core application deployment orchestration.
|
|
7
16
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as q}from"path";import{CloudFormationClient as X}from"@aws-sdk/client-cloudformation";import{EC2Client as Z}from"@aws-sdk/client-ec2";import{success as S,failure as l}from"@fjall/generator";import{logger as I}from"@fjall/util/logger";import{ImageTagSchema as ee,imageTagParameterName as te,maskSensitiveOutput as k}from"@fjall/util";import{parseDockerServicesFromManifest as re}from"@fjall/util/manifest";import{stubCallerIdentity as ae}from"../../types/deployment/index.js";import{getApplicationDeployOrder as oe,getApplicationStackName as ne,getApplicationStepName as W,getApplicationStepId as z,APPLICATION_STACKS as O}from"../../types/operations.js";import{CdkContextBuilder as ie}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as se,bootstrapOrFail as ce}from"../contextHelpers.js";import{runDetectionPipeline as le}from"./detectionPipeline.js";import{STEP_IDS as P,STEP_NAMES as de}from"../../types/stepDefinitions.js";import{StepRegistry as pe}from"../../steps/stepRegistry.js";import{checkTargetReadiness as ue}from"../../aws/targetReadiness.js";import{cascadeHomeRegion as ge}from"../organisation/cascadeHelpers.js";import{withStepLifecycle as me}from"../stepLifecycle.js";import{DOCKER_BUILD_STEP_NAME as Y,runDockerBuild as fe}from"./dockerBuildHelper.js";import{getParallelPhase2Stacks as ke,deployParallelPhase as ye,deployStackSequential as he,runDockerPreCompute as be,createBuildCallbacks as Te}from"./applicationDeployHelpers.js";import{deployCodeOnly as we}from"./codeOnlyDeploy.js";import{collectFullDeployArtefacts as Se}from"./artefactCollection.js";import{runApprovalGate as ve}from"./approvalGate.js";const N="applicationDeploy";function De(t){const s=Object.entries(t);if(s.length===0)return;const n={};for(const[r,i]of s){const h=te(r);n[h]=i}return n}function Ee(t){if(t?.mode!==void 0&&t.mode!=="rollback"){if(t.imageTag)return l(new Error(`--image-tag requires rollback mode (explicit mode '${t.mode}' was supplied alongside an image tag)`));if(t.serviceImageTags)return l(new Error(`serviceImageTags requires rollback mode (explicit mode '${t.mode}' was supplied alongside serviceImageTags)`))}if(t?.mode==="rollback"){if(t.imageTag&&t.serviceImageTags)return l(new Error("rollback mode accepts exactly one of --image-tag or serviceImageTags \u2014 they are mutually exclusive"));if(!t.imageTag&&!t.serviceImageTags)return l(new Error("rollback mode requires --image-tag <tag> or serviceImageTags naming the image(s) to roll to"))}if(t?.serviceImageTags!==void 0){if(t.serviceName)return l(new Error("serviceImageTags already names its services \u2014 --service cannot be combined with it"));const s=Object.entries(t.serviceImageTags);if(s.length===0)return l(new Error("serviceImageTags must name at least one service"));for(const[n,r]of s){const i=ee.safeParse(r);if(!i.success)return l(new Error(`serviceImageTags.${n} is not a valid image tag: ${i.error.message}`))}}return S(void 0)}async function Je(t,s,n){const{callbacks:r,options:i}=t,h=Date.now(),v=i?.mode??(i?.imageTag||i?.serviceImageTags?"rollback":i?.deployOnly?"code-only":"full");if(v==="restart"){const e=new Error('mode "restart" is not a deploy \u2014 call the restart() entry point (fjall rollout) instead');return r.onError?.(e),l(e)}const M=Ee(i);if(!M.success){const e=k(M.error.message),a=new Error(e);return r.onError?.(a),l(a)}const D=ie.buildDeploymentContext({deployType:"application",target:n.appName,path:n.path,region:s.awsProvider.getRegion(),callerIdentity:ae(s.awsProvider.getAccountId()),...se({orgConfig:t.orgConfig,identity:t.identity,skipOidc:t.options?.skipOidc})},{verbose:i?.verbose,infraOnly:i?.infraOnly},t.orgConfig),u=s.frameworkRegistry.resolve({appPath:n.path});let E;const T=v==="rollback";if(u&&!T){E=u.builder.plan({appPath:n.path},u.detection);const e=Te(r),a=await u.builder.build(n.path,E,e,{skipBuild:i?.skipBuild,infraOnly:i?.infraOnly});if(!a.success){const o=new Error(k(a.error.message));return r.onError?.(o),l(o)}}if(v==="code-only"||T){r.onLog?.(T?i?.serviceImageTags?`Rollback mode \u2014 rolling ${Object.keys(i.serviceImageTags).length} service(s) to their release-recorded image tags`:`Rollback mode \u2014 rolling to image tag ${i?.imageTag}`:"Deploy-only mode \u2014 skipping infrastructure pipeline","info");const e=q(n.path,"cdk.out"),a=re(e),o=a.length>0,p=u?.detection.hasDockerfile===!0,d=o||p;I.debug(N,"Deploy-only branch entered",{mode:v,imageTag:i?.imageTag,serviceImageTags:i?.serviceImageTags,appName:n.appName,appPath:n.path,cdkOutPath:e,dockerProviderAvailable:t.dockerProvider!==void 0,builderName:u?.builder.name,hasDockerfileFromManifest:o,hasDockerfileFromDisk:p,hasDockerfile:d,manifestDockerServiceCount:a.length,manifestDockerPaths:a.map(y=>y.docker.path)}),!o&&!p&&r.onLog?.("No Dockerfile detected via manifest or appPath \u2014 skipping Docker build. If this app uses a cross-repo Dockerfile, ensure a full deploy has run first to populate cdk.out/fjall-manifest.json.","warn");let g={};if(!T&&t.dockerProvider!==void 0&&d){I.debug(N,"Running Docker build before code-only deploy",{source:o?"manifest":"disk"});const y=await fe(t,s,n,r);if(!y.success)return l(y.error);g=y.data.contentHashTagsByService}else I.debug(N,"Skipping Docker build",{reason:T?"rollback":t.dockerProvider===void 0?"no dockerProvider":"no Dockerfile detected"});return we(t,s,n,g)}r.onLog?.("Analysing infrastructure\u2026","info");const R=await le(n,s,D,r);if(!R.success){const e=new Error(k(R.error.message));return r.onError?.(e),l(e)}const c=R.data;try{await r.onDetectionComplete?.({...c,builderName:u?.builder.name??"unknown"})}catch(e){const a=e instanceof Error?e.message:String(e),o=new Error(k(a));return r.onError?.(o),l(o)}const J={deploymentType:"application",operation:"deploy",deployOnly:!1,infraOnly:i?.infraOnly??!1,hasDockerfile:c.hasDockerfile,pattern:c.pattern,resources:c.resources,...u&&{builderName:u.builder.name}},x=pe.getSteps(J),L=x.findIndex(e=>e.id===P.TARGET_READINESS),_=await me(r,{stepId:P.TARGET_READINESS,stepName:de.TARGET_READINESS,...L>=0&&{stepIndex:L,totalSteps:x.length}},async()=>{if(i?.skipReadinessCheck)return r.onLog?.("Skipping target readiness check (--skip-readiness-check)","warn"),{kind:"skipped",data:void 0};const e=s.awsProvider.getAccountId(),a=t.orgConfig?.providerAccounts.find(g=>g.id===e)?.name,o=s.awsProvider.getCredentials(),p=ge(t.orgConfig),d=await ue({cloudFormation:s.awsProvider.getClient(X),ec2:new Z({region:p,...o!==void 0&&{credentials:o}})},{id:e,...a!==void 0&&{name:a}},s.awsProvider.getRegion(),t.orgConfig,t.abortSignal);return d.success?d.data.ready?{kind:"completed",data:void 0}:{kind:"error",error:new Error(k(d.data.advisory))}:{kind:"error",error:new Error(k(d.error.message))}},t.abortSignal);if(!_.success)return _;const f=E?E.deployOrder:oe({pattern:c.pattern,resources:c.resources}),b=f.length,j=c.hasDockerfile&&t.dockerProvider!==void 0&&f.includes(O.COMPUTE)&&i?.infraOnly!==!0;if(!c.hasDifferences&&!i?.force&&!j){r.onLog?.("No infrastructure changes detected","info"),r.onLog?.(i?.infraOnly===!0?"Infrastructure-only mode \u2014 application code was not rebuilt. Run with --deploy-only to deploy code changes.":"Nothing to deploy. Run with --deploy-only to redeploy application code.","info");const e=c.hasDockerfile&&t.dockerProvider!==void 0&&f.includes(O.COMPUTE);for(let o=0;o<f.length;o++){const p=f[o];e&&p===O.COMPUTE&&(r.onStepStart?.(P.DOCKER_OPERATIONS,Y),r.onStepComplete?.(P.DOCKER_OPERATIONS,Y,"skipped"));const d=z(p,"deploy"),g=W(p,"deploy");r.onStepStart?.(d,g,o,b),r.onStepComplete?.(d,g,"skipped",o,b)}const a=await s.stackService.resolveWebsiteUrl(n.appName);return S({target:n.appName,deploymentType:"application",outputs:a?{websiteUrl:a}:void 0,noChanges:!0,artefacts:[],durationMs:Date.now()-h})}if(t.approvalGate!==void 0||i?.approvalToken!==void 0&&i.approvalToken!==""||i?.planOnly===!0){const e=q(n.path,"cdk.out"),a=await ve({approvalGate:t.approvalGate,options:i??{},target:n.appName,cdkOutPath:e,detection:{stackChanges:c.stackChanges,currentHashes:c.currentHashes},cfnService:s.cfnService,callbacks:r});if(!a.success)return a;const o=a.data;if(o.kind==="rejected")return r.onLog?.(`Deploy rejected: ${k(o.reason)}`,"warn"),S({target:n.appName,deploymentType:"application",rejected:!0,artefacts:[],...o.planDetail!==void 0?{planDetail:o.planDetail}:{},durationMs:Date.now()-h});if(o.kind==="awaiting")return S({target:n.appName,deploymentType:"application",awaitingApproval:!0,approvalToken:o.approvalToken,assemblyDigest:o.assemblyDigest,planDetail:o.planDetail,artefacts:[],durationMs:Date.now()-h})}const B=await ce(s,D,r);if(!B.success)return B;const w={},C=new Map;let H;for(let e=0;e<f.length;e++){const a=f[e],o=ne(n.appName,a),p=z(a,"deploy"),d=W(a,"deploy"),g=c.stackChanges.get(o)??!0,y=a===O.COMPUTE&&j;if(!g&&!i?.force&&!y){r.onStepStart?.(p,d,e,b),r.onLog?.(`Skipping ${a} \u2014 no changes detected`,"info"),r.onStepComplete?.(p,d,"skipped",e,b);continue}const A=ke(f,e,c.stackChanges,n.appName,i?.force);if(A.length>=2){const K=await ye(A,n,s,D,r,e,b,c,w,C);if(!K.success)return l(K.error);e+=A.length-1;continue}const m=await be(a,t,s,n,r,c.hasDockerfile);if(m!==null&&!m.success)return l(m.error);m!==null&&m.success&&(H=m.data);const V=m!==null&&m.success?m.data.contentHashTagsByService:{},G=De(V),$=await he(a,s,D,r,e,b,w,G!==void 0?{parameters:G}:void 0);if(!$.success)return l($.error);const F=c.currentHashes.get(o);F&&C.set(o,F)}if(C.size>0){const e=await s.hashService.updateStateAfterDeploy(n.path,C);if(!e.success){const a=k(e.error.message);I.debug(N,"Failed to update state file",{error:a}),r.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy unchanged stacks: ${a}`,"warn")}}const U=await s.stackService.resolveWebsiteUrl(n.appName);U&&(w.websiteUrl=U);const Q=await Se(s,n.appName,H,r);return S({target:n.appName,deploymentType:"application",outputs:Object.keys(w).length>0?w:void 0,artefacts:Q,durationMs:Date.now()-h})}export{Je as deployApplication};
|
|
1
|
+
import{join as ie}from"path";import{CloudFormationClient as he}from"@aws-sdk/client-cloudformation";import{EC2Client as Se}from"@aws-sdk/client-ec2";import{success as E,failure as d}from"@fjall/generator";import{logger as M}from"@fjall/util/logger";import{ImageTagSchema as be,getErrorMessage as se,imageTagParameterName as we,maskSensitiveOutput as y}from"@fjall/util";import{parseDockerServicesFromManifest as Te}from"@fjall/util/manifest";import{stubCallerIdentity as Ne}from"../../types/deployment/index.js";import{getApplicationDeployOrder as Ee,getApplicationStackName as I,getApplicationStepName as ce,getApplicationStepId as le,APPLICATION_STACKS as P}from"../../types/operations.js";import{CdkContextBuilder as Pe}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as ve,bootstrapOrFail as De}from"../contextHelpers.js";import{runDetectionPipeline as Re}from"./detectionPipeline.js";import{STEP_IDS as G,STEP_NAMES as Ie}from"../../types/stepDefinitions.js";import{StepRegistry as Ce}from"../../steps/stepRegistry.js";import{checkTargetReadiness as Oe}from"../../aws/targetReadiness.js";import{cascadeHomeRegion as Ae}from"../organisation/cascadeHelpers.js";import{withStepLifecycle as Le}from"../stepLifecycle.js";import{DOCKER_BUILD_STEP_NAME as de,runDockerBuild as Me}from"./dockerBuildHelper.js";import{getParallelPhase2Stacks as Fe,getStackNamesToDeploy as $e,deployParallelPhase as xe,deployStackSequential as Be,runDockerPreCompute as je,createBuildCallbacks as Ge}from"./applicationDeployHelpers.js";import{captureDatabaseConnectionOutputs as _e,captureServiceTaskDefinitions as Ue,reconcileDatabaseEndpointChange as He}from"./databaseEndpointReconcile.js";import{deployCodeOnly as Ke}from"./codeOnlyDeploy.js";import{checkDeployPathStackAvailability as ue}from"../activeDeploymentGuard.js";import{assertLeaseBeforeStack as _}from"./leaseGate.js";import{collectFullDeployArtefacts as We}from"./artefactCollection.js";import{CfnRegistryService as qe}from"../../services/infrastructure/CfnRegistryService.js";import{ChangeSetProbe as ze}from"../../services/infrastructure/changeSetProbe.js";import{runApprovalGate as Je}from"./approvalGate.js";import{buildDestructionTicket as Ye,runDestructionGate as Qe}from"./destructionGate.js";import{DESTRUCTION_RESUME_TTL_MS as Ve,signApprovalToken as Xe}from"./plan/approvalToken.js";import{computeAssemblyDigest as Ze}from"./plan/assemblyDigest.js";import{createMemoisedPlanLoader as et}from"./plan/loadDeployPlan.js";import{runDriftPreFlightGate as tt}from"../drift/preFlightGate.js";import{completeForgetAfterDeploy as rt}from"../remediation/forgetResource.js";import{composePostFailureRepairOffer as pe}from"../remediation/postFailureRepairOffer.js";import{renderPinReportLines as at,runPinRemediation as nt}from"../remediation/pinRemediation.js";import{runRecreatePreFlight as ot}from"../remediation/recreatePreFlight.js";import{runRecreateSurgery as it}from"../remediation/recreateResource.js";const F="applicationDeploy";function st(e){const a=Object.entries(e);if(a.length===0)return;const n={};for(const[t,i]of a){const h=we(t);n[h]=i}return n}function ct(e){if(e?.mode!==void 0&&e.mode!=="rollback"){if(e.imageTag)return d(new Error(`--image-tag requires rollback mode (explicit mode '${e.mode}' was supplied alongside an image tag)`));if(e.serviceImageTags)return d(new Error(`serviceImageTags requires rollback mode (explicit mode '${e.mode}' was supplied alongside serviceImageTags)`))}if(e?.mode==="rollback"){if(e.imageTag&&e.serviceImageTags)return d(new Error("rollback mode accepts exactly one of --image-tag or serviceImageTags \u2014 they are mutually exclusive"));if(!e.imageTag&&!e.serviceImageTags)return d(new Error("rollback mode requires --image-tag <tag> or serviceImageTags naming the image(s) to roll to"))}if(e?.serviceImageTags!==void 0){if(e.serviceName)return d(new Error("serviceImageTags already names its services \u2014 --service cannot be combined with it"));const a=Object.entries(e.serviceImageTags);if(a.length===0)return d(new Error("serviceImageTags must name at least one service"));for(const[n,t]of a){const i=be.safeParse(t);if(!i.success)return d(new Error(`serviceImageTags.${n} is not a valid image tag: ${i.error.message}`))}}return E(void 0)}function ge(e,a,n){if(e.onStackTargets===void 0||n.length===0)return;const t=a.awsProvider.getAccountId(),i=a.awsProvider.getRegion();e.onStackTargets(n.map(h=>({stackName:h,...t!==""?{accountId:t}:{},...i!==""?{region:i}:{}})))}async function qt(e,a,n){const{callbacks:t,options:i}=e,h=Date.now(),$=i?.mode??(i?.imageTag||i?.serviceImageTags?"rollback":i?.deployOnly?"code-only":"full");if($==="restart"){const r=new Error('mode "restart" is not a deploy \u2014 call the restart() entry point (fjall rollout) instead');return t.onError?.(r),d(r)}const J=ct(i);if(!J.success){const r=y(J.error.message),o=new Error(r);return t.onError?.(o),d(o)}const x=Pe.buildDeploymentContext({deployType:"application",target:n.appName,path:n.path,region:a.awsProvider.getRegion(),callerIdentity:Ne(a.awsProvider.getAccountId()),...ve({orgConfig:e.orgConfig,identity:e.identity,skipOidc:e.options?.skipOidc})},{verbose:i?.verbose,infraOnly:i?.infraOnly},e.orgConfig),b=a.frameworkRegistry.resolve({appPath:n.path});let B;const C=$==="rollback";if(b&&!C){B=b.builder.plan({appPath:n.path},b.detection);const r=Ge(t),o=await b.builder.build(n.path,B,r,{skipBuild:i?.skipBuild,infraOnly:i?.infraOnly});if(!o.success){const s=new Error(y(o.error.message));return t.onError?.(s),d(s)}}if($==="code-only"||C){t.onLog?.(C?i?.serviceImageTags?`Rollback mode \u2014 rolling ${Object.keys(i.serviceImageTags).length} service(s) to their release-recorded image tags`:`Rollback mode \u2014 rolling to image tag ${i?.imageTag}`:"Deploy-only mode \u2014 skipping infrastructure pipeline","info");const r=ie(n.path,"cdk.out"),o=Te(r),s=o.length>0,p=b?.detection.hasDockerfile===!0,l=s||p;M.debug(F,"Deploy-only branch entered",{mode:$,imageTag:i?.imageTag,serviceImageTags:i?.serviceImageTags,appName:n.appName,appPath:n.path,cdkOutPath:r,dockerProviderAvailable:e.dockerProvider!==void 0,builderName:b?.builder.name,hasDockerfileFromManifest:s,hasDockerfileFromDisk:p,hasDockerfile:l,manifestDockerServiceCount:o.length,manifestDockerPaths:o.map(m=>m.docker.path)}),!s&&!p&&t.onLog?.("No Dockerfile detected via manifest or appPath \u2014 skipping Docker build. If this app uses a cross-repo Dockerfile, ensure a full deploy has run first to populate cdk.out/fjall-manifest.json.","warn");const u=await ue([I(n.appName,P.COMPUTE)],a.cfnService,e.abortSignal);if(!u.success)return t.onError?.(u.error),d(u.error);ge(t,a,[I(n.appName,P.COMPUTE)]);let k={};if(!C&&e.dockerProvider!==void 0&&l){M.debug(F,"Running Docker build before code-only deploy",{source:s?"manifest":"disk"});const m=await Me(e,a,n,t);if(!m.success)return d(m.error);k=m.data.contentHashTagsByService}else M.debug(F,"Skipping Docker build",{reason:C?"rollback":e.dockerProvider===void 0?"no dockerProvider":"no Dockerfile detected"});const c=await _(e.assertLeaseForStack,I(n.appName,P.COMPUTE),e.abortSignal);return c!==void 0?(t.onError?.(c),d(c)):Ke(e,a,n,k)}t.onLog?.("Analysing infrastructure\u2026","info");const U=await Re(n,a,x,t);if(!U.success){const r=new Error(y(U.error.message));return t.onError?.(r),d(r)}const f=U.data;try{await t.onDetectionComplete?.({...f,builderName:b?.builder.name??"unknown"})}catch(r){const o=new Error(y(se(r)));return t.onError?.(o),d(o)}const fe={deploymentType:"application",operation:"deploy",deployOnly:!1,infraOnly:i?.infraOnly??!1,hasDockerfile:f.hasDockerfile,pattern:f.pattern,resources:f.resources,...b&&{builderName:b.builder.name}},Y=Ce.getSteps(fe),Q=Y.findIndex(r=>r.id===G.TARGET_READINESS),V=await Le(t,{stepId:G.TARGET_READINESS,stepName:Ie.TARGET_READINESS,...Q>=0&&{stepIndex:Q,totalSteps:Y.length}},async()=>{if(i?.skipReadinessCheck)return t.onLog?.("Skipping target readiness check (--skip-readiness-check)","warn"),{kind:"skipped",data:void 0};const r=a.awsProvider.getAccountId(),o=e.orgConfig?.providerAccounts.find(u=>u.id===r)?.name,s=a.awsProvider.getCredentials(),p=Ae(e.orgConfig),l=await Oe({cloudFormation:a.awsProvider.getClient(he),ec2:new Se({region:p,...s!==void 0&&{credentials:s}})},{id:r,...o!==void 0&&{name:o}},a.awsProvider.getRegion(),e.orgConfig,e.abortSignal);return l.success?l.data.ready?{kind:"completed",data:void 0}:{kind:"error",error:new Error(y(l.data.advisory))}:{kind:"error",error:new Error(y(l.error.message))}},e.abortSignal);if(!V.success)return V;const w=B?B.deployOrder:Ee({pattern:f.pattern,resources:f.resources}),v=w.length,X=f.hasDockerfile&&e.dockerProvider!==void 0&&w.includes(P.COMPUTE)&&i?.infraOnly!==!0;if(!f.hasDifferences&&!i?.force&&!X){t.onLog?.("No infrastructure changes detected","info"),t.onLog?.(i?.infraOnly===!0?"Infrastructure-only mode \u2014 application code was not rebuilt. Run with --deploy-only to deploy code changes.":"Nothing to deploy. Run with --deploy-only to redeploy application code.","info");const r=f.hasDockerfile&&e.dockerProvider!==void 0&&w.includes(P.COMPUTE);for(let s=0;s<w.length;s++){const p=w[s];r&&p===P.COMPUTE&&(t.onStepStart?.(G.DOCKER_OPERATIONS,de),t.onStepComplete?.(G.DOCKER_OPERATIONS,de,"skipped"));const l=le(p,"deploy"),u=ce(p,"deploy");t.onStepStart?.(l,u,s,v),t.onStepComplete?.(l,u,"skipped",s,v)}const o=await a.stackService.resolveWebsiteUrl(n.appName);return E({target:n.appName,deploymentType:"application",outputs:o?{websiteUrl:o}:void 0,noChanges:!0,artefacts:[],durationMs:Date.now()-h})}const H=ie(n.path,"cdk.out"),N=$e({deployOrder:w,stackChanges:f.stackChanges,appName:n.appName,force:i?.force===!0,computeBuildPossible:X});ge(t,a,[...N]);const K=await ue([...N],a.cfnService,e.abortSignal);if(!K.success)return t.onError?.(K.error),d(K.error);const Z=Ze(f.currentHashes),W=et({cfnService:a.cfnService,cdkOutPath:H,changedStacks:[...N],assemblyDigest:Z,registry:new qe(a.awsProvider),changeSetProbe:new ze(a.awsProvider),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}),q=await tt(a.awsProvider,{stackNames:[...N],cdkOutPath:H,cfnService:a.cfnService,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(q.kind==="blocked"){const r=new Error(q.message);return t.onError?.(r),d(r)}const ee=q.verifiedAbsentByNecessity??[],te=e.approvalGate!==void 0||i?.approvalToken!==void 0&&i.approvalToken!==""||i?.planOnly===!0;if(te){const r=await Je({approvalGate:e.approvalGate,options:i??{},target:n.appName,cdkOutPath:H,detection:{stackChanges:f.stackChanges,currentHashes:f.currentHashes},cfnService:a.cfnService,loadPlan:W,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!r.success)return r;const o=r.data;if(o.kind==="rejected")return t.onLog?.(`Deploy rejected: ${y(o.reason)}`,"warn"),E({target:n.appName,deploymentType:"application",rejected:!0,artefacts:[],...o.planDetail!==void 0?{planDetail:o.planDetail}:{},durationMs:Date.now()-h});if(o.kind==="awaiting"){const s=await W(),p=s.success?Ye(s.data,ee):void 0;return E({target:n.appName,deploymentType:"application",awaitingApproval:!0,approvalToken:o.approvalToken,assemblyDigest:o.assemblyDigest,planDetail:o.planDetail,...p!==void 0?{destructionTicket:p}:{},artefacts:[],durationMs:Date.now()-h})}}const T=await Qe({loadPlan:W,options:i??{},target:n.appName,callbacks:t,verifiedAbsentByNecessity:ee,...e.destructionConsentGate!==void 0?{consentGate:e.destructionConsentGate}:{}});if(!T.success)return t.onError?.(T.error),d(T.error);if(T.data.kind==="withheld"){const r=te?Xe({assemblyDigest:Z,ttlMs:Ve}):void 0;return E({target:n.appName,deploymentType:"application",destructionPending:!0,destructionTicket:T.data.ticket,destructionOutcome:T.data.outcome,destructionHaltReasons:T.data.reasons,...r!==void 0?{destructionResumeToken:r.token,destructionResumeExpiresAt:r.expiresAt}:{},artefacts:[],durationMs:Date.now()-h})}if(T.data.kind==="proceed"){const{ticket:r,verbsByPhysicalName:o}=T.data,s=r.resources.filter(l=>o.get(l.physicalName)==="pin");if(s.length>0){t.onLog?.(`Pin remediation for ${n.appName}: probing live value(s) for ${s.length} consented pin(s) \u2014 deploy stopped for config write-back; nothing was applied`,"warn");const l=await nt(a.awsProvider,{targets:s.map(u=>({stack:u.stack,logicalId:u.logicalId,resourceType:u.resourceType,physicalName:u.physicalName,offendingProperties:u.offendingProperties})),...e.infrastructureSource!==void 0?{infrastructureContent:e.infrastructureSource.content,infrastructureFilePath:e.infrastructureSource.filePath}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});for(const u of at(l))t.onLog?.(u,"warn");return s.length<r.resources.length&&t.onLog?.("Remaining consented change(s) were not applied \u2014 the config write-back changes the plan, so they re-consent on the next deploy","warn"),E({target:n.appName,deploymentType:"application",pinPending:!0,pinReport:l,pinDeferredConsents:r.resources.length-s.length,destructionTicket:r,artefacts:[],durationMs:Date.now()-h})}const p=r.resources.filter(l=>l.finding==="pinned-name-replacement"&&o.get(l.physicalName)==="recreate");if(p.length>0){const l=new Map;for(const c of p){const m=l.get(c.stack)??[];m.push(c),l.set(c.stack,m)}const u=await ot(a.awsProvider,{stacks:[...l].map(([c,m])=>({stackName:c,targets:m.map(S=>({logicalId:S.logicalId,resourceType:S.resourceType,physicalId:S.physicalName}))})),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!u.success){const c=new Error(y(u.error.message));return t.onError?.(c),d(c)}const k=[];for(const[c,m]of l){const S=await _(e.assertLeaseForStack,c,e.abortSignal,"destroy");if(S!==void 0)return k.length>0&&t.onLog?.(`Surgery already completed on ${k.join("; ")} \u2014 those resources were removed and re-running the deploy resumes their journals and re-creates them.`,"warn"),t.onError?.(S),d(S);const R=m.map(g=>g.physicalName);t.onLog?.(`Recreate remediation for ${n.appName}: orchestrating the pinned-name replacement of ${R.join(", ")} on ${c}`,"warn");const L=await it(a.awsProvider,{stackName:c,targets:m.map(g=>({logicalId:g.logicalId,resourceType:g.resourceType,physicalId:g.physicalName})),appName:n.appName,consentedPhysicalNames:R,doneJournalPolicy:"archive-and-restart",plannedReplacementLogicalIds:m.map(g=>g.logicalId),onProgress:g=>t.onLog?.(g,"info"),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!L.success){const g=k.length>0?` Surgery already completed on ${k.join("; ")} \u2014 those resources were removed and re-running the deploy resumes their journals and re-creates them.`:"",j=new Error(y(`${L.error.message}${g}`));return t.onError?.(j),d(j)}k.push(`${c} (${R.join(", ")})`)}}}const re=await De(a,x,t);if(!re.success)return re;const ae=I(n.appName,P.DATABASE),z=N.has(ae),me=z?await _e(a.cfnService,n.appName):void 0,ke=z?await Ue(a.ecsResolver,a.ecsService,n.appName):void 0,O={},A=new Map;let ne;const D=async()=>{!z||!A.has(ae)||await He({appName:n.appName,connectionOutputsBefore:me,serviceTaskDefinitionsBefore:ke,services:{cfnService:a.cfnService,ecsService:a.ecsService,ecsResolver:a.ecsResolver},callbacks:t,...e.confirmDatabaseEndpointRestart!==void 0?{confirmRestart:e.confirmDatabaseEndpointRestart}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})};for(let r=0;r<w.length;r++){const o=w[r],s=I(n.appName,o),p=le(o,"deploy"),l=ce(o,"deploy");if(!N.has(s)){t.onStepStart?.(p,l,r,v),t.onLog?.(`Skipping ${o} \u2014 no changes detected`,"info"),t.onStepComplete?.(p,l,"skipped",r,v);continue}const u=await _(e.assertLeaseForStack,s,e.abortSignal);if(u!==void 0)return await D(),t.onError?.(u),d(u);const k=Fe(w,r,n.appName,N);if(k.length>=2){const g=await xe(k,n,a,x,t,r,v,f,O,A);if(!g.success)return await D(),d(await pe(a.awsProvider,{stackNames:k.map(j=>I(n.appName,j)),appName:n.appName,originalError:g.error,cfnService:a.cfnService,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}));r+=k.length-1;continue}const c=await je(o,e,a,n,t,f.hasDockerfile);if(c!==null&&!c.success)return await D(),d(c.error);c!==null&&c.success&&(ne=c.data);const m=c!==null&&c.success?c.data.contentHashTagsByService:{},S=st(m);if(c!==null){const g=await _(e.assertLeaseForStack,s,e.abortSignal);if(g!==void 0)return await D(),t.onError?.(g),d(g)}const R=await Be(o,a,x,t,r,v,O,S!==void 0?{parameters:S}:void 0);if(!R.success)return await D(),d(await pe(a.awsProvider,{stackNames:[s],appName:n.appName,originalError:R.error,cfnService:a.cfnService,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}));const L=f.currentHashes.get(s);L&&A.set(s,L)}if(await D(),A.size>0){const r=await a.hashService.updateStateAfterDeploy(n.path,A);if(!r.success){const o=y(r.error.message);M.debug(F,"Failed to update state file",{error:o}),t.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy unchanged stacks: ${o}`,"warn")}}const oe=await a.stackService.resolveWebsiteUrl(n.appName);oe&&(O.websiteUrl=oe);const ye=await We(a,n.appName,ne,t);return await rt(a.awsProvider,{stackNames:[...N],appName:n.appName,onLog:(r,o)=>t.onLog?.(r,o),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}).catch(r=>{M.debug(F,"Forget completion sweep failed",{error:y(se(r))})}),E({target:n.appName,deploymentType:"application",outputs:Object.keys(O).length>0?O:void 0,artefacts:ye,durationMs:Date.now()-h})}export{qt as deployApplication,ge as emitStackTargets};
|
|
@@ -7,12 +7,29 @@ import type { DeployServices } from "../serviceFactory.js";
|
|
|
7
7
|
import type { DetectionResult } from "./detectionPipeline.js";
|
|
8
8
|
import { type DockerBuildProducts } from "./dockerBuildHelper.js";
|
|
9
9
|
import type { BuildCallbacks } from "../../types/frameworkBuilder.js";
|
|
10
|
+
/**
|
|
11
|
+
* Single source of the deploy loop's stack-inclusion predicate: a stack
|
|
12
|
+
* deploys when its template hash changed, when `--force` overrides the hash
|
|
13
|
+
* gate, or when Compute must run for an image build. The destruction gate
|
|
14
|
+
* MUST diff exactly this set — a second derivation lets a hash-unchanged
|
|
15
|
+
* stack deploy under `--force` without the gate ever seeing its live diff
|
|
16
|
+
* (local v1 templates vs a live stack moved to v2 out-of-band: hashes match,
|
|
17
|
+
* the stack escapes the plan, and the forced deploy applies a destructive
|
|
18
|
+
* v2→v1 revert with no ticket).
|
|
19
|
+
*/
|
|
20
|
+
export declare function getStackNamesToDeploy(params: {
|
|
21
|
+
deployOrder: readonly ApplicationStack[];
|
|
22
|
+
stackChanges: ReadonlyMap<string, boolean>;
|
|
23
|
+
appName: string;
|
|
24
|
+
force: boolean;
|
|
25
|
+
computeBuildPossible: boolean;
|
|
26
|
+
}): ReadonlySet<string>;
|
|
10
27
|
/**
|
|
11
28
|
* Identify Phase 2 stacks (Storage, Messaging, Database) that are consecutive
|
|
12
|
-
* in the deploy order and
|
|
13
|
-
* only if there are at least 2.
|
|
29
|
+
* in the deploy order and included in the to-deploy set. Returns them for
|
|
30
|
+
* parallel deployment only if there are at least 2.
|
|
14
31
|
*/
|
|
15
|
-
export declare function getParallelPhase2Stacks(deployOrder: readonly ApplicationStack[], currentIndex: number,
|
|
32
|
+
export declare function getParallelPhase2Stacks(deployOrder: readonly ApplicationStack[], currentIndex: number, appName: string, stackNamesToDeploy: ReadonlySet<string>): ApplicationStack[];
|
|
16
33
|
/**
|
|
17
34
|
* Deploy a group of stacks in parallel, reporting step events for each.
|
|
18
35
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{success as h,failure as
|
|
2
|
-
`);return
|
|
1
|
+
import{success as h,failure as m}from"@fjall/generator";import{maskSensitiveOutput as w}from"@fjall/util";import{isAborted as R}from"../../aws/organisations/types.js";import{APPLICATION_STACKS as B,getApplicationStackName as y,getApplicationStepName as N,getApplicationStepId as C,PARALLEL_DEPLOY_GROUPS as k}from"../../types/operations.js";import{emitProgress as L}from"../../services/supporting/helpers.js";import{forwardOutput as x,forwardResourceProgress as I}from"../contextHelpers.js";import{emptyBuildProducts as _,runDockerBuild as D}from"./dockerBuildHelper.js";import{runWelcomeImageSetup as $}from"./welcomeImageHelper.js";import{withStepLifecycle as j}from"../stepLifecycle.js";function W(e){const r=new Set;for(const n of e.deployOrder){const u=y(e.appName,n),o=e.stackChanges.get(u)??!0,a=n===B.COMPUTE&&e.computeBuildPossible;(o||e.force||a)&&r.add(u)}return r}function Y(e,r,n,u){const o=new Set(k.PHASE_2.stacks),a=[];for(let s=r;s<e.length&&o.has(e[s]);s++)a.push(e[s]);if(a.length<2)return[];const p=a.filter(s=>u.has(y(n,s)));return p.length>=2?p:[]}async function z(e,r,n,u,o,a,p,s,g,S){for(let t=0;t<e.length;t++){const i=e[t],c=C(i,"deploy"),d=N(i,"deploy");o.onStepStart?.(c,d,a+t,p)}L(o,"Deploying infrastructure in parallel\u2026"),o.onParallelPhaseStart?.(e,"Storage and database resources (parallel)");const l=await n.stackService.deployStacksInParallel(e,u,{onOutput:x(o),onResourceProgress:(t,i)=>{o.onResourceProgress?.(t),i&&o.onParallelStackResourceProgress?.(i,t)},onStackComplete:(t,i,c,d)=>{const P=C(t,"deploy"),A=N(t,"deploy"),E=a+e.indexOf(t),O=R(n.abortSignal);o.onStepComplete?.(P,A,i?"completed":O?"cancelled":"error",E,p),!i&&d&&!O&&o.onError?.(new Error(w(d.message)))}});if(!l.success)return o.onParallelPhaseComplete?.([]),m(l.error);const f=l.data.filter(t=>!t.success);if(o.onParallelPhaseComplete?.(l.data.map(t=>({stack:t.stack,success:t.success,error:t.error}))),f.length>0){const t=f.map(c=>c.stack).join(", "),i=f.map(c=>`${c.stack}: ${w(c.error?.message??"Unknown error")}`).join(`
|
|
2
|
+
`);return m(new Error(`Failed to deploy stacks: ${t}
|
|
3
3
|
|
|
4
|
-
${
|
|
4
|
+
${i}`))}for(const t of l.data){if(t.success&&t.outputs)for(const[d,P]of Object.entries(t.outputs))g[d]=String(P);const i=y(r.appName,t.stack),c=s.currentHashes.get(i);c&&S.set(i,c)}return h(void 0)}async function J(e,r,n,u,o,a,p,s){const g=C(e,"deploy"),S=N(e,"deploy");return j(u,{stepId:g,stepName:S,stepIndex:o,totalSteps:a},async()=>{const l=await r.stackService.deployStack(e,n,{onOutput:x(u),onResourceProgress:I(u)},s?.parameters!==void 0?{parameters:s.parameters}:void 0);if(!l.success)return{kind:"error",error:l.error};if(l.data.outputs)for(const[f,t]of Object.entries(l.data.outputs))p[f]=String(t);return{kind:"completed",data:void 0}},r.abortSignal)}async function Q(e,r,n,u,o,a){if(e!==B.COMPUTE||!r.dockerProvider)return null;if(a){const s=await D(r,n,u,o);return s.success?h(s.data):m(s.error)}const p=await $(r,n,u,o);return p.success?h(_()):m(p.error)}function V(e){return{onBuildStart:r=>{e.onOpenNextBuildStart?.(),e.onLog?.(`${r} build started`,"info")},onBuildProgress:(r,n)=>{e.onOpenNextProgress?.(n)},onBuildComplete:r=>{e.onOpenNextBuildComplete?.(),e.onLog?.(`${r} build complete`,"info")},onBuildError:(r,n)=>{e.onOpenNextBuildError?.(n)}}}export{V as createBuildCallbacks,z as deployParallelPhase,J as deployStackSequential,Y as getParallelPhase2Stacks,W as getStackNamesToDeploy,Q as runDockerPreCompute};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as w,failure as
|
|
1
|
+
import{success as w,failure as N}from"@fjall/generator";import{getErrorMessage as S}from"@fjall/util";import{logger as y}from"@fjall/util/logger";import{getApplicationDestroyOrder as b,getApplicationStackName as x,getApplicationStepName as h,getApplicationStepId as P}from"../../types/operations.js";import{emitStackTargets as D}from"./applicationDeploy.js";import{stubCallerIdentity as L}from"../../types/deployment/index.js";import{deriveResourcesFromManifestStacks as R}from"../../types/detection/patternDetection.js";import{CdkContextBuilder as A}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as F}from"../contextHelpers.js";import{deleteStateFile as I,readStateFile as O}from"../../types/config/FjallState.js";async function J(a,s,r){const{callbacks:t}=a,k=Date.now(),m=s.frameworkRegistry.resolve({appPath:r.path})?.detection.pattern??null;let d;try{const e=await O(r.path);if(e!==null){const o=Object.keys(e.templateHashes);o.length>0&&(d=R(o))}}catch(e){y.debug("applicationDestroy","Could not read state file for resource detection",{error:S(e)}),t.onLog?.("Could not read state file for resource detection \u2014 falling back to pattern detection","warn")}const C=A.buildDeploymentContext({deployType:"application",target:r.appName,path:r.path,region:s.awsProvider.getRegion(),callerIdentity:L(s.awsProvider.getAccountId()),...F({orgConfig:a.orgConfig,identity:a.identity})},{verbose:a.options?.verbose},a.orgConfig),p=b({pattern:m,resources:d}),l=p.length;t.onLog?.(`Destroying ${r.appName} (${l} stacks, ${m??"standard"} pattern)`,"info"),D(t,s,p.map(e=>x(r.appName,e)));const f=[],u=[],g=await s.stackService.destroyAllStacks(C,{onOutput:e=>{t.onOutput?.(e)},onLog:t.onLog,onStackCleanupProgress:t.onStackCleanupProgress,onResourceProgress:(e,o)=>{t.onResourceProgress?.(e),o&&t.onParallelStackResourceProgress?.(o,e)},onStackStart:(e,o)=>{const n=P(e,"destroy"),i=h(e,"destroy"),c=p.indexOf(e);t.onStepStart?.(n,i,c,l)},onStackComplete:async(e,o)=>{const n=P(e,"destroy"),i=h(e,"destroy"),c=p.indexOf(e);o.success?o.data?.skipped?(u.push(o.data.stackName||e),t.onStepComplete?.(n,i,"skipped",c,l)):(f.push(o.data?.stackName||e),t.onStepComplete?.(n,i,"completed",c,l)):(t.onStepComplete?.(n,i,"error",c,l),t.onError?.(o.error))},onParallelPhaseStart:(e,o)=>{t.onLog?.(`Parallel phase: ${o}`,"info"),t.onParallelPhaseStart?.(e,o)},onParallelPhaseComplete:e=>{const o=e.filter(n=>!n.success);o.length>0&&t.onLog?.(`Parallel phase completed with ${o.length} failure(s)`,"warn"),t.onParallelPhaseComplete?.(e)}},d,a.abortSignal,a.assertLeaseForStack);if(!g.success)return t.onError?.(g.error),N(g.error);try{await I(r.path)}catch(e){y.debug("applicationDestroy","Failed to delete state file (non-critical)",{error:S(e)}),t.onLog?.("Failed to delete state file (non-critical)","warn")}return w({target:r.appName,deploymentType:"application",stacksDestroyed:f,skippedStacks:u,durationMs:Date.now()-k})}export{J as destroyApplication};
|
|
@@ -16,7 +16,9 @@ import { type Result } from "@fjall/generator";
|
|
|
16
16
|
import type { DeployCallbacks } from "../../types/callbacks.js";
|
|
17
17
|
import type { DeployOptions } from "../../types/params.js";
|
|
18
18
|
import type { ApprovalGate, ApprovalGatePlanDetail } from "../../types/approval.js";
|
|
19
|
-
import {
|
|
19
|
+
import type { CfnRegistrySummaryReader } from "../../services/infrastructure/CfnRegistryService.js";
|
|
20
|
+
import type { CfnTemplateReader } from "./plan/computeDeployPlan.js";
|
|
21
|
+
import { type DeployPlanLoader } from "./plan/loadDeployPlan.js";
|
|
20
22
|
export interface RunApprovalGateParams {
|
|
21
23
|
/** The surface resolver. Optional — a token-resume or plan-only run needs none. */
|
|
22
24
|
approvalGate?: ApprovalGate;
|
|
@@ -28,7 +30,19 @@ export interface RunApprovalGateParams {
|
|
|
28
30
|
currentHashes: ReadonlyMap<string, string>;
|
|
29
31
|
};
|
|
30
32
|
cfnService: CfnTemplateReader;
|
|
33
|
+
/**
|
|
34
|
+
* Registry oracle for replacement-verdict recomputation. Optional — without
|
|
35
|
+
* it plan rows keep raw cloudformation-diff verdicts.
|
|
36
|
+
*/
|
|
37
|
+
registry?: CfnRegistrySummaryReader;
|
|
38
|
+
/**
|
|
39
|
+
* Injected (memoised) plan supplier — applicationDeploy shares one loader
|
|
40
|
+
* between this gate and the unconditional destruction gate so a plan-gated
|
|
41
|
+
* deploy never diffs twice. Omitted, the gate builds its own.
|
|
42
|
+
*/
|
|
43
|
+
loadPlan?: DeployPlanLoader;
|
|
31
44
|
callbacks: DeployCallbacks;
|
|
45
|
+
abortSignal?: AbortSignal;
|
|
32
46
|
}
|
|
33
47
|
export type ApprovalGateOutcome = {
|
|
34
48
|
kind: "proceed";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{success as o,failure as g}from"@fjall/generator";import{computeAssemblyDigest as k}from"./plan/assemblyDigest.js";import{loadDeployPlan as v}from"./plan/loadDeployPlan.js";import{renderPlanLines as h}from"./plan/renderDeployPlan.js";import{signApprovalToken as y,verifyApprovalToken as A}from"./plan/approvalToken.js";function w(e){switch(e){case"superseded":return"the plan changed since it was approved (re-plan and approve again)";case"expired":return"the approval window expired";case"tampered":return"the approval signature did not verify";case"malformed":return"the approval token was malformed"}}function m(e,n,r){const i=n.changeCount===0&&r.length>0?`no resource changes against the live stacks; template hashes differ from the last recorded deploy for ${r.length} stack(s) (${r.join(", ")}) \u2014 applying will redeploy them`:n.summary;e.onLog?.(`Deploy plan: ${i}`,"info");for(const d of h(n))e.onLog?.(d,"info")}async function D(e){const n=k(e.detection.currentHashes),r=e.options.approvalToken;if(r!==void 0&&r!==""){const t=A({token:r,assemblyDigest:n});if(t.ok)return e.callbacks.onLog?.("Approval token verified against the current plan \u2014 proceeding","info"),o({kind:"proceed"});const u=w(t.reason);return e.callbacks.onLog?.(`Approval refused: ${u}`,"warn"),o({kind:"rejected",reason:u})}const i=[...e.detection.stackChanges.entries()].filter(([,t])=>t).map(([t])=>t),p=await(e.loadPlan??(()=>v({cfnService:e.cfnService,cdkOutPath:e.cdkOutPath,changedStacks:i,assemblyDigest:n,...e.registry!==void 0?{registry:e.registry}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})))();if(!p.success)return g(p.error);const s=p.data;m(e.callbacks,s,i);const c={hashDriftStacks:i,resourceChangeCount:s.changeCount,resourceChangedStacks:[...new Set(s.changes.map(t=>t.stack))]},a=y({assemblyDigest:n});if(e.options.autoApprove===!0)return e.callbacks.onLog?.("Plan auto-approved (--auto-approve)","info"),o({kind:"proceed"});if(e.options.planOnly===!0)return o({kind:"awaiting",approvalToken:a.token,assemblyDigest:n,expiresAt:a.expiresAt,planDetail:c});if(e.approvalGate===void 0)return o({kind:"awaiting",approvalToken:a.token,assemblyDigest:n,expiresAt:a.expiresAt,planDetail:c});const f={target:e.target,plan:s,approvalToken:a.token,expiresAt:a.expiresAt,hasDestructiveChanges:s.hasDestructiveChanges},l=await e.approvalGate.resolve(f);switch(l.kind){case"approved":return o({kind:"proceed"});case"rejected":return o({kind:"rejected",reason:l.reason,planDetail:c});case"suspended":return o({kind:"awaiting",approvalToken:l.approvalToken,assemblyDigest:n,expiresAt:a.expiresAt,planDetail:c})}}export{D as runApprovalGate};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { DeployCallbacks } from "../../types/callbacks.js";
|
|
2
|
+
import type { DeployParams } from "../../types/params.js";
|
|
3
|
+
import type { CloudFormationService } from "../../services/infrastructure/CloudFormationService.js";
|
|
4
|
+
import type { EcsService } from "../../services/infrastructure/EcsService.js";
|
|
5
|
+
import type { EcsServiceResolver } from "../../services/infrastructure/EcsServiceResolver.js";
|
|
6
|
+
/**
|
|
7
|
+
* Read the application's Database-stack connection outputs (endpoint/port
|
|
8
|
+
* keys only). Returns `{}` when the stack or its outputs do not exist, and
|
|
9
|
+
* `undefined` when the read itself failed — callers use that distinction to
|
|
10
|
+
* warn that endpoint stability could not be verified rather than silently
|
|
11
|
+
* treating a failed read as "no endpoints".
|
|
12
|
+
*/
|
|
13
|
+
export declare function captureDatabaseConnectionOutputs(cfnService: CloudFormationService, appName: string): Promise<Record<string, string> | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* Snapshot each live ECS service's current task-definition ARN before the
|
|
16
|
+
* stack loop runs. The post-deploy reconcile compares these against the
|
|
17
|
+
* post-deploy ARNs to tell which services CloudFormation already rolled
|
|
18
|
+
* during the deploy (ARN changed ⇒ tasks relaunched after the Database phase
|
|
19
|
+
* and re-resolved the updated secret) versus which still run pre-deploy tasks
|
|
20
|
+
* (ARN unchanged ⇒ stale connection values). Inferring this from build state
|
|
21
|
+
* is wrong in the primary scenario: a config-only database replacement
|
|
22
|
+
* rebuilds the same content-hash image, so the Compute stack no-ops and never
|
|
23
|
+
* rolls anything. Returns `{}` when no services exist yet and `undefined`
|
|
24
|
+
* when the read failed. The resolver reports export-read failures as an empty
|
|
25
|
+
* service list, so the reconcile treats an empty baseline like a failed read:
|
|
26
|
+
* both restart without the baseline — an extra roll is harmless, a missed one
|
|
27
|
+
* is not.
|
|
28
|
+
*/
|
|
29
|
+
export declare function captureServiceTaskDefinitions(ecsResolver: EcsServiceResolver, ecsService: EcsService, appName: string): Promise<Record<string, string> | undefined>;
|
|
30
|
+
export interface DatabaseEndpointReconcileParams {
|
|
31
|
+
appName: string;
|
|
32
|
+
/** Pre-deploy connection-output capture; `undefined` when the read failed. */
|
|
33
|
+
connectionOutputsBefore: Record<string, string> | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Pre-deploy serviceArn → task-definition ARN baseline; `undefined` when
|
|
36
|
+
* the read failed (every service is then restarted — the safe direction).
|
|
37
|
+
*/
|
|
38
|
+
serviceTaskDefinitionsBefore: Record<string, string> | undefined;
|
|
39
|
+
services: {
|
|
40
|
+
cfnService: CloudFormationService;
|
|
41
|
+
ecsService: EcsService;
|
|
42
|
+
ecsResolver: EcsServiceResolver;
|
|
43
|
+
};
|
|
44
|
+
callbacks: DeployCallbacks;
|
|
45
|
+
confirmRestart?: DeployParams["confirmDatabaseEndpointRestart"];
|
|
46
|
+
abortSignal?: AbortSignal;
|
|
47
|
+
}
|
|
48
|
+
export type DatabaseEndpointReconcileOutcome = {
|
|
49
|
+
kind: "not-needed";
|
|
50
|
+
} | {
|
|
51
|
+
kind: "unverified";
|
|
52
|
+
} | {
|
|
53
|
+
kind: "already-current";
|
|
54
|
+
} | {
|
|
55
|
+
kind: "declined";
|
|
56
|
+
} | {
|
|
57
|
+
kind: "reconciled";
|
|
58
|
+
services: string[];
|
|
59
|
+
} | {
|
|
60
|
+
kind: "failed";
|
|
61
|
+
} | {
|
|
62
|
+
kind: "cancelled";
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Post-deploy reconcile for a replaced database. A create-only property
|
|
66
|
+
* change (e.g. `snapshotIdentifier`) replaces the database: the credentials
|
|
67
|
+
* secret updates in place (same ARN, new host), so the ECS task definition is
|
|
68
|
+
* byte-identical and CloudFormation makes no ECS change — running tasks keep
|
|
69
|
+
* the stale connection values injected at launch and silently write to the
|
|
70
|
+
* doomed old database until CloudFormation deletes it. This step diffs the
|
|
71
|
+
* Database stack's connection outputs across the deploy and restarts the
|
|
72
|
+
* services whose task-definition ARN did not change during the deploy (those
|
|
73
|
+
* whose ARN moved were already relaunched after the Database phase).
|
|
74
|
+
* Best-effort: every failure warns with a `fjall rollout` hint and never
|
|
75
|
+
* fails the deploy.
|
|
76
|
+
*/
|
|
77
|
+
export declare function reconcileDatabaseEndpointChange(params: DatabaseEndpointReconcileParams): Promise<DatabaseEndpointReconcileOutcome>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{maskSensitiveOutput as g}from"@fjall/util";import{logger as b}from"@fjall/util/logger";import{getApplicationStackName as R,APPLICATION_STACKS as T}from"../../types/operations.js";import{extractEcsServiceName as N}from"../../aws/utils/arnParser.js";import{isAborted as C}from"../../aws/organisations/types.js";import{resolveServiceTaskDefinition as O}from"./serviceImageTagsRollback.js";import{registerAndRollTaskDefinition as E}from"./taskDefinitionRoll.js";const w="databaseEndpointReconcile",j=["Endpoint","Port"];async function I(a,t){const i=R(t,T.DATABASE),o=await a.getStackOutputs(i);if(!o.success){b.debug(w,"Could not read database stack outputs",{stackName:i,error:g(o.error.message)});return}const e={};for(const d of o.data){const r=d.OutputKey,l=d.OutputValue;r===void 0||l===void 0||j.some(u=>r.endsWith(u))&&(e[r]=l)}return e}async function W(a,t,i){const o=await a.getDeployableClusterAndServices(i);if(!o.success){b.debug(w,"Could not discover services pre-deploy",{appName:i,error:g(o.error.message)});return}const{clusterArn:e,serviceArns:d}=o.data;if(e===void 0||d.length===0)return{};const r=await t.describeServices(e,d);if(!r.success){b.debug(w,"Could not describe services pre-deploy",{appName:i,error:g(r.error.message)});return}const l={};for(const u of r.data)u.serviceArn!==void 0&&u.taskDefinition!==void 0&&(l[u.serviceArn]=u.taskDefinition);return l}function x(a,t){return Object.keys(a).filter(i=>t[i]!==void 0&&t[i]!==a[i]).sort()}async function q(a){const{appName:t,connectionOutputsBefore:i,services:o,callbacks:e,abortSignal:d}=a,r=`Run \`fjall rollout ${t}\` to restart them manually.`,l=`Could not verify the database endpoint was unchanged by this deploy. If the database was replaced (e.g. restored from a snapshot), run \`fjall rollout ${t}\` so running services reconnect to it.`;if(i===void 0)return e.onLog?.(l,"warn"),{kind:"unverified"};const u=await I(o.cfnService,t);if(u===void 0)return e.onLog?.(l,"warn"),{kind:"unverified"};const h=x(i,u);if(h.length===0)return{kind:"not-needed"};if(e.onLog?.(`Database connection outputs changed this deploy (${h.join(", ")}) \u2014 the database was replaced.`,"info"),C(d))return e.onLog?.(`Deploy cancelled before services were restarted onto the new database endpoint. ${r}`,"warn"),{kind:"cancelled"};const k=await o.ecsResolver.getDeployableClusterAndServices(t);if(!k.success)return e.onLog?.(`Could not discover this application's ECS services to restart them onto the new database endpoint: ${g(k.error.message)}. ${r}`,"warn"),{kind:"failed"};const{clusterArn:m,serviceArns:$}=k.data;if(m===void 0||$.length===0)return e.onLog?.(`Database connection outputs changed but no running ECS services were found to restart. If this application has running services, run \`fjall rollout ${t}\` so they reconnect to the new database endpoint.`,"warn"),{kind:"not-needed"};const A=a.serviceTaskDefinitionsBefore,L=A!==void 0&&Object.keys(A).length>0,v=[];let S=0,D=0;const y=(n,s)=>{e.onLog?.(`Could not restart ${n} onto the new database endpoint: ${g(s)}. ${r}`,"warn"),D+=1};for(const n of $){if(C(d))return e.onLog?.(`Deploy cancelled before services were restarted onto the new database endpoint. ${r}`,"warn"),{kind:"cancelled"};const s=N(n)??n,c=await O({ecsService:o.ecsService},m,n,s);if(!c.success){y(s,c.error.message);continue}const f=A?.[n];if(L&&f===void 0){S+=1;continue}if(f!==void 0&&f!==c.data.previousTaskDefArn){S+=1;continue}v.push({serviceArn:n,serviceName:s,resolved:c.data})}if(v.length===0)return D>0?{kind:"failed"}:(e.onLog?.(`Services were already relaunched during this deploy \u2014 no restart needed. If something other than this deploy relaunched them, run \`fjall rollout ${t}\` to be safe.`,"info"),{kind:"already-current"});if(a.confirmRestart!==void 0){const n={appName:t,changedOutputs:h,serviceCount:v.length};let s;try{s=await a.confirmRestart(n)}catch(c){return e.onLog?.(`Restart confirmation failed: ${g(c instanceof Error?c.message:String(c))}. ${r}`,"warn"),{kind:"failed"}}if(!s)return e.onLog?.(`Restart declined \u2014 running containers are still connected to the old database endpoint. ${r}`,"warn"),{kind:"declined"}}e.onLog?.(`Restarting ${v.length} service${v.length===1?"":"s"} so running containers reconnect to the new database\u2026`,"info");const p=[];for(const n of v){if(C(d))return e.onLog?.(`Deploy cancelled before all services were restarted onto the new database endpoint. ${r}`,"warn"),{kind:"cancelled"};let s=n.resolved;if(a.confirmRestart!==void 0){const f=await O({ecsService:o.ecsService},m,n.serviceArn,n.serviceName);if(!f.success){y(n.serviceName,f.error.message);continue}if(f.data.previousTaskDefArn!==n.resolved.previousTaskDefArn){e.onLog?.(`${n.serviceName} was relaunched while awaiting confirmation \u2014 skipping its restart.`,"info");continue}s=f.data}const c=await E({ecsService:o.ecsService},{clusterArn:m,serviceArn:n.serviceArn,serviceName:n.serviceName,taskDefinition:s.taskDefinition,containerDefinitions:s.containerDefinitions,previousTaskDefArn:s.previousTaskDefArn,startedAtMs:Date.now()},e);if(!c.success){y(n.serviceName,c.error.message);continue}p.push(n.serviceName)}return p.length>0&&(b.debug(w,"Restarted services after database replacement",{appName:t,changedOutputs:h,services:p,alreadyRolled:S}),e.onLog?.(`Restarted ${p.length} service${p.length===1?"":"s"} onto the new database endpoint.`,"info")),D>0?{kind:"failed"}:{kind:"reconciled",services:p}}export{I as captureDatabaseConnectionOutputs,W as captureServiceTaskDefinitions,q as reconcileDatabaseEndpointChange};
|
|
@@ -17,13 +17,21 @@ export interface DeploySessionContext {
|
|
|
17
17
|
* `AdministratorAccess` and the OIDC subject encodes no resource narrowing, so
|
|
18
18
|
* without this the session is an org-wide admin bearer credential.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* Three accepted v1 limitations (not app-confinement guarantees):
|
|
21
21
|
* - Session policies do not propagate across `sts:AssumeRole`, so mutation via
|
|
22
22
|
* the CDK deploy/cfn-exec roles is out of this policy's reach — the real
|
|
23
23
|
* confinement is the Phase E `FjallDeployBoundary` permission boundary.
|
|
24
24
|
* - The `stack/${appPascal}*` prefix wildcard over-grants a prefix-collision
|
|
25
25
|
* sibling app (`Web` vs `WebApp`) — same low-risk, same-account class as the
|
|
26
26
|
* ECR baseline-prefix note in `buildSecretSession.ts`.
|
|
27
|
+
* - The `-cache` NotResource entry exempts `repository/<appKebab>-cache` from
|
|
28
|
+
* the foreign-ECR Deny. CLI app creation reserves the `-cache` suffix
|
|
29
|
+
* (`hasReservedAppNameSuffix`, `@fjall/util`); the webapp create route does
|
|
30
|
+
* NOT yet enforce it (its pinned @fjall/util predates the helper — wiring
|
|
31
|
+
* lands with the 2.26.x bump), so until then a webapp-created sibling app
|
|
32
|
+
* could take that name. The residual beyond that is a pre-existing
|
|
33
|
+
* customer-created repo of that name in the BYOC account — same accepted
|
|
34
|
+
* class as `cdk-*`.
|
|
27
35
|
*
|
|
28
36
|
* DENY-list, not allow-list (deliberate). `fjall deploy` runs `cdk deploy`: the
|
|
29
37
|
* caller's session performs synth lookups, asset uploads to the CDK asset bucket,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as p,failure as s}from"@fjall/generator";import{toKebab as m,toPascalCase as d}from"@fjall/util";import{MAX_INLINE_POLICY_CHARS as
|
|
1
|
+
import{success as p,failure as s}from"@fjall/generator";import{toKebab as m,toPascalCase as d}from"@fjall/util";import{buildCacheRepositoryName as u}from"@fjall/util/docker";import{MAX_INLINE_POLICY_CHARS as i}from"./buildSecretSession.js";const f=["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:CreateChangeSet","cloudformation:ExecuteChangeSet","cloudformation:DeleteChangeSet","cloudformation:CancelUpdateStack","cloudformation:ContinueUpdateRollback","cloudformation:RollbackStack","cloudformation:SetStackPolicy","cloudformation:UpdateTerminationProtection"],y=["ecr:PutImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:BatchDeleteImage","ecr:DeleteRepository","ecr:SetRepositoryPolicy","ecr:DeleteRepositoryPolicy"];function k(a){const{region:o,accountId:e,partition:t}=a,n=d(a.appName),c=m(a.appName),l=[{Sid:"FjallDeployInheritAdmin",Effect:"Allow",Action:"*",Resource:"*"},{Sid:"FjallDeployDenyForeignStackMutation",Effect:"Deny",Action:f,NotResource:[`arn:${t}:cloudformation:${o}:${e}:stack/${n}*/*`,`arn:${t}:cloudformation:${o}:${e}:stack/CDKToolkit/*`]},{Sid:"FjallDeployDenyForeignEcrMutation",Effect:"Deny",Action:y,NotResource:[`arn:${t}:ecr:${o}:${e}:repository/${c}`,`arn:${t}:ecr:${o}:${e}:repository/${u(c)}`,`arn:${t}:ecr:${o}:${e}:repository/cdk-*`]}],r=JSON.stringify({Version:"2012-10-17",Statement:l});return r.length>i?s(new Error(`Deploy session policy is ${r.length} chars, exceeding the ${i}-char AWS inline-policy limit.`)):p(r)}export{k as buildDeploySessionPolicy};
|