@fjall/deploy-core 0.89.4 → 0.89.5

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.
@@ -12,8 +12,8 @@ export interface AwsProvider {
12
12
  getClient<T>(ClientClass: AwsSdkClientConstructor<T>): T;
13
13
  /** AWS region for this context. */
14
14
  getRegion(): string;
15
- /** AWS account ID (resolved via STS GetCallerIdentity). */
16
- getAccountId(): string | undefined;
15
+ /** AWS account ID — always available (callers resolve before calling deploy-core). */
16
+ getAccountId(): string;
17
17
  /** Raw credentials for subprocess environments (CDK). */
18
18
  getCredentials(): AwsProviderCredentials | undefined;
19
19
  /** Export credentials to process.env for spawned subprocesses. */
@@ -9,13 +9,12 @@ import type { AwsProvider, AwsProviderCredentials, AwsSdkClientConstructor } fro
9
9
  export declare class SimpleAwsProvider implements AwsProvider {
10
10
  private readonly credentials;
11
11
  private readonly region;
12
- private accountId;
12
+ private readonly accountId;
13
13
  private readonly clientCache;
14
14
  constructor(awsCredentials: AwsCredentials);
15
15
  getClient<T>(ClientClass: AwsSdkClientConstructor<T>): T;
16
16
  getRegion(): string;
17
- getAccountId(): string | undefined;
18
- setAccountId(accountId: string): void;
17
+ getAccountId(): string;
19
18
  getCredentials(): AwsProviderCredentials;
20
19
  exportToEnv(): void;
21
20
  assumeRole(roleArn: string, sessionName: string): Promise<AwsProviderCredentials>;
@@ -37,9 +37,6 @@ export class SimpleAwsProvider {
37
37
  getAccountId() {
38
38
  return this.accountId;
39
39
  }
40
- setAccountId(accountId) {
41
- this.accountId = accountId;
42
- }
43
40
  getCredentials() {
44
41
  return this.credentials;
45
42
  }
@@ -59,7 +56,7 @@ export class SimpleAwsProvider {
59
56
  const response = await stsClient.send(new AssumeRoleCommand({
60
57
  RoleArn: roleArn,
61
58
  RoleSessionName: sessionName
62
- }));
59
+ }), { abortSignal: AbortSignal.timeout(30_000) });
63
60
  const assumed = response.Credentials;
64
61
  if (!assumed?.AccessKeyId || !assumed?.SecretAccessKey) {
65
62
  throw new Error(`AssumeRole for ${roleArn} returned incomplete credentials`);
@@ -21,6 +21,11 @@ export async function deployApplication(params, services, operation) {
21
21
  target: operation.appName,
22
22
  path: operation.path,
23
23
  region: services.awsProvider.getRegion(),
24
+ callerIdentity: {
25
+ Account: services.awsProvider.getAccountId(),
26
+ Arn: "",
27
+ UserId: ""
28
+ },
24
29
  ...buildParamsContext(params)
25
30
  }, {
26
31
  verbose: options?.verbose,
@@ -6,4 +6,5 @@ import type { DeployParams } from "../types/params.js";
6
6
  export declare function buildParamsContext(params: DeployParams): {
7
7
  orgConfig?: string;
8
8
  fjallOrgId?: string;
9
+ fjallOidcConfigured?: boolean;
9
10
  };
@@ -9,6 +9,7 @@ export function buildParamsContext(params) {
9
9
  : {}),
10
10
  ...(params.identity !== undefined
11
11
  ? { fjallOrgId: params.identity.fjallOrgId }
12
- : {})
12
+ : {}),
13
+ ...(params.options?.skipOidc ? { fjallOidcConfigured: true } : {})
13
14
  };
14
15
  }
@@ -42,7 +42,7 @@ function buildOrgContext(params, services, operation, deployType, accountName) {
42
42
  region: services.awsProvider.getRegion(),
43
43
  accountName,
44
44
  callerIdentity: {
45
- Account: services.awsProvider.getAccountId() ?? "",
45
+ Account: services.awsProvider.getAccountId(),
46
46
  Arn: "",
47
47
  UserId: ""
48
48
  },
@@ -52,16 +52,37 @@ function buildOrgContext(params, services, operation, deployType, accountName) {
52
52
  infraOnly: params.options?.infraOnly
53
53
  }, params.orgConfig);
