@fjall/deploy-core 2.4.7 → 2.4.8
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
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
116 files minified at 2026-05-
|
|
1
|
+
116 files minified at 2026-05-27T22:11:30.371Z
|
|
@@ -14,3 +14,8 @@ import type { DeployServices } from "./serviceFactory.js";
|
|
|
14
14
|
* responsibility. deploy-core receives credentials and deploys.
|
|
15
15
|
*/
|
|
16
16
|
export declare function deployOrganisation(params: DeployParams, services: DeployServices, operation: OrganisationOperation): Promise<Result<DeployResult>>;
|
|
17
|
+
export interface OrgDetailsForSynth {
|
|
18
|
+
orgId: string;
|
|
19
|
+
rootId: string;
|
|
20
|
+
managementAccountId: string;
|
|
21
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{success as
|
|
2
|
-
`);t.onLog?.(
|
|
3
|
-
${
|
|
1
|
+
import{success as _,failure as I}from"@fjall/generator";import{OrganizationsClient as ot}from"@aws-sdk/client-organizations";import{ORGANISATION_TYPES as D,getOrganisationStackName as v}from"../types/operations.js";import{CdkContextBuilder as et}from"../services/supporting/CdkContextBuilder.js";import{stubCallerIdentity as nt}from"../types/deployment/index.js";import{ensureOrganisationExists as rt}from"../aws/organisations/organisation.js";import{buildParamsContext as at,collectStackOutputs as z,synthOrFail as B,bootstrapOrFail as V,forwardOutput as W,forwardResourceProgress as q}from"./contextHelpers.js";import{partitionAccounts as st,deployCascadeAccount as H,readPlatformIpamPoolIds as ct,deployDomains as it}from"./cascadeHelpers.js";import{maskSensitiveOutput as g}from"@fjall/util";import{INFRA_STEP_NAME as T,STEP_IDS as w}from"../types/stepDefinitions.js";async function St(r,o,e){const s=Date.now();switch(e.type){case D.ORGANISATION:return ut(r,o,e,s);case D.PLATFORM:return X(r,o,e,"platform",s);case D.ACCOUNT:return X(r,o,e,"account",s);default:{const t=e.type;return I(new Error(`Unsupported organisation type: ${String(t)}`))}}}function J(r,o,e,s,t,a){return et.buildDeploymentContext({deployType:s,target:e.target,path:e.path,region:o.awsProvider.getRegion(),accountName:a,callerIdentity:nt(o.awsProvider.getAccountId()),orgId:t.orgId,rootId:t.rootId,managementAccountId:t.managementAccountId,...at({orgConfig:r.orgConfig,identity:r.identity,skipOidc:r.options?.skipOidc})},{verbose:r.options?.verbose,infraOnly:r.options?.infraOnly},r.orgConfig)}async function Q(r){const o=r.awsProvider.getClient(ot),e=await rt(o);return e.success?_({orgId:e.data.orgId,rootId:e.data.rootId,managementAccountId:e.data.managementAccountId}):I(e.error)}const n={CONNECT:{id:w.CONNECT,name:T.CONNECT},PREPARE:{id:w.PREPARE_ENVIRONMENT,name:T.PREPARE},DEPLOY:{id:w.DEPLOY,name:T.DEPLOY},MONITORING:{id:w.MONITORING,name:T.MONITORING},ORG_DEPLOY:{id:w.ORG_DEPLOY,name:"Deploying organisation infrastructure"}},d=4;async function X(r,o,e,s,t){const{callbacks:a}=r;a.onStepComplete?.(n.CONNECT.id,n.CONNECT.name,"completed",0,d),a.onStepStart?.(n.PREPARE.id,n.PREPARE.name,1,d);const f=await Q(o);if(!f.success){a.onStepComplete?.(n.PREPARE.id,n.PREPARE.name,"error",1,d);const p=new Error(g(f.error.message));return a.onError?.(p),I(p)}const E=J(r,o,e,s,f.data,s==="account"?e.target:void 0);a.onLog?.(`Synthesising ${s} infrastructure\u2026`,"info");const P=await B(o,E,a,"CDK synthesis failed");if(!P.success)return a.onStepComplete?.(n.PREPARE.id,n.PREPARE.name,"error",1,d),P;const N=await V(o,E,a);if(!N.success)return a.onStepComplete?.(n.PREPARE.id,n.PREPARE.name,"error",1,d),N;a.onStepComplete?.(n.PREPARE.id,n.PREPARE.name,"completed",1,d);const k=v(e.type);a.onStepStart?.(n.DEPLOY.id,n.DEPLOY.name,2,d);const l=await o.cdkService.runCdkDeploy(E,k,W(a),q(a),o.awsProvider);if(!l.success){a.onStepComplete?.(n.DEPLOY.id,n.DEPLOY.name,"error",2,d);const p=new Error(g(l.error));return a.onError?.(p),I(p)}a.onStepComplete?.(n.DEPLOY.id,n.DEPLOY.name,"completed",2,d);const O=await o.cfnService.getStackOutputs(k);O.success||a.onLog?.("Failed to read stack outputs (non-critical)","debug");const R=z(O);return a.onStepStart?.(n.MONITORING.id,n.MONITORING.name,3,d),a.onStepComplete?.(n.MONITORING.id,n.MONITORING.name,"completed",3,d),_({target:e.target,deploymentType:"organisation",outputs:R,durationMs:Date.now()-t})}async function ut(r,o,e,s){const{callbacks:t,options:a}=r,f=r.orgConfig?.providerAccounts??[],E=await Q(o);if(!E.success){const i=new Error(g(E.error.message));return t.onError?.(i),I(i)}const P=J(r,o,e,"organisation",E.data),N=a?.cascade!==!1,l=2+(N?f.length:0),{id:O,name:R}=n.PREPARE;t.onStepStart?.(O,R,0,l),t.onLog?.("Synthesising organisation infrastructure\u2026","info");const p=await B(o,P,t,"CDK synthesis failed");if(!p.success)return t.onStepComplete?.(O,R,"error",0,l),p;const x=await V(o,P,t);if(!x.success)return t.onStepComplete?.(O,R,"error",0,l),x;t.onStepComplete?.(O,R,"completed",0,l);const{id:L,name:b}=n.ORG_DEPLOY;t.onStepStart?.(L,b,1,l);const $=v(D.ORGANISATION),F=await o.cdkService.runCdkDeploy(P,$,W(t),q(t),o.awsProvider);if(!F.success){t.onStepComplete?.(L,b,"error",1,l);const i=new Error(g(F.error));return t.onError?.(i),I(i)}const j=await o.cfnService.getStackOutputs($);j.success||t.onLog?.("Failed to read org stack outputs (non-critical)","debug");const Z=z(j);t.onStepComplete?.(L,b,"completed",1,l);const c=[],y=[];if(N&&f.length>0){t.onCascadeStart?.();let i=0,G=!1,K=!1;const{platformAccount:S,memberAccounts:M}=st(f);if(S){t.onCascadePhaseStart?.("platform");const u=await H(r,o,e,S,"platform",t);u.success?(G=!0,u.data.outputs&&y.push({accountId:S.id,outputs:u.data.outputs})):c.push({accountId:S.id,error:u.error.message}),t.onCascadePhaseComplete?.("platform")}let U=new Map;if(G&&S&&(U=await ct(o,S,t)),r.domainProvider){const u=await it(r.domainProvider,t);K=u.domainsDeployed>0;for(const A of u.errors)c.push({accountId:"domains",error:g(A)})}if(M.length>0){t.onCascadePhaseStart?.("accounts");const u=o.awsProvider.getRegion();(await Promise.allSettled(M.map(m=>{const Y=u.replace(/-/g,""),C=U.get(`${m.id}-${Y}`);return H(r,o,e,m,"account",t,C)}))).forEach((m,Y)=>{const C=M[Y];if(!C)return;if(m.status==="rejected"){c.push({accountId:C.id,error:g(m.reason instanceof Error?m.reason.message:String(m.reason))});return}const h=m.value;h.success?(i++,h.data.outputs&&y.push({accountId:C.id,outputs:h.data.outputs})):c.push({accountId:C.id,error:h.error.message})}),t.onCascadePhaseComplete?.("accounts")}if(t.onCascadeComplete?.({platformDeployed:G,domainsDeployed:K,accountsDeployed:i,accountsFailed:c.length,errors:c}),c.length>0){const u=c.map(A=>` ${A.accountId}: ${A.error}`).join(`
|
|
2
|
+
`);t.onLog?.(g(`Cascade completed with ${c.length} failure(s):
|
|
3
|
+
${u}`),"warn")}}const tt=c.length>0?c.map(i=>g(`${i.accountId}: ${i.error}`)):void 0;return _({target:e.target,deploymentType:"organisation",outputs:Z,...y.length>0?{cascadeOutputs:y}:{},durationMs:Date.now()-s,warnings:tt})}export{St as deployOrganisation};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Result } from "@fjall/generator";
|
|
2
2
|
import type { AwsProvider } from "../aws/AwsProvider.js";
|
|
3
|
-
import type { OUTree } from "../aws/organisations/types.js";
|
|
3
|
+
import type { OUTree, AccountInfo } from "../aws/organisations/types.js";
|
|
4
4
|
export type OrgSetupPhase = "create-organisation" | "enable-policies" | "enable-service-access" | "enable-ram-sharing" | "activate-trusted-access" | "enable-ipam" | "configure-backup" | "create-accounts" | "create-organisational-units" | "place-accounts" | "activate-cost-tags" | "check-identity-centre" | "register-security-delegates";
|
|
5
5
|
export interface OrgSetupCallbacks {
|
|
6
6
|
onPhaseStart?(phase: OrgSetupPhase): void;
|
|
@@ -15,7 +15,7 @@ export interface OrgSetupConfig {
|
|
|
15
15
|
}>;
|
|
16
16
|
platformAccountId?: string;
|
|
17
17
|
organisationalUnits: string[] | OUTree;
|
|
18
|
-
accountPlacements?:
|
|
18
|
+
accountPlacements?: AccountInfo[];
|
|
19
19
|
costAllocationTags?: string[];
|
|
20
20
|
skipIdentityCentre?: boolean;
|
|
21
21
|
securityDelegateAccountId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{success as y,failure as h}from"@fjall/generator";import{OrganizationsClient as v}from"@aws-sdk/client-organizations";import{RAMClient as x}from"@aws-sdk/client-ram";import{CloudFormationClient as T}from"@aws-sdk/client-cloudformation";import{EC2Client as M}from"@aws-sdk/client-ec2";import{BackupClient as
|
|
1
|
+
import{success as y,failure as h}from"@fjall/generator";import{OrganizationsClient as v}from"@aws-sdk/client-organizations";import{RAMClient as x}from"@aws-sdk/client-ram";import{CloudFormationClient as T}from"@aws-sdk/client-cloudformation";import{EC2Client as M}from"@aws-sdk/client-ec2";import{BackupClient as D}from"@aws-sdk/client-backup";import{CostExplorerClient as N}from"@aws-sdk/client-cost-explorer";import{SSOAdminClient as B}from"@aws-sdk/client-sso-admin";import{ensureOrganisationExists as F}from"../aws/organisations/organisation.js";import{enablePolicyTypes as L}from"../aws/organisations/policies.js";import{enableServiceAccess as W}from"../aws/organisations/serviceAccess.js";import{enableRamSharing as j}from"../aws/organisations/ram.js";import{activateTrustedAccess as z}from"../aws/organisations/trustedAccess.js";import{enableIpamDelegatedAdmin as G}from"../aws/organisations/ipam.js";import{updateBackupGlobalSettings as K}from"../aws/organisations/backup.js";import{listAccounts as q,createAccount as H}from"../aws/organisations/accounts.js";import{ensureOrganisationalUnitsExist as J,placeAccountsInOUs as Q,buildAccountToOUMap as V}from"../aws/organisations/organisationalUnits.js";import{activateCostAllocationTags as X}from"../aws/organisations/costAllocation.js";import{checkIdentityCentreStatus as Y}from"../aws/organisations/identityCentre.js";import{registerSecurityDelegates as Z}from"../aws/organisations/delegatedAdmin.js";async function Pe(r,o,e){const n=[],s=[],t=[],c=[];let C;const u=r.getClient(v),A=r.getClient(x),S=r.getClient(T),E=r.getClient(M),I=r.getClient(D),w=r.getClient(N),O=r.getClient(B);e?.onPhaseStart?.("create-organisation"),e?.onProgress?.("Ensuring AWS Organisation exists");const p=await F(u);if(!p.success)return e?.onError?.("create-organisation",p.error),e?.onPhaseComplete?.("create-organisation","error"),h(p.error);const{orgId:R,rootId:f}=p.data;if(e?.onPhaseComplete?.("create-organisation","completed"),n.push("create-organisation"),await a("enable-policies",()=>(e?.onProgress?.("Enabling organisation policy types"),L(u,f)),n,t,e),await a("enable-service-access",()=>(e?.onProgress?.("Enabling AWS service access"),W(u)),n,t,e),await a("enable-ram-sharing",()=>(e?.onProgress?.("Enabling RAM sharing"),j(A)),n,t,e),await a("activate-trusted-access",()=>(e?.onProgress?.("Activating CloudFormation trusted access"),z(S)),n,t,e),o.platformAccountId){const i=o.platformAccountId;await a("enable-ipam",()=>(e?.onProgress?.("Enabling IPAM delegated administrator"),G(E,i)),n,t,e)}await a("configure-backup",()=>(e?.onProgress?.("Updating backup global settings"),K(I)),n,t,e),e?.onPhaseStart?.("create-accounts"),e?.onProgress?.("Checking for missing accounts");const d=await _(u,o.accounts,c);d.success?(n.push("create-accounts"),e?.onPhaseComplete?.("create-accounts","completed")):(t.push({phase:"create-accounts",error:d.error.message}),e?.onError?.("create-accounts",d.error),e?.onPhaseComplete?.("create-accounts","error"));let m={};e?.onPhaseStart?.("create-organisational-units"),e?.onProgress?.("Ensuring organisational units exist");const g=await J(u,f,o.organisationalUnits);if(g.success?(m=g.data,n.push("create-organisational-units"),e?.onPhaseComplete?.("create-organisational-units","completed")):(t.push({phase:"create-organisational-units",error:g.error.message}),e?.onError?.("create-organisational-units",g.error),e?.onPhaseComplete?.("create-organisational-units","error")),Object.keys(m).length===0)s.push("place-accounts"),e?.onPhaseStart?.("place-accounts"),e?.onPhaseComplete?.("place-accounts","skipped");else if(o.accountPlacements===void 0){const i=new Error("Account placements not provided despite OUs being created. Caller must populate accountPlacements so accounts can be moved into their target OUs.");t.push({phase:"place-accounts",error:i.message}),e?.onPhaseStart?.("place-accounts"),e?.onError?.("place-accounts",i),e?.onPhaseComplete?.("place-accounts","error")}else if(o.accountPlacements.length===0)s.push("place-accounts"),e?.onPhaseStart?.("place-accounts"),e?.onPhaseComplete?.("place-accounts","skipped");else{const i=o.accountPlacements,U=Array.isArray(o.organisationalUnits)?void 0:V(o.organisationalUnits,m);await a("place-accounts",()=>(e?.onProgress?.("Placing accounts in organisational units"),Q(u,m,i,U)),n,t,e)}const P=o.costAllocationTags??[];if(P.length>0?await a("activate-cost-tags",()=>(e?.onProgress?.("Activating cost allocation tags"),X(w,P.map(i=>({TagKey:i})))),n,t,e):(s.push("activate-cost-tags"),e?.onPhaseStart?.("activate-cost-tags"),e?.onPhaseComplete?.("activate-cost-tags","skipped")),o.skipIdentityCentre)s.push("check-identity-centre"),e?.onPhaseStart?.("check-identity-centre"),e?.onPhaseComplete?.("check-identity-centre","skipped");else{e?.onPhaseStart?.("check-identity-centre"),e?.onProgress?.("Checking Identity Centre status");const i=await Y(O);i.success?(C=i.data.enabled?"enabled":"not-enabled",n.push("check-identity-centre"),e?.onPhaseComplete?.("check-identity-centre","completed")):(t.push({phase:"check-identity-centre",error:i.error.message}),e?.onError?.("check-identity-centre",i.error),e?.onPhaseComplete?.("check-identity-centre","error"))}const l=o.securityDelegateAccountId;return l?await a("register-security-delegates",()=>(e?.onProgress?.("Registering security service delegated administrators"),Z(u,l)),n,t,e):(s.push("register-security-delegates"),e?.onPhaseStart?.("register-security-delegates"),e?.onPhaseComplete?.("register-security-delegates","skipped")),y({organisationId:R,createdAccounts:c,identityCentreStatus:C,phasesCompleted:n,phasesSkipped:s,errors:t})}async function a(r,o,e,n,s){s?.onPhaseStart?.(r);const t=await o();t.success?(e.push(r),s?.onPhaseComplete?.(r,"completed")):(n.push({phase:r,error:t.error.message}),s?.onError?.(r,t.error),s?.onPhaseComplete?.(r,"error"))}async function _(r,o,e){const n=await q(r);if(!n.success)return h(n.error);const s=new Set(n.data.map(t=>t.Name?.toLowerCase()).filter(t=>t!==void 0));for(const t of o){if(s.has(t.name.toLowerCase()))continue;const c=await H(r,t.name,t.email);if(!c.success)return h(c.error);e.push({name:c.data.accountName,accountId:c.data.accountId})}return y(void 0)}export{Pe as runOrganisationSetup};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/deploy-core",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.8",
|
|
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",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@aws-sdk/client-s3": "^3.1038.0",
|
|
74
74
|
"@aws-sdk/client-sso-admin": "^3.1038.0",
|
|
75
75
|
"@aws-sdk/client-sts": "^3.1038.0",
|
|
76
|
-
"@fjall/generator": "^2.4.
|
|
76
|
+
"@fjall/generator": "^2.4.8",
|
|
77
77
|
"@fjall/util": "^0.100.0",
|
|
78
78
|
"@smithy/node-http-handler": "^4.6.1",
|
|
79
79
|
"zod": "^4.4.3"
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
"@types/node": "^25.6.0",
|
|
83
83
|
"vitest": "^4.1.5"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "a1e1f954e39ecbe0360ac6124dba4146aa747f36"
|
|
86
86
|
}
|