@devramps/cli 0.1.21 → 0.1.23

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.
Files changed (2) hide show
  1. package/dist/index.js +89 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -270,7 +270,7 @@ var MultiStackProgress = class {
270
270
  const filled = Math.round(this.barWidth * percentage);
271
271
  const empty = this.barWidth - filled;
272
272
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
273
- const typeLabel = this.getTypeLabel(stackType).padEnd(5);
273
+ const typeLabel = this.getTypeLabel(stackType).padEnd(6);
274
274
  const accountLabel = `${accountId} ${region.padEnd(12)}`;
275
275
  const countLabel = `${completed}/${total}`;
276
276
  const displayName = stackName.padEnd(this.maxStackNameLen);
@@ -1556,25 +1556,35 @@ function addOidcProviderResource(template, conditional = true, oidcProviderUrl)
1556
1556
  }
1557
1557
  };
1558
1558
  }
1559
- function buildOidcTrustPolicy(accountId, subject, oidcProviderUrl) {
1559
+ function buildOidcTrustPolicy(accountId, subject, oidcProviderUrl, additionalTrustedAccounts) {
1560
1560
  const providerUrl = oidcProviderUrl || OIDC_PROVIDER_URL;
1561
- return {
1562
- Version: "2012-10-17",
1563
- Statement: [
1564
- {
1565
- Effect: "Allow",
1566
- Principal: {
1567
- Federated: `arn:aws:iam::${accountId}:oidc-provider/${providerUrl}`
1568
- },
1569
- Action: "sts:AssumeRoleWithWebIdentity",
1570
- Condition: {
1571
- StringEquals: {
1572
- [`${providerUrl}:sub`]: subject,
1573
- [`${providerUrl}:aud`]: "sts.amazonaws.com"
1574
- }
1561
+ const statements = [
1562
+ {
1563
+ Effect: "Allow",
1564
+ Principal: {
1565
+ Federated: `arn:aws:iam::${accountId}:oidc-provider/${providerUrl}`
1566
+ },
1567
+ Action: "sts:AssumeRoleWithWebIdentity",
1568
+ Condition: {
1569
+ StringEquals: {
1570
+ [`${providerUrl}:sub`]: subject,
1571
+ [`${providerUrl}:aud`]: "sts.amazonaws.com"
1575
1572
  }
1576
1573
  }
1577
- ]
1574
+ }
1575
+ ];
1576
+ if (additionalTrustedAccounts && additionalTrustedAccounts.length > 0) {
1577
+ statements.push({
1578
+ Effect: "Allow",
1579
+ Principal: {
1580
+ AWS: additionalTrustedAccounts.map((id) => `arn:aws:iam::${id}:root`)
1581
+ },
1582
+ Action: "sts:AssumeRole"
1583
+ });
1584
+ }
1585
+ return {
1586
+ Version: "2012-10-17",
1587
+ Statement: statements
1578
1588
  };
1579
1589
  }
1580
1590
  function createIamRoleResource(roleName, trustPolicy, policies, additionalTags = []) {
@@ -1938,7 +1948,7 @@ function createTerraformStateBucketPolicy(bucketName, cicdAccountId, allowedAcco
1938
1948
 
1939
1949
  // src/templates/org-stack.ts
1940
1950
  function generateOrgStackTemplate(options) {
1941
- const { orgSlug, cicdAccountId, targetAccountIds, oidcProviderUrl } = options;
1951
+ const { orgSlug, cicdAccountId, targetAccountIds, oidcProviderUrl, additionalTrustedAccounts } = options;
1942
1952
  const template = createBaseTemplate(`DevRamps Org Stack for ${orgSlug}`);
1943
1953
  const kmsKeyPolicy = buildKmsKeyPolicy(cicdAccountId, targetAccountIds);
1944
1954
  template.Resources.DevRampsKMSKey = createKmsKeyResource(
@@ -1968,7 +1978,7 @@ function generateOrgStackTemplate(options) {
1968
1978
  PolicyDocument: bucketPolicy
1969
1979
  }
1970
1980
  };
1971
- const trustPolicy = buildOidcTrustPolicy(cicdAccountId, `org:${orgSlug}/cicd`, oidcProviderUrl);
1981
+ const trustPolicy = buildOidcTrustPolicy(cicdAccountId, `org:${orgSlug}/cicd`, oidcProviderUrl, additionalTrustedAccounts);
1972
1982
  const orgRolePolicies = buildOrgRolePolicies(orgSlug);
1973
1983
  template.Resources.DevRampsCICDDeploymentRole = createIamRoleResource(
1974
1984
  getOrgRoleName(),
@@ -2342,6 +2352,38 @@ var DOCKER_IMPORT_PERMISSIONS = {
2342
2352
  resources: ["*"]
2343
2353
  };
2344
2354
 
2355
+ // src/permissions/lambda-deploy.ts
2356
+ var LAMBDA_DEPLOY_PERMISSIONS = {
2357
+ actions: [
2358
+ // Update function code (S3 bundle or container image)
2359
+ "lambda:UpdateFunctionCode",
2360
+ // Poll for update completion
2361
+ "lambda:GetFunctionConfiguration",
2362
+ "lambda:GetFunction"
2363
+ ],
2364
+ resources: ["*"]
2365
+ };
2366
+
2367
+ // src/permissions/lambda-invoke.ts
2368
+ var LAMBDA_INVOKE_PERMISSIONS = {
2369
+ actions: [
2370
+ // Invoke the Lambda function
2371
+ "lambda:InvokeFunction"
2372
+ ],
2373
+ resources: ["*"]
2374
+ };
2375
+
2376
+ // src/permissions/cloudfront-invalidate.ts
2377
+ var CLOUDFRONT_INVALIDATE_PERMISSIONS = {
2378
+ actions: [
2379
+ // Create invalidation
2380
+ "cloudfront:CreateInvalidation",
2381
+ // Poll for invalidation completion
2382
+ "cloudfront:GetInvalidation"
2383
+ ],
2384
+ resources: ["*"]
2385
+ };
2386
+
2345
2387
  // src/permissions/custom.ts
2346
2388
  function getCustomPermissions(stepType) {
2347
2389
  verbose(
@@ -2359,6 +2401,9 @@ var PERMISSIONS_REGISTRY = {
2359
2401
  "DEVRAMPS:EKS:DEPLOY": EKS_DEPLOY_PERMISSIONS,
2360
2402
  "DEVRAMPS:EKS:HELM": EKS_HELM_PERMISSIONS,
2361
2403
  "DEVRAMPS:ECS:DEPLOY": ECS_DEPLOY_PERMISSIONS,
2404
+ "DEVRAMPS:LAMBDA:DEPLOY": LAMBDA_DEPLOY_PERMISSIONS,
2405
+ "DEVRAMPS:LAMBDA:INVOKE": LAMBDA_INVOKE_PERMISSIONS,
2406
+ "DEVRAMPS:CLOUDFRONT:INVALIDATE": CLOUDFRONT_INVALIDATE_PERMISSIONS,
2362
2407
  // Artifact mirroring steps (CI/CD account -> deployment account)
2363
2408
  "DEVRAMPS:MIRROR:ECR": MIRROR_ECR_PERMISSIONS,
2364
2409
  "DEVRAMPS:MIRROR:S3": MIRROR_S3_PERMISSIONS,
@@ -2398,13 +2443,14 @@ function generateStageStackTemplate(options) {
2398
2443
  additionalPolicies,
2399
2444
  dockerArtifacts,
2400
2445
  bundleArtifacts,
2401
- oidcProviderUrl
2446
+ oidcProviderUrl,
2447
+ additionalTrustedAccounts
2402
2448
  } = options;
2403
2449
  const template = createBaseTemplate(
2404
2450
  `DevRamps Stage Stack for ${pipelineSlug}/${stageName}`
2405
2451
  );
2406
2452
  const roleName = generateStageRoleName(pipelineSlug, stageName);
2407
- const trustPolicy = buildStageTrustPolicy(accountId, orgSlug, pipelineSlug, oidcProviderUrl);
2453
+ const trustPolicy = buildStageTrustPolicy(accountId, orgSlug, pipelineSlug, oidcProviderUrl, additionalTrustedAccounts);
2408
2454
  const policies = buildStagePolicies(steps, additionalPolicies);
2409
2455
  template.Resources.StageDeploymentRole = createIamRoleResource(
2410
2456
  roleName,
@@ -2489,9 +2535,9 @@ function generateStageStackTemplate(options) {
2489
2535
  }
2490
2536
  return template;
2491
2537
  }
2492
- function buildStageTrustPolicy(accountId, orgSlug, pipelineSlug, oidcProviderUrl) {
2538
+ function buildStageTrustPolicy(accountId, orgSlug, pipelineSlug, oidcProviderUrl, additionalTrustedAccounts) {
2493
2539
  const subject = `org:${orgSlug}/pipeline:${pipelineSlug}`;
2494
- return buildOidcTrustPolicy(accountId, subject, oidcProviderUrl);
2540
+ return buildOidcTrustPolicy(accountId, subject, oidcProviderUrl, additionalTrustedAccounts);
2495
2541
  }
2496
2542
  function buildStagePolicies(steps, additionalPolicies) {
2497
2543
  const policies = [];
@@ -2560,12 +2606,12 @@ function buildStagePolicies(steps, additionalPolicies) {
2560
2606
 
2561
2607
  // src/templates/import-stack.ts
2562
2608
  function generateImportStackTemplate(options) {
2563
- const { pipelineSlug, orgSlug, accountId, oidcProviderUrl } = options;
2609
+ const { pipelineSlug, orgSlug, accountId, oidcProviderUrl, additionalTrustedAccounts } = options;
2564
2610
  const template = createBaseTemplate(
2565
2611
  `DevRamps Import Stack for ${pipelineSlug} - grants read access for artifact imports`
2566
2612
  );
2567
2613
  const roleName = generateImportRoleName(pipelineSlug);
2568
- const trustPolicy = buildOidcTrustPolicy(accountId, `org:${orgSlug}/cicd`, oidcProviderUrl);
2614
+ const trustPolicy = buildOidcTrustPolicy(accountId, `org:${orgSlug}/cicd`, oidcProviderUrl, additionalTrustedAccounts);
2569
2615
  const policies = buildImportRolePolicies();
2570
2616
  template.Resources.ImportRole = createIamRoleResource(
2571
2617
  roleName,
@@ -2743,7 +2789,8 @@ async function bootstrapCommand(options) {
2743
2789
  process.exit(0);
2744
2790
  }
2745
2791
  const oidcProviderUrl = getOidcProviderUrlFromEndpoint(options.endpointOverride);
2746
- await executeDeployment(plan, pipelines, pipelineArtifacts, authData, identity.accountId, options, oidcProviderUrl);
2792
+ const additionalTrustedAccounts = options.additionalTrustedAccounts ? options.additionalTrustedAccounts.split(",").map((s) => s.trim()) : void 0;
2793
+ await executeDeployment(plan, pipelines, pipelineArtifacts, authData, identity.accountId, options, oidcProviderUrl, additionalTrustedAccounts);
2747
2794
  } catch (error2) {
2748
2795
  if (error2 instanceof DevRampsError) {
2749
2796
  error(error2.message);
@@ -3016,7 +3063,7 @@ async function confirmDeploymentPlan(plan) {
3016
3063
  ]
3017
3064
  });
3018
3065
  }
3019
- async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, currentAccountId, options, oidcProviderUrl) {
3066
+ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts) {
3020
3067
  const results = { success: 0, failed: 0 };
3021
3068
  const remainingStacks = 1 + plan.pipelineStacks.length + plan.stageStacks.length + plan.importStacks.length;
3022
3069
  newline();
@@ -3079,7 +3126,7 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
3079
3126
  mainProgress.start();
3080
3127
  const orgPromise = (async () => {
3081
3128
  try {
3082
- await deployOrgStack(plan, pipelines, authData, currentAccountId, options, oidcProviderUrl);
3129
+ await deployOrgStack(plan, pipelines, authData, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts);
3083
3130
  return { stack: plan.orgStack.stackName, success: true };
3084
3131
  } catch (error2) {
3085
3132
  return {
@@ -3103,7 +3150,7 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
3103
3150
  });
3104
3151
  const stagePromises = plan.stageStacks.map(async (stack) => {
3105
3152
  try {
3106
- await deployStageStack(stack, authData, currentAccountId, options, oidcProviderUrl);
3153
+ await deployStageStack(stack, authData, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts);
3107
3154
  return { stack: stack.stackName, success: true };
3108
3155
  } catch (error2) {
3109
3156
  return {
@@ -3115,7 +3162,7 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
3115
3162
  });
3116
3163
  const importPromises = plan.importStacks.map(async (stack) => {
3117
3164
  try {
3118
- await deployImportStack(stack, currentAccountId, options, oidcProviderUrl);
3165
+ await deployImportStack(stack, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts);
3119
3166
  return { stack: `${stack.stackName} (${stack.accountId})`, success: true };
3120
3167
  } catch (error2) {
3121
3168
  return {
@@ -3152,7 +3199,7 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
3152
3199
  process.exit(1);
3153
3200
  }
3154
3201
  }
3155
- async function deployOrgStack(plan, pipelines, authData, currentAccountId, options, oidcProviderUrl) {
3202
+ async function deployOrgStack(plan, pipelines, authData, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts) {
3156
3203
  const { orgSlug, cicdAccountId, cicdRegion } = authData;
3157
3204
  const credentials = cicdAccountId !== currentAccountId ? (await assumeRoleForAccount({
3158
3205
  targetAccountId: cicdAccountId,
@@ -3183,7 +3230,8 @@ async function deployOrgStack(plan, pipelines, authData, currentAccountId, optio
3183
3230
  orgSlug,
3184
3231
  cicdAccountId,
3185
3232
  targetAccountIds,
3186
- oidcProviderUrl
3233
+ oidcProviderUrl,
3234
+ additionalTrustedAccounts
3187
3235
  });
3188
3236
  const deployOptions = {
3189
3237
  stackName: plan.orgStack.stackName,
@@ -3235,7 +3283,7 @@ async function deployAccountStack(stack, currentAccountId, options, oidcProvider
3235
3283
  await previewStackChanges(deployOptions);
3236
3284
  await deployStack(deployOptions);
3237
3285
  }
3238
- async function deployStageStack(stack, authData, currentAccountId, options, oidcProviderUrl) {
3286
+ async function deployStageStack(stack, authData, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts) {
3239
3287
  const credentials = stack.accountId !== currentAccountId ? (await assumeRoleForAccount({
3240
3288
  targetAccountId: stack.accountId,
3241
3289
  currentAccountId,
@@ -3250,7 +3298,8 @@ async function deployStageStack(stack, authData, currentAccountId, options, oidc
3250
3298
  additionalPolicies: stack.additionalPolicies,
3251
3299
  dockerArtifacts: stack.dockerArtifacts,
3252
3300
  bundleArtifacts: stack.bundleArtifacts,
3253
- oidcProviderUrl
3301
+ oidcProviderUrl,
3302
+ additionalTrustedAccounts
3254
3303
  });
3255
3304
  const deployOptions = {
3256
3305
  stackName: stack.stackName,
@@ -3262,7 +3311,7 @@ async function deployStageStack(stack, authData, currentAccountId, options, oidc
3262
3311
  await previewStackChanges(deployOptions);
3263
3312
  await deployStack(deployOptions);
3264
3313
  }
3265
- async function deployImportStack(stack, currentAccountId, options, oidcProviderUrl) {
3314
+ async function deployImportStack(stack, currentAccountId, options, oidcProviderUrl, additionalTrustedAccounts) {
3266
3315
  const credentials = stack.accountId !== currentAccountId ? (await assumeRoleForAccount({
3267
3316
  targetAccountId: stack.accountId,
3268
3317
  currentAccountId,
@@ -3272,7 +3321,8 @@ async function deployImportStack(stack, currentAccountId, options, oidcProviderU
3272
3321
  pipelineSlug: stack.pipelineSlug,
3273
3322
  orgSlug: stack.orgSlug,
3274
3323
  accountId: stack.accountId,
3275
- oidcProviderUrl
3324
+ oidcProviderUrl,
3325
+ additionalTrustedAccounts
3276
3326
  });
3277
3327
  const deployOptions = {
3278
3328
  stackName: stack.stackName,
@@ -3302,5 +3352,8 @@ program.command("bootstrap").description("Bootstrap IAM roles in target AWS acco
3302
3352
  ).option(
3303
3353
  "--endpoint-override <url>",
3304
3354
  "Override the DevRamps API endpoint (for testing, e.g., http://localhost:3000)"
3355
+ ).option(
3356
+ "--additional-trusted-accounts <accounts>",
3357
+ "Comma-separated AWS account IDs to add to role trust policies (for local dev testing)"
3305
3358
  ).action(bootstrapCommand);
3306
3359
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devramps/cli",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "DevRamps CLI - Bootstrap AWS infrastructure for CI/CD pipelines",
5
5
  "main": "dist/index.js",
6
6
  "bin": {