@mtndev/cli 1.1.0 → 2.0.1
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/CHANGELOG.md +91 -0
- package/cjs/__chunks/VH7oDXx4.cjs +28 -0
- package/cjs/commands/aws/ec2/allow-ip/handler.cjs +261 -0
- package/cjs/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
- package/cjs/commands/aws/ec2/allow-ip/index.cjs +25 -0
- package/cjs/commands/aws/ec2/allow-ip/index.d.ts +3 -0
- package/cjs/commands/aws/ec2/allow-ip/schema.cjs +33 -0
- package/cjs/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
- package/cjs/commands/aws/ec2/allow-ip/utils.cjs +379 -0
- package/cjs/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
- package/cjs/commands/aws/iam/admin-group.cjs +111 -0
- package/cjs/commands/aws/iam/admin-group.d.ts +55 -0
- package/cjs/commands/aws/iam/break-glass/handler.cjs +127 -0
- package/cjs/commands/aws/iam/break-glass/handler.d.ts +7 -0
- package/cjs/commands/aws/iam/break-glass/index.cjs +7 -0
- package/cjs/commands/aws/iam/break-glass/index.d.ts +2 -0
- package/cjs/commands/aws/iam/break-glass/schema.cjs +21 -0
- package/cjs/commands/aws/iam/break-glass/schema.d.ts +25 -0
- package/cjs/commands/aws/iam/check-admin/handler.cjs +89 -0
- package/cjs/commands/aws/iam/check-admin/handler.d.ts +5 -0
- package/cjs/commands/aws/iam/check-admin/index.cjs +7 -0
- package/cjs/commands/aws/iam/check-admin/index.d.ts +2 -0
- package/cjs/commands/aws/iam/check-admin/schema.cjs +19 -0
- package/cjs/commands/aws/iam/check-admin/schema.d.ts +19 -0
- package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
- package/cjs/commands/aws/iam/policies/sts-federation.json +11 -0
- package/cjs/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
- package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
- package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
- package/cjs/commands/aws/iam/policies/user-admins-write-list.json +117 -0
- package/cjs/commands/aws/iam/remove-admin/handler.cjs +120 -0
- package/cjs/commands/aws/iam/remove-admin/handler.d.ts +6 -0
- package/cjs/commands/aws/iam/remove-admin/index.cjs +7 -0
- package/cjs/commands/aws/iam/remove-admin/index.d.ts +2 -0
- package/cjs/commands/aws/iam/remove-admin/schema.cjs +22 -0
- package/cjs/commands/aws/iam/remove-admin/schema.d.ts +28 -0
- package/cjs/commands/aws/iam/setup-acl/handler.cjs +227 -0
- package/cjs/commands/aws/iam/setup-acl/handler.d.ts +6 -0
- package/cjs/commands/aws/iam/setup-acl/index.cjs +13 -0
- package/cjs/commands/aws/iam/setup-acl/index.d.ts +3 -0
- package/cjs/commands/aws/iam/setup-acl/schema.cjs +19 -0
- package/cjs/commands/aws/iam/setup-acl/schema.d.ts +24 -0
- package/cjs/commands/aws/iam/setup-acl/utils.cjs +305 -0
- package/cjs/commands/aws/iam/setup-acl/utils.d.ts +61 -0
- package/cjs/commands/aws/iam/users/handler.cjs +59 -0
- package/cjs/commands/aws/iam/users/handler.d.ts +5 -0
- package/cjs/commands/aws/iam/users/index.cjs +18 -0
- package/cjs/commands/aws/iam/users/index.d.ts +3 -0
- package/cjs/commands/aws/iam/users/schema.cjs +17 -0
- package/cjs/commands/aws/iam/users/schema.d.ts +18 -0
- package/cjs/commands/aws/iam/users/utils.cjs +454 -0
- package/cjs/commands/aws/iam/users/utils.d.ts +119 -0
- package/cjs/commands/aws/index.cjs +223 -0
- package/cjs/commands/aws/index.d.ts +14 -0
- package/cjs/commands/aws/route53/add-record/handler.cjs +264 -0
- package/cjs/commands/aws/route53/add-record/handler.d.ts +36 -0
- package/cjs/commands/aws/route53/add-record/index.cjs +26 -0
- package/cjs/commands/aws/route53/add-record/index.d.ts +3 -0
- package/cjs/commands/aws/route53/add-record/schema.cjs +43 -0
- package/cjs/commands/aws/route53/add-record/schema.d.ts +45 -0
- package/cjs/commands/aws/route53/add-record/utils.cjs +404 -0
- package/cjs/commands/aws/route53/add-record/utils.d.ts +216 -0
- package/cjs/commands/aws/route53/remove-record/handler.cjs +114 -0
- package/cjs/commands/aws/route53/remove-record/handler.d.ts +6 -0
- package/cjs/commands/aws/route53/remove-record/index.cjs +5 -0
- package/cjs/commands/aws/route53/remove-record/index.d.ts +2 -0
- package/cjs/commands/aws/route53/remove-record/schema.cjs +22 -0
- package/cjs/commands/aws/route53/remove-record/schema.d.ts +30 -0
- package/cjs/commands/aws/schema.cjs +19 -0
- package/cjs/commands/aws/schema.d.ts +13 -0
- package/cjs/commands/aws/ses/send-email/handler.cjs +73 -0
- package/cjs/commands/aws/ses/send-email/handler.d.ts +5 -0
- package/cjs/commands/aws/ses/send-email/index.cjs +9 -0
- package/cjs/commands/aws/ses/send-email/index.d.ts +3 -0
- package/cjs/commands/aws/ses/send-email/schema.cjs +24 -0
- package/cjs/commands/aws/ses/send-email/schema.d.ts +39 -0
- package/cjs/commands/aws/ses/send-email/utils.cjs +87 -0
- package/cjs/commands/aws/ses/send-email/utils.d.ts +47 -0
- package/cjs/commands/aws/ses/smtp-password.cjs +72 -0
- package/cjs/commands/aws/ses/smtp-password.d.ts +21 -0
- package/cjs/commands/aws/utils/exec-aws.cjs +145 -0
- package/cjs/commands/aws/utils/exec-aws.d.ts +79 -0
- package/cjs/commands/aws/utils/resolve-policy-path.cjs +15 -0
- package/cjs/commands/aws/utils/resolve-policy-path.d.ts +8 -0
- package/cjs/commands/aws/utils/resolve-profile.cjs +93 -0
- package/cjs/commands/aws/utils/resolve-profile.d.ts +28 -0
- package/cjs/commands/aws/utils/tty.cjs +54 -0
- package/cjs/commands/aws/utils/tty.d.ts +24 -0
- package/cjs/commands/db/create-readonly-user/handler.cjs +254 -0
- package/cjs/commands/db/create-readonly-user/handler.d.ts +5 -0
- package/cjs/commands/db/create-readonly-user/index.cjs +18 -0
- package/cjs/commands/db/create-readonly-user/index.d.ts +3 -0
- package/cjs/commands/db/create-readonly-user/mysql.cjs +102 -0
- package/cjs/commands/db/create-readonly-user/mysql.d.ts +33 -0
- package/cjs/commands/db/create-readonly-user/postgres.cjs +209 -0
- package/cjs/commands/db/create-readonly-user/postgres.d.ts +31 -0
- package/cjs/commands/db/create-readonly-user/schema.cjs +39 -0
- package/cjs/commands/db/create-readonly-user/schema.d.ts +55 -0
- package/cjs/commands/db/create-readonly-user/utils.cjs +160 -0
- package/cjs/commands/db/create-readonly-user/utils.d.ts +112 -0
- package/cjs/commands/db/index.cjs +46 -0
- package/cjs/commands/db/index.d.ts +6 -0
- package/cjs/commands/doppler/handler.cjs +95 -9
- package/cjs/commands/doppler/index.cjs +33 -41
- package/cjs/commands/doppler/index.d.ts +1 -0
- package/cjs/commands/doppler/schema.cjs +130 -6
- package/cjs/commands/doppler/schema.d.ts +233 -17
- package/cjs/commands/doppler/set-secret.cjs +378 -0
- package/cjs/commands/doppler/set-secret.d.ts +113 -0
- package/cjs/commands/doppler/utils/exec.cjs +106 -12
- package/cjs/commands/doppler/utils.cjs +412 -30
- package/cjs/commands/doppler/utils.d.ts +32 -8
- package/cjs/commands/icons/handler.cjs +82 -8
- package/cjs/commands/icons/index.cjs +15 -31
- package/cjs/commands/icons/schema.cjs +101 -13
- package/cjs/commands/icons/schema.d.ts +1 -1
- package/cjs/commands/icons/utils.cjs +131 -13
- package/cjs/commands/index.cjs +54 -82
- package/cjs/commands/schema.cjs +25 -8
- package/cjs/index.cjs +3 -4
- package/esm/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
- package/esm/commands/aws/ec2/allow-ip/handler.js +258 -0
- package/esm/commands/aws/ec2/allow-ip/index.d.ts +3 -0
- package/esm/commands/aws/ec2/allow-ip/index.js +4 -0
- package/esm/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
- package/esm/commands/aws/ec2/allow-ip/schema.js +29 -0
- package/esm/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
- package/esm/commands/aws/ec2/allow-ip/utils.js +363 -0
- package/esm/commands/aws/iam/admin-group.d.ts +55 -0
- package/esm/commands/aws/iam/admin-group.js +104 -0
- package/esm/commands/aws/iam/break-glass/handler.d.ts +7 -0
- package/esm/commands/aws/iam/break-glass/handler.js +124 -0
- package/esm/commands/aws/iam/break-glass/index.d.ts +2 -0
- package/esm/commands/aws/iam/break-glass/index.js +4 -0
- package/esm/commands/aws/iam/break-glass/schema.d.ts +25 -0
- package/esm/commands/aws/iam/break-glass/schema.js +19 -0
- package/esm/commands/aws/iam/check-admin/handler.d.ts +5 -0
- package/esm/commands/aws/iam/check-admin/handler.js +86 -0
- package/esm/commands/aws/iam/check-admin/index.d.ts +2 -0
- package/esm/commands/aws/iam/check-admin/index.js +4 -0
- package/esm/commands/aws/iam/check-admin/schema.d.ts +19 -0
- package/esm/commands/aws/iam/check-admin/schema.js +17 -0
- package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
- package/esm/commands/aws/iam/policies/sts-federation.json +11 -0
- package/esm/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
- package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
- package/esm/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
- package/esm/commands/aws/iam/policies/user-admins-write-list.json +117 -0
- package/esm/commands/aws/iam/remove-admin/handler.d.ts +6 -0
- package/esm/commands/aws/iam/remove-admin/handler.js +117 -0
- package/esm/commands/aws/iam/remove-admin/index.d.ts +2 -0
- package/esm/commands/aws/iam/remove-admin/index.js +4 -0
- package/esm/commands/aws/iam/remove-admin/schema.d.ts +28 -0
- package/esm/commands/aws/iam/remove-admin/schema.js +20 -0
- package/esm/commands/aws/iam/setup-acl/handler.d.ts +6 -0
- package/esm/commands/aws/iam/setup-acl/handler.js +224 -0
- package/esm/commands/aws/iam/setup-acl/index.d.ts +3 -0
- package/esm/commands/aws/iam/setup-acl/index.js +4 -0
- package/esm/commands/aws/iam/setup-acl/schema.d.ts +24 -0
- package/esm/commands/aws/iam/setup-acl/schema.js +18 -0
- package/esm/commands/aws/iam/setup-acl/utils.d.ts +61 -0
- package/esm/commands/aws/iam/setup-acl/utils.js +298 -0
- package/esm/commands/aws/iam/users/handler.d.ts +5 -0
- package/esm/commands/aws/iam/users/handler.js +56 -0
- package/esm/commands/aws/iam/users/index.d.ts +3 -0
- package/esm/commands/aws/iam/users/index.js +4 -0
- package/esm/commands/aws/iam/users/schema.d.ts +18 -0
- package/esm/commands/aws/iam/users/schema.js +16 -0
- package/esm/commands/aws/iam/users/utils.d.ts +119 -0
- package/esm/commands/aws/iam/users/utils.js +440 -0
- package/esm/commands/aws/index.d.ts +14 -0
- package/esm/commands/aws/index.js +142 -0
- package/esm/commands/aws/route53/add-record/handler.d.ts +36 -0
- package/esm/commands/aws/route53/add-record/handler.js +258 -0
- package/esm/commands/aws/route53/add-record/index.d.ts +3 -0
- package/esm/commands/aws/route53/add-record/index.js +4 -0
- package/esm/commands/aws/route53/add-record/schema.d.ts +45 -0
- package/esm/commands/aws/route53/add-record/schema.js +40 -0
- package/esm/commands/aws/route53/add-record/utils.d.ts +216 -0
- package/esm/commands/aws/route53/add-record/utils.js +389 -0
- package/esm/commands/aws/route53/remove-record/handler.d.ts +6 -0
- package/esm/commands/aws/route53/remove-record/handler.js +111 -0
- package/esm/commands/aws/route53/remove-record/index.d.ts +2 -0
- package/esm/commands/aws/route53/remove-record/index.js +3 -0
- package/esm/commands/aws/route53/remove-record/schema.d.ts +30 -0
- package/esm/commands/aws/route53/remove-record/schema.js +21 -0
- package/esm/commands/aws/schema.d.ts +13 -0
- package/esm/commands/aws/schema.js +16 -0
- package/esm/commands/aws/ses/send-email/handler.d.ts +5 -0
- package/esm/commands/aws/ses/send-email/handler.js +70 -0
- package/esm/commands/aws/ses/send-email/index.d.ts +3 -0
- package/esm/commands/aws/ses/send-email/index.js +4 -0
- package/esm/commands/aws/ses/send-email/schema.d.ts +39 -0
- package/esm/commands/aws/ses/send-email/schema.js +23 -0
- package/esm/commands/aws/ses/send-email/utils.d.ts +47 -0
- package/esm/commands/aws/ses/send-email/utils.js +84 -0
- package/esm/commands/aws/ses/smtp-password.d.ts +21 -0
- package/esm/commands/aws/ses/smtp-password.js +69 -0
- package/esm/commands/aws/utils/exec-aws.d.ts +79 -0
- package/esm/commands/aws/utils/exec-aws.js +137 -0
- package/esm/commands/aws/utils/resolve-policy-path.d.ts +8 -0
- package/esm/commands/aws/utils/resolve-policy-path.js +14 -0
- package/esm/commands/aws/utils/resolve-profile.d.ts +28 -0
- package/esm/commands/aws/utils/resolve-profile.js +88 -0
- package/esm/commands/aws/utils/tty.d.ts +24 -0
- package/esm/commands/aws/utils/tty.js +51 -0
- package/esm/commands/db/create-readonly-user/handler.d.ts +5 -0
- package/esm/commands/db/create-readonly-user/handler.js +251 -0
- package/esm/commands/db/create-readonly-user/index.d.ts +3 -0
- package/esm/commands/db/create-readonly-user/index.js +4 -0
- package/esm/commands/db/create-readonly-user/mysql.d.ts +33 -0
- package/esm/commands/db/create-readonly-user/mysql.js +98 -0
- package/esm/commands/db/create-readonly-user/postgres.d.ts +31 -0
- package/esm/commands/db/create-readonly-user/postgres.js +205 -0
- package/esm/commands/db/create-readonly-user/schema.d.ts +55 -0
- package/esm/commands/db/create-readonly-user/schema.js +35 -0
- package/esm/commands/db/create-readonly-user/utils.d.ts +112 -0
- package/esm/commands/db/create-readonly-user/utils.js +151 -0
- package/esm/commands/db/index.d.ts +6 -0
- package/esm/commands/db/index.js +31 -0
- package/esm/commands/doppler/handler.js +92 -9
- package/esm/commands/doppler/index.d.ts +1 -0
- package/esm/commands/doppler/index.js +6 -41
- package/esm/commands/doppler/schema.d.ts +233 -17
- package/esm/commands/doppler/schema.js +125 -7
- package/esm/commands/doppler/set-secret.d.ts +113 -0
- package/esm/commands/doppler/set-secret.js +370 -0
- package/esm/commands/doppler/utils/exec.js +100 -12
- package/esm/commands/doppler/utils.d.ts +32 -8
- package/esm/commands/doppler/utils.js +396 -30
- package/esm/commands/icons/handler.js +79 -8
- package/esm/commands/icons/index.js +4 -31
- package/esm/commands/icons/schema.d.ts +1 -1
- package/esm/commands/icons/schema.js +97 -15
- package/esm/commands/icons/utils.js +125 -13
- package/esm/commands/index.js +49 -78
- package/esm/commands/schema.js +22 -7
- package/esm/index.js +3 -4
- package/package.json +12 -2
- package/vitest.config.ts +11 -0
- package/cjs/__chunks/4GFJUCSP.cjs +0 -52
- package/cjs/__chunks/4SFWHCB3.cjs +0 -133
- package/cjs/__chunks/B2KFW7T7.cjs +0 -1
- package/cjs/__chunks/EMMC33QA.cjs +0 -401
- package/cjs/__chunks/INFOPAHN.cjs +0 -117
- package/cjs/__chunks/J36P6UNE.cjs +0 -75
- package/cjs/__chunks/NIMXXHJQ.cjs +0 -92
- package/cjs/__chunks/NSRFG4DF.cjs +0 -100
- package/cjs/__chunks/WNJ3ZYLI.cjs +0 -1
- package/cjs/__chunks/ZMDIOZPT.cjs +0 -22
- package/esm/__chunks/46HGXFME.js +0 -0
- package/esm/__chunks/6G4PXXKF.js +0 -75
- package/esm/__chunks/6L5RNR7G.js +0 -100
- package/esm/__chunks/FL7AILGH.js +0 -133
- package/esm/__chunks/HJSXC6HP.js +0 -117
- package/esm/__chunks/O262GK4B.js +0 -401
- package/esm/__chunks/O3CCA76Q.js +0 -22
- package/esm/__chunks/SJXQJ7RS.js +0 -92
- package/esm/__chunks/SNCKIAOR.js +0 -0
- package/esm/__chunks/X3R5PSWH.js +0 -52
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { prompt, promptChoice, promptYesNo } from "../aws/utils/tty.js";
|
|
2
|
+
import { execDoppler } from "./utils.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
5
|
+
//#region src/commands/doppler/set-secret.js
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} DopplerProject
|
|
8
|
+
* @property {string} id
|
|
9
|
+
* @property {string} name
|
|
10
|
+
* @property {string} [description]
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} DopplerEnvironment
|
|
14
|
+
* @property {string} id
|
|
15
|
+
* @property {string} name
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} DopplerConfig
|
|
19
|
+
* @property {string} name
|
|
20
|
+
* @property {string} environment
|
|
21
|
+
* @property {boolean} [root]
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* List Doppler projects (paginated until exhausted or cap).
|
|
25
|
+
* @param {{ verbose?: boolean; limit?: number }} [params]
|
|
26
|
+
* @returns {DopplerProject[]}
|
|
27
|
+
*/
|
|
28
|
+
function listProjects(params = {}) {
|
|
29
|
+
const { verbose = false, limit = 500 } = params;
|
|
30
|
+
/** @type {DopplerProject[]} */
|
|
31
|
+
const projects = [];
|
|
32
|
+
let page = 1;
|
|
33
|
+
while (projects.length < limit) {
|
|
34
|
+
const batch = execDoppler([
|
|
35
|
+
"projects",
|
|
36
|
+
"--json",
|
|
37
|
+
"--page",
|
|
38
|
+
String(page),
|
|
39
|
+
"--number",
|
|
40
|
+
"100"
|
|
41
|
+
], "json", true, verbose);
|
|
42
|
+
if (!Array.isArray(batch) || batch.length === 0) break;
|
|
43
|
+
for (const raw of batch) projects.push({
|
|
44
|
+
id: String(raw.id ?? raw.name ?? ""),
|
|
45
|
+
name: String(raw.name ?? raw.id ?? ""),
|
|
46
|
+
description: raw.description ? String(raw.description) : ""
|
|
47
|
+
});
|
|
48
|
+
if (batch.length < 100) break;
|
|
49
|
+
page += 1;
|
|
50
|
+
}
|
|
51
|
+
return projects.filter((project) => project.name).sort((a, b) => a.name.localeCompare(b.name));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* List environments for a project.
|
|
55
|
+
* @param {{ project: string; verbose?: boolean }} params
|
|
56
|
+
* @returns {DopplerEnvironment[]}
|
|
57
|
+
*/
|
|
58
|
+
function listEnvironments(params) {
|
|
59
|
+
const { project, verbose = false } = params;
|
|
60
|
+
const data = execDoppler([
|
|
61
|
+
"environments",
|
|
62
|
+
"--json",
|
|
63
|
+
"--project",
|
|
64
|
+
project
|
|
65
|
+
], "json", true, verbose);
|
|
66
|
+
if (!Array.isArray(data)) return [];
|
|
67
|
+
return data.map((raw) => ({
|
|
68
|
+
id: String(raw.id ?? ""),
|
|
69
|
+
name: String(raw.name ?? raw.id ?? "")
|
|
70
|
+
})).filter((env) => env.id).sort((a, b) => a.id.localeCompare(b.id));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* List configs for a project, optionally filtered by environment.
|
|
74
|
+
* @param {{ project: string; environment?: string; verbose?: boolean }} params
|
|
75
|
+
* @returns {DopplerConfig[]}
|
|
76
|
+
*/
|
|
77
|
+
function listConfigs(params) {
|
|
78
|
+
const { project, environment, verbose = false } = params;
|
|
79
|
+
/** @type {string[]} */
|
|
80
|
+
const args = [
|
|
81
|
+
"configs",
|
|
82
|
+
"--json",
|
|
83
|
+
"--project",
|
|
84
|
+
project
|
|
85
|
+
];
|
|
86
|
+
if (environment) args.push("--environment", environment);
|
|
87
|
+
const data = execDoppler(args, "json", true, verbose);
|
|
88
|
+
if (!Array.isArray(data)) return [];
|
|
89
|
+
return data.map((raw) => ({
|
|
90
|
+
name: String(raw.name ?? ""),
|
|
91
|
+
environment: String(raw.environment ?? ""),
|
|
92
|
+
root: Boolean(raw.root)
|
|
93
|
+
})).filter((config) => config.name).sort((a, b) => a.name.localeCompare(b.name));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get an existing secret value (raw), or null if missing.
|
|
97
|
+
* @param {{
|
|
98
|
+
* project: string;
|
|
99
|
+
* config: string;
|
|
100
|
+
* name: string;
|
|
101
|
+
* verbose?: boolean;
|
|
102
|
+
* }} params
|
|
103
|
+
* @returns {string | null}
|
|
104
|
+
*/
|
|
105
|
+
function getSecret(params) {
|
|
106
|
+
const { project, config, name, verbose = false } = params;
|
|
107
|
+
try {
|
|
108
|
+
const data = execDoppler([
|
|
109
|
+
"secrets",
|
|
110
|
+
"get",
|
|
111
|
+
name,
|
|
112
|
+
"--project",
|
|
113
|
+
project,
|
|
114
|
+
"--config",
|
|
115
|
+
config,
|
|
116
|
+
"--plain",
|
|
117
|
+
"--raw"
|
|
118
|
+
], "string", true, verbose);
|
|
119
|
+
if (typeof data !== "string") return null;
|
|
120
|
+
const value = data.replace(/\n$/, "");
|
|
121
|
+
return value.length > 0 ? value : "";
|
|
122
|
+
} catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Set a secret via stdin so values need no shell escaping.
|
|
128
|
+
* @param {{
|
|
129
|
+
* project: string;
|
|
130
|
+
* config: string;
|
|
131
|
+
* name: string;
|
|
132
|
+
* value: string;
|
|
133
|
+
* verbose?: boolean;
|
|
134
|
+
* }} params
|
|
135
|
+
*/
|
|
136
|
+
function setSecret(params) {
|
|
137
|
+
const { project, config, name, value, verbose = false } = params;
|
|
138
|
+
const args = [
|
|
139
|
+
"secrets",
|
|
140
|
+
"set",
|
|
141
|
+
name,
|
|
142
|
+
"--project",
|
|
143
|
+
project,
|
|
144
|
+
"--config",
|
|
145
|
+
config,
|
|
146
|
+
"--no-interactive"
|
|
147
|
+
];
|
|
148
|
+
if (verbose) console.log(chalk.gray(` Executing: doppler ${args.join(" ")} <stdin value (${value.length} chars)>`));
|
|
149
|
+
const result = spawnSync("doppler", args, {
|
|
150
|
+
encoding: "utf-8",
|
|
151
|
+
input: value
|
|
152
|
+
});
|
|
153
|
+
if (result.error) throw new Error(result.error.message);
|
|
154
|
+
if (result.status !== 0) {
|
|
155
|
+
const stderr = (result.stderr || result.stdout || "").trim();
|
|
156
|
+
throw new Error(stderr || `doppler secrets set failed for ${name}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* @param {{ projects: DopplerProject[]; projectOption?: string }} params
|
|
161
|
+
* @returns {Promise<string>}
|
|
162
|
+
*/
|
|
163
|
+
async function resolveProject(params) {
|
|
164
|
+
const { projects, projectOption } = params;
|
|
165
|
+
if (projectOption) {
|
|
166
|
+
const match = projects.find((project) => project.name === projectOption || project.id === projectOption);
|
|
167
|
+
if (!match) throw new Error(`Project "${projectOption}" not found. Available examples: ${projects.slice(0, 8).map((project) => project.name).join(", ")}`);
|
|
168
|
+
return match.name;
|
|
169
|
+
}
|
|
170
|
+
if (projects.length === 0) throw new Error("No Doppler projects found for this account.");
|
|
171
|
+
let candidates = projects;
|
|
172
|
+
if (projects.length > 30) {
|
|
173
|
+
const filter = await prompt(` Filter projects (${projects.length} total, Enter for all): `);
|
|
174
|
+
if (filter) {
|
|
175
|
+
const lower = filter.toLowerCase();
|
|
176
|
+
candidates = projects.filter((project) => project.name.toLowerCase().includes(lower) || project.id.toLowerCase().includes(lower));
|
|
177
|
+
if (candidates.length === 0) throw new Error(`No projects matched "${filter}".`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const maxShown = 50;
|
|
181
|
+
const shown = candidates.slice(0, maxShown);
|
|
182
|
+
if (candidates.length > maxShown) console.log(chalk.yellow(` Showing first ${maxShown} of ${candidates.length} matches — refine with a filter next time.`));
|
|
183
|
+
const chosen = shown[await promptChoice({
|
|
184
|
+
message: "Choose a Doppler project:",
|
|
185
|
+
options: shown.map((project) => project.description ? `${project.name} — ${project.description}` : project.name)
|
|
186
|
+
})];
|
|
187
|
+
if (!chosen) throw new Error("No project selected");
|
|
188
|
+
return chosen.name;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* @param {{
|
|
192
|
+
* environments: DopplerEnvironment[];
|
|
193
|
+
* environmentOption?: string;
|
|
194
|
+
* }} params
|
|
195
|
+
* @returns {Promise<string | "all">}
|
|
196
|
+
*/
|
|
197
|
+
async function resolveEnvironment(params) {
|
|
198
|
+
const { environments, environmentOption } = params;
|
|
199
|
+
if (environmentOption) {
|
|
200
|
+
const normalized = environmentOption.trim().toLowerCase();
|
|
201
|
+
if (normalized === "all" || normalized === "*") return "all";
|
|
202
|
+
const match = environments.find((env) => env.id.toLowerCase() === normalized || env.name.toLowerCase() === normalized);
|
|
203
|
+
if (!match) throw new Error(`Environment "${environmentOption}" not found. Available: ${environments.map((env) => env.id).join(", ")}`);
|
|
204
|
+
return match.id;
|
|
205
|
+
}
|
|
206
|
+
if (environments.length === 0) return "all";
|
|
207
|
+
const options = [...environments.map((env) => `${env.id} (${env.name})`), "all environments"];
|
|
208
|
+
const index = await promptChoice({
|
|
209
|
+
message: "Choose an environment:",
|
|
210
|
+
options
|
|
211
|
+
});
|
|
212
|
+
if (index === options.length - 1) return "all";
|
|
213
|
+
const chosen = environments[index];
|
|
214
|
+
if (!chosen) throw new Error("No environment selected");
|
|
215
|
+
return chosen.id;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* @param {{
|
|
219
|
+
* configs: DopplerConfig[];
|
|
220
|
+
* configOption?: string;
|
|
221
|
+
* environment: string | "all";
|
|
222
|
+
* }} params
|
|
223
|
+
* @returns {Promise<string[]>}
|
|
224
|
+
*/
|
|
225
|
+
async function resolveConfigs(params) {
|
|
226
|
+
const { configs, configOption, environment } = params;
|
|
227
|
+
const scoped = environment === "all" ? configs : configs.filter((config) => config.environment === environment);
|
|
228
|
+
if (scoped.length === 0) throw new Error(environment === "all" ? "No configs found in this project." : `No configs found for environment "${environment}".`);
|
|
229
|
+
if (configOption) {
|
|
230
|
+
const normalized = configOption.trim().toLowerCase();
|
|
231
|
+
if (normalized === "all" || normalized === "*") return scoped.map((config) => config.name);
|
|
232
|
+
const requested = configOption.split(",").map((value) => value.trim());
|
|
233
|
+
const names = new Set(scoped.map((config) => config.name));
|
|
234
|
+
const missing = requested.filter((name) => !names.has(name));
|
|
235
|
+
if (missing.length > 0) throw new Error(`Config(s) not found: ${missing.join(", ")}. Available: ${[...names].join(", ")}`);
|
|
236
|
+
return requested;
|
|
237
|
+
}
|
|
238
|
+
if (scoped.length === 1) {
|
|
239
|
+
const only = scoped[0];
|
|
240
|
+
if (!only) throw new Error("No config selected");
|
|
241
|
+
console.log(` Config: ${only.name}`);
|
|
242
|
+
return [only.name];
|
|
243
|
+
}
|
|
244
|
+
const options = [...scoped.map((config) => config.root ? `${config.name} (root, env: ${config.environment})` : `${config.name} (env: ${config.environment})`), `all configs listed (${scoped.length})`];
|
|
245
|
+
const index = await promptChoice({
|
|
246
|
+
message: "Choose a config:",
|
|
247
|
+
options
|
|
248
|
+
});
|
|
249
|
+
if (index === options.length - 1) return scoped.map((config) => config.name);
|
|
250
|
+
const chosen = scoped[index];
|
|
251
|
+
if (!chosen) throw new Error("No config selected");
|
|
252
|
+
return [chosen.name];
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* @param {string | undefined} nameOption
|
|
256
|
+
* @returns {Promise<string>}
|
|
257
|
+
*/
|
|
258
|
+
async function resolveSecretName(nameOption) {
|
|
259
|
+
if (nameOption) return nameOption;
|
|
260
|
+
const raw = await prompt(" Secret name (e.g. DATABASE_URL): ");
|
|
261
|
+
if (!raw) throw new Error("Secret name is required");
|
|
262
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(raw)) throw new Error("Secret name must be a valid env var identifier (letters, numbers, underscore)");
|
|
263
|
+
return raw;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* @param {string | undefined} valueOption
|
|
267
|
+
* @returns {Promise<string>}
|
|
268
|
+
*/
|
|
269
|
+
async function resolveSecretValue(valueOption) {
|
|
270
|
+
if (valueOption !== void 0) return valueOption;
|
|
271
|
+
const raw = await prompt(" Secret value: ");
|
|
272
|
+
if (raw === "") {
|
|
273
|
+
if (!await promptYesNo({
|
|
274
|
+
message: " Set an empty value?",
|
|
275
|
+
defaultYes: false
|
|
276
|
+
})) throw new Error("Secret value is required");
|
|
277
|
+
}
|
|
278
|
+
return raw;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Interactively (or via flags) set a Doppler secret on one or more configs.
|
|
282
|
+
* @param {{
|
|
283
|
+
* project?: string;
|
|
284
|
+
* environment?: string;
|
|
285
|
+
* config?: string;
|
|
286
|
+
* name?: string;
|
|
287
|
+
* value?: string;
|
|
288
|
+
* yes?: boolean;
|
|
289
|
+
* verbose?: boolean;
|
|
290
|
+
* }} options
|
|
291
|
+
*/
|
|
292
|
+
async function setSecretInteractive(options) {
|
|
293
|
+
const { project: projectOption, environment: environmentOption, config: configOption, name: nameOption, value: valueOption, yes = false, verbose = false } = options;
|
|
294
|
+
console.log(chalk.blue("\nSet Doppler secret"));
|
|
295
|
+
console.log("");
|
|
296
|
+
const project = await resolveProject({
|
|
297
|
+
projects: listProjects({ verbose }),
|
|
298
|
+
projectOption
|
|
299
|
+
});
|
|
300
|
+
console.log(`Project: ${project}`);
|
|
301
|
+
console.log("");
|
|
302
|
+
const environment = await resolveEnvironment({
|
|
303
|
+
environments: listEnvironments({
|
|
304
|
+
project,
|
|
305
|
+
verbose
|
|
306
|
+
}),
|
|
307
|
+
environmentOption
|
|
308
|
+
});
|
|
309
|
+
console.log(environment === "all" ? "Environment: all" : `Environment: ${environment}`);
|
|
310
|
+
console.log("");
|
|
311
|
+
const targetConfigs = await resolveConfigs({
|
|
312
|
+
configs: listConfigs({
|
|
313
|
+
project,
|
|
314
|
+
environment: environment === "all" ? void 0 : environment,
|
|
315
|
+
verbose
|
|
316
|
+
}),
|
|
317
|
+
configOption,
|
|
318
|
+
environment
|
|
319
|
+
});
|
|
320
|
+
console.log(`Config(s): ${targetConfigs.join(", ")}`);
|
|
321
|
+
console.log("");
|
|
322
|
+
const name = await resolveSecretName(nameOption);
|
|
323
|
+
const value = await resolveSecretValue(valueOption);
|
|
324
|
+
/** @type {{ config: string; existing: string | null }[]} */
|
|
325
|
+
const existingByConfig = [];
|
|
326
|
+
for (const config of targetConfigs) {
|
|
327
|
+
const existing = getSecret({
|
|
328
|
+
project,
|
|
329
|
+
config,
|
|
330
|
+
name,
|
|
331
|
+
verbose
|
|
332
|
+
});
|
|
333
|
+
existingByConfig.push({
|
|
334
|
+
config,
|
|
335
|
+
existing
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
const overwrites = existingByConfig.filter((entry) => entry.existing !== null);
|
|
339
|
+
console.log("");
|
|
340
|
+
console.log("Plan:");
|
|
341
|
+
console.log(` Project: ${project}`);
|
|
342
|
+
console.log(` Configs: ${targetConfigs.join(", ")}`);
|
|
343
|
+
console.log(` Name: ${name}`);
|
|
344
|
+
console.log(` Value: ${value.length === 0 ? "(empty)" : `(${value.length} chars)`}`);
|
|
345
|
+
if (overwrites.length > 0) console.log(chalk.yellow(` Overwrite: ${overwrites.length} config(s) already have this secret (${overwrites.map((entry) => entry.config).join(", ")})`));
|
|
346
|
+
else console.log(chalk.green(" Overwrite: none (new secret on all targets)"));
|
|
347
|
+
console.log("");
|
|
348
|
+
if (!yes) {
|
|
349
|
+
if (!await promptYesNo({
|
|
350
|
+
message: overwrites.length > 0 ? "Overwrite / set this secret?" : "Set this secret?",
|
|
351
|
+
defaultYes: false
|
|
352
|
+
})) {
|
|
353
|
+
console.log("Aborted.");
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
console.log("");
|
|
357
|
+
}
|
|
358
|
+
for (const config of targetConfigs) {
|
|
359
|
+
setSecret({
|
|
360
|
+
project,
|
|
361
|
+
config,
|
|
362
|
+
name,
|
|
363
|
+
value,
|
|
364
|
+
verbose
|
|
365
|
+
});
|
|
366
|
+
console.log(chalk.green(` ✓ set ${name} on ${project}/${config}`));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
export { getSecret, listConfigs, listEnvironments, listProjects, setSecret, setSecretInteractive };
|
|
@@ -1,12 +1,100 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
//#region src/commands/doppler/utils/exec.js
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {'silent' | 'verbose' | 'default'} VerbosityLevel
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} ExecOptions
|
|
9
|
+
* @property {'string' | 'number' | 'json'} [stdoutParser='string'] - How to parse stdout
|
|
10
|
+
* @property {boolean} [throwOnError=true] - Whether to throw on error
|
|
11
|
+
* @property {VerbosityLevel} [verbosity='default'] - Output verbosity level
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Execute a command and parse the output
|
|
15
|
+
* @param {string} command - Command to execute
|
|
16
|
+
* @param {import('child_process').ExecSyncOptions & ExecOptions} [options={}] - Execution options (inherits all execSync options + custom options)
|
|
17
|
+
* @returns {string | number | any} - Parsed output based on stdoutParser
|
|
18
|
+
*/
|
|
19
|
+
function exec(command, options = {}) {
|
|
20
|
+
const { stdoutParser = "string", throwOnError = true, verbosity = "default", stdio: userStdio, ...execSyncOptions } = options;
|
|
21
|
+
try {
|
|
22
|
+
if (verbosity === "verbose") console.log(chalk.gray(` Executing: ${command}`));
|
|
23
|
+
/** @type {import('child_process').StdioOptions} */
|
|
24
|
+
let stdio;
|
|
25
|
+
if (userStdio) stdio = userStdio;
|
|
26
|
+
else if (verbosity === "verbose") stdio = "inherit";
|
|
27
|
+
else if (verbosity === "silent") stdio = "pipe";
|
|
28
|
+
else stdio = [
|
|
29
|
+
"pipe",
|
|
30
|
+
"pipe",
|
|
31
|
+
"pipe"
|
|
32
|
+
];
|
|
33
|
+
const result = execSync(command, {
|
|
34
|
+
encoding: "utf-8",
|
|
35
|
+
stdio,
|
|
36
|
+
...execSyncOptions
|
|
37
|
+
});
|
|
38
|
+
if (stdio === "inherit") return stdoutParser === "string" ? "" : void 0;
|
|
39
|
+
if (!result || typeof result === "string" && !result.trim()) return stdoutParser === "string" ? "" : void 0;
|
|
40
|
+
switch (stdoutParser) {
|
|
41
|
+
case "json": try {
|
|
42
|
+
return JSON.parse(result);
|
|
43
|
+
} catch (parseError) {
|
|
44
|
+
if (throwOnError) throw new Error(`Failed to parse JSON output: ${parseError.message}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
case "number": {
|
|
48
|
+
const num = parseFloat(result.trim());
|
|
49
|
+
if (isNaN(num)) {
|
|
50
|
+
if (throwOnError) throw new Error(`Failed to parse number from output: ${result}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
return num;
|
|
54
|
+
}
|
|
55
|
+
default: return result;
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (!throwOnError) return;
|
|
59
|
+
if (error.stderr) throw new Error(error.stderr.toString());
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Execute a command with string output
|
|
65
|
+
* @param {string} command - Command to execute
|
|
66
|
+
* @param {import('child_process').ExecSyncOptions & ExecOptions} [options] - Execution options
|
|
67
|
+
* @returns {string}
|
|
68
|
+
*/
|
|
69
|
+
function execString(command, options = {}) {
|
|
70
|
+
return exec(command, {
|
|
71
|
+
...options,
|
|
72
|
+
stdoutParser: "string"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Execute a command with JSON output
|
|
77
|
+
* @param {string} command - Command to execute
|
|
78
|
+
* @param {import('child_process').ExecSyncOptions & ExecOptions} [options] - Execution options
|
|
79
|
+
* @returns {any}
|
|
80
|
+
*/
|
|
81
|
+
function execJson(command, options = {}) {
|
|
82
|
+
return exec(command, {
|
|
83
|
+
...options,
|
|
84
|
+
stdoutParser: "json"
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Execute a command with number output
|
|
89
|
+
* @param {string} command - Command to execute
|
|
90
|
+
* @param {import('child_process').ExecSyncOptions & ExecOptions} [options] - Execution options
|
|
91
|
+
* @returns {number}
|
|
92
|
+
*/
|
|
93
|
+
function execNumber(command, options = {}) {
|
|
94
|
+
return exec(command, {
|
|
95
|
+
...options,
|
|
96
|
+
stdoutParser: "number"
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { exec, execJson, execNumber, execString };
|
|
@@ -8,17 +8,24 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export function execDoppler(args: string[], parser?: "string" | "json", silent?: boolean, verbose?: boolean): string | any;
|
|
10
10
|
/**
|
|
11
|
-
* Check if
|
|
11
|
+
* Check if the Doppler CLI is installed and the user is logged in.
|
|
12
|
+
* Does not require a local project setup (doppler setup).
|
|
13
|
+
* @param {boolean} verbose - Show verbose output
|
|
14
|
+
*/
|
|
15
|
+
export function checkDopplerAuth(verbose?: boolean): void;
|
|
16
|
+
/**
|
|
17
|
+
* Check if doppler CLI is installed, logged in, and a project is configured.
|
|
12
18
|
* @param {boolean} verbose - Show verbose output
|
|
13
19
|
*/
|
|
14
20
|
export function checkDependencies(verbose?: boolean): void;
|
|
15
21
|
/**
|
|
16
|
-
* Get list of configurations based on
|
|
17
|
-
* @param {string}
|
|
22
|
+
* Get list of configurations based on environments parameter
|
|
23
|
+
* @param {string} environments - Comma-separated env names ('all', 'dev', 'dev,stg', etc.)
|
|
18
24
|
* @param {boolean} verbose - Show verbose output
|
|
25
|
+
* @param {string | null} project - Optional Doppler project name
|
|
19
26
|
* @returns {string[]}
|
|
20
27
|
*/
|
|
21
|
-
export function getConfigs(
|
|
28
|
+
export function getConfigs(environments: string, verbose?: boolean, project?: string | null): string[];
|
|
22
29
|
/**
|
|
23
30
|
* Normalize escape sequences in file content
|
|
24
31
|
* @param {string} content - File content
|
|
@@ -42,22 +49,39 @@ export function promptConfirmation(message: string): Promise<boolean>;
|
|
|
42
49
|
* Download configurations from Doppler
|
|
43
50
|
* @param {{
|
|
44
51
|
* verbose: boolean;
|
|
45
|
-
*
|
|
52
|
+
* environments: string;
|
|
46
53
|
* }} options - Options for downloading configurations
|
|
47
54
|
*/
|
|
48
55
|
export function downloadConfigs(options: {
|
|
49
56
|
verbose: boolean;
|
|
50
|
-
|
|
57
|
+
environments: string;
|
|
51
58
|
}): Promise<void>;
|
|
52
59
|
/**
|
|
53
60
|
* Upload configurations to Doppler
|
|
54
61
|
* @param {{
|
|
55
|
-
*
|
|
62
|
+
* environments: string;
|
|
56
63
|
* verbose: boolean;
|
|
57
64
|
* }} options - Options for uploading configurations
|
|
58
65
|
*/
|
|
59
66
|
export function uploadConfigs(options: {
|
|
60
|
-
|
|
67
|
+
environments: string;
|
|
68
|
+
verbose: boolean;
|
|
69
|
+
}): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Clone secrets from one Doppler project to another
|
|
72
|
+
* @param {{
|
|
73
|
+
* from: string;
|
|
74
|
+
* to: string;
|
|
75
|
+
* environments: string;
|
|
76
|
+
* force: boolean;
|
|
77
|
+
* verbose: boolean;
|
|
78
|
+
* }} options
|
|
79
|
+
*/
|
|
80
|
+
export function cloneProject({ from, to, environments, force, verbose }: {
|
|
81
|
+
from: string;
|
|
82
|
+
to: string;
|
|
83
|
+
environments: string;
|
|
84
|
+
force: boolean;
|
|
61
85
|
verbose: boolean;
|
|
62
86
|
}): Promise<void>;
|
|
63
87
|
export type VerbosityLevel = import("./utils/exec.js").VerbosityLevel;
|