54
54
  }
55
+ /**
56
+ * Infrastructure deployment step names — match the webapp's
57
+ * EXPECTED_INFRASTRUCTURE_STEPS exactly so the UI timeline lights up.
58
+ */
59
+ const INFRA_STEPS = {
60
+ CONNECT: { id: "connect", name: "Connect securely" },
61
+ PREPARE: { id: "prepare", name: "Prepare environment" },
62
+ DEPLOY: { id: "deploy", name: "Deploy infrastructure" },
63
+ MONITORING: { id: "monitoring", name: "Enable monitoring" }
64
+ };
65
+ const INFRA_STEP_TOTAL = 4;
55
66
  /**
56
67
  * Deploy a single organisation component (platform or account).
68
+ *
69
+ * Emits 4 named steps matching the webapp's expected infrastructure
70
+ * timeline: Connect securely → Prepare environment → Deploy
71
+ * infrastructure → Enable monitoring.
57
72
  */
58
73
  async function deploySingleComponent(params, services, operation, deployType, startTime) {
59
74
  const { callbacks } = params;
75
+ // Step 1: Connect securely — already seeded by the webapp trigger.
76
+ // Complete it now: credentials are available by the time deploy-core runs.
77
+ callbacks.onStepComplete?.(INFRA_STEPS.CONNECT.id, INFRA_STEPS.CONNECT.name, "completed", 0, INFRA_STEP_TOTAL);
78
+ // Step 2: Prepare environment (synth + bootstrap)
79
+ callbacks.onStepStart?.(INFRA_STEPS.PREPARE.id, INFRA_STEPS.PREPARE.name, 1, INFRA_STEP_TOTAL);
60
80
  const context = buildOrgContext(params, services, operation, deployType, deployType === "account" ? operation.target : undefined);
61
81
  // Synth
62
82
  callbacks.onLog?.(`Synthesising ${deployType} infrastructure…`, "info");
63
83
  const synthResult = await services.cdkService.runCdkSynth(context, (chunk) => callbacks.onCdkOutput?.(chunk, "synth"));
64
84
  if (!synthResult.success) {
85
+ callbacks.onStepComplete?.(INFRA_STEPS.PREPARE.id, INFRA_STEPS.PREPARE.name, "error", 1, INFRA_STEP_TOTAL);
65
86
  const error = new Error(`CDK synthesis failed: ${synthResult.error}`);
66
87
  callbacks.onError?.(error);
67
88
  return failure(error);
@@ -71,24 +92,28 @@ async function deploySingleComponent(params, services, operation, deployType, st
71
92
  const bootstrapResult = await services.cdkService.runCdkBootstrap(context, (chunk) => callbacks.onOutput?.(chunk));
72
93
  if (!bootstrapResult.success) {
73
94
  callbacks.onCDKBootstrap?.("failed");
95
+ callbacks.onStepComplete?.(INFRA_STEPS.PREPARE.id, INFRA_STEPS.PREPARE.name, "error", 1, INFRA_STEP_TOTAL);
74
96
  const error = new Error(`Bootstrap failed: ${bootstrapResult.error}`);
75
97
  callbacks.onError?.(error);
76
98
  return failure(error);
77
99
  }
78
100
  callbacks.onCDKBootstrap?.("complete");
79
- // Deploy
101
+ callbacks.onStepComplete?.(INFRA_STEPS.PREPARE.id, INFRA_STEPS.PREPARE.name, "completed", 1, INFRA_STEP_TOTAL);
102
+ // Step 3: Deploy infrastructure
80
103
  const stackName = getOrganisationStackName(operation.type);
81
- const stepId = `${deployType}-deploy`;
82
- const stepName = `Deploying ${deployType} infrastructure`;
83
- callbacks.onStepStart?.(stepId, stepName, 0, 1);
104
+ callbacks.onStepStart?.(INFRA_STEPS.DEPLOY.id, INFRA_STEPS.DEPLOY.name, 2, INFRA_STEP_TOTAL);
84
105
  const deployResult = await services.cdkService.runCdkDeploy(context, stackName, (chunk) => callbacks.onOutput?.(chunk), (event) => callbacks.onResourceProgress?.(event), services.awsProvider);
85
106
  if (!deployResult.success) {
86
- callbacks.onStepComplete?.(stepId, stepName, "error", 0, 1);
107
+ callbacks.onStepComplete?.(INFRA_STEPS.DEPLOY.id, INFRA_STEPS.DEPLOY.name, "error", 2, INFRA_STEP_TOTAL);
87
108
  const error = new Error(deployResult.error);
88
109
  callbacks.onError?.(error);
89
110
  return failure(error);
90
111
  }
91
- callbacks.onStepComplete?.(stepId, stepName, "completed", 0, 1);
112
+ callbacks.onStepComplete?.(INFRA_STEPS.DEPLOY.id, INFRA_STEPS.DEPLOY.name, "completed", 2, INFRA_STEP_TOTAL);
113
+ // Step 4: Enable monitoring — CloudTrail + alarms are part of the
114
+ // Account stack. Signal post-deploy readiness.
115
+ callbacks.onStepStart?.(INFRA_STEPS.MONITORING.id, INFRA_STEPS.MONITORING.name, 3, INFRA_STEP_TOTAL);
116
+ callbacks.onStepComplete?.(INFRA_STEPS.MONITORING.id, INFRA_STEPS.MONITORING.name, "completed", 3, INFRA_STEP_TOTAL);
92
117
  return success({
93
118
  target: operation.target,
94
119
  deploymentType: "organisation",
@@ -19,6 +19,7 @@ export interface CdkContext {
19
19
  managementAccountId?: string;
20
20
  ipamPoolId?: string;
21
21
  fjallOrgId?: string;
22
+ fjallOidcConfigured?: string;
22
23
  orgConfig?: string;
23
24
  }
24
25
  export interface CdkOptions {
@@ -70,6 +70,7 @@ export class CdkService {
70
70
  managementAccountId: context.managementAccountId,
71
71
  ipamPoolId: context.ipamPoolId,
72
72
  fjallOrgId: context.fjallOrgId,
73
+ fjallOidcConfigured: context.fjallOidcConfigured ? "true" : undefined,
73
74
  orgConfig: context.orgConfig
74
75
  };
75
76
  }
@@ -10,7 +10,7 @@ export interface AwsCredentials {
10
10
  secretAccessKey: string;
11
11
  sessionToken?: string;
12
12
  region: string;
13
- accountId?: string;
13
+ accountId: string;
14
14
  }
15
15
  /**
16
16
  * Pre-fetched organisation identity for org deployments.
@@ -14,6 +14,7 @@ export interface DeploymentContext {
14
14
  managementAccountId?: string;
15
15
  ipamPoolId?: string;
16
16
  fjallOrgId?: string;
17
+ fjallOidcConfigured?: boolean;
17
18
  orgConfig?: string;
18
19
  options: {
19
20
  verbose?: boolean;
@@ -60,6 +60,8 @@ export interface DeployOptions {
60
60
  deployOnly?: boolean;
61
61
  passThroughCDK?: boolean;
62
62
  environment?: string;
63
+ /** Skip OIDC provider creation — set when OIDC is already configured (webapp Quick Create). */
64
+ skipOidc?: boolean;
63
65
  }
64
66
  export type DeploymentType = "application" | "organisation";
65
67
  export interface DeployResult {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/deploy-core",
3
- "version": "0.89.4",
3
+ "version": "0.89.5",
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",
@@ -32,12 +32,12 @@
32
32
  "@aws-sdk/client-ram": "^3.1009.0",
33
33
  "@aws-sdk/client-sso-admin": "^3.1009.0",
34
34
  "@aws-sdk/client-sts": "^3.1009.0",
35
- "@fjall/generator": "^0.89.4",
36
- "@fjall/util": "^0.89.4",
35
+ "@fjall/generator": "^0.89.5",
36
+ "@fjall/util": "^0.89.5",
37
37
  "zod": "^4.3.6"
38
38
  },
39
39
  "devDependencies": {
40
40
  "vitest": "^3.2.3"
41
41
  },
42
- "gitHead": "6b2b2d2082b8c07174f4091202cd5bd9862f5556"
42
+ "gitHead": "1680c1a0be16950e9e10e571163ccc42198f6a8e"
43
43
  }