@fjall/deploy-core 2.33.0 → 3.0.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/SimpleAwsProvider.js +1 -1
- package/dist/src/aws/cloudtrail/orgTrailDelivery.js +1 -1
- package/dist/src/aws/organisations/accountGlobals.js +1 -1
- package/dist/src/aws/organisations/accounts.js +1 -1
- package/dist/src/aws/organisations/backup.js +2 -2
- package/dist/src/aws/organisations/costAllocation.js +1 -1
- package/dist/src/aws/organisations/delegatedAdmin.js +2 -2
- package/dist/src/aws/organisations/identityCentre.js +1 -1
- package/dist/src/aws/organisations/identityCentreSnapshot.js +1 -1
- package/dist/src/aws/organisations/importedAccounts.js +1 -1
- package/dist/src/aws/organisations/ipam.js +1 -1
- package/dist/src/aws/organisations/oidcProvider.js +1 -1
- package/dist/src/aws/organisations/organisation.js +1 -1
- package/dist/src/aws/organisations/organisationalUnits.js +1 -1
- package/dist/src/aws/organisations/pagination.js +1 -1
- package/dist/src/aws/organisations/policies.js +1 -1
- package/dist/src/aws/organisations/ram.js +1 -1
- package/dist/src/aws/organisations/rootAccess.js +3 -3
- package/dist/src/aws/organisations/serviceAccess.js +1 -1
- package/dist/src/aws/organisations/trustedAccess.js +1 -1
- package/dist/src/aws/organisations/types.js +1 -1
- package/dist/src/aws/regions/regionOptStatus.js +1 -1
- package/dist/src/aws/sts/assumeRoot.js +1 -1
- package/dist/src/aws/targetReadiness.js +1 -1
- package/dist/src/aws/targetSetAdvisory.js +1 -1
- package/dist/src/aws/utils/arnParser.js +1 -1
- package/dist/src/aws/utils/awsErrorHandler.js +1 -1
- package/dist/src/aws/utils/cloudformationEventHelpers.js +1 -1
- package/dist/src/aws/utils/cloudformationEvents.js +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +1 -1
- package/dist/src/orchestration/activeDeploymentGuard.js +5 -5
- package/dist/src/orchestration/application/applicationDeploy.js +1 -1
- package/dist/src/orchestration/application/applicationDeployHelpers.js +3 -3
- package/dist/src/orchestration/application/applicationDestroy.js +1 -1
- package/dist/src/orchestration/application/approvalGate.js +1 -1
- package/dist/src/orchestration/application/artefactCollection.js +1 -1
- package/dist/src/orchestration/application/buildArgResolver.js +1 -1
- package/dist/src/orchestration/application/buildGroupValidator.js +1 -1
- package/dist/src/orchestration/application/buildSecretResolver.js +1 -1
- package/dist/src/orchestration/application/buildSecretSession.js +1 -1
- package/dist/src/orchestration/application/codeOnlyDeploy.js +1 -1
- package/dist/src/orchestration/application/databaseEndpointReconcile.js +1 -1
- package/dist/src/orchestration/application/deploySessionPolicy.js +1 -1
- package/dist/src/orchestration/application/destroyPreFlight.js +1 -1
- package/dist/src/orchestration/application/destructionGate.js +3 -3
- package/dist/src/orchestration/application/detectionPipeline.js +1 -1
- package/dist/src/orchestration/application/dockerBuildHelper.js +1 -1
- package/dist/src/orchestration/application/ecrCacheRepository.js +1 -1
- package/dist/src/orchestration/application/lambdaCodeOnlyRollout.js +1 -1
- package/dist/src/orchestration/application/leaseGate.js +1 -1
- package/dist/src/orchestration/application/openNextBuild.js +3 -3
- package/dist/src/orchestration/application/plan/approvalToken.js +1 -1
- package/dist/src/orchestration/application/plan/assemblyDigest.js +2 -2
- package/dist/src/orchestration/application/plan/buildDeployPlan.js +1 -1
- package/dist/src/orchestration/application/plan/changeSetEscalation.js +1 -1
- package/dist/src/orchestration/application/plan/classify.js +1 -1
- package/dist/src/orchestration/application/plan/computeDeployPlan.js +1 -1
- package/dist/src/orchestration/application/plan/loadDeployPlan.js +1 -1
- package/dist/src/orchestration/application/plan/pinnedNames.js +1 -1
- package/dist/src/orchestration/application/plan/registryOverlay.js +1 -1
- package/dist/src/orchestration/application/plan/renderDeployPlan.js +1 -1
- package/dist/src/orchestration/application/serviceImageTagsRollback.js +1 -1
- package/dist/src/orchestration/application/taskDefinitionRoll.js +1 -1
- package/dist/src/orchestration/application/welcomeImageHelper.js +1 -1
- package/dist/src/orchestration/builders/dockerBuilder.js +1 -1
- package/dist/src/orchestration/builders/frameworkRegistry.js +1 -1
- package/dist/src/orchestration/builders/openNextBuilder.js +1 -1
- package/dist/src/orchestration/builders/staticSiteBuilder.js +2 -2
- package/dist/src/orchestration/contextHelpers.js +1 -1
- package/dist/src/orchestration/deploy.js +1 -1
- package/dist/src/orchestration/destroy.js +1 -1
- package/dist/src/orchestration/dockerBuildParamsKeys.js +1 -1
- package/dist/src/orchestration/dockerInterface.d.ts +16 -0
- package/dist/src/orchestration/domain/caaPreflight.d.ts +56 -0
- package/dist/src/orchestration/domain/caaPreflight.js +1 -0
- package/dist/src/orchestration/domain/delegatedDomainDeploy.d.ts +79 -0
- package/dist/src/orchestration/domain/delegatedDomainDeploy.js +1 -0
- package/dist/src/orchestration/domain/delegationDestroyMirror.d.ts +141 -0
- package/dist/src/orchestration/domain/delegationDestroyMirror.js +1 -0
- package/dist/src/orchestration/domain/index.d.ts +10 -0
- package/dist/src/orchestration/domain/index.js +1 -0
- package/dist/src/orchestration/domain/nsPropagationGate.d.ts +59 -0
- package/dist/src/orchestration/domain/nsPropagationGate.js +1 -0
- package/dist/src/orchestration/domain/types.d.ts +75 -0
- package/dist/src/orchestration/domain/types.js +1 -0
- package/dist/src/orchestration/domainInterface.d.ts +10 -0
- package/dist/src/orchestration/drift/classifyDriftFailure.js +1 -1
- package/dist/src/orchestration/drift/detectStackDrift.js +1 -1
- package/dist/src/orchestration/drift/driftPreFlight.js +5 -5
- package/dist/src/orchestration/drift/driftProbe.d.ts +12 -6
- package/dist/src/orchestration/drift/driftProbe.js +1 -1
- package/dist/src/orchestration/drift/driftSuspectJournal.js +1 -1
- package/dist/src/orchestration/drift/preFlightGate.d.ts +10 -2
- package/dist/src/orchestration/drift/preFlightGate.js +2 -2
- package/dist/src/orchestration/drift/route53Names.d.ts +35 -0
- package/dist/src/orchestration/drift/route53Names.js +1 -0
- package/dist/src/orchestration/drift/route53RecordPreflight.d.ts +105 -0
- package/dist/src/orchestration/drift/route53RecordPreflight.js +2 -0
- package/dist/src/orchestration/index.d.ts +3 -1
- package/dist/src/orchestration/index.js +1 -1
- package/dist/src/orchestration/manifestSecretParser.js +1 -1
- package/dist/src/orchestration/organisation/accountsConfig.js +1 -1
- package/dist/src/orchestration/organisation/cascadeDestroyHelpers.js +1 -1
- package/dist/src/orchestration/organisation/cascadeHelpers.d.ts +18 -1
- package/dist/src/orchestration/organisation/cascadeHelpers.js +1 -1
- package/dist/src/orchestration/organisation/cascadeSummary.js +1 -1
- package/dist/src/orchestration/organisation/organisationDeploy.js +1 -1
- package/dist/src/orchestration/organisation/organisationDestroy.js +2 -2
- package/dist/src/orchestration/organisation/organisationSetup.js +1 -1
- package/dist/src/orchestration/organisation/reconcileProviderAccounts.js +1 -1
- package/dist/src/orchestration/organisationDeploy/cascadeExecution.js +1 -1
- package/dist/src/orchestration/organisationDeploy/infraSteps.js +1 -1
- package/dist/src/orchestration/organisationDeploy/orgCascadeDeploy.js +3 -3
- package/dist/src/orchestration/organisationDeploy/orgContext.js +1 -1
- package/dist/src/orchestration/organisationDeploy/resolveCascadeAccounts.js +1 -1
- package/dist/src/orchestration/organisationDeploy/singleComponentDeploy.js +1 -1
- package/dist/src/orchestration/organisationDeploy/trailReconciliation.js +1 -1
- package/dist/src/orchestration/probes/deleteBlockProbes.js +1 -1
- package/dist/src/orchestration/remediation/driftRepairGate.js +1 -1
- package/dist/src/orchestration/remediation/forensicsCapture.js +1 -1
- package/dist/src/orchestration/remediation/forgetResource.js +1 -1
- package/dist/src/orchestration/remediation/pinRemediation.js +1 -1
- package/dist/src/orchestration/remediation/postFailureRepairOffer.js +8 -8
- package/dist/src/orchestration/remediation/recreatePreFlight.js +1 -1
- package/dist/src/orchestration/remediation/recreateResource.js +1 -1
- package/dist/src/orchestration/remediation/remediationJournal.js +2 -2
- package/dist/src/orchestration/remediation/removalUpdate.js +1 -1
- package/dist/src/orchestration/remediation/retainFlip.js +1 -1
- package/dist/src/orchestration/resolveOperation.js +1 -1
- package/dist/src/orchestration/restart/restartApplication.js +1 -1
- package/dist/src/orchestration/restart/secretsDrift.js +1 -1
- package/dist/src/orchestration/secretArnResolver.js +1 -1
- package/dist/src/orchestration/serviceFactory.js +1 -1
- package/dist/src/orchestration/spawnHelpers.js +1 -1
- package/dist/src/orchestration/stackCleanup/bucketOps.js +1 -1
- package/dist/src/orchestration/stackCleanup/failedStack.js +1 -1
- package/dist/src/orchestration/stackCleanup/logging.js +1 -1
- package/dist/src/orchestration/stackCleanup/messages.js +1 -1
- package/dist/src/orchestration/stackCleanup/orphanSweep.js +1 -1
- package/dist/src/orchestration/stackCleanup/preEmpty.js +1 -1
- package/dist/src/orchestration/stackCleanup/stackResources.js +1 -1
- package/dist/src/orchestration/stepLifecycle.js +1 -1
- package/dist/src/orchestration/trailMigration/memberTrailCleanup.js +1 -1
- package/dist/src/orchestration/trailMigration/trailMigration.js +1 -1
- package/dist/src/orchestration/unlock/bucketPolicyTriage.js +1 -1
- package/dist/src/orchestration/unlock/restoreAndReconcileQuarantinedBucket.js +1 -1
- package/dist/src/orchestration/unlock/restoreBucketPolicy.js +1 -1
- package/dist/src/orchestration/unlock/scpRemediation.js +1 -1
- package/dist/src/orchestration/unlock/toResourcePolicyStatements.js +1 -1
- package/dist/src/orchestration/unlock/unlockBucket.js +1 -1
- package/dist/src/orchestration/unlock/unlockQueue.js +1 -1
- package/dist/src/services/application/ApplicationStackService.d.ts +7 -0
- package/dist/src/services/application/ApplicationStackService.js +1 -1
- package/dist/src/services/application/applicationStackHelpers.js +3 -3
- package/dist/src/services/infrastructure/CdkArgumentBuilder.js +1 -1
- package/dist/src/services/infrastructure/CdkCommandRunner.js +2 -2
- package/dist/src/services/infrastructure/CdkErrorFormatter.js +10 -10
- package/dist/src/services/infrastructure/CdkEventMonitoring.js +1 -1
- package/dist/src/services/infrastructure/CdkOutputAnalyser.js +2 -2
- package/dist/src/services/infrastructure/CdkOutputParser.js +2 -2
- package/dist/src/services/infrastructure/CdkProcessManager.js +3 -3
- package/dist/src/services/infrastructure/CdkService.d.ts +1 -1
- package/dist/src/services/infrastructure/CdkService.js +2 -2
- package/dist/src/services/infrastructure/CdkServiceTypes.d.ts +39 -0
- package/dist/src/services/infrastructure/CfnRegistryService.js +1 -1
- package/dist/src/services/infrastructure/CloudFormationService.js +1 -1
- package/dist/src/services/infrastructure/EcrImageInspectorService.js +1 -1
- package/dist/src/services/infrastructure/EcsService.js +1 -1
- package/dist/src/services/infrastructure/EcsServiceResolver.js +1 -1
- package/dist/src/services/infrastructure/LambdaService.js +1 -1
- package/dist/src/services/infrastructure/SsmParameterMetadataService.js +1 -1
- package/dist/src/services/infrastructure/cancelInFlightStack.js +3 -3
- package/dist/src/services/infrastructure/cdkServiceHelpers.js +1 -1
- package/dist/src/services/infrastructure/changeSetProbe.js +1 -1
- package/dist/src/services/infrastructure/constructMapEnrichment.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/services/supporting/TemplateHashService.js +1 -1
- package/dist/src/services/supporting/helpers.js +1 -1
- package/dist/src/steps/stepRegistry.js +1 -1
- package/dist/src/types/ProgressEvent.js +1 -1
- package/dist/src/types/application/ApplicationServiceTypes.js +1 -1
- package/dist/src/types/callbacks.js +1 -1
- package/dist/src/types/config/FjallState.js +1 -1
- package/dist/src/types/constants.js +1 -1
- package/dist/src/types/deployEmitter.js +1 -1
- package/dist/src/types/deployEvent.d.ts +1 -0
- package/dist/src/types/deployEvent.js +1 -1
- package/dist/src/types/deployEventParse.js +1 -1
- package/dist/src/types/deployment/DeploymentServiceTypes.js +1 -1
- 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/detection/patternDetection.js +1 -1
- package/dist/src/types/detection/patternTypes.d.ts +9 -0
- package/dist/src/types/drift.js +1 -1
- package/dist/src/types/errors/CdkError.js +1 -1
- package/dist/src/types/errors/ServiceError.js +1 -1
- package/dist/src/types/operations.d.ts +26 -2
- package/dist/src/types/operations.js +1 -1
- package/dist/src/types/params.d.ts +20 -0
- package/dist/src/types/remediation.js +1 -1
- package/dist/src/types/stepDefinitions.d.ts +3 -0
- package/dist/src/types/stepDefinitions.js +1 -1
- package/dist/src/util/dockerfileDetection.js +1 -1
- package/dist/src/util/sequencedCallbacks.js +1 -1
- package/dist/src/util/sleepAbortable.js +1 -1
- package/package.json +5 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{createHash as
|
|
1
|
+
var N=Object.defineProperty;var d=(e,i)=>N(e,"name",{value:i,configurable:!0});import{createHash as D}from"node:crypto";import{success as m,failure as x}from"@fjall/generator";import{maskSensitiveOutput as C}from"@fjall/util";import{remediationPlaceholderPhysicalId as L}from"../../types/remediation.js";import{pinProbeCoverage as v}from"../remediation/pinRemediation.js";const b={"replacement-required":["abort","pin","recreate"],"pinned-name-replacement":["abort","pin","recreate"],"data-loss-delete":["abort","forget","recreate"],"resource-deleted":["abort","repair","forget","recreate"],"stack-deleted":["abort","repair","recreate"]};function G(e){return b[e]}d(G,"legalRemediationVerbs");const h={"replacement-required":["pin","recreate"],"pinned-name-replacement":["pin","recreate"],"data-loss-delete":["recreate"],"resource-deleted":["forget"],"stack-deleted":[]};function P(e){return h[e]}d(P,"executableRemediationVerbs");function y(e){const i=P(e.finding);return e.verbs.filter(t=>t==="abort"||i.includes(t)&&(t!=="pin"||v(e.resourceType,e.offendingProperties).covered))}d(y,"advertisableRemediationVerbs");function R(e){if(e.action==="replace")return e.pinnedPhysicalName!==void 0?"pinned-name-replacement":e.dataLoss?"replacement-required":void 0;if(e.action==="delete"&&e.dataLoss&&!e.retained)return"data-loss-delete"}d(R,"findingForChange");function T(e,i,t){if(i==="data-loss-delete")return"removed from the synthesised template \u2014 CloudFormation will delete the live resource and its data";const o=t.length>0?`${t.join(", ")} forces replacement`:"replacement required (no property-level detail available)",n=e.replacementMode==="may"||e.replacementMode==="conditional"?" (conditional verdict \u2014 worst-cased towards ceremony)":"";return i==="pinned-name-replacement"?`${o}${n}; CloudFormation refuses in-stack replacement of custom-named resources`:`${o}${n}`}d(T,"causeForChange");function E(e,i){const t=D("sha256");t.update(e),t.update(`
|
|
2
2
|
`);const o=i.map(n=>`${n.stack}|${n.logicalId}|${n.resourceType}|${n.physicalName}|${n.finding}`).sort();for(const n of o)t.update(n),t.update(`
|
|
3
|
-
`);return t.digest("hex")}function
|
|
3
|
+
`);return t.digest("hex")}d(E,"computeTicketDigest");function M(e,i){const t=new Set((i??[]).map(n=>`${n.stackName}
|
|
4
4
|
${n.logicalId}`)),o=[];for(const n of e.changes){if(n.action==="delete"&&t.has(`${n.stack}
|
|
5
|
-
${n.address}`))continue;const s=
|
|
5
|
+
${n.address}`))continue;const s=R(n);if(s===void 0)continue;const r=n.propertyChanges.filter(l=>l.forcesReplacement).map(l=>l.path);o.push({stack:n.stack,logicalId:n.address,resourceType:n.resourceType,physicalName:n.pinnedPhysicalName??L(n.stack,n.address),finding:s,cause:T(n,s,r),offendingProperties:r,verdictSource:n.verdictSource??"cdk-spec (unverified)",dataLossRisk:n.dataLoss,verbs:[...b[s]]})}if(o.length!==0)return{ticketDigest:E(e.assemblyDigest,o),resources:o}}d(M,"buildDestructionTicket");function $(e){const{ticket:i,consents:t,consentDigest:o}=e,n=o!==void 0&&o!==i.ticketDigest,s=new Map(i.resources.map(a=>[a.physicalName,a])),r=t.map(a=>{const p=s.get(a.physicalName);return p===void 0?{physicalName:a.physicalName,verb:a.verb,verdict:"unmatched",detail:"no pending destructive resource has this exact name"}:p.verbs.includes(a.verb)?{physicalName:a.physicalName,verb:a.verb,verdict:"matched"}:{physicalName:a.physicalName,verb:a.verb,verdict:"wrong-verb",detail:`legal verbs for ${p.finding}: ${y(p).join(", ")}`}}),l=new Set(r.filter(a=>a.verdict==="matched").map(a=>a.physicalName)),f=i.resources.map(a=>a.physicalName).filter(a=>!l.has(a)),g=!n&&f.length===0&&r.length>0&&r.every(a=>a.verdict==="matched");return{rows:r,uncovered:f,digestMismatch:n,satisfied:g,...n&&o!==void 0?{suppliedDigest:o,currentDigest:i.ticketDigest}:{}}}d($,"evaluateDestructionConsents");function S(e){const i=[];for(const t of e.resources){const o=t.dataLossRisk?" (data loss)":"";i.push(`! ${t.finding} ${t.resourceType} ${t.stack}/${t.logicalId}${o}`),i.push(` physical name: ${t.physicalName}`),i.push(` cause: ${t.cause}`),i.push(` legal verbs: ${y(t).join(" | ")}`)}return i}d(S,"renderDestructionTicketLines");function j(e){const i=[];if(e.digestMismatch){const t=e.suppliedDigest!==void 0&&e.currentDigest!==void 0?` (consents were minted against '${e.suppliedDigest}'; the pending destructive changes now digest to '${e.currentDigest}')`:"";i.push(`consent digest mismatch: the plan changed since consent was given \u2014 re-review and consent again${t}`)}if(e.rows.length>0){i.push("consent verdicts:");for(const t of e.rows){const o=t.detail!==void 0?` \u2014 ${t.detail}`:"";i.push(` ${t.physicalName}=${t.verb} ${t.verdict}${o}`)}}if(e.uncovered.length>0){i.push("awaiting consent:");for(const t of e.uncovered)i.push(` ${t}`)}return i}d(j,"renderConsentVerdictLines");function w(e,i){const t=new Map(e.resources.map(n=>[n.physicalName,n])),o=[];for(const n of i){if(n.verdict!=="matched")continue;const s=t.get(n.physicalName);if(s!==void 0){if(n.verb==="abort"){o.push(`${n.physicalName}: aborted by operator consent`);continue}if(!h[s.finding].includes(n.verb)){o.push(`${n.physicalName}: verb '${n.verb}' is accepted vocabulary but not yet executable in this release for ${s.finding} \u2014 executable today: ${h[s.finding].join(", ")||"none (abort only)"}`);continue}if(n.verb==="pin"){const r=v(s.resourceType,s.offendingProperties);r.covered||o.push(`${n.physicalName}: verb 'pin' has no live-value probe for ${r.unsupportedPairs.join(", ")} in this release \u2014 pin cannot capture the live value(s) into the config for this resource. Executable today for ${s.finding}: ${h[s.finding].filter(l=>l!=="pin").join(", ")||"none (abort only)"}`)}}}return o}d(w,"collectExecutionHalts");async function H(e){const i=await e.loadPlan();if(!i.success)return x(new Error(C(`Destruction gate could not compute the deploy plan: ${i.error.message}`)));const t=M(i.data,e.verifiedAbsentByNecessity);if(t===void 0)return m({kind:"clear"});const o=d(c=>{e.callbacks.onLog?.(`Destruction gate: ${t.resources.length} destructive change(s) proceeding under named consent (${c.rows.map(u=>`${u.physicalName}=${u.verb}`).join(", ")})`,"warn");const k=new Map(c.rows.filter(u=>u.verdict==="matched").map(u=>[u.physicalName,u.verb]));return m({kind:"proceed",ticket:t,verbsByPhysicalName:k})},"proceedUnderConsent"),n=e.options.destructionConsents??[];let s=$({ticket:t,consents:n,...e.options.destructionConsentDigest!==void 0?{consentDigest:e.options.destructionConsentDigest}:{}}),r=s.satisfied?w(t,s.rows):[];if(s.satisfied&&r.length===0)return o(s);const l=[];if(e.consentGate!==void 0&&n.length===0&&e.options.destructionConsentDigest===void 0){const c=await e.consentGate.resolve({target:e.target,ticket:t});if(c.kind==="abort")l.push("declined at the interactive destruction ceremony \u2014 nothing was applied");else if(s=$({ticket:t,consents:c.consents,consentDigest:c.ticketDigest}),r=s.satisfied?w(t,s.rows):[],s.satisfied&&r.length===0)return o(s)}const f=[...l,...r],g=s.satisfied&&s.rows.some(c=>c.verdict==="matched"&&c.verb==="abort"),a=l.length>0||g?"declined":r.length>0?"consent-not-executable":s.rows.length>0||s.digestMismatch?"consents-invalid":"awaiting-consent",p={"awaiting-consent":`Destructive changes for ${e.target} require named consent \u2014 deploy withheld, nothing was applied`,declined:`Deployment of ${e.target} declined \u2014 the destructive changes were not consented; nothing was applied`,"consents-invalid":`Deployment of ${e.target} withheld \u2014 the supplied consents did not match the pending destructive changes; nothing was applied`,"consent-not-executable":`Deployment of ${e.target} withheld \u2014 consent was given, but the consented remediation is not yet executable in this release; nothing was applied`};e.callbacks.onLog?.(p[a],"warn");for(const c of S(t))e.callbacks.onLog?.(c,"warn");for(const c of j(s))e.callbacks.onLog?.(c,"warn");for(const c of f)e.callbacks.onLog?.(c,"warn");return(a==="awaiting-consent"||a==="consents-invalid")&&e.callbacks.onLog?.("Consent with --remediate <physicalName>=<verb> (repeatable; exact, case-sensitive) or --allow-replace <physicalName> for plain replacements. No blanket flag exists: --auto-approve, --skip-confirmation and approval tokens never satisfy this gate.","warn"),m({kind:"withheld",outcome:a,ticket:t,report:s,reasons:f})}d(H,"runDestructionGate");export{y as advertisableRemediationVerbs,M as buildDestructionTicket,E as computeTicketDigest,$ as evaluateDestructionConsents,P as executableRemediationVerbs,G as legalRemediationVerbs,j as renderConsentVerdictLines,S as renderDestructionTicketLines,H as runDestructionGate};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as
|
|
1
|
+
var N=Object.defineProperty;var w=(s,t)=>N(s,"name",{value:t,configurable:!0});import{join as F}from"path";import{success as H,failure as o}from"@fjall/generator";import{logger as M}from"@fjall/util/logger";import{maskSensitiveOutput as a}from"@fjall/util";import{deriveResourcesFromManifestStacks as O}from"../../types/detection/patternDetection.js";import{emitProgress as l,PROGRESS_MESSAGES as R}from"../../services/supporting/helpers.js";import{parseRequiredSecretsFromManifest as L,parseImportedSecretNamesFromManifest as q}from"../manifestSecretParser.js";import{resolveSecretArns as T}from"../secretArnResolver.js";import{isAborted as B}from"../../aws/organisations/types.js";import{parseDockerDeclarationsFromManifest as G}from"@fjall/util/manifest";async function V(s,t,i,e,S){e.onDetectionPhaseChange?.("detect","started");const C=t.frameworkRegistry.resolve({appPath:s.path}),y=C?.detection.pattern??null,k=C?.detection.hasDatabase??!1;e.onLog?.(`Pattern detected: ${y??"standard"}`,"info"),e.onDetectionPhaseChange?.("detect","completed");const h=F(s.path,"cdk.out");e.onDetectionPhaseChange?.("synth","started"),l(e,R.SYNTH);const D=await t.cdkService.runCdkSynth(i,r=>e.onCdkOutput?.(r,"synth"));if(!D.success)return o(new Error(a(`CDK synthesis failed: ${D.error}`)));if(e.onDetectionPhaseChange?.("synth","completed"),i.resolvedSecretArns===void 0){const r=q(h);if(r.length>0){e.onLog?.(`Resolving ${r.length} imported secret ARN(s)\u2026`,"info");const n=await T(t.awsProvider,r);if(!n.success)return o(new Error(a(n.error.message)));i.resolvedSecretArns=JSON.stringify(n.data);const g=await t.cdkService.runCdkSynth(i,$=>e.onCdkOutput?.($,"synth"));if(!g.success)return o(new Error(a(`CDK synthesis failed: ${g.error}`)))}}const d=L(h);d.length>0&&e.onLog?.(`Found ${d.length} required secret path(s) in manifest`,"info"),e.onDetectionPhaseChange?.("hash","started"),l(e,R.HASH);const m=await t.hashService.getTemplateHashes(h);if(!m.success)return o(new Error(a(`Template hash computation failed: ${m.error.message}`)));const f=m.data,u=await t.hashService.compareWithState(f,s.path);if(!u.success)return o(new Error(a(`Hash comparison failed: ${u.error.message}`)));const c=u.data;e.onDetectionPhaseChange?.("hash","completed");const p=new Map(c.stackChanges);for(const[r,n]of c.stackChanges){if(B(S))break;n||await t.cfnService.stackExists(r,void 0,S)||(M.debug("detectionPipeline","Stale hash detected \u2014 stack missing in CFN",{stackName:r}),p.set(r,!0))}const v=Array.from(f.keys()),P=O(v),A=P.hasCompute&&G(h).declaresBuild,E=Array.from(p.values()).some(Boolean);return e.onLog?.(`Detection complete: ${c.changedCount} changed, ${c.unchangedCount} unchanged`,"info"),H({pattern:y,hasDatabase:k,hasDifferences:E,stackChanges:p,currentHashes:f,resources:P,hasDockerfile:A,requiredSecrets:d})}w(V,"runDetectionPipeline");export{V as runDetectionPipeline};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isAbsolute as M,join as _,dirname as z,resolve as F}from"node:path";import{existsSync as j}from"node:fs";import{success as N,failure as h}from"@fjall/generator";import{deriveContentHashTag as J,getErrorMessage as U,maskSensitiveOutput as b,toKebab as x}from"@fjall/util";import{evaluateBakeGuard as X,evaluateResolvedBuildArgValues as Y,acknowledgedBuildArgKeys as q,createBakeWarningDeduper as Q,buildCacheRepositoryName as G,BAKE_GUARD_EXPOSURE_CLAUSE as Z}from"@fjall/util/docker";import{runWithBoundedConcurrency as ee,resolveBuildConcurrency as re}from"@fjall/util/buildConcurrency";import{logger as L}from"@fjall/util/logger";import{parseDockerServicesFromManifest as te,parseLambdaDockerServicesFromManifest as ne}from"@fjall/util/manifest";import{STEP_IDS as A}from"../../types/stepDefinitions.js";import{isAborted as V}from"../../aws/organisations/types.js";import{resolveBuildSecrets as oe,resolveSecretRefValue as ie,resolveBuildSecretSessionProvider as se,sourcedRefsFromBuildArgs as ae}from"./buildSecretResolver.js";import{partitionForRegion as de}from"./buildSecretSession.js";import{resolveBuildArgs as ce}from"./buildArgResolver.js";import{validateBuildGroup as ue}from"./buildGroupValidator.js";import{ensureBuildCacheRepository as le}from"./ecrCacheRepository.js";const T="dockerBuildHelper",C="Building and pushing Docker image";function fe(e,n,t){const r=_(n,e);if(j(r))return{path:r,base:n};if(t!==""&&t!==n){const o=_(t,e);if(j(o))return{path:o,base:t}}return{path:r,base:n}}function me(e,n,t){const r=e.docker.path,o=e.docker.context;let s,a;if(M(r))s=r,a=n;else{const g=fe(r,n,t);s=g.path,a=g.base}return{buildContext:o?M(o)?F(o):F(a,o):F(z(s)),dockerfilePath:s,target:e.docker.target,resolvedViaFallback:a!==n}}function ge(e){return`${e.buildContext}|${e.dockerfilePath}|${e.target??""}`}function pe(e,n){return`Dockerfile not found for service '${e}' at ${n}. Checked the synth directory and the working directory. If your Dockerfile lives at the project root with the CDK app in a subdirectory, set an absolute docker.context (the build context must share the Dockerfile's directory).`}function he(e){return e.startsWith("cn-")?"amazonaws.com.cn":"amazonaws.com"}function W(e,n){return`${e}.dkr.ecr.${n}.${he(n)}`}function be(e,n,t){return`${W(e,n)}/${x(t)}`}function ye(e,n,t){return`${W(e,n)}/${G(x(t))}`}function ve(e,n,t){const r=new Map;for(const o of e){const s=me(o,n,t),a=ge(s),m=r.get(a);m?m.members.push(o):r.set(a,{identity:s,members:[o]})}return Array.from(r.values())}async function Se(e,n,t,r,o){const s=await e.buildAndPush({appName:n.appName,appPath:n.path,region:t,accountId:r},(a,m,g,S)=>{o.onDockerProgress?.(b(a),m,g,S)});return s.success?N({imageUri:s.data.imageUri,imageTag:s.data.imageTag}):h(s.error)}function H(){return{contentHashTagsByService:{},imageDigestsByService:{}}}async function we(e,n,t,r,o,s,a,m,g,S,E,f,k,w){const l=e.members[0];if(!j(e.identity.dockerfilePath))return h(new Error(pe(l.name,e.identity.dockerfilePath)));e.identity.resolvedViaFallback&&m.onLog?.(`Building service '${l.name}' from ${e.identity.dockerfilePath} (resolved at the project root).`,"info");const v=[...l.docker.buildSecrets??[],...k??[]],P=ue({serviceName:l.name,dockerfilePath:e.identity.dockerfilePath,buildContext:e.identity.buildContext,...e.identity.target!==void 0&&{target:e.identity.target},...l.docker.buildArgs!==void 0&&{buildArgs:l.docker.buildArgs},...v.length>0&&{buildSecrets:v},members:e.members.map(i=>({serviceName:i.name,...i.docker.buildArgs!==void 0&&{buildArgs:i.docker.buildArgs},...i.docker.buildSecrets!==void 0&&{buildSecrets:i.docker.buildSecrets}}))});if(!P.success)return h(P.error);const d=X(l.docker.buildArgs,x(t.appName));for(const i of d.warnings){const y=b(i.message);w(y)&&m.onLog?.(y,"warn")}if(d.findings.length>0)return h(new Error(b(d.findings.map(i=>i.message).join(" "))));const c=v,D=ae(l.docker.buildArgs),I={appName:t.appName,region:r,accountId:o,partition:de(r)},$=await se(g,[...c,...D],I);if(!$.success)return h($.error);const O=$.data,R=await ce({manifestBuildArgs:l.docker.buildArgs,serviceDir:e.identity.buildContext,appDir:t.path,...E!==void 0&&{stage:E},shellEnv:process.env,...f!==void 0&&{flagBuildArgs:f},resolveSourcedValue:(i,y)=>ie(O,{id:i,...y},S)});if(!R.success)return h(R.error);const B=R.data.buildArgs;for(const i of R.data.inferredDotenvKeys){const y=b(`buildArg "${i}" was auto-declared from a .env file and will be baked into the image \u2014 ${Z}.`);w(y)&&m.onLog?.(y,"warn")}const u=Y(B,x(t.appName),q(l.docker.buildArgs));if(u.length>0)return h(new Error(b(u.map(i=>i.message).join(" "))));let p;if(c.length>0){const i=await oe(O,c,S);if(!i.success)return h(i.error);p=i.data}try{if(V(S))return h(new Error(`Build of service '${l.name}' was aborted before the docker build started`));const i=e.members.some(K=>K.isLambda===!0),y={appName:t.appName,appPath:e.identity.buildContext,region:r,accountId:o,buildContext:e.identity.buildContext,dockerfilePath:e.identity.dockerfilePath,pushByDigest:!0,serviceName:l.name,targetsLambda:i,...a!==void 0&&{cacheRepoUri:a},...e.identity.target!==void 0&&{target:e.identity.target},...Object.keys(B).length>0&&{buildArgs:B},...p!==void 0&&{buildSecrets:p.resolved}};return await Ee(e,y,n,s,m)}finally{p!==void 0&&await p.cleanup().catch(()=>m.onLog?.("Build-secret cleanup failed.","warn"))}}async function Ee(e,n,t,r,o){const s=await t.buildAndPush(n,(f,k,w,l)=>{o.onDockerProgress?.(b(f),k,w,l)});if(!s.success)return h(s.error);const a=s.data.imageDigest;if(typeof a!="string"||!a.startsWith("sha256:"))return h(new Error(`Buildx push succeeded but returned an invalid digest: ${b(String(a))}`));const m={},g={},S=[];for(const f of e.members){const k=f.docker.target,w=J(a,f.name,k);if(!w.success)return h(w.error);const l=w.data,v=f.name;m[v]=l,g[v]=a,S.push(`${r}:${l}`)}const E=await t.tagByDigest({sourceImage:r,digest:a,tags:S});return E.success?N({contentHashTagsByService:m,imageDigestsByService:g}):h(E.error)}function ke(e,n){const t=new Map(e.map(r=>[r.name,r]));for(const r of n){const o=t.get(r.name);if(o!==void 0&&JSON.stringify(o.docker)!==JSON.stringify(r.docker))throw new Error(`ECS service "${o.name}" and Lambda image key "${r.name}" share one build key but declare different docker configs \u2014 the second build would silently overwrite the first and both would deploy the same image. Rename one of them, or make the docker configs identical to deliberately share the build.`)}}async function Fe(e,n,t,r){const o=e.dockerProvider;if(!o)return N(H());const s=n.awsProvider.getAccountId();if(!s)return r.onLog?.("Skipping Docker build \u2014 account ID not available","warn"),N(H());const a=n.awsProvider.getRegion(),m=_(t.path,"cdk.out");let g;try{const d=te(m),c=ne(m);ke(d,c),g=[...d,...c]}catch(d){const c=new Error(b(U(d)));return r.onError?.(c),h(c)}const S=be(s,a,t.appName);if(L.debug(T,"runDockerBuild starting",{appName:t.appName,appPath:t.path,accountId:s,region:a,cdkOutPath:m,manifestServiceCount:g.length,manifestServices:g.map(d=>({name:d.name,path:d.docker.path,context:d.docker.context,target:d.docker.target})),stepId:A.DOCKER_OPERATIONS,stepName:C}),r.onStepStart?.(A.DOCKER_OPERATIONS,C),g.length===0){r.onLog?.("Initialising ECR repository\u2026","info");const d=await o.initialiseECR({appName:t.appName,region:a,accountId:s});d.success||r.onLog?.(`ECR initialisation failed: ${b(d.error.message)}`,"warn"),r.onLog?.("Building and pushing Docker image\u2026","info");const c=await Se(o,t,a,s,r);if(!c.success){L.debug(T,"Docker buildAndPush (legacy) failed",{appName:t.appName,error:b(c.error.message)}),r.onStepComplete?.(A.DOCKER_OPERATIONS,C,"error");const D=new Error(b(c.error.message));return r.onError?.(D),h(D)}return r.onStepComplete?.(A.DOCKER_OPERATIONS,C,"completed"),r.onLog?.(`Docker image pushed: ${c.data.imageUri}`,"info"),N(H())}const E=await o.preflight?.();if(E!==void 0&&!E.success){r.onStepComplete?.(A.DOCKER_OPERATIONS,C,"error");const d=new Error(b(E.error.message));return r.onError?.(d),h(d)}const f=ve(g,t.path,e.workingDirectory);let k=ye(s,a,t.appName);const w=await le(n.awsProvider,G(x(t.appName)),e.abortSignal);w.success||(k=void 0,r.onLog?.(`Building without registry cache \u2014 ${w.error.message}`,"warn")),r.onLog?.(`Building and pushing ${g.length} service image(s) in ${f.length} group(s)\u2026`,"info");let l=!1;if(o.beginEcrSession!==void 0){const d=await o.beginEcrSession({accountId:s,region:a});if(!d.success){r.onStepComplete?.(A.DOCKER_OPERATIONS,C,"error");const c=new Error(b(d.error.message));return r.onError?.(c),h(c)}l=!0}const v=new AbortController,P=()=>v.abort();e.abortSignal!==void 0&&(e.abortSignal.aborted?v.abort():e.abortSignal.addEventListener("abort",P,{once:!0}));try{const d=()=>V(e.abortSignal)?"the deployment was cancelled":"a sibling group failed";let c;const D=re(f.length),I=Q(),$=f.map((u,p)=>async()=>{const i=u.members.map(K=>K.name).join(", ");if(v.signal.aborted)throw new Error(`Build of group ${p+1}/${f.length} (${i}) was not started \u2014 ${d()}`);r.onLog?.(`Building group ${p+1}/${f.length} (${i})\u2026`,"info");const y=await we(u,o,t,a,s,S,k,r,n.awsProvider,v.signal,e.options?.environment,e.options?.flagBuildArgs,e.options?.flagBuildSecrets,I);if(!y.success)throw c===void 0&&(c={error:y.error,leader:u.members[0]?.name,members:i}),v.abort(),y.error;return y.data}),O=await ee($,D,{abortOnFirstFailure:!0,abortSignal:v.signal});if(c===void 0)for(let u=0;u<f.length;u++){const p=O[u];if(!(p!==void 0&&p.success)){c={error:p!==void 0&&!p.success?p.error:new Error(`Build of group ${u+1}/${f.length} never ran \u2014 ${d()}`),leader:f[u].members[0]?.name,members:f[u].members.map(i=>i.name).join(", ")};break}}if(c!==void 0){L.debug(T,"Docker buildAndPush failed",{appName:t.appName,leader:c.leader,members:c.members,error:b(c.error.message)}),r.onStepComplete?.(A.DOCKER_OPERATIONS,C,"error");const u=new Error(b(c.error.message));return r.onError?.(u),h(u)}const R={},B={};for(const u of O)if(!(u===void 0||!u.success)){for(const[p,i]of Object.entries(u.data.contentHashTagsByService))R[p]=i;for(const[p,i]of Object.entries(u.data.imageDigestsByService))B[p]=i}return L.debug(T,"Docker buildAndPush succeeded",{appName:t.appName,services:g.map(u=>u.name),groupCount:f.length,contentHashTags:R}),r.onStepComplete?.(A.DOCKER_OPERATIONS,C,"completed"),r.onLog?.(`Docker images pushed for ${g.length} service(s)`,"info"),N({contentHashTagsByService:R,imageDigestsByService:B,repoUri:S})}finally{e.abortSignal?.removeEventListener("abort",P),l&&o.endEcrSession!==void 0&&await o.endEcrSession().catch(d=>{L.debug(T,"endEcrSession cleanup failed",{error:b(U(d))})})}}export{C as DOCKER_BUILD_STEP_NAME,be as ecrRepoUri,H as emptyBuildProducts,Fe as runDockerBuild};
|
|
1
|
+
var J=Object.defineProperty;var g=(e,n)=>J(e,"name",{value:n,configurable:!0});import{isAbsolute as U,join as F,dirname as X,resolve as j}from"node:path";import{existsSync as H}from"node:fs";import{success as P,failure as b}from"@fjall/generator";import{deriveContentHashTag as Y,getErrorMessage as G,maskSensitiveOutput as y,toKebab as L}from"@fjall/util";import{evaluateBakeGuard as q,evaluateResolvedBuildArgValues as Q,acknowledgedBuildArgKeys as Z,createBakeWarningDeduper as ee,buildCacheRepositoryName as V,BAKE_GUARD_EXPOSURE_CLAUSE as re}from"@fjall/util/docker";import{runWithBoundedConcurrency as te,resolveBuildConcurrency as ne}from"@fjall/util/buildConcurrency";import{logger as T}from"@fjall/util/logger";import{parseDockerServicesFromManifest as oe,parseLambdaDockerServicesFromManifest as ie}from"@fjall/util/manifest";import{STEP_IDS as C}from"../../types/stepDefinitions.js";import{isAborted as W}from"../../aws/organisations/types.js";import{resolveBuildSecrets as se,resolveSecretRefValue as ae,resolveBuildSecretSessionProvider as de,sourcedRefsFromBuildArgs as ce}from"./buildSecretResolver.js";import{partitionForRegion as ue}from"./buildSecretSession.js";import{resolveBuildArgs as le}from"./buildArgResolver.js";import{validateBuildGroup as fe}from"./buildGroupValidator.js";import{ensureBuildCacheRepository as ge}from"./ecrCacheRepository.js";const I="dockerBuildHelper",D="Building and pushing Docker image";function me(e,n,t){const r=F(n,e);if(H(r))return{path:r,base:n};if(t!==""&&t!==n){const o=F(t,e);if(H(o))return{path:o,base:t}}return{path:r,base:n}}g(me,"resolveAgainstBases");function pe(e,n,t){const r=e.docker.path,o=e.docker.context;let c,s;if(U(r))c=r,s=n;else{const p=me(r,n,t);c=p.path,s=p.base}return{buildContext:o?U(o)?j(o):j(s,o):j(X(c)),dockerfilePath:c,target:e.docker.target,resolvedViaFallback:s!==n}}g(pe,"resolveBuildIdentity");function he(e){return`${e.buildContext}|${e.dockerfilePath}|${e.target??""}`}g(he,"buildIdentityKey");function be(e,n){return`Dockerfile not found for service '${e}' at ${n}. Checked the synth directory and the working directory. If your Dockerfile lives at the project root with the CDK app in a subdirectory, set an absolute docker.context (the build context must share the Dockerfile's directory).`}g(be,"dockerfileNotFoundMessage");function ye(e){return e.startsWith("cn-")?"amazonaws.com.cn":"amazonaws.com"}g(ye,"ecrDnsSuffix");function z(e,n){return`${e}.dkr.ecr.${n}.${ye(n)}`}g(z,"ecrRegistryHost");function ve(e,n,t){return`${z(e,n)}/${L(t)}`}g(ve,"ecrRepoUri");function Se(e,n,t){return`${z(e,n)}/${V(L(t))}`}g(Se,"ecrCacheRepoUri");function we(e,n,t){const r=new Map;for(const o of e){const c=pe(o,n,t),s=he(c),m=r.get(s);m?m.members.push(o):r.set(s,{identity:c,members:[o]})}return Array.from(r.values())}g(we,"groupServicesByIdentity");async function Ee(e,n,t,r,o,c){const s=await e.buildAndPush({appName:n.appName,appPath:n.path,region:t,accountId:r,...o!==void 0&&{abortSignal:o}},(m,p,S,E)=>{c.onDockerProgress?.(y(m),p,S,E)});return s.success?P({imageUri:s.data.imageUri,imageTag:s.data.imageTag}):b(s.error)}g(Ee,"buildLegacyFallback");function M(){return{contentHashTagsByService:{},imageDigestsByService:{}}}g(M,"emptyBuildProducts");async function ke(e,n,t,r,o,c,s,m,p,S,E,f,R,k){const l=e.members[0];if(!H(e.identity.dockerfilePath))return b(new Error(be(l.name,e.identity.dockerfilePath)));e.identity.resolvedViaFallback&&m.onLog?.(`Building service '${l.name}' from ${e.identity.dockerfilePath} (resolved at the project root).`,"info");const w=[...l.docker.buildSecrets??[],...R??[]],$=fe({serviceName:l.name,dockerfilePath:e.identity.dockerfilePath,buildContext:e.identity.buildContext,...e.identity.target!==void 0&&{target:e.identity.target},...l.docker.buildArgs!==void 0&&{buildArgs:l.docker.buildArgs},...w.length>0&&{buildSecrets:w},members:e.members.map(i=>({serviceName:i.name,...i.docker.buildArgs!==void 0&&{buildArgs:i.docker.buildArgs},...i.docker.buildSecrets!==void 0&&{buildSecrets:i.docker.buildSecrets}}))});if(!$.success)return b($.error);const a=q(l.docker.buildArgs,L(t.appName));for(const i of a.warnings){const v=y(i.message);k(v)&&m.onLog?.(v,"warn")}if(a.findings.length>0)return b(new Error(y(a.findings.map(i=>i.message).join(" "))));const d=w,B=ce(l.docker.buildArgs),K={appName:t.appName,region:r,accountId:o,partition:ue(r)},O=await de(p,[...d,...B],K);if(!O.success)return b(O.error);const x=O.data,A=await le({manifestBuildArgs:l.docker.buildArgs,serviceDir:e.identity.buildContext,appDir:t.path,...E!==void 0&&{stage:E},shellEnv:process.env,...f!==void 0&&{flagBuildArgs:f},resolveSourcedValue:g((i,v)=>ae(x,{id:i,...v},S),"resolveSourcedValue")});if(!A.success)return b(A.error);const N=A.data.buildArgs;for(const i of A.data.inferredDotenvKeys){const v=y(`buildArg "${i}" was auto-declared from a .env file and will be baked into the image \u2014 ${re}.`);k(v)&&m.onLog?.(v,"warn")}const u=Q(N,L(t.appName),Z(l.docker.buildArgs));if(u.length>0)return b(new Error(y(u.map(i=>i.message).join(" "))));let h;if(d.length>0){const i=await se(x,d,S);if(!i.success)return b(i.error);h=i.data}try{if(W(S))return b(new Error(`Build of service '${l.name}' was aborted before the docker build started`));const i=e.members.some(_=>_.isLambda===!0),v={appName:t.appName,appPath:e.identity.buildContext,region:r,accountId:o,buildContext:e.identity.buildContext,dockerfilePath:e.identity.dockerfilePath,pushByDigest:!0,serviceName:l.name,targetsLambda:i,...s!==void 0&&{cacheRepoUri:s},...e.identity.target!==void 0&&{target:e.identity.target},...Object.keys(N).length>0&&{buildArgs:N},...h!==void 0&&{buildSecrets:h.resolved},...S!==void 0&&{abortSignal:S}};return await Re(e,v,n,c,m)}finally{h!==void 0&&await h.cleanup().catch(()=>m.onLog?.("Build-secret cleanup failed.","warn"))}}g(ke,"buildGroup");async function Re(e,n,t,r,o){const c=await t.buildAndPush(n,(f,R,k,l)=>{o.onDockerProgress?.(y(f),R,k,l)});if(!c.success)return b(c.error);const s=c.data.imageDigest;if(typeof s!="string"||!s.startsWith("sha256:"))return b(new Error(`Buildx push succeeded but returned an invalid digest: ${y(String(s))}`));const m={},p={},S=[];for(const f of e.members){const R=f.docker.target,k=Y(s,f.name,R);if(!k.success)return b(k.error);const l=k.data,w=f.name;m[w]=l,p[w]=s,S.push(`${r}:${l}`)}const E=await t.tagByDigest({sourceImage:r,digest:s,tags:S});return E.success?P({contentHashTagsByService:m,imageDigestsByService:p}):b(E.error)}g(Re,"buildGroupWithParams");function Ae(e,n){const t=new Map(e.map(r=>[r.name,r]));for(const r of n){const o=t.get(r.name);if(o!==void 0&&JSON.stringify(o.docker)!==JSON.stringify(r.docker))throw new Error(`ECS service "${o.name}" and Lambda image key "${r.name}" share one build key but declare different docker configs \u2014 the second build would silently overwrite the first and both would deploy the same image. Rename one of them, or make the docker configs identical to deliberately share the build.`)}}g(Ae,"assertNoCrossEntityBuildKeyDivergence");async function Me(e,n,t,r){const o=e.dockerProvider;if(!o)return P(M());const c=n.awsProvider.getAccountId();if(!c)return r.onLog?.("Skipping Docker build \u2014 account ID not available","warn"),P(M());const s=n.awsProvider.getRegion(),m=F(t.path,"cdk.out");let p;try{const a=oe(m),d=ie(m);Ae(a,d),p=[...a,...d]}catch(a){const d=new Error(y(G(a)));return r.onError?.(d),b(d)}const S=ve(c,s,t.appName);if(T.debug(I,"runDockerBuild starting",{appName:t.appName,appPath:t.path,accountId:c,region:s,cdkOutPath:m,manifestServiceCount:p.length,manifestServices:p.map(a=>({name:a.name,path:a.docker.path,context:a.docker.context,target:a.docker.target})),stepId:C.DOCKER_OPERATIONS,stepName:D}),r.onStepStart?.(C.DOCKER_OPERATIONS,D),p.length===0){r.onLog?.("Initialising ECR repository\u2026","info");const a=await o.initialiseECR({appName:t.appName,region:s,accountId:c});a.success||r.onLog?.(`ECR initialisation failed: ${y(a.error.message)}`,"warn"),r.onLog?.("Building and pushing Docker image\u2026","info");const d=await Ee(o,t,s,c,e.abortSignal,r);if(!d.success){T.debug(I,"Docker buildAndPush (legacy) failed",{appName:t.appName,error:y(d.error.message)}),r.onStepComplete?.(C.DOCKER_OPERATIONS,D,"error");const B=new Error(y(d.error.message));return r.onError?.(B),b(B)}return r.onStepComplete?.(C.DOCKER_OPERATIONS,D,"completed"),r.onLog?.(`Docker image pushed: ${d.data.imageUri}`,"info"),P(M())}const E=await o.preflight?.();if(E!==void 0&&!E.success){r.onStepComplete?.(C.DOCKER_OPERATIONS,D,"error");const a=new Error(y(E.error.message));return r.onError?.(a),b(a)}const f=we(p,t.path,e.workingDirectory);let R=Se(c,s,t.appName);const k=await ge(n.awsProvider,V(L(t.appName)),e.abortSignal);k.success||(R=void 0,r.onLog?.(`Building without registry cache \u2014 ${k.error.message}`,"warn")),r.onLog?.(`Building and pushing ${p.length} service image(s) in ${f.length} group(s)\u2026`,"info");let l=!1;if(o.beginEcrSession!==void 0){const a=await o.beginEcrSession({accountId:c,region:s,...e.abortSignal!==void 0&&{abortSignal:e.abortSignal}});if(!a.success){r.onStepComplete?.(C.DOCKER_OPERATIONS,D,"error");const d=new Error(y(a.error.message));return r.onError?.(d),b(d)}l=!0}const w=new AbortController,$=g(()=>w.abort(),"onCallerAbort");e.abortSignal!==void 0&&(e.abortSignal.aborted?w.abort():e.abortSignal.addEventListener("abort",$,{once:!0}));try{const a=g(()=>W(e.abortSignal)?"the deployment was cancelled":"a sibling group failed","skipCause");let d;const B=ne(f.length),K=ee(),O=f.map((u,h)=>async()=>{const i=u.members.map(_=>_.name).join(", ");if(w.signal.aborted)throw new Error(`Build of group ${h+1}/${f.length} (${i}) was not started \u2014 ${a()}`);r.onLog?.(`Building group ${h+1}/${f.length} (${i})\u2026`,"info");const v=await ke(u,o,t,s,c,S,R,r,n.awsProvider,w.signal,e.options?.environment,e.options?.flagBuildArgs,e.options?.flagBuildSecrets,K);if(!v.success)throw d===void 0&&(d={error:v.error,leader:u.members[0]?.name,members:i}),w.abort(),v.error;return v.data}),x=await te(O,B,{abortOnFirstFailure:!0,abortSignal:w.signal});if(d===void 0)for(let u=0;u<f.length;u++){const h=x[u];if(!(h!==void 0&&h.success)){d={error:h!==void 0&&!h.success?h.error:new Error(`Build of group ${u+1}/${f.length} never ran \u2014 ${a()}`),leader:f[u].members[0]?.name,members:f[u].members.map(i=>i.name).join(", ")};break}}if(d!==void 0){T.debug(I,"Docker buildAndPush failed",{appName:t.appName,leader:d.leader,members:d.members,error:y(d.error.message)}),r.onStepComplete?.(C.DOCKER_OPERATIONS,D,"error");const u=new Error(y(d.error.message));return r.onError?.(u),b(u)}const A={},N={};for(const u of x)if(!(u===void 0||!u.success)){for(const[h,i]of Object.entries(u.data.contentHashTagsByService))A[h]=i;for(const[h,i]of Object.entries(u.data.imageDigestsByService))N[h]=i}return T.debug(I,"Docker buildAndPush succeeded",{appName:t.appName,services:p.map(u=>u.name),groupCount:f.length,contentHashTags:A}),r.onStepComplete?.(C.DOCKER_OPERATIONS,D,"completed"),r.onLog?.(`Docker images pushed for ${p.length} service(s)`,"info"),P({contentHashTagsByService:A,imageDigestsByService:N,repoUri:S})}finally{e.abortSignal?.removeEventListener("abort",$),l&&o.endEcrSession!==void 0&&await o.endEcrSession().catch(a=>{T.debug(I,"endEcrSession cleanup failed",{error:y(G(a))})})}}g(Me,"runDockerBuild");export{D as DOCKER_BUILD_STEP_NAME,ve as ecrRepoUri,M as emptyBuildProducts,Me as runDockerBuild};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ECRClient as
|
|
1
|
+
var u=Object.defineProperty;var n=(t,r)=>u(t,"name",{value:r,configurable:!0});import{ECRClient as m,CreateRepositoryCommand as y,PutLifecyclePolicyCommand as d}from"@aws-sdk/client-ecr";import{success as p,failure as c}from"@fjall/generator";import{getErrorMessage as a,maskSensitiveOutput as l}from"@fjall/util";import{untaggedLifecyclePolicyText as f,CACHE_REPO_UNTAGGED_RETENTION_DAYS as g}from"@fjall/util/docker";import{logger as C}from"@fjall/util/logger";import{composeSdkAbortSignal as s,extractErrorName as E}from"../../aws/organisations/types.js";const T="EcrCacheRepository";async function _(t,r,o){const i=t.getClient(m);try{await i.send(new y({repositoryName:r,imageScanningConfiguration:{scanOnPush:!0},imageTagMutability:"MUTABLE"}),{abortSignal:s(o)}),C.debug(T,"Created build-cache repository",{cacheRepositoryName:r})}catch(e){if(E(e)!=="RepositoryAlreadyExistsException")return c(new Error(`Could not create build-cache repository '${r}': ${l(a(e))}`))}try{await i.send(new d({repositoryName:r,lifecyclePolicyText:f(g)}),{abortSignal:s(o)})}catch(e){return c(new Error(`Could not set lifecycle policy on build-cache repository '${r}': ${l(a(e))}`))}return p(void 0)}n(_,"ensureBuildCacheRepository");export{_ as ensureBuildCacheRepository};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as
|
|
1
|
+
var K=Object.defineProperty;var f=(e,t)=>K(e,"name",{value:t,configurable:!0});import{join as w}from"path";import{success as L,failure as A}from"@fjall/generator";import{artefactOutputKey as h,maskSensitiveOutput as I}from"@fjall/util";import{parseLambdaDockerEntriesFromManifest as $}from"@fjall/util/manifest";import{isAborted as P}from"../../aws/organisations/types.js";import{ecrRepoUri as k}from"./dockerBuildHelper.js";import{rebaseRollbackTagForService as N,deriveEcrRepositoryArn as O}from"./codeOnlyDeploy.js";function b(){return{outputs:{},artefacts:[],failures:[],rolledImageKeys:[]}}f(b,"emptyOutcome");function v(e,t,n){return P(n)?(e.failures.push(`${t}: rollout cancelled before this function was reached`),!0):!1}f(v,"pushCancelledIfAborted");function U(e,t,n,a,i,c,r){const o=O(i),s=`${i}:${a}`;e.outputs[h(t,"ImageTag")]=a,e.outputs[h(t,"ImageUri")]=s,e.outputs[h(t,"ImageDigest")]=c,o!==""&&(e.outputs[h(t,"EcrRepositoryArn")]=o),e.artefacts.push({serviceName:t,imageTag:a,imageUri:s,imageDigest:c,...o!==""?{ecrRepositoryArn:o}:{},functionArn:r.functionArn,publishedVersion:r.version}),e.rolledImageKeys.some(m=>m.serviceName===n)||e.rolledImageKeys.push({serviceName:n,imageTag:a})}f(U,"recordLambdaRollout");async function R(e,t,n,a,i,c,r,o){r.onLog?.(`Updating Lambda function ${n.name} to ${c}`,"info");const s=await e.lambdaService.updateFunctionCode(n.name,`${a}@${i}`,o);if(!s.success){t.failures.push(`${n.name}: ${I(s.error.message)}`);return}s.data.unverifiedReason!==void 0&&r.onLog?.(`Updated ${n.name}, but completion of the update could not be verified: ${s.data.unverifiedReason}`,"warn"),U(t,n.name,n.imageKey,c,a,i,s.data)}f(R,"rolloutOne");function C(e,t){return e.toLowerCase()===t.toLowerCase()}f(C,"matchesLambdaFunctionName");function E(e,t){return t?e.filter(n=>C(n.name,t)):e}f(E,"filterByService");async function z(e,t,n,a,i,c,r,o){const s=b(),m=w(t.path,"cdk.out"),g=E($(m),r);for(const u of g){if(v(s,u.name,o))continue;const p=n[u.imageKey],d=a[u.imageKey];p===void 0||d===void 0||await R(e,s,u,i,d,p,c,o)}return s}f(z,"rolloutLambdaPrimary");async function G(e,t,n,a,i,c,r){const o=b(),s=w(t.path,"cdk.out"),m=E($(s),c);if(m.length===0)return o;const g=e.awsProvider.getAccountId(),u=e.awsProvider.getRegion(),p=k(g,u,t.appName);for(const d of m){if(v(o,d.name,r))continue;const l=N(n,d.imageKey,a),y=await e.ecrImageInspector.getImageDigest(p,l,r);if(!y.success||y.data===void 0){const F=y.success?"not an ECR repository":I(y.error.message);o.failures.push(`${d.name}: image tag '${l}' (rebased from '${n}') could not be resolved to a digest: ${F}`);continue}await R(e,o,d,p,y.data,l,i,r)}return o}f(G,"rolloutLambdaImageTag");async function H(e,t,n,a){const i=w(t.path,"cdk.out"),r=$(i).map(u=>({entry:u,tag:n[u.name]})).filter(u=>u.tag!==void 0);if(r.length===0)return L({matched:r,digestsByFunctionName:new Map,repoUri:""});const o=e.awsProvider.getAccountId(),s=e.awsProvider.getRegion(),m=k(o,s,t.appName),g=new Map;for(const{entry:u,tag:p}of r){if(P(a))return A(new Error("Pre-flight cancelled. No function was rolled."));const d=await e.ecrImageInspector.getImageDigest(m,p,a);if(!d.success||d.data===void 0){const l=d.success?"not an ECR repository":I(d.error.message);return A(new Error(`Lambda function '${u.name}': image tag '${p}' could not be resolved to a digest: ${l}. No function was rolled.`))}g.set(u.name,d.data)}return L({matched:r,digestsByFunctionName:g,repoUri:m})}f(H,"preflightLambdaServiceImageTags");async function J(e,t,n,a){const i=b();for(const{entry:c,tag:r}of t.matched){if(v(i,c.name,a))continue;const o=t.digestsByFunctionName.get(c.name);o!==void 0&&await R(e,i,c,t.repoUri,o,r,n,a)}return i}f(J,"executeLambdaServiceImageTagsRollout");export{J as executeLambdaServiceImageTagsRollout,C as matchesLambdaFunctionName,H as preflightLambdaServiceImageTags,G as rolloutLambdaImageTag,z as rolloutLambdaPrimary};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BaseServiceError as
|
|
1
|
+
var s=Object.defineProperty;var d=(r,e)=>s(r,"name",{value:e,configurable:!0});import{BaseServiceError as o}from"../../types/errors/ServiceError.js";class a extends o{static{d(this,"LeaseDeniedError")}stackName;constructor(e,n){super("LEASE_DENIED",e),this.stackName=n}}function i(r,e){return`Deployment lease denied ${e==="destroy"?`before destroying ${r}`:`before deploying ${r}`} \u2014 the server released or superseded this deployment (it may have been cancelled, adopted by another runner, or force-released). ${e==="destroy"?"Stacks already destroyed are gone; remaining stacks stand.":"Already-completed stacks stand."} Check the deployment in the Fjall dashboard.`}d(i,"buildLeaseDeniedMessage");async function y(r,e,n,t="deploy"){if(r===void 0)return;if(await r(e,n)==="denied")return new a(i(e,t),e)}d(y,"assertLeaseBeforeStack");export{a as LeaseDeniedError,y as assertLeaseBeforeStack};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createRequire as
|
|
2
|
-
${
|
|
3
|
-
${d}`))}const
|
|
1
|
+
var v=Object.defineProperty;var a=(i,r)=>v(i,"name",{value:r,configurable:!0});import{createRequire as S}from"module";import{existsSync as N,statSync as b,rmSync as T}from"fs";import{join as l}from"path";import{success as x,failure as o}from"@fjall/generator";import{filterDangerousEnvVars as P,maskSensitiveOutput as u,parseShellArgs as D}from"@fjall/util";import{logger as m}from"@fjall/util/logger";import{isOpenNextPattern as j}from"../../types/detection/patternDetection.js";import{spawnWithTimeout as w}from"../spawnHelpers.js";const g="@opennextjs/aws",M=6e5,B=3e4;function R(i){const r=S(l(i,"package.json"));let e;try{e=r.resolve.paths(g)}catch(n){return o(new Error(`Cannot determine module search paths for ${g}. Ensure it is installed in your project. (${n instanceof Error?n.message:String(n)})`))}if(!e||e.length===0)return o(new Error(`Cannot determine module search paths for ${g}. Ensure it is installed in your project.`));for(const n of e){const p=l(n,"@opennextjs","aws");try{if(b(p).isDirectory()){const t=l(n,".bin","open-next");if(!N(t)){m.debug("openNextBuild","Package found but binary missing",{nodeModulesPath:n,binPath:t});continue}return m.debug("openNextBuild","Resolved OpenNext binary",{binPath:t}),x(t)}}catch(s){m.debug("openNextBuild","Package not at location",{nodeModulesPath:n,error:String(s)})}}return o(new Error(`Cannot find ${g} package. Ensure it is installed in your project: npm install ${g}`))}a(R,"resolveOpenNextBinary");function y(i){const r=l(i,".open-next");if(N(r))try{T(r,{recursive:!0,force:!0}),m.debug("openNextBuild","Cleaned up stale .open-next directory",{path:r})}catch(e){m.debug("openNextBuild","Failed to clean up .open-next",{error:String(e)})}}a(y,"cleanupOpenNextOutput");function h(i,r,e,n){switch(i.type){case"timeout":return e?.(),n?.(r.timeoutMsg),o(new Error(r.timeoutMsg));case"aborted":return e?.(),n?.(r.abortedMsg),o(new Error(r.abortedMsg));case"enoent":return e?.(),n?.(r.enoentMsg),o(new Error(r.enoentMsg));case"spawn_error":{const p=`${r.spawnErrorPrefix}: ${i.error.message}`;return e?.(),n?.(p),o(new Error(p))}default:return}}a(h,"handleSpawnError");async function C(i,r,e){r.onOpenNextProgress?.(u("Generating Payload import map..."));const[n,...p]=D("npx payload generate:importmap"),s=P(globalThis.process.env),t=await w({command:n,args:p,cwd:i,env:{...s,FORCE_COLOR:"0"},timeout:B,...e!==void 0&&{abortSignal:e},onStdoutData:a(f=>{r.onOpenNextProgress?.(u(f.trim()))},"onStdoutData")}),O=h(t,{timeoutMsg:`Payload import map generation timed out after ${B/1e3} seconds`,abortedMsg:"Payload import map generation cancelled",enoentMsg:"Payload CLI not found. Ensure payload is installed: npm install payload",spawnErrorPrefix:"Failed to generate Payload import map"});if(O)return O;if(t.type!=="success")return o(new Error("Unexpected spawn result"));if(t.code!==0){const f=u(t.stderr||t.stdout);return o(new Error(`Payload import map generation failed (exit code ${t.code}):
|
|
2
|
+
${f}`))}return m.debug("openNextBuild","Payload import map generated",{appPath:i}),r.onOpenNextProgress?.(u("Payload import map generated")),x(void 0)}a(C,"generatePayloadImportMap");async function K(i,r,e,n,p){if(!j(r))return x(void 0);if(n?.skipBuild||n?.infraOnly)return m.debug("openNextBuild","Build skipped",{skipBuild:n?.skipBuild,infraOnly:n?.infraOnly}),e.onLog?.(n?.infraOnly?"Infrastructure-only mode \u2014 skipping OpenNext build":"Build skipped (--skip-build)","info"),x(void 0);const s=i.path;if(r==="payload"){const d=await C(s,e,p);if(!d.success)return e.onOpenNextBuildError?.(u(d.error.message)),y(s),o(d.error)}const t=R(s);if(!t.success)return e.onOpenNextBuildError?.(u(t.error.message)),o(t.error);const O=t.data;e.onOpenNextBuildStart?.(),e.onOpenNextProgress?.(u("Starting OpenNext build..."));const f=P(globalThis.process.env),_=l(s,"node_modules"),c=await w({command:O,args:["build"],cwd:s,env:{...f,FORCE_COLOR:"0",NODE_PATH:_,npm_config_loglevel:"error",PNPM_HOME:f.PNPM_HOME||""},timeout:M,...p!==void 0&&{abortSignal:p},onStdoutData:a(d=>{e.onOpenNextProgress?.(u(d.trim()))},"onStdoutData"),onStderrData:a(d=>{e.onOpenNextProgress?.(u(d.trim()))},"onStderrData")}),E=h(c,{timeoutMsg:`OpenNext build timed out after ${M/1e3} seconds`,abortedMsg:"OpenNext build cancelled",enoentMsg:"OpenNext binary not found. Ensure Node.js is installed and in PATH.",spawnErrorPrefix:"Failed to spawn OpenNext build"},()=>y(s),d=>e.onOpenNextBuildError?.(d));if(E)return E;if(c.type!=="success")return o(new Error("Unexpected spawn result"));if(c.code!==0){y(s);const d=u(c.stderr||c.stdout);return e.onOpenNextBuildError?.(`OpenNext build failed (exit code ${c.code})`),o(new Error(`OpenNext build failed (exit code ${c.code}):
|
|
3
|
+
${d}`))}const $=l(s,".open-next");return N($)?(e.onOpenNextBuildComplete?.(),e.onOpenNextProgress?.(u("OpenNext build completed successfully")),x(void 0)):(e.onOpenNextBuildError?.("OpenNext build completed but .open-next directory not found"),o(new Error("OpenNext build completed but .open-next directory not found")))}a(K,"runOpenNextBuild");export{M as BUILD_TIMEOUT_MS,B as IMPORT_MAP_TIMEOUT_MS,K as runOpenNextBuild};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHmac as
|
|
1
|
+
var m=Object.defineProperty;var a=(e,t)=>m(e,"name",{value:t,configurable:!0});import{createHmac as i,randomBytes as p,timingSafeEqual as T}from"node:crypto";import{digestHead as u}from"./assemblyDigest.js";const f=16,E=900*1e3,R=1500*60*1e3,S=/^([0-9a-f]{32})\.([0-9]{1,16})\.([0-9a-f]{32})$/;function x(){const e=process.env.FJALL_APPROVAL_TOKEN_SECRET;return e!==void 0&&e!==""?{secret:Buffer.from(e,"utf8"),stable:!0}:{secret:p(32),stable:!1}}a(x,"resolveSecret");const{secret:d,stable:_}=x();function b(e){const t=u(e.assemblyDigest),r=e.now??Date.now,o=e.ttlMs??E,n=r()+o,s=i("sha256",d).update(`${t}.${n}`).digest().subarray(0,f).toString("hex");return{token:`${t}.${n}.${s}`,expiresAt:new Date(n).toISOString()}}a(b,"signApprovalToken");function h(e){const t=S.exec(e.token);if(t===null)return{ok:!1,reason:"malformed"};const r=t[1],o=t[2],n=t[3];if(r===void 0||o===void 0||n===void 0)return{ok:!1,reason:"malformed"};if(r!==u(e.assemblyDigest))return{ok:!1,reason:"superseded"};const s=parseInt(o,10);if(!Number.isFinite(s))return{ok:!1,reason:"malformed"};if((e.now??Date.now)()>s)return{ok:!1,reason:"expired"};if(_){const l=i("sha256",d).update(`${r}.${o}`).digest().subarray(0,f),c=Buffer.from(n,"hex");if(c.length!==f||!T(l,c))return{ok:!1,reason:"tampered"}}return{ok:!0}}a(h,"verifyApprovalToken");export{S as APPROVAL_TOKEN_PATTERN,E as DEFAULT_APPROVAL_TTL_MS,R as DESTRUCTION_RESUME_TTL_MS,b as signApprovalToken,h as verifyApprovalToken};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createHash as
|
|
2
|
-
`);return
|
|
1
|
+
var c=Object.defineProperty;var r=(t,o)=>c(t,"name",{value:o,configurable:!0});import{createHash as n}from"node:crypto";function i(t){const o=[...t.entries()].sort(([s],[a])=>s<a?-1:s>a?1:0),e=n("sha256");for(const[s,a]of o)e.update(s),e.update("\0"),e.update(a),e.update(`
|
|
2
|
+
`);return e.digest("hex")}r(i,"computeAssemblyDigest");function p(t){return n("sha256").update(t).digest("hex").slice(0,32)}r(p,"digestHead");export{i as computeAssemblyDigest,p as digestHead};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{diffTemplate as
|
|
1
|
+
var y=Object.defineProperty;var i=(n,a)=>y(n,"name",{value:a,configurable:!0});import{diffTemplate as h}from"@aws-cdk/cloudformation-diff";import{classifyImpact as g,derivePropertyChanges as C,isDataLoss as T}from"./classify.js";import{renderPlanSummary as v}from"./renderDeployPlan.js";function k(){return{create:0,update:0,replace:0,delete:0,read:0,"no-op":0}}i(k,"emptyCounts");function R(n,a){const t=[],s=k();let p=!1,u=!1;for(const r of n){const c=h(r.oldTemplate??{},r.newTemplate??{});c.iamChanges.permissionsBroadened&&(p=!0),c.securityGroupChanges.hasChanges&&(u=!0),c.resources.forEachDifference((l,o)=>{const e=g(o.changeImpact);if(s[e.action]+=1,e.action==="no-op")return;const d=o.newResourceType??o.oldResourceType??"AWS::Unknown::Resource";t.push({stack:r.stackName,address:l,resourceType:d,action:e.action,replacementMode:e.replacementMode,destructive:e.destructive,retained:e.retained,dataLoss:T({action:e.action,retained:e.retained,resourceType:d}),propertyChanges:C(o.propertyUpdates)})})}const m=t.length,f=t.some(r=>r.destructive);return{changes:t,changeCount:m,counts:s,hasDestructiveChanges:f,iamBroadening:p,securityGroupBroadening:u,assemblyDigest:a,summary:v({counts:s,changes:t})}}i(R,"buildDeployPlan");export{R as buildDeployPlan};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{maskSensitiveOutput as
|
|
1
|
+
var S=Object.defineProperty;var n=(t,r)=>S(t,"name",{value:r,configurable:!0});import{maskSensitiveOutput as w}from"@fjall/util";import{logger as p}from"@fjall/util/logger";import{isAborted as g}from"../../../aws/organisations/types.js";import{isDataLoss as T,isStatefulResourceType as C}from"./classify.js";import{recountActions as M}from"./registryOverlay.js";import{renderPlanSummary as b}from"./renderDeployPlan.js";const f="ChangeSetEscalation";function N(t){return t.action!=="replace"||t.retained||t.replacementMode!=="conditional"&&t.replacementMode!=="may"?!1:C(t.resourceType)||t.pinnedPhysicalName!==void 0}n(N,"needsChangeSetEscalation");function L(t){return`change-set preflight proved this update applies in place (${t.replacementMode} verdict downgraded)`}n(L,"downgradeNote");function $(t){return{...t,action:"update",replacementMode:"none",destructive:!1,dataLoss:!1,propertyChanges:t.propertyChanges.map(r=>({...r,forcesReplacement:!1})),verdictSource:"change-set",interruptionNote:L(t)}}n($,"downgradeToInPlace");function B(t){return{...t,action:"replace",replacementMode:"will",destructive:!0,dataLoss:T({action:"replace",retained:t.retained,resourceType:t.resourceType}),verdictSource:"change-set"}}n(B,"upgradeToDefinite");function D(t){return t.verdictSource!=="registry"?t:{...t,verdictSource:"registry (change-set unverified)"}}n(D,"annotateUnverified");async function O(t){const{plan:r,probe:l,stacks:m,abortSignal:c}=t,d=r.changes.filter(N);if(d.length===0)return r;const y=new Map(m.map(e=>[e.stackName,e])),v=[...new Set(d.map(e=>e.stack))],o=new Map;for(const e of v){if(g(c)){o.set(e,"unverified");continue}const s=y.get(e);if(s===void 0){p.warn(f,"No synthesised template for escalated stack",{stackName:e}),o.set(e,"unverified");continue}const a=await l.probeStackReplacements({stackName:e,template:s.newTemplate,...c!==void 0?{abortSignal:c}:{}});if(!a.success){p.warn(f,"Change-set probe degraded to registry verdict",{stackName:e,error:w(a.error.message)}),o.set(e,"unverified");continue}o.set(e,a.data.replacementByLogicalId)}const k=new Set(d.map(e=>`${e.stack}|${e.address}`)),i=r.changes.map(e=>{if(!k.has(`${e.stack}|${e.address}`))return e;const s=o.get(e.stack);if(s===void 0||s==="unverified")return D(e);const a=s.get(e.address)??"False";return a==="False"?$(e):a==="True"?B(e):(p.warn(f,"Change set could not decide \u2014 keeping worst case",{stack:e.stack,address:e.address,resourceType:e.resourceType}),e)}),u=M(i);return u["no-op"]=r.counts["no-op"],{...r,changes:i,counts:u,hasDestructiveChanges:i.some(e=>e.destructive),summary:b({counts:u,changes:i})}}n(O,"applyChangeSetEscalation");export{O as applyChangeSetEscalation,N as needsChangeSetEscalation};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ResourceImpact as t}from"@aws-cdk/cloudformation-diff";function
|
|
1
|
+
var i=Object.defineProperty;var a=(e,n)=>i(e,"name",{value:n,configurable:!0});import{ResourceImpact as t}from"@aws-cdk/cloudformation-diff";function f(e){switch(e){case t.WILL_CREATE:return{action:"create",replacementMode:"none",destructive:!1,retained:!1};case t.WILL_UPDATE:return{action:"update",replacementMode:"none",destructive:!1,retained:!1};case t.WILL_REPLACE:return{action:"replace",replacementMode:"will",destructive:!0,retained:!1};case t.MAY_REPLACE:return{action:"replace",replacementMode:"may",destructive:!0,retained:!1};case t.WILL_DESTROY:return{action:"delete",replacementMode:"none",destructive:!0,retained:!1};case t.WILL_ORPHAN:return{action:"delete",replacementMode:"none",destructive:!1,retained:!0};case t.WILL_IMPORT:return{action:"read",replacementMode:"none",destructive:!1,retained:!1};case t.NO_CHANGE:return{action:"no-op",replacementMode:"none",destructive:!1,retained:!1};default:{const n=e;return{action:"replace",replacementMode:"conditional",destructive:!0,retained:!1}}}}a(f,"classifyImpact");const o=["AWS::RDS::","AWS::DynamoDB::Table","AWS::DynamoDB::GlobalTable","AWS::S3::Bucket","AWS::EFS::FileSystem","AWS::ElastiCache::","AWS::Redshift::","AWS::DocDB::","AWS::Neptune::","AWS::OpenSearchService::Domain","AWS::Elasticsearch::Domain","AWS::MSK::Cluster","AWS::QLDB::Ledger","AWS::Timestream::","AWS::EC2::Volume","AWS::FSx::"];function s(e){return o.some(n=>e.startsWith(n))}a(s,"isStatefulResourceType");function S(e){return e.retained||e.action!=="replace"&&e.action!=="delete"?!1:s(e.resourceType)}a(S,"isDataLoss");const l=new Set([t.WILL_REPLACE,t.MAY_REPLACE]);function A(e){if(e===void 0)return[];const n=[];for(const[c,r]of Object.entries(e))if(r.isDifferent!==!1&&(n.push({path:c,forcesReplacement:r.changeImpact!==void 0&&l.has(r.changeImpact)}),n.length>=100))break;return n}a(A,"derivePropertyChanges");export{f as classifyImpact,A as derivePropertyChanges,S as isDataLoss,s as isStatefulResourceType};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
var f=Object.defineProperty;var l=(e,t)=>f(e,"name",{value:t,configurable:!0});import{success as s,failure as n}from"@fjall/generator";import{maskSensitiveOutput as u}from"@fjall/util";import{isAborted as p}from"../../../aws/organisations/types.js";import{buildDeployPlan as d}from"./buildDeployPlan.js";import{applyChangeSetEscalation as g}from"./changeSetEscalation.js";import{applyRegistryOverlay as m}from"./registryOverlay.js";function y(e){const t=e.trim();if(t==="")return s({});try{return s(JSON.parse(t))}catch(r){return n(new Error(`Failed to parse deployed template: ${u(r instanceof Error?r.message:String(r))}`))}}l(y,"parseTemplateBody");async function E(e){const t=[];for(const i of e.stacks){if(p(e.abortSignal))return n(new Error("Deploy-plan computation aborted"));const o=await e.cfnService.getTemplate(i.stackName,e.abortSignal);let c={};if(o.success){const a=y(o.data);if(!a.success)return n(a.error);c=a.data}else if(o.error.errorType!=="stack_not_found")return n(o.error);t.push({stackName:i.stackName,oldTemplate:c,newTemplate:i.newTemplate})}let r=d(t,e.assemblyDigest);return e.registry!==void 0&&(r=await m({plan:r,registry:e.registry,stacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})),e.changeSetProbe!==void 0&&(r=await g({plan:r,probe:e.changeSetProbe,stacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})),s(r)}l(E,"computeDeployPlan");export{E as computeDeployPlan};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as
|
|
1
|
+
var a=Object.defineProperty;var o=(e,t)=>a(e,"name",{value:t,configurable:!0});import{join as l}from"node:path";import{readFile as s}from"node:fs/promises";import{failure as f}from"@fjall/generator";import{maskSensitiveOutput as d}from"@fjall/util";import{computeDeployPlan as u}from"./computeDeployPlan.js";async function g(e){const t=[];for(const r of e.changedStacks){const c=l(e.cdkOutPath,`${r}.template.json`);let i;try{i=JSON.parse(await s(c,"utf8"))}catch(n){return f(new Error(d(`Failed to read synthesised template for ${r}: ${n instanceof Error?n.message:String(n)}`)))}t.push({stackName:r,newTemplate:i})}return u({cfnService:e.cfnService,stacks:t,assemblyDigest:e.assemblyDigest,...e.registry!==void 0?{registry:e.registry}:{},...e.changeSetProbe!==void 0?{changeSetProbe:e.changeSetProbe}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})}o(g,"loadDeployPlan");function P(e){let t;return()=>(t??=g(e),t)}o(P,"createMemoisedPlanLoader");export{P as createMemoisedPlanLoader,g as loadDeployPlan};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{PHYSICAL_NAME_FALLBACK_PROPERTIES as
|
|
1
|
+
var d=Object.defineProperty;var i=(e,n)=>d(e,"name",{value:n,configurable:!0});import{PHYSICAL_NAME_FALLBACK_PROPERTIES as c}from"@fjall/util";const u="/properties/";function s(e){if(e===void 0||e.length!==1)return;const n=e[0];if(n===void 0||!n.startsWith(u))return;const r=n.slice(u.length);if(!(r===""||r.includes("/")))return r}i(s,"namingPropertyFromIdentifier");function f(e){if(typeof e=="string"&&e!=="")return e;if(typeof e=="number")return String(e)}i(f,"literalValue");function l(e){if(e.properties===void 0)return;const n=s(e.primaryIdentifier);if(n!==void 0){const t=f(e.properties[n]);if(t!==void 0)return t}const r=c[e.resourceType];if(r!==void 0)return f(e.properties[r])}i(l,"findPinnedPhysicalName");function y(e,n){if(typeof e!="object"||e===null)return;const r=e.Resources;if(typeof r!="object"||r===null)return;const t=r[n];if(typeof t!="object"||t===null)return;const o=t.Properties;if(!(typeof o!="object"||o===null||Array.isArray(o)))return o}i(y,"resourcePropertiesFromTemplate");export{l as findPinnedPhysicalName,y as resourcePropertiesFromTemplate};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{maskSensitiveOutput as
|
|
1
|
+
var g=Object.defineProperty;var p=(e,t)=>g(e,"name",{value:t,configurable:!0});import{maskSensitiveOutput as O}from"@fjall/util";import{logger as v}from"@fjall/util/logger";import{isAborted as R}from"../../../aws/organisations/types.js";import{isDataLoss as C}from"./classify.js";import{findPinnedPhysicalName as h,resourcePropertiesFromTemplate as P}from"./pinnedNames.js";import{renderPlanSummary as N}from"./renderDeployPlan.js";const T="RegistryOverlay",k={"AWS::RDS::DBInstance#Port":"port changes apply in place with a brief interruption (instance reboot + dependent-service re-point window); to keep the live port instead, pin it \u2014 set `port` in your fjall config to the current live value and the change disappears","AWS::RDS::DBCluster#Port":"port changes apply in place with a brief interruption (cluster reboot + dependent-service re-point window); to keep the live port instead, pin it \u2014 set `port` in your fjall config to the current live value and the change disappears"},I="/properties/";function b(e,t){const o=`${I}${e}`;if(t.createOnlyProperties.includes(o))return"will";if(t.conditionalCreateOnlyProperties.includes(o))return"conditional";const i=`${o}/`;return t.createOnlyProperties.some(s=>s.startsWith(i))||t.conditionalCreateOnlyProperties.some(s=>s.startsWith(i))?"conditional":"none"}p(b,"registryVerdictForProperty");function D(e){return e.includes("will")?"will":e.includes("conditional")?"conditional":"none"}p(D,"worstVerdict");function M(e,t){const o=t.map(i=>k[`${e.resourceType}#${i}`]).filter(i=>i!==void 0);if(o.length!==0)return o.join("; ")}p(M,"interruptionNoteFor");function w(e){return(e.action==="update"||e.action==="replace")&&!e.retained}p(w,"isOverlayCandidate");function x(e){return w(e)||e.action==="delete"}p(x,"needsSummary");function E(e,t,o){if(e.action==="delete"&&t!==void 0){const n=h({resourceType:e.resourceType,properties:o,primaryIdentifier:t.primaryIdentifier});return{change:{...e,...n!==void 0?{pinnedPhysicalName:n}:{}}}}if(!w(e))return{change:e};if(t===void 0||e.propertyChanges.length===0)return{change:{...e,verdictSource:"cdk-spec (unverified)"}};const i=e.propertyChanges.map(n=>({path:n.path,verdict:b(n.path,t)})),c=D(i.map(n=>n.verdict)),s=c==="none"?"update":"replace",d=c,m=c!=="none",u=C({action:s,retained:e.retained,resourceType:e.resourceType}),l=e.propertyChanges.map((n,S)=>({...n,forcesReplacement:i[S]?.verdict!=="none"})),r=i.filter(n=>n.verdict==="none").map(n=>n.path),a=c==="none"?M(e,r):void 0,f=h({resourceType:e.resourceType,properties:o,primaryIdentifier:t.primaryIdentifier}),y={...e,action:s,replacementMode:d,destructive:m,dataLoss:u,propertyChanges:l,verdictSource:"registry",...a!==void 0?{interruptionNote:a}:{},...f!==void 0?{pinnedPhysicalName:f}:{}};return e.replacementMode===d?{change:y}:{change:y,disagreement:{stack:e.stack,address:e.address,resourceType:e.resourceType,cdkSpecMode:e.replacementMode,registryMode:d,paths:i.map(n=>n.path)}}}p(E,"overlayResourceChange");function $(e){const t={create:0,update:0,replace:0,delete:0,read:0,"no-op":0};for(const o of e)t[o.action]+=1;return t}p($,"recountActions");async function _(e){const{plan:t,registry:o,stacks:i,abortSignal:c}=e,s=new Set(t.changes.filter(x).map(r=>r.resourceType));if(s.size===0)return t;const d=new Map;for(const r of s){if(R(c))break;const a=await o.getSchemaSummary(r,c);a.success?d.set(r,a.data):v.warn(T,"Registry oracle unavailable for type",{typeName:r,error:O(a.error.message)})}const m=new Map(i.map(r=>[r.stackName,r])),u=t.changes.map(r=>{const a=m.get(r.stack),f=r.action==="delete"?P(a?.oldTemplate,r.address):P(a?.newTemplate,r.address),{change:y,disagreement:n}=E(r,d.get(r.resourceType),f);return n!==void 0&&v.warn(T,"Registry verdict disagrees with bundled CDK spec",{...n,paths:n.paths.join(",")}),y}),l=$(u);return l["no-op"]=t.counts["no-op"],{...t,changes:u,counts:l,hasDestructiveChanges:u.some(r=>r.destructive),summary:N({counts:l,changes:u})}}p(_,"applyRegistryOverlay");export{k as INTERRUPTION_NOTES,_ as applyRegistryOverlay,E as overlayResourceChange,$ as recountActions,b as registryVerdictForProperty};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
var p=Object.defineProperty;var n=(a,e)=>p(a,"name",{value:e,configurable:!0});const c={create:0,update:1,replace:2,delete:3,read:4,"no-op":5},u={create:"+",update:"~",replace:"\xB1",delete:"-",read:">","no-op":" "};function h(a){const{counts:e}=a,t=[];if(e.create>0&&t.push(`${e.create} to create`),e.update>0&&t.push(`${e.update} to update`),e.replace>0&&t.push(`${e.replace} to replace`),e.delete>0&&t.push(`${e.delete} to destroy`),e.read>0&&t.push(`${e.read} to read`),t.length===0)return"No changes";const s=a.changes.filter(o=>o.destructive).length,d=a.changes.filter(o=>o.dataLoss).length,r=[];s>0&&r.push(`${s} destructive`),d>0&&r.push(`${d} with data loss`);const i=t.join(", ");return r.length>0?`${i} (${r.join(", ")})`:i}n(h,"renderPlanSummary");function f(a){return a.changes.slice().sort((e,t)=>c[e.action]-c[t.action]||`${e.stack}/${e.address}`.localeCompare(`${t.stack}/${t.address}`)).map(e=>{const t=[];e.replacementMode==="may"&&t.push("may replace"),e.replacementMode==="conditional"&&t.push("conditional replace"),e.dataLoss&&t.push("data loss"),e.retained&&t.push("retained"),(e.verdictSource==="cdk-spec (unverified)"||e.verdictSource==="registry (change-set unverified)")&&t.push("unverified");const s=t.length>0?` (${t.join(", ")})`:"";return`${u[e.action]} ${e.action.padEnd(7)} ${e.resourceType} ${e.stack}/${e.address}${s}`})}n(f,"renderPlanLines");function $(a){return a.changes.map(e=>({address:e.address,resourceType:e.resourceType,action:e.action,stack:e.stack,replacementMode:e.replacementMode,dataLoss:e.dataLoss,...e.propertyChanges.length>0&&{propertyChanges:e.propertyChanges}}))}n($,"toWirePlanChanges");export{f as renderPlanLines,h as renderPlanSummary,$ as toWirePlanChanges};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
var E=Object.defineProperty;var l=(s,c)=>E(s,"name",{value:c,configurable:!0});import{success as D,failure as g}from"@fjall/generator";import{maskSensitiveOutput as h}from"@fjall/util";import{extractEcsServiceName as $}from"../../aws/utils/arnParser.js";import{isAborted as k}from"../../aws/organisations/types.js";import{stripTagOrDigest as N}from"../../services/infrastructure/EcrImageInspectorService.js";function S(s,c){const a=s.toLowerCase(),r=c.toLowerCase();return a===r||a.endsWith(r)}l(S,"matchesServiceName");function M(s,c){const a=Object.entries(c),r=[],d=[],n=new Set,o=s.map(e=>{const t=$(e)??e;return{serviceArn:e,serviceName:t,lowerName:t.toLowerCase()}}),i=new Map,u=new Set;for(const e of o){const t=a.find(([f])=>f.toLowerCase()===e.lowerName);t!==void 0&&(i.set(e.serviceArn,t),u.add(t[0]))}const m=new Map,v=new Map;for(const e of o){if(i.has(e.serviceArn))continue;const t=a.filter(([f])=>!u.has(f)&&S(e.serviceName,f)).sort(([f],[w])=>w.length-f.length)[0];t!==void 0&&(m.set(e.serviceArn,t),v.set(t[0],(v.get(t[0])??0)+1))}for(const e of o){const t=m.get(e.serviceArn),f=i.get(e.serviceArn)??(t!==void 0&&v.get(t[0])===1?t:void 0);if(f===void 0){d.push(e.serviceName);continue}const[w,y]=f;n.add(w),r.push({serviceArn:e.serviceArn,serviceName:e.serviceName,tag:y,mapKey:w})}const p=a.map(([e])=>e).filter(e=>!n.has(e));return{matched:r,unmatchedLiveServiceNames:d,staleMapKeys:p}}l(M,"matchServiceImageTagsToLiveServices");async function x(s,c,a,r,d){const n=await s.ecsService.describeServices(c,[a],d);if(!n.success)return g(new Error(`Failed to describe service ${r}: ${h(n.error.message)}`));const o=n.data[0];if(!o?.taskDefinition)return g(new Error(`Service ${r} has no task definition`));const i=o.taskDefinition,u=await s.ecsService.getLatestTaskDefinition(i,d);if(!u.success)return g(new Error(`Failed to fetch task definition for ${r}: ${h(u.error.message)}`));const m=u.data;if(!m||!m.containerDefinitions||m.containerDefinitions.length===0)return g(new Error(`Task definition for ${r} has no container definitions`));const v=m.containerDefinitions,p=v.find(t=>t.image)?.image;if(!p)return g(new Error(`Task definition for ${r} has no container image \u2014 cannot derive repository URI`));const e=N(p);return D({previousTaskDefArn:i,taskDefinition:m,containerDefinitions:v,repoUri:e})}l(x,"resolveServiceTaskDefinition");async function K(s,c,a,r){const d=new Map;for(const n of a){if(k(r))return g(new Error("Pre-flight cancelled. No service was rolled."));const o=await x(s,c,n.serviceArn,n.serviceName,r);if(!o.success)return g(new Error(`Pre-flight failed resolving the current task definition for ${n.serviceName} (tag ${n.tag}): ${h(o.error.message)}. No service was rolled.`));const i=await s.ecrImageInspector.getImageDigest(o.data.repoUri,n.tag,r);if(!i.success||i.data===void 0){const u=i.success?"ECR returned no digest for this tag (non-ECR repository, or the image is missing)":h(i.error.message);return g(new Error(`Pre-flight digest resolution failed for ${n.serviceName} (tag ${n.tag}): ${u}. No service was rolled.`))}d.set(n.serviceArn,{taskDefinition:o.data,imageDigest:i.data})}return D(d)}l(K,"preflightResolveServiceImageTagDigests");export{M as matchServiceImageTagsToLiveServices,S as matchesServiceName,K as preflightResolveServiceImageTagDigests,x as resolveServiceTaskDefinition};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
var $=Object.defineProperty;var l=(t,s)=>$(t,"name",{value:s,configurable:!0});import{success as y,failure as f}from"@fjall/generator";import{logger as E}from"@fjall/util/logger";import{maskSensitiveOutput as g}from"@fjall/util";const x="taskDefinitionRoll";async function P(t,s,r,C){const{clusterArn:m,serviceArn:a,serviceName:n,taskDefinition:e,containerDefinitions:v,previousTaskDefArn:D,imageDigest:k,startedAtMs:w}=s,d=e.family;if(!d)return f(new Error(`Task definition for ${n} has no family`));const p=await t.ecsService.registerTaskDefinition({family:d,taskRoleArn:e.taskRoleArn,executionRoleArn:e.executionRoleArn,networkMode:e.networkMode,containerDefinitions:v,volumes:e.volumes,placementConstraints:e.placementConstraints,requiresCompatibilities:e.requiresCompatibilities,cpu:e.cpu,memory:e.memory,runtimePlatform:e.runtimePlatform,proxyConfiguration:e.proxyConfiguration,inferenceAccelerators:e.inferenceAccelerators,pidMode:e.pidMode,ipcMode:e.ipcMode,ephemeralStorage:e.ephemeralStorage},C);if(!p.success)return f(new Error(`Failed to register task definition for ${n}: ${p.error.message}`));const i=p.data;r.onTaskDefRegistered?.({serviceName:n,taskDefinitionArn:i,previousTaskDefinitionArn:D,revision:M(i),family:d,...k!==void 0?{imageDigest:k}:{}});const A=await t.ecsService.updateService(m,a,{taskDefinition:i,forceNewDeployment:!0},C);if(!A.success)return f(new Error(`Failed to update service ${n}: ${A.error.message}`));const R=await t.ecsService.pollDeployment({clusterArn:m,serviceArn:a,waitForCompletion:!0,progressCallback:l(o=>{const S=o.latestEvent?` \u2014 ${g(o.latestEvent)}`:"";r.onECSProgress?.(`${n}: ${g(o.message)}${S}`,o.percentComplete)},"progressCallback")}),c=Date.now()-w;if(!R.success){const o=g(R.error.message);return r.onECSComplete?.({serviceName:n,serviceArn:a,success:!1,taskDefinitionArn:i,durationMs:c,reason:o}),f(new Error(`ECS rollout failed for ${n}: ${o}`))}const u=await t.ecsService.getDeploymentStatus(m,a);return r.onECSComplete?.({serviceName:n,serviceArn:a,success:!0,taskDefinitionArn:i,durationMs:c,finalRunningCount:u.success?u.data.runningCount:void 0,finalDesiredCount:u.success?u.data.desiredCount:void 0}),E.debug(x,`Rolled ${n} successfully`,{serviceArn:a,newTaskDefArn:i,previousTaskDefArn:D,durationMs:c}),y({newTaskDefArn:i,durationMs:c})}l(P,"registerAndRollTaskDefinition");function M(t){const s=t.lastIndexOf(":");if(s<0)return 0;const r=t.slice(s+1);return/^\d+$/.test(r)?parseInt(r,10):0}l(M,"extractRevision");export{M as extractRevision,P as registerAndRollTaskDefinition};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
var I=Object.defineProperty;var p=(g,n)=>I(g,"name",{value:n,configurable:!0});import{success as m,failure as c}from"@fjall/generator";import{maskSensitiveOutput as d}from"@fjall/util";import{STEP_IDS as i}from"../../types/stepDefinitions.js";const S="Tagging container images";async function _(g,n,a,e){const r=g.dockerProvider;if(!r)return m(void 0);const s=n.awsProvider.getAccountId();if(!s)return e.onLog?.("Skipping ECR initialisation \u2014 account ID not available","warn"),m(void 0);const E=n.awsProvider.getRegion();e.onStepStart?.(i.DOCKER_OPERATIONS,"Initialising container repository"),e.onLog?.("Initialising ECR repository with welcome image\u2026","info");const u=await r.initialiseECR({appName:a.appName,region:E,accountId:s});if(u.success||e.onLog?.(d(`ECR initialisation warning: ${u.error.message}`),"warn"),e.onStepComplete?.(i.DOCKER_OPERATIONS,"Initialising container repository","completed"),r.tagImages){e.onStepStart?.(i.TAG_ECR_IMAGES,S),e.onLog?.("Tagging ECR images for ECS services\u2026","info");const f=p(o=>{e.onLog?.(d(o),"info")},"tagProgress"),t=await r.tagImages({appName:a.appName,appPath:a.path,region:E,accountId:s},f);if(!t.success){const o=new Error(d(t.error.message));return e.onError?.(o),e.onStepComplete?.(i.TAG_ECR_IMAGES,S,"error"),c(o)}e.onLog?.(`Tagged ${t.data.taggedServices.length} service(s): ${t.data.taggedServices.join(", ")}`,"info");for(const o of t.data.taggedServices)e.onStepStart?.(`tag-ecr-images-${o}`,`Tagged ${o}`),e.onStepComplete?.(`tag-ecr-images-${o}`,`Tagged ${o}`,"completed");e.onStepComplete?.(i.TAG_ECR_IMAGES,S,"completed")}return m(void 0)}p(_,"runWelcomeImageSetup");export{_ as runWelcomeImageSetup};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
var n=Object.defineProperty;var a=(r,e)=>n(r,"name",{value:e,configurable:!0});import{existsSync as i,readFileSync as l}from"fs";import{join as c}from"path";import{success as u}from"@fjall/generator";import{logger as f}from"@fjall/util/logger";import{getErrorMessage as d}from"@fjall/util";import{hasDockerfile as p}from"../../util/dockerfileDetection.js";import{INFRASTRUCTURE_FILENAME as m}from"../../types/constants.js";import{getApplicationDeployOrder as h,getApplicationDestroyOrder as D}from"../../types/operations.js";const o={hasNetwork:!0,hasCompute:!0,hasDatabase:!1,hasStorage:!1,hasMessaging:!1,hasCdn:!1};function b(r){try{const e=c(r,m);return i(e)?{exists:!0,hasDatabase:l(e,"utf-8").includes("DatabaseFactory.build(")}:{exists:!1,hasDatabase:!1}}catch(e){return f.debug("dockerBuilder","Failed to read infrastructure file",{appPath:r,error:d(e)}),{exists:!1,hasDatabase:!1}}}a(b,"detectResources");const S={name:"docker",priority:100,detect(r){const{exists:e,hasDatabase:s}=b(r.appPath);if(!e)return{detected:!1,pattern:null,reason:"No infrastructure.ts found",resources:o,hasDatabase:!1,hasDockerfile:!1};const t=p(r.appPath);return{detected:!0,pattern:null,reason:t?"infrastructure.ts found with Dockerfile":"infrastructure.ts found (no Dockerfile)",resources:{...o,hasDatabase:s},hasDatabase:s,hasDockerfile:t}},plan(r,e){const s=e.resources;return{builderName:"docker",deployOrder:h({resources:s}),destroyOrder:D({resources:s}),parallelDestroy:!1,preBuildCommands:[],buildCommand:null,requiresDockerBuild:e.hasDockerfile,resources:s}},async build(r,e,s,t){return u(void 0)}};export{S as dockerBuilder};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{openNextBuilder as
|
|
1
|
+
var c=Object.defineProperty;var u=(d,t)=>c(d,"name",{value:t,configurable:!0});import{openNextBuilder as s}from"./openNextBuilder.js";import{staticSiteBuilder as l}from"./staticSiteBuilder.js";import{dockerBuilder as f}from"./dockerBuilder.js";class o{static{u(this,"FrameworkRegistry")}builders;constructor(t){this.builders=[...t].sort((r,e)=>r.priority-e.priority)}resolve(t,r){if(r){const e=this.builders.find(n=>n.name===r);if(!e)return null;const i=e.detect(t);return{builder:e,detection:{...i,detected:!0}}}for(const e of this.builders){const i=e.detect(t);if(i.detected)return{builder:e,detection:i}}return null}static createDefault(){return new o([s,l,f])}static create(t){return new o(t)}}export{o as FrameworkRegistry};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{basename as
|
|
1
|
+
var i=Object.defineProperty;var o=(r,e)=>i(r,"name",{value:e,configurable:!0});import{basename as l}from"path";import{success as c,parseInfrastructure as f,isOpenNextPatternType as m}from"@fjall/generator";import{logger as y}from"@fjall/util/logger";import{OPENNEXT_DEPLOY_ORDER as x,OPENNEXT_DESTROY_ORDER as N}from"../../types/operations.js";import{readInfrastructureContent as O}from"../../types/detection/patternDetection.js";import{runOpenNextBuild as B,BUILD_TIMEOUT_MS as h,IMPORT_MAP_TIMEOUT_MS as g}from"../application/openNextBuild.js";function u(r){return{hasNetwork:!0,hasCompute:!0,hasDatabase:r,hasStorage:!0,hasMessaging:!0,hasCdn:!0}}o(u,"openNextResources");const R={name:"opennext",priority:10,detect(r){const e={detected:!1,pattern:null,reason:"No OpenNext pattern found",resources:u(!1),hasDatabase:!1,hasDockerfile:!1},t=O(r.appPath);if(t===null||t==="")return{...e,reason:"No infrastructure.ts found"};const a=f(t).patternResources.find(s=>m(s.type));if(a===void 0)return{...e,reason:'No PatternFactory with type: "payload" or "nextjs" in infrastructure.ts'};if(a.type==="payload")return{detected:!0,pattern:"payload",reason:'PatternFactory with type: "payload" detected',resources:u(!0),hasDatabase:!0,hasDockerfile:!1};if(a.type==="nextjs"){const s=a.config.database!==void 0;return{detected:!0,pattern:"nextjs",reason:'PatternFactory with type: "nextjs" detected',resources:u(s),hasDatabase:s,hasDockerfile:!1}}return{...e,reason:"PatternFactory found but no recognised pattern type"}},plan(r,e){const t=e.pattern==="payload"?[{name:"payload-import-map",binary:"npx",args:["payload","generate:importmap"],timeoutMs:g}]:[];return{builderName:"opennext",deployOrder:x,destroyOrder:N,parallelDestroy:!0,preBuildCommands:t,buildCommand:{name:"open-next-build",binary:"open-next",args:["build"],timeoutMs:h},requiresDockerBuild:!1,resources:e.resources}},async build(r,e,t,n){if(n?.skipBuild||n?.infraOnly)return y.debug("openNextBuilder","Build skipped",{skipBuild:n.skipBuild,infraOnly:n.infraOnly}),c(void 0);const a={kind:"application",appName:l(r)||"app",path:r},d=e.preBuildCommands.some(p=>p.name==="payload-import-map")?"payload":"nextjs";return await B(a,d,{onOpenNextBuildStart:o(()=>t.onBuildStart?.("opennext"),"onOpenNextBuildStart"),onOpenNextProgress:o(p=>t.onBuildProgress?.("opennext",p),"onOpenNextProgress"),onOpenNextBuildComplete:o(()=>t.onBuildComplete?.("opennext"),"onOpenNextBuildComplete"),onOpenNextBuildError:o(p=>t.onBuildError?.("opennext",p),"onOpenNextBuildError")},void 0,n?.abortSignal)}};export{R as openNextBuilder};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
${e}`))}if(r.artefactDir!==void 0){const e=
|
|
1
|
+
var b=Object.defineProperty;var l=(o,r)=>b(o,"name",{value:r,configurable:!0});import{existsSync as B}from"fs";import{resolve as m}from"path";import{success as p,failure as u,parseInfrastructure as g}from"@fjall/generator";import{filterDangerousEnvVars as D,maskSensitiveOutput as d,parseShellArgs as E}from"@fjall/util";import{logger as h}from"@fjall/util/logger";import{getApplicationDeployOrder as w,getApplicationDestroyOrder as O}from"../../types/operations.js";import{readInfrastructureContent as S}from"../../types/detection/patternDetection.js";import{spawnWithTimeout as C}from"../spawnHelpers.js";const P=6e5,y={hasNetwork:!1,hasCompute:!1,hasDatabase:!1,hasStorage:!1,hasMessaging:!1,hasCdn:!0};function T(o){return g(o).patternResources.some(r=>r.type==="staticsite")}l(T,"hasStaticSitePattern");function I(o){const r=S(o);if(r===null||r==="")return;const t=g(r).patternResources.find(n=>n.type==="staticsite");if(t===void 0||t.type!=="staticsite")return;const{source:i,build:s}=t.config,a=s?.command,c=s?.outputDir;if(!(i===void 0||i===""||a===void 0||a===""||c===void 0||c===""))return{source:i,command:a,outputDir:c}}l(I,"readStaticSiteBuildInputs");const U={name:"staticsite",priority:50,detect(o){const r={detected:!1,pattern:null,reason:"No static-site pattern found",resources:y,hasDatabase:!1,hasDockerfile:!1},t=S(o.appPath);return t===null||t===""?{...r,reason:"No infrastructure.ts found"}:T(t)?{detected:!0,pattern:"staticsite",reason:'PatternFactory with type: "staticsite" detected',resources:y,hasDatabase:!1,hasDockerfile:!1}:{...r,reason:'No PatternFactory with type: "staticsite"'}},plan(o,r){const t=I(o.appPath);let i=null;if(t!==void 0){const[s,...a]=E(t.command);s!==void 0&&(i={name:"static-site-build",binary:s,args:a,timeoutMs:P,cwd:t.source})}return{builderName:"staticsite",deployOrder:w({resources:r.resources}),destroyOrder:O({resources:r.resources}),parallelDestroy:!1,preBuildCommands:[],buildCommand:i,requiresDockerBuild:!1,artefactDir:t?.outputDir,resources:r.resources}},async build(o,r,t,i){if(i?.skipBuild||i?.infraOnly)return h.debug("staticSiteBuilder","Build skipped",{skipBuild:i.skipBuild,infraOnly:i.infraOnly}),p(void 0);const{buildCommand:s}=r;if(s===null){const e='Static-site build command could not be read from infrastructure.ts. The pattern needs an inline build block \u2014 build: { command: "npm run build", outputDir: "out" } \u2014 with literal strings, not variables or expressions.';return t.onBuildError?.("staticsite",e),u(new Error(e))}const a=m(o,s.cwd??"."),c=D(globalThis.process.env);t.onBuildStart?.("staticsite"),t.onBuildProgress?.("staticsite",d("Starting static-site build..."));const n=await C({command:s.binary,args:[...s.args],cwd:a,env:{...c,FORCE_COLOR:"0"},timeout:s.timeoutMs,...i?.abortSignal!==void 0&&{abortSignal:i.abortSignal},onStdoutData:l(e=>t.onBuildProgress?.("staticsite",d(e.trim())),"onStdoutData"),onStderrData:l(e=>t.onBuildProgress?.("staticsite",d(e.trim())),"onStderrData")});if(n.type==="timeout"){const e=`Static-site build timed out after ${s.timeoutMs/1e3} seconds`;return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.type==="aborted"){const e="Static-site build cancelled";return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.type==="enoent"){const e=`Static-site build command not found: ${s.binary}. Ensure it is installed and in PATH.`;return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.type==="spawn_error"){const e=d(`Failed to spawn static-site build: ${n.error.message}`);return t.onBuildError?.("staticsite",e),u(new Error(e))}if(n.code!==0){const e=d(n.stderr||n.stdout);return t.onBuildError?.("staticsite",`Static-site build failed (exit code ${n.code})`),u(new Error(`Static-site build failed (exit code ${n.code}):
|
|
2
|
+
${e}`))}if(r.artefactDir!==void 0){const e=m(a,r.artefactDir);if(!B(e)){const f=`Static-site build completed but output directory '${r.artefactDir}' was not found`;return t.onBuildError?.("staticsite",f),u(new Error(f))}}return t.onBuildComplete?.("staticsite"),t.onBuildProgress?.("staticsite",d("Static-site build completed successfully")),p(void 0)}};export{P as STATIC_BUILD_TIMEOUT_MS,U as staticSiteBuilder};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
var R=Object.defineProperty;var n=(e,r)=>R(e,"name",{value:r,configurable:!0});import{success as l,failure as u}from"@fjall/generator";import{getErrorMessage as y,maskSensitiveOutput as f,sleep as g}from"@fjall/util";import{logger as S}from"@fjall/util/logger";import{IAMClient as w}from"@aws-sdk/client-iam";import{hasOrganisationTierAccount as b}from"../aws/organisations/accountGlobals.js";import{reconcileOidcProviderAfterDeploy as h}from"../aws/organisations/oidcProvider.js";import{SimpleAwsProvider as T}from"../aws/SimpleAwsProvider.js";const _={account:"active",draining:"draining",org:"removed"};function $(e,r){return e!==void 0&&e!==""&&r!==void 0&&r!==""&&e!==r}n($,"targetsNonPrimaryRegion");function N(e){const r=$(e.region,e.primaryRegion);return{...e.orgConfig!==void 0?{orgConfig:JSON.stringify(e.orgConfig)}:{},...e.identity!==void 0?{fjallOrgId:e.identity.fjallOrgId}:{},...e.skipOidc?{fjallOidcConfigured:!0}:{},...r?{fjallAccountGlobalsConfigured:!0}:{},...e.trailLifecycle!==void 0?{fjallAccountTrailState:_[e.trailLifecycle]}:{}}}n(N,"buildParamsContext");function U(e,r,t,o){if(t!==void 0)return t;if(e==="account")return b(r?.providerAccounts)?o===!0:!0}n(U,"resolveAccountBootstrapSkipOidc");function v(e){return e.fjallOrgId!==void 0&&e.fjallOrgId!==""&&e.fjallOidcConfigured!==!0&&e.fjallAccountGlobalsConfigured!==!0}n(v,"synthCarriedOidcConnector");async function V(e,r,t,o){v(e)&&await h(r.getClient(w),t,o)}n(V,"reconcileOidcProviderIfCarried");function K(e){return r=>e.onOutput?.(r)}n(K,"forwardOutput");function z(e){return r=>e.onResourceProgress?.(r)}n(z,"forwardResourceProgress");function J(e){if(!e.success||e.data.length===0)return;const r={};for(const t of e.data)t.OutputKey&&t.OutputValue!==void 0&&(r[t.OutputKey]=t.OutputValue);return Object.keys(r).length>0?r:void 0}n(J,"collectStackOutputs");const E="OrganizationAccountAccessRole",p=5,x=5e3,M=3e4;function j(e){return`arn:aws:iam::${e}:role/${E}`}n(j,"buildCascadeRoleArn");function k(e,r){return r===void 0?g(e):r.aborted?Promise.resolve():new Promise(t=>{const o=n(()=>{t()},"onAbort");r.addEventListener("abort",o,{once:!0}),g(e).then(()=>{r.removeEventListener("abort",o),t()})})}n(k,"sleepAbortable");async function X(e,r,t,o,i){if(!e.assumeRole)return u(new Error("AwsProvider does not support assumeRole"));const c=j(r),C=e.assumeRole.bind(e);let s;for(let d=0;d<=p;d++)try{s=await C(c,o);break}catch(a){const A=a instanceof Error?a.name:void 0;if(A==="AccessDenied"||A==="AccessDeniedException")return u(new Error(`Access denied assuming ${E} in account ${r}. The role may not exist or may not trust the management account.`));if(d<p){const m=Math.min(x*2**d,M);if(S.debug("assumeCascadeRole",`Attempt ${d+1} failed for account ${r}, retrying in ${Math.round(m/1e3)}s`,{error:f(y(a))}),await k(m,i),i?.aborted)return u(new Error(`Aborted while retrying assume-role for account ${r}`));continue}return u(new Error(`Failed to assume role in account ${r} after ${p+1} attempts: ${f(y(a))}`))}if(!s)return u(new Error(`Failed to assume role in account ${r}`));const O=new T({accessKeyId:s.accessKeyId,secretAccessKey:s.secretAccessKey,sessionToken:s.sessionToken,region:t,accountId:r});return l({provider:O,credentials:{accessKeyId:s.accessKeyId,secretAccessKey:s.secretAccessKey,sessionToken:s.sessionToken}})}n(X,"assumeCascadeRole");async function q(e,r,t,o){const i=await e.cdkService.runCdkSynth(r,c=>t.onCdkOutput?.(c,"synth"));if(!i.success){const c=new Error(f(`${o}: ${i.error}`));return t.onError?.(c),u(c)}return l(void 0)}n(q,"synthOrFail");async function H(e,r,t){t.onCDKBootstrap?.("bootstrapping");const o=await e.cdkService.runCdkBootstrap(r,K(t));if(!o.success){t.onCDKBootstrap?.("failed");const i=new Error(f(`Bootstrap failed: ${o.error}`));return t.onError?.(i),u(i)}return t.onCDKBootstrap?.("complete"),l(void 0)}n(H,"bootstrapOrFail");export{X as assumeCascadeRole,H as bootstrapOrFail,j as buildCascadeRoleArn,N as buildParamsContext,J as collectStackOutputs,K as forwardOutput,z as forwardResourceProgress,V as reconcileOidcProviderIfCarried,U as resolveAccountBootstrapSkipOidc,v as synthCarriedOidcConnector,q as synthOrFail,$ as targetsNonPrimaryRegion};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
var w=Object.defineProperty;var l=(e,o)=>w(e,"name",{value:o,configurable:!0});import{success as f,failure as b}from"@fjall/generator";import{isApplicationOperation as g}from"../types/operations.js";import{isAborted as A}from"../aws/organisations/types.js";import{checkRegionEnabled as k,regionDisabledMessage as m}from"../aws/regions/regionOptStatus.js";import{createDeployServices as D}from"./serviceFactory.js";import{resolveOperation as v}from"./resolveOperation.js";import{deployApplication as C}from"./application/applicationDeploy.js";import{deployOrganisation as E}from"./organisation/organisationDeploy.js";async function B(e){const o=Date.now(),c=await k(e.awsCredentials.region,e.awsCredentials,e.abortSignal);if(c==="disabled"){const i=new Error(m(e.awsCredentials.region));return e.callbacks.onError?.(i),b(i)}c==="enabling"&&e.callbacks.onProgress?.({type:"warning",message:`Region ${e.awsCredentials.region} is still activating (opt-in status ENABLING); the deploy may fail until activation completes.`});let a;const p=e.callbacks.onFailureAnalysis,s={...e,callbacks:{...e.callbacks,onFailureAnalysis:l(i=>{a=i,p?.(i)},"onFailureAnalysis")}},d=D(s),n=await v(e.target,e.workingDirectory);if(!n.success)return e.callbacks.onError?.(n.error),n;const r=n.data,y=g(r)?"application":"organisation",t=g(r)?await C(s,d,r):await E(s,d,r);if(A(e.abortSignal))return f({target:e.target,deploymentType:y,cancelled:!0,artefacts:[],durationMs:Date.now()-o});if(!t.success)return t;const u=a!==void 0&&t.data.failureAnalysis===void 0?{...t.data,failureAnalysis:a}:t.data;return f({...u,...u.durationMs===void 0?{durationMs:Date.now()-o}:{}})}l(B,"deploy");export{B as deploy};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as a,failure as
|
|
1
|
+
var p=Object.defineProperty;var l=(t,r)=>p(t,"name",{value:r,configurable:!0});import{success as a,failure as g}from"@fjall/generator";import{isApplicationOperation as u,isOrganisationOperation as y,getApplicationStackName as b,getOrganisationStackName as k,APPLICATION_STACKS as w}from"../types/operations.js";import{isAborted as d}from"../aws/organisations/types.js";import{createDeployServices as S}from"./serviceFactory.js";import{resolveOperation as D}from"./resolveOperation.js";import{destroyApplication as v}from"./application/applicationDestroy.js";import{destroyOrganisation as A}from"./organisation/organisationDestroy.js";import{checkActiveDeployments as C}from"./activeDeploymentGuard.js";async function h(t){const r=Date.now(),n=S({target:t.target,workingDirectory:t.workingDirectory,awsCredentials:t.awsCredentials,callbacks:t.callbacks,options:{verbose:t.options?.verbose,force:t.options?.force,cascade:t.options?.cascade,skipConfirmation:t.options?.skipConfirmation},orgConfig:t.orgConfig,identity:t.identity,...t.abortSignal!==void 0?{abortSignal:t.abortSignal}:{}}),i=await D(t.target,t.workingDirectory);if(!i.success)return t.callbacks.onError?.(i.error),i;const e=i.data;if(!t.options?.force){const o=u(e)?Object.values(w).map(f=>b(e.appName,f)):[k(e.type)],c=await C(o,n.cfnService,t.abortSignal);if(!c.success)return t.callbacks.onError?.(c.error),g(c.error)}if(u(e)){const o=await v(t,n,e);return d(t.abortSignal)?a({target:t.target,deploymentType:"application",cancelled:!0,durationMs:Date.now()-r}):o.success&&o.data.durationMs===void 0?a({...o.data,durationMs:Date.now()-r}):o}if(y(e)){const o=await A(t,n,e);return d(t.abortSignal)?a({target:t.target,deploymentType:"organisation",cancelled:!0,durationMs:Date.now()-r}):o}const s=new Error(`Unsupported destroy target: ${t.target}`);return t.callbacks.onError?.(s),g(s)}l(h,"destroy");export{h as destroy};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={appName:!0,appPath:!0,region:!0,accountId:!0,imageTag:!0,services:!0,platform:!0,cacheRepoUri:!0,serviceName:!0,target:!0,dockerfilePath:!0,buildContext:!0,imageTags:!0,pushByDigest:!0,buildArgs:!0,buildSecrets:!0,targetsLambda:!0},t=Object.keys(e);export{t as ALL_DOCKER_BUILD_PARAM_KEYS};
|
|
1
|
+
const e={appName:!0,appPath:!0,region:!0,accountId:!0,imageTag:!0,services:!0,platform:!0,cacheRepoUri:!0,serviceName:!0,target:!0,dockerfilePath:!0,buildContext:!0,imageTags:!0,pushByDigest:!0,buildArgs:!0,buildSecrets:!0,targetsLambda:!0,abortSignal:!0},t=Object.keys(e);export{t as ALL_DOCKER_BUILD_PARAM_KEYS};
|