@fjall/deploy-core 2.19.5 → 2.20.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/organisations/oidcProvider.d.ts +28 -0
- package/dist/src/aws/organisations/oidcProvider.js +1 -0
- package/dist/src/aws/organisations/organisation.d.ts +10 -1
- package/dist/src/aws/organisations/organisation.js +1 -1
- package/dist/src/orchestration/organisation/cascadeDestroyHelpers.js +1 -1
- package/dist/src/orchestration/organisation/organisationDestroy.js +2 -2
- package/dist/src/orchestration/organisationDeploy/orgContext.d.ts +11 -1
- package/dist/src/orchestration/organisationDeploy/orgContext.js +1 -1
- package/dist/src/orchestration/organisationDeploy/singleComponentDeploy.js +1 -1
- package/package.json +5 -5
package/dist/.minified
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
153 files minified at 2026-06-23T06:42:25.535Z
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type IAMClient } from "@aws-sdk/client-iam";
|
|
2
|
+
import { type Result } from "@fjall/generator";
|
|
3
|
+
import type { DeployCallbacks } from "../../types/callbacks.js";
|
|
4
|
+
export interface OidcProviderTeardownResult {
|
|
5
|
+
deleted: boolean;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Reference-counted teardown of the account-global `https://fjall.io` OIDC
|
|
10
|
+
* provider. The provider is an IAM singleton shared by every Fjall deploy role
|
|
11
|
+
* in the account and is now Retain-on-stack-delete (adopt-if-exists), so the
|
|
12
|
+
* only safe deleter is one that confirms NOTHING still federates it.
|
|
13
|
+
*
|
|
14
|
+
* Deletes only when (a) the provider exists and (b) no IAM role's trust policy
|
|
15
|
+
* references its ARN. ListRoles returns the URL-encoded
|
|
16
|
+
* AssumeRolePolicyDocument inline, so a single paginated sweep answers the
|
|
17
|
+
* reference count without a GetRole per role. Any surviving reference — a
|
|
18
|
+
* surviving connect/account stack's deploy role — short-circuits to a no-op.
|
|
19
|
+
*
|
|
20
|
+
* Failure messages stay raw — callers mask at their output boundary.
|
|
21
|
+
*/
|
|
22
|
+
export declare function deleteOidcProviderIfUnreferenced(client: IAMClient, abortSignal?: AbortSignal): Promise<Result<OidcProviderTeardownResult>>;
|
|
23
|
+
/**
|
|
24
|
+
* Best-effort wrapper around {@link deleteOidcProviderIfUnreferenced}: surfaces
|
|
25
|
+
* the outcome via callbacks/logger and swallows failures. A cleanup miss leaves
|
|
26
|
+
* a harmless orphaned provider and must never block a teardown.
|
|
27
|
+
*/
|
|
28
|
+
export declare function cleanupOrphanedOidcProvider(client: IAMClient, callbacks: DeployCallbacks, abortSignal?: AbortSignal): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ListOpenIDConnectProvidersCommand as f,ListRolesCommand as u,DeleteOpenIDConnectProviderCommand as m}from"@aws-sdk/client-iam";import{success as d,failure as v}from"@fjall/generator";import{maskSensitiveOutput as I,getErrorMessage as O}from"@fjall/util";import{logger as a}from"@fjall/util/logger";import{composeSdkAbortSignal as s,isAborted as c}from"./types.js";const w="fjall.io",D=`:oidc-provider/${w}`;async function C(i,e){try{if(c(e))return d({deleted:!1,reason:"aborted"});const r=((await i.send(new f({}),{abortSignal:s(e)})).OpenIDConnectProviderList??[]).map(o=>o.Arn).find(o=>typeof o=="string"&&o.endsWith(D));if(r===void 0)return d({deleted:!1,reason:"provider not present"});let t;do{if(c(e))return d({deleted:!1,reason:"aborted"});const o=await i.send(new u({Marker:t}),{abortSignal:s(e)});for(const l of o.Roles??[]){const p=l.AssumeRolePolicyDocument;if(typeof p=="string"&&decodeURIComponent(p).includes(r))return d({deleted:!1,reason:`still referenced by role ${l.RoleName??"(unknown)"}`})}t=o.IsTruncated===!0?o.Marker:void 0}while(t!==void 0);return await i.send(new m({OpenIDConnectProviderArn:r}),{abortSignal:s(e)}),d({deleted:!0,reason:"deleted orphaned provider"})}catch(n){return n instanceof Error&&n.name==="NoSuchEntityException"?d({deleted:!1,reason:"provider not present"}):v(new Error(`Failed to evaluate OIDC provider teardown: ${O(n)}`))}}async function P(i,e,n){const r=await C(i,n);if(!r.success){const t=I(r.error.message);a.debug("oidcTeardown","OIDC provider teardown probe failed",{error:t}),e.onLog?.(`OIDC provider cleanup skipped: ${t}`,"warn");return}if(r.data.deleted){a.info("oidcTeardown","Deleted orphaned account-global OIDC provider"),e.onLog?.("Removed the orphaned Fjall OIDC provider","info");return}a.debug("oidcTeardown","OIDC provider retained",{reason:r.data.reason})}export{P as cleanupOrphanedOidcProvider,C as deleteOidcProviderIfUnreferenced};
|
|
@@ -8,5 +8,14 @@ import { type OrgDetails } from "./types.js";
|
|
|
8
8
|
export declare function ensureOrganisationExists(client: OrganizationsClient, abortSignal?: AbortSignal): Promise<Result<OrgDetails>>;
|
|
9
9
|
/**
|
|
10
10
|
* Describe the current AWS Organisation, returning null if none exists.
|
|
11
|
+
*
|
|
12
|
+
* Read-only — never creates. With `tolerateAccessDenied`, an AccessDenied from
|
|
13
|
+
* either DescribeOrganization or ListRoots also resolves to null: a standalone
|
|
14
|
+
* account whose role lacks `organizations:*` is not in — and does not need — an
|
|
15
|
+
* organisation, so a solo deploy proceeds standalone rather than failing. The
|
|
16
|
+
* default (flag absent) still rethrows AccessDenied so the org/cascade paths
|
|
17
|
+
* surface a genuine permissions error.
|
|
11
18
|
*/
|
|
12
|
-
export declare function describeOrganisation(client: OrganizationsClient, abortSignal?: AbortSignal
|
|
19
|
+
export declare function describeOrganisation(client: OrganizationsClient, abortSignal?: AbortSignal, opts?: {
|
|
20
|
+
tolerateAccessDenied?: boolean;
|
|
21
|
+
}): Promise<Result<OrgDetails | null>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DescribeOrganizationCommand as
|
|
1
|
+
import{DescribeOrganizationCommand as m,CreateOrganizationCommand as I,ListRootsCommand as w}from"@aws-sdk/client-organizations";import{success as s,failure as a}from"@fjall/generator";import{getErrorMessage as g}from"@fjall/util";import{extractErrorName as c,isAccessDenied as f,composeSdkAbortSignal as u,AWS_ERROR_NAMES as A}from"./types.js";async function h(e,t){try{let n=!1,r=await d(e,t);if(!r)try{r=(await e.send(new I({FeatureSet:"ALL"}),{abortSignal:u(t)})).Organization??null,n=!0}catch(i){if(c(i)==="AlreadyInOrganizationException"){if(r=await d(e,t),!r)return a(new Error("Account is already in an organisation but DescribeOrganization returned nothing"))}else throw i}if(!r?.Id||!r.MasterAccountId)return a(new Error("Organisation is missing required fields (Id or MasterAccountId)"));const o=await l(e,t);return o.success?s({orgId:r.Id,rootId:o.data,managementAccountId:r.MasterAccountId,created:n}):o}catch(n){return a(new Error(`Failed to ensure organisation exists: ${g(n)}`))}}async function M(e,t,n){try{const r=await d(e,t,n);if(!r)return s(null);if(!r.Id||!r.MasterAccountId)return a(new Error("Organisation is missing required fields (Id or MasterAccountId)"));const o=await l(e,t);return o.success?s({orgId:r.Id,rootId:o.data,managementAccountId:r.MasterAccountId,created:!1}):o}catch(r){return n?.tolerateAccessDenied===!0&&f(c(r))?s(null):a(new Error(`Failed to describe organisation: ${g(r)}`))}}async function l(e,t){const r=(await e.send(new w({}),{abortSignal:u(t)})).Roots??[];return r.length===0||!r[0]?.Id?a(new Error("No organisation root found")):s(r[0].Id)}async function d(e,t,n){try{return(await e.send(new m({}),{abortSignal:u(t)})).Organization??null}catch(r){const o=c(r);if(o===A.ORGS_NOT_IN_USE||n?.tolerateAccessDenied===!0&&f(o))return null;throw r}}export{M as describeOrganisation,h as ensureOrganisationExists};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as
|
|
1
|
+
import{join as b}from"path";import{logger as f}from"@fjall/util/logger";import{maskSensitiveOutput as s,getErrorMessage as v}from"@fjall/util";import{stubCallerIdentity as B}from"../../types/deployment/index.js";import{CloudFormationClient as P,DescribeStacksCommand as _}from"@aws-sdk/client-cloudformation";import{S3Client as w}from"@aws-sdk/client-s3";import{BackupClient as x}from"@aws-sdk/client-backup";import{IAMClient as F}from"@aws-sdk/client-iam";import{accountHasDisasterRecovery as M,describeSurvivingBackupVault as K,formatSurvivingVaultWarning as L}from"../../aws/organisations/backup.js";import{cleanupOrphanedOidcProvider as V}from"../../aws/organisations/oidcProvider.js";import{composeSdkAbortSignal as j}from"../../aws/organisations/types.js";import{ORGANISATION_TYPES as E,getOrganisationStackName as U}from"../../types/operations.js";import{CdkContextBuilder as G}from"../../services/supporting/CdkContextBuilder.js";import{regionSuffix as H}from"../../types/config/FjallState.js";import{buildParamsContext as W,assumeCascadeRole as Y,forwardOutput as N}from"../contextHelpers.js";import{cascadeOperationKey as q}from"./cascadeHelpers.js";import{capturedSweepBuckets as z,cleanupFailedStack as J,preEmptyStackBuckets as Q,sweepOrphanedDestroyBuckets as O}from"../stackCleanup.js";import{STACK_NOT_FOUND_PATTERN as X,STACK_FAILED_STATE_PATTERN as Z}from"../../types/constants.js";async function we(a,n,d,e,t,r,o,y){const S=Date.now(),c=q(e.name,r),l=(i,p=i)=>(o.onCascadeAccountComplete?.(c,!1,p,r),{accountName:e.name,accountId:e.id,region:r,success:!1,duration:Date.now()-S,error:i});o.onCascadeAccountStart?.(c,e.id,r,t);const g=await Y(n.awsProvider,e.id,r,`fjall-cascade-destroy-${e.name}`);if(!g.success){const i=s(g.error.message);return l(`AssumeRole failed: ${i}`,i)}const{provider:u,credentials:k}=g.data,T=b(d.path,`cdk.out.${e.id}.${H(r)}`),A=G.buildDeploymentContext({deployType:t,target:d.target,path:d.path,assemblyDir:T,region:r,accountName:e.name,callerIdentity:B(e.id),...W({orgConfig:a.orgConfig,identity:a.identity,region:r,primaryRegion:y?.primaryRegion})},{verbose:a.options?.verbose},a.orgConfig);o.onCascadeAccountPhaseChange?.(c,"synth",r);const D=await n.cdkService.runCdkSynth(A,N(o));if(!D.success)return l(s(`Synth failed: ${D.error}`));o.onCascadeAccountPhaseChange?.(c,"destroy",r);const m=U(t==="platform"?E.PLATFORM:E.ACCOUNT);M(e.environment,a.orgConfig?.disasterRecoveryRegion)&&await ee(u.getClient(x),r,o,a.abortSignal);const I=await Q(u.getClient(P),u.getClient(w),m,o,a.abortSignal),C=z(I),h=await n.cdkService.runCdkDestroy(A,m,N(o),i=>o.onCascadeAccountResourceProgress?.(c,i,r),u,!0,k);if(!h.success){const i=h.error;if(i.includes(Z)){f.warn("cascadeDestroy",`CDK destroy failed on ${m} in failed state, retrying via CloudFormation API`,{region:r,account:e.name});try{await J(m,r,k,{accountId:e.id,abortSignal:a.abortSignal},o)}catch($){const R=`cleanupFailedStack threw for ${m}: ${s(v($))}`;f.warn("cascadeDestroy",R),o.onLog?.(R,"warn")}const p=await te(m,u.getClient(P),a.abortSignal);return p.deleted?(C.length>0&&await O(u.getClient(w),C,o,a.abortSignal),o.onCascadeAccountComplete?.(c,!0,void 0,r),{accountName:e.name,accountId:e.id,region:r,success:!0,duration:Date.now()-S}):p.error?l(s(p.error)):l(s(`Stack ${m} cleanup attempted but stack still exists in ${r}`))}return l(s(i))}return C.length>0&&await O(u.getClient(w),C,o,a.abortSignal),(y?.primaryRegion===void 0||r===y.primaryRegion)&&await V(u.getClient(F),o,a.abortSignal),o.onCascadeAccountComplete?.(c,!0,void 0,r),{accountName:e.name,accountId:e.id,region:r,success:!0,duration:Date.now()-S}}async function ee(a,n,d,e){try{const t=await K(a,n,e);if(!t.success){f.debug("cascadeDestroy","Backup-vault survival probe failed",{region:n,error:s(t.error.message)});return}if(t.data===null)return;d.onProgress?.({type:"warning",message:L(t.data),metadata:{source:"backup-vault-survival"}}),f.warn("cascadeDestroy","Backup vault survives destroy",{region:n,vaultName:t.data.vaultName,recoveryPointCount:t.data.recoveryPointCount,lockPermanent:t.data.lockPermanent})}catch(t){f.debug("cascadeDestroy","Backup-vault survival probe threw",{region:n,error:s(v(t))})}}async function te(a,n,d){try{const t=(await n.send(new _({StackName:a}),{abortSignal:j(d)})).Stacks?.[0]?.StackStatus;return!t||t==="DELETE_COMPLETE"?{deleted:!0}:{deleted:!1,error:`Stack still in ${t} after cleanup attempt`}}catch(e){if(e instanceof Error&&e.message?.includes(X))return{deleted:!0};const t=s(v(e));return f.debug("cascadeDestroy","Stack verification failed",{error:t}),{deleted:!1,error:`Stack verification failed: ${t}`}}}export{we as destroyCascadeAccount};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{CloudFormationClient as
|
|
1
|
+
import{CloudFormationClient as $}from"@aws-sdk/client-cloudformation";import{S3Client as T}from"@aws-sdk/client-s3";import{IAMClient as _}from"@aws-sdk/client-iam";import{success as P,failure as M}from"@fjall/generator";import{maskSensitiveOutput as O,getErrorMessage as k,mapSettledWithConcurrency as v}from"@fjall/util";import{stubCallerIdentity as b}from"../../types/deployment/index.js";import{ORGANISATION_TYPES as L,getOrganisationStackName as x}from"../../types/operations.js";import{CdkContextBuilder as B}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as G,synthOrFail as Y,forwardOutput as j,forwardResourceProgress as F}from"../contextHelpers.js";import{destroyCascadeAccount as N}from"./cascadeDestroyHelpers.js";import{cleanupOrphanedOidcProvider as U}from"../../aws/organisations/oidcProvider.js";import{capturedSweepBuckets as H,preEmptyStackBuckets as W,sweepOrphanedDestroyBuckets as X}from"../stackCleanup.js";import{partitionAccounts as q,buildRegionList as z,buildAccountRegionPairs as J,cascadeHomeRegion as K,CASCADE_MAX_CONCURRENCY as Q}from"./cascadeHelpers.js";import{projectScalarSummary as V}from"./cascadeSummary.js";import{STEP_IDS as Z}from"../../types/stepDefinitions.js";const D=Z.ORG_DESTROY,E="Destroying organisation infrastructure";async function Ct(o,r,c){const S=Date.now(),{callbacks:t}=o,l=o.orgConfig?.providerAccounts??[],g=K(o.orgConfig),m=z(o.orgConfig),{platformAccount:u,memberAccounts:f}=q(l),h=o.options?.cascade!==!1;t.onLog?.(`Destroying organisation infrastructure (${l.length} accounts, ${m.length} region(s))`,"info");const n=[],p=[],w=[];let R;if(h){t.onCascadeStart?.();const A=Date.now();if(f.length>0){t.onCascadePhaseStart?.("accounts");const a=J(f,m),d=await v(a,Q,({account:i,region:s})=>N(o,r,c,i,"account",s,t,{primaryRegion:g}));for(let i=0;i<d.length;i++){const s=d[i],e=a[i];if(!(!s||!e))if(s.status==="fulfilled")if(s.value.success)p.push(`Account-${e.account.name}-${e.region}`),w.push({accountId:e.account.id,accountName:e.account.name,region:e.region,result:"succeeded",durationMs:s.value.duration});else{const y=O(s.value.error??"Unknown error");w.push({accountId:e.account.id,accountName:e.account.name,region:e.region,result:"failed",durationMs:s.value.duration,error:y}),n.push({accountId:e.account.id,error:y})}else{const y=O(k(s.reason));w.push({accountId:e.account.id,accountName:e.account.name,region:e.region,result:"failed",durationMs:0,error:y}),n.push({accountId:e.account.id,error:y})}}t.onCascadePhaseComplete?.("accounts")}if(u){t.onCascadePhaseStart?.("platform");const a=await N(o,r,c,u,"platform",u.region??g,t);if(a.success)p.push("Platform"),R={accountId:u.id,result:"succeeded",durationMs:a.duration};else{const d=O(a.error??"Platform destroy failed");n.push({accountId:u.id,error:d}),R={accountId:u.id,result:"failed",durationMs:a.duration,error:d}}t.onCascadePhaseComplete?.("platform")}const C={members:w,...R!==void 0?{platform:R}:{},domainsDeployed:!1,errors:n,totalDurationMs:Date.now()-A};if(t.onCascadeComplete?.(V(C)),t.onCascadeLedger?.(C),n.length>0){const a=n.map(i=>` ${i.accountId}: ${i.error}`).join(`
|
|
2
2
|
`),d=new Error(`Cascade destroy completed with ${n.length} failure(s):
|
|
3
|
-
${a}`);t.onError?.(d),t.onLog?.(d.message,"warn")}}if(n.length>0)return t.onLog?.("Skipping organisation root stack destroy due to cascade failures","warn"),
|
|
3
|
+
${a}`);t.onError?.(d),t.onLog?.(d.message,"warn")}}if(n.length>0)return t.onLog?.("Skipping organisation root stack destroy due to cascade failures","warn"),P({target:c.target,deploymentType:"organisation",stacksDestroyed:p,durationMs:Date.now()-S,warnings:n.map(C=>`${C.accountId}: ${C.error}`)});t.onStepStart?.(D,E,0,1);const I=await tt(o,r,c,r.awsProvider.getRegion(),t);if(I.success)p.push("Organisation"),t.onStepComplete?.(D,E,"completed",0,1);else return t.onStepComplete?.(D,E,"error",0,1),M(I.error);return P({target:c.target,deploymentType:"organisation",stacksDestroyed:p,durationMs:Date.now()-S})}async function tt(o,r,c,S,t){const l=B.buildDeploymentContext({deployType:"organisation",target:c.target,path:c.path,region:S,callerIdentity:b(r.awsProvider.getAccountId()),...G({orgConfig:o.orgConfig,identity:o.identity})},{verbose:o.options?.verbose},o.orgConfig),g=x(L.ORGANISATION);t.onLog?.("Synthesising organisation infrastructure\u2026","info");const m=await Y(r,l,t,"Organisation synth failed");if(!m.success)return m;const u=await W(r.awsProvider.getClient($),r.awsProvider.getClient(T),g,t,o.abortSignal),f=H(u);t.onLog?.(`Destroying ${g} stack\u2026`,"info");const h=await r.cdkService.runCdkDestroy(l,g,j(t),F(t),r.awsProvider,!0);if(!h.success){const n=new Error(O(`Organisation destroy failed: ${h.error}`));return t.onError?.(n),M(n)}return f.length>0&&await X(r.awsProvider.getClient(T),f,t,o.abortSignal),await U(r.awsProvider.getClient(_),t,o.abortSignal),P(void 0)}export{Ct as destroyOrganisation};
|
|
@@ -8,5 +8,15 @@ export interface OrgDetailsForSynth {
|
|
|
8
8
|
rootId: string;
|
|
9
9
|
managementAccountId: string;
|
|
10
10
|
}
|
|
11
|
-
export declare function buildOrgContext(params: DeployParams, services: DeployServices, operation: OrganisationOperation, deployType: "organisation" | "platform" | "account", orgDetails: OrgDetailsForSynth, accountName?: string, trailLifecycle?: ProviderAccount["trailLifecycle"], targetIsOrganisationTier?: boolean): import("../../types/deployment/DeploymentTypes.js").DeploymentContext;
|
|
11
|
+
export declare function buildOrgContext(params: DeployParams, services: DeployServices, operation: OrganisationOperation, deployType: "organisation" | "platform" | "account", orgDetails: OrgDetailsForSynth | undefined, accountName?: string, trailLifecycle?: ProviderAccount["trailLifecycle"], targetIsOrganisationTier?: boolean): import("../../types/deployment/DeploymentTypes.js").DeploymentContext;
|
|
12
12
|
export declare function resolveOrgDetails(services: DeployServices, abortSignal?: AbortSignal): Promise<Result<OrgDetailsForSynth>>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve org details for a SOLO-estate single-component deploy. Read-only — a
|
|
15
|
+
* standalone account deploy must NEVER create an organisation (the mutating
|
|
16
|
+
* resolveOrgDetails would CreateOrganization for an account not in an org, or
|
|
17
|
+
* fail on AccessDenied for a standalone role that cannot DescribeOrganization).
|
|
18
|
+
* Both outcomes resolve to `undefined`: the Account stack synthesises standalone
|
|
19
|
+
* without org details. Returns details only when the account genuinely has a
|
|
20
|
+
* describable, root-listable organisation.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveOrgDetailsForSolo(services: DeployServices, abortSignal?: AbortSignal): Promise<OrgDetailsForSynth | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as
|
|
1
|
+
import{success as s,failure as u}from"@fjall/generator";import{OrganizationsClient as a}from"@aws-sdk/client-organizations";import{CdkContextBuilder as l}from"../../services/supporting/CdkContextBuilder.js";import{stubCallerIdentity as m}from"../../types/deployment/index.js";import{ensureOrganisationExists as I,describeOrganisation as f}from"../../aws/organisations/organisation.js";import{buildParamsContext as C,resolveAccountBootstrapSkipOidc as O}from"../contextHelpers.js";function w(o,n,r,t,e,d,c,g){const i=n.awsProvider.getRegion();return l.buildDeploymentContext({deployType:t,target:r.target,path:r.path,region:i,accountName:d,callerIdentity:m(n.awsProvider.getAccountId()),orgId:e?.orgId,rootId:e?.rootId,managementAccountId:e?.managementAccountId,...C({orgConfig:o.orgConfig,identity:o.identity,skipOidc:O(t,o.orgConfig,o.options?.skipOidc,g),...t!=="organisation"?{region:i,primaryRegion:o.orgConfig?.primaryRegion}:{},trailLifecycle:c})},{verbose:o.options?.verbose,infraOnly:o.options?.infraOnly},o.orgConfig)}async function P(o,n){const r=o.awsProvider.getClient(a),t=await I(r,n);return t.success?s({orgId:t.data.orgId,rootId:t.data.rootId,managementAccountId:t.data.managementAccountId}):u(t.error)}async function k(o,n){const r=o.awsProvider.getClient(a),t=await f(r,n,{tolerateAccessDenied:!0});if(!(!t.success||t.data===null))return{orgId:t.data.orgId,rootId:t.data.rootId,managementAccountId:t.data.managementAccountId}}export{w as buildOrgContext,P as resolveOrgDetails,k as resolveOrgDetailsForSolo};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as N}from"@fjall/generator";import{BackupClient as w}from"@aws-sdk/client-backup";import{IAMClient as D}from"@aws-sdk/client-iam";import{getOrganisationStackName as I}from"../../types/operations.js";import{accountHasDisasterRecovery as k,describeBackupVaultExists as y}from"../../aws/organisations/backup.js";import{describeAccountGlobalsExist as L,buildMissingAccountGlobalsAdvisory as T}from"../../aws/organisations/accountGlobals.js";import{targetsNonPrimaryRegion as h,synthOrFail as
|
|
1
|
+
import{success as N}from"@fjall/generator";import{BackupClient as w}from"@aws-sdk/client-backup";import{IAMClient as D}from"@aws-sdk/client-iam";import{getOrganisationStackName as I}from"../../types/operations.js";import{accountHasDisasterRecovery as k,describeBackupVaultExists as y}from"../../aws/organisations/backup.js";import{describeAccountGlobalsExist as L,buildMissingAccountGlobalsAdvisory as T}from"../../aws/organisations/accountGlobals.js";import{targetsNonPrimaryRegion as h,synthOrFail as v,bootstrapOrFail as F,forwardOutput as M,forwardResourceProgress as G}from"../contextHelpers.js";import{accountTier as S}from"@fjall/util";import{buildOrgContext as Y,resolveOrgDetails as x,resolveOrgDetailsForSolo as B}from"./orgContext.js";import{hasOrganisationTierAccount as V}from"../../aws/organisations/accountGlobals.js";import{INFRA_STEPS as o,INFRA_STEP_TOTAL as i,failPrepareStep as c,maskAndFail as d,readStackOutputsBestEffort as _}from"./infraSteps.js";async function ot(n,r,a,s,E){const{callbacks:t}=n;t.onStepComplete?.(o.CONNECT.id,o.CONNECT.name,"completed",0,i),t.onStepStart?.(o.PREPARE.id,o.PREPARE.name,1,i);const R=r.awsProvider.getRegion(),l=n.orgConfig?.primaryRegion;if(l!==void 0&&h(R,l)){const e=await L(r.awsProvider.getClient(D),n.abortSignal);if(!e.success)return c(t),d(t,e.error.message);if(!e.data)return c(t),d(t,T({target:a.target,deployRegion:R,primaryRegion:l,...n.orgConfig!==void 0?{providerAccounts:n.orgConfig.providerAccounts}:{}}))}let f;if(V(n.orgConfig?.providerAccounts)){const e=await x(r,n.abortSignal);if(!e.success)return c(t),d(t,e.error.message);f=e.data}else f=await B(r,n.abortSignal);const u=s==="account"?n.orgConfig?.providerAccounts.find(e=>e.name===a.target):n.orgConfig?.providerAccounts.find(e=>S(e)==="platform"),A=s==="account"&&u!==void 0&&S(u)==="organisation",g=Y(n,r,a,s,f,s==="account"?a.target:void 0,u?.trailLifecycle,A),m=n.orgConfig?.disasterRecoveryRegion;if(s==="account"&&(m!==void 0&&m!=="")&&(u===void 0||k(u.environment,m))){const e=await y(r.awsProvider.getClient(w),n.abortSignal);if(!e.success)return c(t),d(t,e.error.message);g.fjallAdoptBackupVault=e.data}t.onLog?.(`Synthesising ${s} infrastructure\u2026`,"info");const p=await v(r,g,t,"CDK synthesis failed");if(!p.success)return c(t),p;const O=await F(r,g,t);if(!O.success)return c(t),O;t.onStepComplete?.(o.PREPARE.id,o.PREPARE.name,"completed",1,i);const P=I(a.type);t.onStepStart?.(o.DEPLOY.id,o.DEPLOY.name,2,i);const C=await r.cdkService.runCdkDeploy(g,P,M(t),G(t),r.awsProvider);if(!C.success)return t.onStepComplete?.(o.DEPLOY.id,o.DEPLOY.name,"error",2,i),d(t,C.error);t.onStepComplete?.(o.DEPLOY.id,o.DEPLOY.name,"completed",2,i);const b=await _(r,t,P,"Failed to read stack outputs (non-critical)");return t.onStepStart?.(o.MONITORING.id,o.MONITORING.name,3,i),t.onStepComplete?.(o.MONITORING.id,o.MONITORING.name,"completed",3,i),N({target:a.target,deploymentType:"organisation",outputs:b,durationMs:Date.now()-E})}export{ot as deploySingleComponent};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/deploy-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"description": "Shared deployment engine for Fjall — used by CLI and webapp worker",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -78,16 +78,16 @@
|
|
|
78
78
|
"@aws-sdk/client-sqs": "^3.1067.0",
|
|
79
79
|
"@aws-sdk/client-sso-admin": "^3.1038.0",
|
|
80
80
|
"@aws-sdk/client-sts": "^3.1038.0",
|
|
81
|
-
"@fjall/generator": "^2.
|
|
82
|
-
"@fjall/util": "^2.
|
|
81
|
+
"@fjall/generator": "^2.20.0",
|
|
82
|
+
"@fjall/util": "^2.20.0",
|
|
83
83
|
"@smithy/node-http-handler": "^4.6.1",
|
|
84
84
|
"tsx": "^4.21.0",
|
|
85
85
|
"zod": "^4.4.3"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
|
-
"@types/node": "^
|
|
88
|
+
"@types/node": "^26.0.0",
|
|
89
89
|
"typescript": "^6.0.3",
|
|
90
90
|
"vitest": "^4.1.5"
|
|
91
91
|
},
|
|
92
|
-
"gitHead": "
|
|
92
|
+
"gitHead": "ec556d44a8a32fbdc1a2e1ca3c1f22224b0d27c2"
|
|
93
93
|
}
|