@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.
- package/dist/index.js +89 -36
- 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(
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
{
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
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
|
-
|
|
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();
|