@catladder/cli 0.0.0-next-aea5d3ad → 0.0.0-next-2b60440e
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/bundles/cli/index.js +705 -229
- package/dist/bundles/runner-images/semantic-release/Dockerfile +15 -12
- package/dist/bundles/runner-images/semantic-release/scripts/semanticRelease +10 -1
- package/dist/bundles/skills/catladder-cli/references/commands.md +37 -2
- package/dist/bundles/skills/catladder-secrets/SKILL.md +42 -9
- package/dist/cli/src/commands/index.d.ts +4 -0
- package/dist/cli/src/commands/index.js +9 -1
- package/dist/cli/src/commands/index.js.map +1 -1
- package/dist/cli/src/commands/project/commandConfigSecrets.d.ts +6 -1
- package/dist/cli/src/commands/project/commandConfigSecrets.js +56 -15
- package/dist/cli/src/commands/project/commandConfigSecrets.js.map +1 -1
- package/dist/cli/src/commands/project/secrets/commandSecretsList.d.ts +24 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsList.js +64 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsList.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPull.d.ts +19 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPull.js +48 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPull.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPush.d.ts +19 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPush.js +74 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPush.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsSet.d.ts +24 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsSet.js +82 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsSet.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/document.d.ts +47 -0
- package/dist/cli/src/commands/project/secrets/document.js +180 -0
- package/dist/cli/src/commands/project/secrets/document.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/parseKeysInput.d.ts +2 -0
- package/dist/cli/src/commands/project/secrets/parseKeysInput.js +10 -0
- package/dist/cli/src/commands/project/secrets/parseKeysInput.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/scope.d.ts +35 -0
- package/dist/cli/src/commands/project/secrets/scope.js +113 -0
- package/dist/cli/src/commands/project/secrets/scope.js.map +1 -0
- package/dist/cli/src/utils/readStdin.d.ts +2 -0
- package/dist/cli/src/utils/readStdin.js +13 -0
- package/dist/cli/src/utils/readStdin.js.map +1 -0
- package/dist/runner-images/semantic-release/Dockerfile +15 -12
- package/dist/runner-images/semantic-release/scripts/semanticRelease +10 -1
- package/dist/skills/catladder-cli/references/commands.md +37 -2
- package/dist/skills/catladder-secrets/SKILL.md +42 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/commands/index.ts +4 -0
- package/src/commands/project/commandConfigSecrets.ts +76 -15
- package/src/commands/project/secrets/__tests__/document.test.ts +122 -0
- package/src/commands/project/secrets/commandSecretsList.ts +75 -0
- package/src/commands/project/secrets/commandSecretsPull.ts +55 -0
- package/src/commands/project/secrets/commandSecretsPush.ts +100 -0
- package/src/commands/project/secrets/commandSecretsSet.ts +102 -0
- package/src/commands/project/secrets/document.ts +269 -0
- package/src/commands/project/secrets/parseKeysInput.ts +8 -0
- package/src/commands/project/secrets/scope.ts +151 -0
- package/src/utils/readStdin.ts +8 -0
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.d.ts +0 -2
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js +0 -206
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js.map +0 -1
- package/src/apps/cli/commands/project/commandConfigSecrets.ts +0 -322
|
@@ -357,219 +357,6 @@ exports.getProjectMongodbAllPodsSortedWithLabel = getProjectMongodbAllPodsSorted
|
|
|
357
357
|
|
|
358
358
|
/***/ }),
|
|
359
359
|
|
|
360
|
-
/***/ 58002:
|
|
361
|
-
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
362
|
-
|
|
363
|
-
"use strict";
|
|
364
|
-
|
|
365
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
366
|
-
exports.projectConfigSecrets = void 0;
|
|
367
|
-
const pipeline_1 = __nccwpck_require__(60241);
|
|
368
|
-
const common_tags_1 = __nccwpck_require__(63779);
|
|
369
|
-
const lodash_es_1 = __nccwpck_require__(64284);
|
|
370
|
-
const getProjectConfig_1 = __nccwpck_require__(50001);
|
|
371
|
-
const commandSecretsSyncGithub_1 = __nccwpck_require__(50962);
|
|
372
|
-
const editAsFile_1 = __nccwpck_require__(82805);
|
|
373
|
-
const github_1 = __nccwpck_require__(18036);
|
|
374
|
-
const gitlab_1 = __nccwpck_require__(4508);
|
|
375
|
-
const promise_1 = __nccwpck_require__(51762);
|
|
376
|
-
/* for convenience, parse json objects. that makes it easier to edit secrets that are object */
|
|
377
|
-
const resolveJson = (v) => Object.fromEntries(Object.entries(v).map(([componentName, envs]) => {
|
|
378
|
-
return [
|
|
379
|
-
componentName,
|
|
380
|
-
Object.fromEntries(Object.entries(envs).map(([env, secrets]) => [
|
|
381
|
-
env,
|
|
382
|
-
Object.fromEntries(Object.entries(secrets).map(([key, value]) => {
|
|
383
|
-
try {
|
|
384
|
-
return [key, JSON.parse(value)];
|
|
385
|
-
}
|
|
386
|
-
catch (e) {
|
|
387
|
-
return [key, value];
|
|
388
|
-
}
|
|
389
|
-
})),
|
|
390
|
-
])),
|
|
391
|
-
];
|
|
392
|
-
}));
|
|
393
|
-
const getSecretEnvVarKeysToConfigure = async (env, componentName) => {
|
|
394
|
-
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
395
|
-
return [
|
|
396
|
-
...jobOnlyVars.build.secretEnvVarKeys,
|
|
397
|
-
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
398
|
-
...secretEnvVarKeys,
|
|
399
|
-
]
|
|
400
|
-
.filter((k) => !k.hidden)
|
|
401
|
-
.map((k) => k.key);
|
|
402
|
-
};
|
|
403
|
-
const getEnvVarsToEdit = async (instance, env, componentName) => {
|
|
404
|
-
const secretEnvVarKeys = await getSecretEnvVarKeysToConfigure(env, componentName);
|
|
405
|
-
const normalEnvVars = await (0, getProjectConfig_1.getEnvVarsResolved)(instance, env, componentName);
|
|
406
|
-
const jobOnlyEnvVars = await (0, getProjectConfig_1.getJobOnlyEnvVarsResolved)(instance, env, componentName);
|
|
407
|
-
const allEnvVars = {
|
|
408
|
-
...normalEnvVars,
|
|
409
|
-
...jobOnlyEnvVars,
|
|
410
|
-
};
|
|
411
|
-
return Object.fromEntries(secretEnvVarKeys.map((key) => {
|
|
412
|
-
const value = allEnvVars[key];
|
|
413
|
-
// due to some quirky way to resolve these variables, unset variables have the $CL_ prefix, so we remove thouse here
|
|
414
|
-
const variableIsNotSet = value === "$" + (0, pipeline_1.getSecretVarName)(env, componentName, key);
|
|
415
|
-
return [key, variableIsNotSet ? "🚨 FILL ME" : value];
|
|
416
|
-
}));
|
|
417
|
-
};
|
|
418
|
-
const doItFor = async (instance, envAndComponents) => {
|
|
419
|
-
let valuesToEdit = Object.fromEntries(await Promise.all(Object.entries(envAndComponents).map(async ([componentName, envs]) => [
|
|
420
|
-
componentName,
|
|
421
|
-
Object.fromEntries(await Promise.all(envs.map(async (env) => [
|
|
422
|
-
env,
|
|
423
|
-
await getEnvVarsToEdit(instance, env, componentName),
|
|
424
|
-
]))),
|
|
425
|
-
])));
|
|
426
|
-
let hasErrors = true;
|
|
427
|
-
while (hasErrors) {
|
|
428
|
-
valuesToEdit = await (0, editAsFile_1.editAsFile)(resolveJson(valuesToEdit), (0, common_tags_1.stripIndents) `
|
|
429
|
-
Please fill in all secrets for:
|
|
430
|
-
|
|
431
|
-
${Object.entries(envAndComponents)
|
|
432
|
-
.map(([componentName, envs]) => `- ${componentName}: ${envs.join(", ")}`)
|
|
433
|
-
.join("\n")}
|
|
434
|
-
|
|
435
|
-
`);
|
|
436
|
-
// check for errors
|
|
437
|
-
hasErrors = false;
|
|
438
|
-
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
439
|
-
for (const env of envs) {
|
|
440
|
-
const usedKeys = valuesToEdit[componentName][env]
|
|
441
|
-
? Object.keys(valuesToEdit[componentName][env])
|
|
442
|
-
: [];
|
|
443
|
-
// check whether newValues have the exact number of keys
|
|
444
|
-
const secretEnvVarKeys = await getSecretEnvVarKeysToConfigure(env, componentName);
|
|
445
|
-
const extranous = (0, lodash_es_1.difference)(usedKeys, secretEnvVarKeys);
|
|
446
|
-
const missing = (0, lodash_es_1.difference)(secretEnvVarKeys, usedKeys);
|
|
447
|
-
if (extranous.length > 0 || missing.length > 0) {
|
|
448
|
-
instance.log("");
|
|
449
|
-
instance.log(`😿 Oh no! There is something wrong with "${componentName}"`);
|
|
450
|
-
instance.log("");
|
|
451
|
-
if (extranous.length > 0) {
|
|
452
|
-
instance.log("these secrets are not declared in the config");
|
|
453
|
-
extranous.forEach((key) => instance.log(key));
|
|
454
|
-
instance.log("");
|
|
455
|
-
}
|
|
456
|
-
if (missing.length > 0) {
|
|
457
|
-
instance.log("these secrets have not been provided:");
|
|
458
|
-
missing.forEach((key) => instance.log(key));
|
|
459
|
-
instance.log("");
|
|
460
|
-
}
|
|
461
|
-
await (0, promise_1.delay)(1000);
|
|
462
|
-
const shouldContinue = await instance.confirm("Try again? 🤔");
|
|
463
|
-
if (!shouldContinue) {
|
|
464
|
-
throw new Error("abort");
|
|
465
|
-
}
|
|
466
|
-
hasErrors = true;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
472
|
-
if (!config) {
|
|
473
|
-
throw new Error("no catladder config found");
|
|
474
|
-
}
|
|
475
|
-
instance.log("");
|
|
476
|
-
instance.log("writing all secrets to the vault, please wait...");
|
|
477
|
-
instance.log("");
|
|
478
|
-
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
479
|
-
for (const env of envs) {
|
|
480
|
-
instance.log("writing " + env + ":" + componentName + "...\n");
|
|
481
|
-
await (await instance.getVaultManager()).writeSecrets(env, componentName, valuesToEdit[componentName][env]);
|
|
482
|
-
instance.log("");
|
|
483
|
-
instance.log("✅ " + env + ":" + componentName);
|
|
484
|
-
instance.log("--------------------------------\n");
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
await mirrorSecretsToCiBackends(instance, config, envAndComponents, valuesToEdit);
|
|
488
|
-
instance.log("done! 😻");
|
|
489
|
-
instance.log("");
|
|
490
|
-
};
|
|
491
|
-
/**
|
|
492
|
-
* the vault is the source of truth; every enabled CI backend receives
|
|
493
|
-
* a mirrored copy of the edited secrets (gitlab variables, github
|
|
494
|
-
* secrets), so all CI systems stay in sync
|
|
495
|
-
*/
|
|
496
|
-
const mirrorSecretsToCiBackends = async (instance, config, envAndComponents, valuesToEdit) => {
|
|
497
|
-
const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
|
|
498
|
-
// gitlab mirror (unless gitlab is the vault itself, then it is
|
|
499
|
-
// already written)
|
|
500
|
-
if ((0, pipeline_1.getVaultConfig)(config).type !== "gitlab" && enabled.includes("gitlab")) {
|
|
501
|
-
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
502
|
-
for (const env of envs) {
|
|
503
|
-
await (0, gitlab_1.upsertAllVariables)(instance, valuesToEdit[componentName][env], env, componentName);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
instance.log("✅ mirrored to gitlab");
|
|
507
|
-
}
|
|
508
|
-
if (!enabled.includes("github")) {
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const kinds = new Map();
|
|
512
|
-
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
513
|
-
for (const env of envs) {
|
|
514
|
-
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
515
|
-
[
|
|
516
|
-
...secretEnvVarKeys,
|
|
517
|
-
...jobOnlyVars.build.secretEnvVarKeys,
|
|
518
|
-
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
519
|
-
].forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
const secrets = Object.entries(envAndComponents).flatMap(([componentName, envs]) => envs.flatMap((env) => {
|
|
523
|
-
var _a;
|
|
524
|
-
return Object.entries((_a = valuesToEdit[componentName][env]) !== null && _a !== void 0 ? _a : {}).map(([key, value]) => {
|
|
525
|
-
var _a;
|
|
526
|
-
const name = (0, pipeline_1.getSecretVarName)(env, componentName, key);
|
|
527
|
-
return {
|
|
528
|
-
name,
|
|
529
|
-
value: typeof value === "string" ? value : JSON.stringify(value !== null && value !== void 0 ? value : ""),
|
|
530
|
-
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
|
|
531
|
-
};
|
|
532
|
-
});
|
|
533
|
-
}));
|
|
534
|
-
if (secrets.length === 0) {
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
538
|
-
instance.log("⚠️ github pipeline is enabled, but the github cli (gh) is not authenticated — run `project secrets-sync-github` later to mirror the secrets");
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
const repo = await (0, commandSecretsSyncGithub_1.getConfiguredGithubRepo)();
|
|
542
|
-
if (!repo) {
|
|
543
|
-
instance.log("⚠️ github pipeline is enabled, but no github repository was found — run `project secrets-sync-github` later to mirror the secrets");
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
instance.log(`mirroring ${secrets.length} secrets to github ('${repo}')...`);
|
|
547
|
-
await (0, commandSecretsSyncGithub_1.pushSecretsToGithub)(instance, repo, secrets, await (0, commandSecretsSyncGithub_1.collectSecretTargets)(config));
|
|
548
|
-
};
|
|
549
|
-
const projectConfigSecrets = async (io, envComponent) => {
|
|
550
|
-
if (!envComponent) {
|
|
551
|
-
const allEnvAndcomponents = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
552
|
-
await doItFor(io, allEnvAndcomponents);
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
const { env, componentName } = (0, getProjectConfig_1.parseChoice)(envComponent);
|
|
556
|
-
// componentName can be null. in this case, iterate over all components
|
|
557
|
-
if (!componentName) {
|
|
558
|
-
const components = await (0, getProjectConfig_1.getProjectComponents)();
|
|
559
|
-
await doItFor(io, Object.fromEntries(components.map((c) => [c, [env]])));
|
|
560
|
-
}
|
|
561
|
-
if (componentName) {
|
|
562
|
-
await doItFor(io, {
|
|
563
|
-
[componentName]: [env],
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
};
|
|
568
|
-
exports.projectConfigSecrets = projectConfigSecrets;
|
|
569
|
-
//# sourceMappingURL=commandConfigSecrets.js.map
|
|
570
|
-
|
|
571
|
-
/***/ }),
|
|
572
|
-
|
|
573
360
|
/***/ 88089:
|
|
574
361
|
/***/ ((__unused_webpack_module, exports) => {
|
|
575
362
|
|
|
@@ -2533,7 +2320,7 @@ exports.commandKubeStopPortforward = (0, defineCommand_1.defineCommand)({
|
|
|
2533
2320
|
"use strict";
|
|
2534
2321
|
|
|
2535
2322
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2536
|
-
exports.commandStarwars = exports.commandDadjoke = exports.commandSecurityAuditCreate = exports.commandSecurityAuditEvaluate = exports.commandSecurityAuditCiJob = exports.commandRestoreDb = exports.commandMongoDestroyMember = exports.commandMongoPortForward = exports.commandMongoGetShell = exports.commandTriggerCronjobProject = exports.commandDeleteProject = exports.commandPauseProject = exports.commandDeletePods = exports.commandGetShell = exports.commandListPods = exports.commandNamespace = exports.commandSecurityEvaluate = exports.commandProjectRestoreDb = exports.commandCiJobLog = exports.commandCiJobOpen = exports.commandDoctor = exports.commandSetup = exports.commandGetMyTotalWorktime = exports.commandRenewToken = exports.commandTriggerCronjobGeneral = exports.commandOpenLogs = exports.commandSecretsSyncGithub = exports.commandSecretsClearBackups = exports.commandConfigSecrets = exports.commandCloudSqlProxy = exports.commandOpenGit = exports.commandOpenEnv = exports.commandPortForward = exports.commandEnvVars = exports.commandKubePortForward = exports.commandKubeGetShell = exports.commandKubeStopPortforward = exports.commandKubeListPods = exports.commandKubeListSecrets = exports.commandKubeListNamespaces = exports.commandKubeCurrentContext = void 0;
|
|
2323
|
+
exports.commandStarwars = exports.commandDadjoke = exports.commandSecurityAuditCreate = exports.commandSecurityAuditEvaluate = exports.commandSecurityAuditCiJob = exports.commandRestoreDb = exports.commandMongoDestroyMember = exports.commandMongoPortForward = exports.commandMongoGetShell = exports.commandTriggerCronjobProject = exports.commandDeleteProject = exports.commandPauseProject = exports.commandDeletePods = exports.commandGetShell = exports.commandListPods = exports.commandNamespace = exports.commandSecurityEvaluate = exports.commandProjectRestoreDb = exports.commandCiJobLog = exports.commandCiJobOpen = exports.commandDoctor = exports.commandSetup = exports.commandGetMyTotalWorktime = exports.commandRenewToken = exports.commandTriggerCronjobGeneral = exports.commandOpenLogs = exports.commandSecretsSyncGithub = exports.commandSecretsClearBackups = exports.commandSecretsList = exports.commandSecretsSet = exports.commandSecretsPush = exports.commandSecretsPull = exports.commandConfigSecrets = exports.commandCloudSqlProxy = exports.commandOpenGit = exports.commandOpenEnv = exports.commandPortForward = exports.commandEnvVars = exports.commandKubePortForward = exports.commandKubeGetShell = exports.commandKubeStopPortforward = exports.commandKubeListPods = exports.commandKubeListSecrets = exports.commandKubeListNamespaces = exports.commandKubeCurrentContext = void 0;
|
|
2537
2324
|
// General commands
|
|
2538
2325
|
var commandKubeCurrentContext_1 = __nccwpck_require__(70243);
|
|
2539
2326
|
Object.defineProperty(exports, "commandKubeCurrentContext", ({ enumerable: true, get: function () { return commandKubeCurrentContext_1.commandKubeCurrentContext; } }));
|
|
@@ -2562,6 +2349,14 @@ var commandCloudSqlProxy_1 = __nccwpck_require__(10878);
|
|
|
2562
2349
|
Object.defineProperty(exports, "commandCloudSqlProxy", ({ enumerable: true, get: function () { return commandCloudSqlProxy_1.commandCloudSqlProxy; } }));
|
|
2563
2350
|
var commandConfigSecrets_1 = __nccwpck_require__(40876);
|
|
2564
2351
|
Object.defineProperty(exports, "commandConfigSecrets", ({ enumerable: true, get: function () { return commandConfigSecrets_1.commandConfigSecrets; } }));
|
|
2352
|
+
var commandSecretsPull_1 = __nccwpck_require__(2835);
|
|
2353
|
+
Object.defineProperty(exports, "commandSecretsPull", ({ enumerable: true, get: function () { return commandSecretsPull_1.commandSecretsPull; } }));
|
|
2354
|
+
var commandSecretsPush_1 = __nccwpck_require__(1460);
|
|
2355
|
+
Object.defineProperty(exports, "commandSecretsPush", ({ enumerable: true, get: function () { return commandSecretsPush_1.commandSecretsPush; } }));
|
|
2356
|
+
var commandSecretsSet_1 = __nccwpck_require__(65514);
|
|
2357
|
+
Object.defineProperty(exports, "commandSecretsSet", ({ enumerable: true, get: function () { return commandSecretsSet_1.commandSecretsSet; } }));
|
|
2358
|
+
var commandSecretsList_1 = __nccwpck_require__(97240);
|
|
2359
|
+
Object.defineProperty(exports, "commandSecretsList", ({ enumerable: true, get: function () { return commandSecretsList_1.commandSecretsList; } }));
|
|
2565
2360
|
var commandSecretsClearBackups_1 = __nccwpck_require__(49558);
|
|
2566
2361
|
Object.defineProperty(exports, "commandSecretsClearBackups", ({ enumerable: true, get: function () { return commandSecretsClearBackups_1.commandSecretsClearBackups; } }));
|
|
2567
2362
|
var commandSecretsSyncGithub_1 = __nccwpck_require__(50962);
|
|
@@ -2977,34 +2772,75 @@ exports.commandCloudSqlProxy = (0, defineCommand_1.defineCommand)({
|
|
|
2977
2772
|
|
|
2978
2773
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2979
2774
|
exports.commandConfigSecrets = void 0;
|
|
2775
|
+
const common_tags_1 = __nccwpck_require__(63779);
|
|
2980
2776
|
const defineCommand_1 = __nccwpck_require__(39489);
|
|
2981
|
-
const
|
|
2982
|
-
const
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
// so for now we bridge it.
|
|
2777
|
+
const editAsFile_1 = __nccwpck_require__(82805);
|
|
2778
|
+
const promise_1 = __nccwpck_require__(51762);
|
|
2779
|
+
const document_1 = __nccwpck_require__(52283);
|
|
2780
|
+
const scope_1 = __nccwpck_require__(17712);
|
|
2781
|
+
const parseKeysInput_1 = __nccwpck_require__(55443);
|
|
2987
2782
|
exports.commandConfigSecrets = (0, defineCommand_1.defineCommand)({
|
|
2988
2783
|
name: "project config-secrets",
|
|
2989
|
-
description: "setup/update secrets
|
|
2784
|
+
description: "setup/update secrets in the vault via your editor",
|
|
2990
2785
|
group: "project",
|
|
2991
2786
|
inputs: {
|
|
2992
2787
|
envComponent: {
|
|
2993
2788
|
type: "string",
|
|
2994
|
-
message: "
|
|
2789
|
+
message: "scope: env:component, env:, :component or empty for everything",
|
|
2995
2790
|
positional: true,
|
|
2996
2791
|
required: false,
|
|
2997
|
-
choices: async () => (0,
|
|
2792
|
+
choices: async () => (0, scope_1.secretsScopeChoices)(),
|
|
2793
|
+
},
|
|
2794
|
+
key: {
|
|
2795
|
+
type: "string",
|
|
2796
|
+
message: "only edit these secrets (comma-separated keys)",
|
|
2797
|
+
required: false,
|
|
2998
2798
|
},
|
|
2999
2799
|
},
|
|
3000
2800
|
execute: async (ctx) => {
|
|
3001
2801
|
const envComponent = await ctx.get("envComponent");
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
await (0,
|
|
2802
|
+
const keys = (0, parseKeysInput_1.parseKeysInput)(await ctx.get("key"));
|
|
2803
|
+
if (!ctx.interactive) {
|
|
2804
|
+
throw new Error("project config-secrets opens an editor and needs an interactive terminal — " +
|
|
2805
|
+
"use `project secrets-pull`, `project secrets-push` or `project secrets-set` instead");
|
|
2806
|
+
}
|
|
2807
|
+
const scope = await (0, scope_1.resolveSecretsScope)(envComponent);
|
|
2808
|
+
const scoped = await (0, scope_1.getScopedSecretKeys)(scope, keys);
|
|
2809
|
+
let document = await (0, document_1.buildSecretsDocument)(ctx, scoped);
|
|
2810
|
+
let hasErrors = true;
|
|
2811
|
+
while (hasErrors) {
|
|
2812
|
+
document = await (0, editAsFile_1.editAsFile)(document, (0, common_tags_1.stripIndents) `
|
|
2813
|
+
Please fill in all secrets for:
|
|
2814
|
+
|
|
2815
|
+
${(0, scope_1.formatScope)(scoped)}
|
|
2816
|
+
|
|
2817
|
+
`);
|
|
2818
|
+
const problems = (0, document_1.checkSecretsDocument)(document, scoped, {
|
|
2819
|
+
requireComplete: true,
|
|
2820
|
+
});
|
|
2821
|
+
hasErrors = problems.length > 0;
|
|
2822
|
+
if (hasErrors) {
|
|
2823
|
+
ctx.log("");
|
|
2824
|
+
ctx.log("😿 Oh no! There is something wrong:");
|
|
2825
|
+
ctx.log("");
|
|
2826
|
+
problems.forEach((problem) => ctx.log(problem));
|
|
2827
|
+
ctx.log("");
|
|
2828
|
+
await (0, promise_1.delay)(1000);
|
|
2829
|
+
const shouldContinue = await ctx.confirm("Try again? 🤔");
|
|
2830
|
+
if (!shouldContinue) {
|
|
2831
|
+
throw new Error("abort");
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
const { writes, skipped } = (0, document_1.collectSecretsWrites)(document, scoped);
|
|
2836
|
+
if (skipped.length > 0) {
|
|
2837
|
+
ctx.log("");
|
|
2838
|
+
ctx.log("⏭️ these secrets are still unset and will not be written:");
|
|
2839
|
+
skipped.forEach((entry) => ctx.log(` - ${entry}`));
|
|
2840
|
+
}
|
|
2841
|
+
await (0, document_1.writeSecretsAndMirror)(ctx, writes);
|
|
2842
|
+
ctx.log("done! 😻");
|
|
2843
|
+
ctx.log("");
|
|
3008
2844
|
},
|
|
3009
2845
|
});
|
|
3010
2846
|
//# sourceMappingURL=commandConfigSecrets.js.map
|
|
@@ -4248,6 +4084,626 @@ exports.commandTriggerCronjobProject = (0, defineCommand_1.defineCommand)({
|
|
|
4248
4084
|
|
|
4249
4085
|
/***/ }),
|
|
4250
4086
|
|
|
4087
|
+
/***/ 97240:
|
|
4088
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4089
|
+
|
|
4090
|
+
"use strict";
|
|
4091
|
+
|
|
4092
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4093
|
+
exports.commandSecretsList = void 0;
|
|
4094
|
+
const pipeline_1 = __nccwpck_require__(60241);
|
|
4095
|
+
const defineCommand_1 = __nccwpck_require__(39489);
|
|
4096
|
+
const scope_1 = __nccwpck_require__(17712);
|
|
4097
|
+
const parseKeysInput_1 = __nccwpck_require__(55443);
|
|
4098
|
+
exports.commandSecretsList = (0, defineCommand_1.defineCommand)({
|
|
4099
|
+
name: "project secrets-list",
|
|
4100
|
+
description: "lists the declared secrets of a scope with their set/unset status (values only with --reveal)",
|
|
4101
|
+
group: "project",
|
|
4102
|
+
inputs: {
|
|
4103
|
+
envComponent: {
|
|
4104
|
+
type: "string",
|
|
4105
|
+
message: "scope: env:component, env:, :component or empty for everything",
|
|
4106
|
+
positional: true,
|
|
4107
|
+
required: false,
|
|
4108
|
+
choices: async () => (0, scope_1.secretsScopeChoices)(),
|
|
4109
|
+
},
|
|
4110
|
+
key: {
|
|
4111
|
+
type: "string",
|
|
4112
|
+
message: "only these secrets (comma-separated keys)",
|
|
4113
|
+
required: false,
|
|
4114
|
+
},
|
|
4115
|
+
reveal: {
|
|
4116
|
+
type: "boolean",
|
|
4117
|
+
message: "also print the secret values",
|
|
4118
|
+
default: false,
|
|
4119
|
+
},
|
|
4120
|
+
check: {
|
|
4121
|
+
type: "boolean",
|
|
4122
|
+
message: "exit with an error when any secret is unset (for CI/agents)",
|
|
4123
|
+
default: false,
|
|
4124
|
+
},
|
|
4125
|
+
},
|
|
4126
|
+
execute: async (ctx) => {
|
|
4127
|
+
const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
|
|
4128
|
+
const scoped = await (0, scope_1.getScopedSecretKeys)(scope, (0, parseKeysInput_1.parseKeysInput)(await ctx.get("key")));
|
|
4129
|
+
const reveal = await ctx.get("reveal");
|
|
4130
|
+
const names = scoped.flatMap(({ env, componentName, keys }) => keys.map((key) => (0, pipeline_1.getSecretVarName)(env, componentName, key)));
|
|
4131
|
+
const values = await (await ctx.getVaultManager()).readSecrets(names, ctx);
|
|
4132
|
+
let unsetCount = 0;
|
|
4133
|
+
let setCount = 0;
|
|
4134
|
+
for (const { env, componentName, keys } of scoped) {
|
|
4135
|
+
for (const key of keys) {
|
|
4136
|
+
const value = values[(0, pipeline_1.getSecretVarName)(env, componentName, key)];
|
|
4137
|
+
if (value === undefined) {
|
|
4138
|
+
unsetCount += 1;
|
|
4139
|
+
ctx.log(`🚨 ${env}:${componentName} ${key} (unset)`);
|
|
4140
|
+
}
|
|
4141
|
+
else {
|
|
4142
|
+
setCount += 1;
|
|
4143
|
+
ctx.log(`✅ ${env}:${componentName} ${key}` + (reveal ? ` = ${value}` : ""));
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
ctx.log("");
|
|
4148
|
+
ctx.log(`${setCount} set, ${unsetCount} unset`);
|
|
4149
|
+
if ((await ctx.get("check")) && unsetCount > 0) {
|
|
4150
|
+
throw new Error(`${unsetCount} secrets are unset`);
|
|
4151
|
+
}
|
|
4152
|
+
},
|
|
4153
|
+
});
|
|
4154
|
+
//# sourceMappingURL=commandSecretsList.js.map
|
|
4155
|
+
|
|
4156
|
+
/***/ }),
|
|
4157
|
+
|
|
4158
|
+
/***/ 2835:
|
|
4159
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4160
|
+
|
|
4161
|
+
"use strict";
|
|
4162
|
+
|
|
4163
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4164
|
+
exports.commandSecretsPull = void 0;
|
|
4165
|
+
const fs_extra_1 = __nccwpck_require__(96954);
|
|
4166
|
+
const yaml_1 = __nccwpck_require__(6637);
|
|
4167
|
+
const defineCommand_1 = __nccwpck_require__(39489);
|
|
4168
|
+
const document_1 = __nccwpck_require__(52283);
|
|
4169
|
+
const scope_1 = __nccwpck_require__(17712);
|
|
4170
|
+
const parseKeysInput_1 = __nccwpck_require__(55443);
|
|
4171
|
+
exports.commandSecretsPull = (0, defineCommand_1.defineCommand)({
|
|
4172
|
+
name: "project secrets-pull",
|
|
4173
|
+
description: "prints the current secrets of a scope as yaml (unset ones as a placeholder) — edit and feed to secrets-push",
|
|
4174
|
+
group: "project",
|
|
4175
|
+
inputs: {
|
|
4176
|
+
envComponent: {
|
|
4177
|
+
type: "string",
|
|
4178
|
+
message: "scope: env:component, env:, :component or empty for everything",
|
|
4179
|
+
positional: true,
|
|
4180
|
+
required: false,
|
|
4181
|
+
choices: async () => (0, scope_1.secretsScopeChoices)(),
|
|
4182
|
+
},
|
|
4183
|
+
key: {
|
|
4184
|
+
type: "string",
|
|
4185
|
+
message: "only these secrets (comma-separated keys)",
|
|
4186
|
+
required: false,
|
|
4187
|
+
},
|
|
4188
|
+
out: {
|
|
4189
|
+
type: "string",
|
|
4190
|
+
message: "write the yaml to this file instead of stdout",
|
|
4191
|
+
required: false,
|
|
4192
|
+
},
|
|
4193
|
+
},
|
|
4194
|
+
execute: async (ctx) => {
|
|
4195
|
+
const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
|
|
4196
|
+
const scoped = await (0, scope_1.getScopedSecretKeys)(scope, (0, parseKeysInput_1.parseKeysInput)(await ctx.get("key")));
|
|
4197
|
+
const document = await (0, document_1.buildSecretsDocument)(ctx, scoped);
|
|
4198
|
+
const yaml = (0, yaml_1.stringify)(document, { aliasDuplicateObjects: false });
|
|
4199
|
+
const out = await ctx.get("out");
|
|
4200
|
+
if (out) {
|
|
4201
|
+
await (0, fs_extra_1.writeFile)(out, yaml);
|
|
4202
|
+
ctx.log(`wrote secrets to ${out} — ⚠️ contains secret values, don't commit it`);
|
|
4203
|
+
}
|
|
4204
|
+
else {
|
|
4205
|
+
ctx.log(yaml);
|
|
4206
|
+
}
|
|
4207
|
+
},
|
|
4208
|
+
});
|
|
4209
|
+
//# sourceMappingURL=commandSecretsPull.js.map
|
|
4210
|
+
|
|
4211
|
+
/***/ }),
|
|
4212
|
+
|
|
4213
|
+
/***/ 1460:
|
|
4214
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4215
|
+
|
|
4216
|
+
"use strict";
|
|
4217
|
+
|
|
4218
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4219
|
+
exports.commandSecretsPush = void 0;
|
|
4220
|
+
const fs_extra_1 = __nccwpck_require__(96954);
|
|
4221
|
+
const yaml_1 = __nccwpck_require__(6637);
|
|
4222
|
+
const defineCommand_1 = __nccwpck_require__(39489);
|
|
4223
|
+
const readStdin_1 = __nccwpck_require__(185);
|
|
4224
|
+
const document_1 = __nccwpck_require__(52283);
|
|
4225
|
+
const scope_1 = __nccwpck_require__(17712);
|
|
4226
|
+
const parseKeysInput_1 = __nccwpck_require__(55443);
|
|
4227
|
+
exports.commandSecretsPush = (0, defineCommand_1.defineCommand)({
|
|
4228
|
+
name: "project secrets-push",
|
|
4229
|
+
description: "writes secrets from a yaml document (secrets-pull format, --file or stdin) to the vault; may be partial",
|
|
4230
|
+
group: "project",
|
|
4231
|
+
inputs: {
|
|
4232
|
+
envComponent: {
|
|
4233
|
+
type: "string",
|
|
4234
|
+
message: "scope: env:component, env:, :component or empty for everything",
|
|
4235
|
+
positional: true,
|
|
4236
|
+
required: false,
|
|
4237
|
+
choices: async () => (0, scope_1.secretsScopeChoices)(),
|
|
4238
|
+
},
|
|
4239
|
+
key: {
|
|
4240
|
+
type: "string",
|
|
4241
|
+
message: "only write these secrets (comma-separated keys)",
|
|
4242
|
+
required: false,
|
|
4243
|
+
},
|
|
4244
|
+
file: {
|
|
4245
|
+
type: "string",
|
|
4246
|
+
message: "yaml file to push (component → env → key: value); stdin when omitted",
|
|
4247
|
+
required: false,
|
|
4248
|
+
},
|
|
4249
|
+
},
|
|
4250
|
+
execute: async (ctx) => {
|
|
4251
|
+
const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
|
|
4252
|
+
const scoped = await (0, scope_1.getScopedSecretKeys)(scope, (0, parseKeysInput_1.parseKeysInput)(await ctx.get("key")));
|
|
4253
|
+
const file = await ctx.get("file");
|
|
4254
|
+
if (!file && process.stdin.isTTY) {
|
|
4255
|
+
throw new Error("nothing to push — pass --file <secrets.yml> or pipe yaml (secrets-pull format) to stdin");
|
|
4256
|
+
}
|
|
4257
|
+
const raw = file
|
|
4258
|
+
? (await (0, fs_extra_1.readFile)(file)).toString("utf-8")
|
|
4259
|
+
: await (0, readStdin_1.readStdin)();
|
|
4260
|
+
const document = (0, yaml_1.parse)(raw);
|
|
4261
|
+
if (!document || typeof document !== "object") {
|
|
4262
|
+
throw new Error("the document must be a yaml object: component → env → key: value (see secrets-pull)");
|
|
4263
|
+
}
|
|
4264
|
+
const problems = (0, document_1.checkSecretsDocument)(document, scoped, {
|
|
4265
|
+
requireComplete: false,
|
|
4266
|
+
});
|
|
4267
|
+
if (problems.length > 0) {
|
|
4268
|
+
throw new Error("😿 the document does not match the config:\n" +
|
|
4269
|
+
problems.map((problem) => ` - ${problem}`).join("\n"));
|
|
4270
|
+
}
|
|
4271
|
+
const { writes, skipped } = (0, document_1.collectSecretsWrites)(document, scoped);
|
|
4272
|
+
if (skipped.length > 0) {
|
|
4273
|
+
ctx.log("⏭️ skipping placeholder/empty values:");
|
|
4274
|
+
skipped.forEach((entry) => ctx.log(` - ${entry}`));
|
|
4275
|
+
}
|
|
4276
|
+
if (writes.length === 0) {
|
|
4277
|
+
ctx.log("no secrets to write 🤷");
|
|
4278
|
+
return;
|
|
4279
|
+
}
|
|
4280
|
+
ctx.log("about to write:");
|
|
4281
|
+
writes.forEach(({ env, componentName, secrets }) => ctx.log(` - ${env}:${componentName}: ${Object.keys(secrets).join(", ")}`));
|
|
4282
|
+
const confirmed = await ctx.confirm("continue? 🤔");
|
|
4283
|
+
if (!confirmed) {
|
|
4284
|
+
throw new Error("abort");
|
|
4285
|
+
}
|
|
4286
|
+
await (0, document_1.writeSecretsAndMirror)(ctx, writes);
|
|
4287
|
+
ctx.log("done! 😻");
|
|
4288
|
+
},
|
|
4289
|
+
});
|
|
4290
|
+
//# sourceMappingURL=commandSecretsPush.js.map
|
|
4291
|
+
|
|
4292
|
+
/***/ }),
|
|
4293
|
+
|
|
4294
|
+
/***/ 65514:
|
|
4295
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4296
|
+
|
|
4297
|
+
"use strict";
|
|
4298
|
+
|
|
4299
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4300
|
+
exports.commandSecretsSet = void 0;
|
|
4301
|
+
const fs_extra_1 = __nccwpck_require__(96954);
|
|
4302
|
+
const defineCommand_1 = __nccwpck_require__(39489);
|
|
4303
|
+
const readStdin_1 = __nccwpck_require__(185);
|
|
4304
|
+
const document_1 = __nccwpck_require__(52283);
|
|
4305
|
+
const scope_1 = __nccwpck_require__(17712);
|
|
4306
|
+
const resolveValue = async (io, value, valueFile) => {
|
|
4307
|
+
if (valueFile) {
|
|
4308
|
+
// a trailing newline is almost never part of the secret
|
|
4309
|
+
return (await (0, fs_extra_1.readFile)(valueFile)).toString("utf-8").replace(/\n$/, "");
|
|
4310
|
+
}
|
|
4311
|
+
if (value !== undefined) {
|
|
4312
|
+
return value;
|
|
4313
|
+
}
|
|
4314
|
+
if (!process.stdin.isTTY) {
|
|
4315
|
+
return (await (0, readStdin_1.readStdin)()).replace(/\n$/, "");
|
|
4316
|
+
}
|
|
4317
|
+
return io.promptDirect({
|
|
4318
|
+
name: "value",
|
|
4319
|
+
type: "string",
|
|
4320
|
+
message: "value",
|
|
4321
|
+
});
|
|
4322
|
+
};
|
|
4323
|
+
exports.commandSecretsSet = (0, defineCommand_1.defineCommand)({
|
|
4324
|
+
name: "project secrets-set",
|
|
4325
|
+
description: "sets one secret — in one env (dev:web), one env everywhere (dev:), or all envs of a component (:web); value via --value, --value-file or stdin",
|
|
4326
|
+
group: "project",
|
|
4327
|
+
inputs: {
|
|
4328
|
+
envComponent: {
|
|
4329
|
+
type: "string",
|
|
4330
|
+
message: "scope: env:component, env:, or :component",
|
|
4331
|
+
positional: true,
|
|
4332
|
+
choices: async () => (0, scope_1.secretsScopeChoices)(),
|
|
4333
|
+
},
|
|
4334
|
+
key: {
|
|
4335
|
+
type: "string",
|
|
4336
|
+
message: "which secret?",
|
|
4337
|
+
positional: true,
|
|
4338
|
+
choices: async (ctx) => {
|
|
4339
|
+
const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
|
|
4340
|
+
const scoped = await (0, scope_1.getScopedSecretKeys)(scope);
|
|
4341
|
+
return [...new Set(scoped.flatMap(({ keys }) => keys))];
|
|
4342
|
+
},
|
|
4343
|
+
},
|
|
4344
|
+
value: {
|
|
4345
|
+
type: "string",
|
|
4346
|
+
message: "the secret value (prefer --value-file or stdin over shell history)",
|
|
4347
|
+
required: false,
|
|
4348
|
+
},
|
|
4349
|
+
valueFile: {
|
|
4350
|
+
type: "string",
|
|
4351
|
+
message: "read the secret value from this file",
|
|
4352
|
+
required: false,
|
|
4353
|
+
},
|
|
4354
|
+
},
|
|
4355
|
+
execute: async (ctx) => {
|
|
4356
|
+
const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
|
|
4357
|
+
const key = await ctx.get("key");
|
|
4358
|
+
// drops env/component pairs where the key is not declared and
|
|
4359
|
+
// throws when it is declared nowhere in the scope
|
|
4360
|
+
const scoped = await (0, scope_1.getScopedSecretKeys)(scope, [key]);
|
|
4361
|
+
const value = await resolveValue(ctx, await ctx.get("value"), await ctx.get("valueFile"));
|
|
4362
|
+
const targets = scoped.map(({ env, componentName }) => `${env}:${componentName}`);
|
|
4363
|
+
ctx.log(`setting ${key} in: ${targets.join(", ")}`);
|
|
4364
|
+
if (targets.length > 1) {
|
|
4365
|
+
const confirmed = await ctx.confirm(`write the same value to ${targets.length} environments? 🤔`);
|
|
4366
|
+
if (!confirmed) {
|
|
4367
|
+
throw new Error("abort");
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
const writes = scoped.map(({ env, componentName }) => ({
|
|
4371
|
+
env,
|
|
4372
|
+
componentName,
|
|
4373
|
+
secrets: { [key]: value },
|
|
4374
|
+
}));
|
|
4375
|
+
await (0, document_1.writeSecretsAndMirror)(ctx, writes);
|
|
4376
|
+
ctx.log("done! 😻");
|
|
4377
|
+
},
|
|
4378
|
+
});
|
|
4379
|
+
//# sourceMappingURL=commandSecretsSet.js.map
|
|
4380
|
+
|
|
4381
|
+
/***/ }),
|
|
4382
|
+
|
|
4383
|
+
/***/ 52283:
|
|
4384
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4385
|
+
|
|
4386
|
+
"use strict";
|
|
4387
|
+
|
|
4388
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4389
|
+
exports.writeSecretsAndMirror = exports.collectSecretsWrites = exports.checkSecretsDocument = exports.buildSecretsDocument = exports.FILL_ME = void 0;
|
|
4390
|
+
const pipeline_1 = __nccwpck_require__(60241);
|
|
4391
|
+
const getProjectConfig_1 = __nccwpck_require__(50001);
|
|
4392
|
+
const github_1 = __nccwpck_require__(18036);
|
|
4393
|
+
const gitlab_1 = __nccwpck_require__(4508);
|
|
4394
|
+
const commandSecretsSyncGithub_1 = __nccwpck_require__(50962);
|
|
4395
|
+
/** placeholder for secrets that have no value in the vault yet */
|
|
4396
|
+
exports.FILL_ME = "🚨 FILL ME";
|
|
4397
|
+
/* for convenience, parse json values. that makes it easier to edit secrets that are objects */
|
|
4398
|
+
const parseJsonValue = (value) => {
|
|
4399
|
+
try {
|
|
4400
|
+
return JSON.parse(value);
|
|
4401
|
+
}
|
|
4402
|
+
catch (e) {
|
|
4403
|
+
return value;
|
|
4404
|
+
}
|
|
4405
|
+
};
|
|
4406
|
+
/**
|
|
4407
|
+
* builds the document for the given scope with the current values from
|
|
4408
|
+
* the vault; unset secrets appear as the FILL_ME placeholder
|
|
4409
|
+
*/
|
|
4410
|
+
const buildSecretsDocument = async (io, scoped) => {
|
|
4411
|
+
var _a;
|
|
4412
|
+
const names = scoped.flatMap(({ env, componentName, keys }) => keys.map((key) => (0, pipeline_1.getSecretVarName)(env, componentName, key)));
|
|
4413
|
+
const values = await (await io.getVaultManager()).readSecrets(names, io);
|
|
4414
|
+
const document = {};
|
|
4415
|
+
for (const { env, componentName, keys } of scoped) {
|
|
4416
|
+
(_a = document[componentName]) !== null && _a !== void 0 ? _a : (document[componentName] = {});
|
|
4417
|
+
document[componentName][env] = Object.fromEntries(keys.map((key) => {
|
|
4418
|
+
const value = values[(0, pipeline_1.getSecretVarName)(env, componentName, key)];
|
|
4419
|
+
return [key, value === undefined ? exports.FILL_ME : parseJsonValue(value)];
|
|
4420
|
+
}));
|
|
4421
|
+
}
|
|
4422
|
+
return document;
|
|
4423
|
+
};
|
|
4424
|
+
exports.buildSecretsDocument = buildSecretsDocument;
|
|
4425
|
+
/**
|
|
4426
|
+
* validates a document against the scope. Undeclared components, envs
|
|
4427
|
+
* or keys are always problems; missing keys only when `requireComplete`
|
|
4428
|
+
* (the guided editor flow) — pushes may be partial.
|
|
4429
|
+
*/
|
|
4430
|
+
const checkSecretsDocument = (document, scoped, { requireComplete }) => {
|
|
4431
|
+
var _a, _b;
|
|
4432
|
+
const problems = [];
|
|
4433
|
+
const scopedKeys = new Map();
|
|
4434
|
+
scoped.forEach(({ env, componentName, keys }) => scopedKeys.set(`${env}:${componentName}`, keys));
|
|
4435
|
+
const scopedComponents = new Set(scoped.map((s) => s.componentName));
|
|
4436
|
+
for (const [componentName, envs] of Object.entries(document !== null && document !== void 0 ? document : {})) {
|
|
4437
|
+
if (!scopedComponents.has(componentName)) {
|
|
4438
|
+
problems.push(`"${componentName}" is not a component in this scope — remove it or widen the scope`);
|
|
4439
|
+
continue;
|
|
4440
|
+
}
|
|
4441
|
+
for (const [env, secrets] of Object.entries(envs !== null && envs !== void 0 ? envs : {})) {
|
|
4442
|
+
const keys = scopedKeys.get(`${env}:${componentName}`);
|
|
4443
|
+
if (!keys) {
|
|
4444
|
+
problems.push(`"${env}:${componentName}" is not in this scope — remove it or widen the scope`);
|
|
4445
|
+
continue;
|
|
4446
|
+
}
|
|
4447
|
+
const extraneous = Object.keys(secrets !== null && secrets !== void 0 ? secrets : {}).filter((key) => !keys.includes(key));
|
|
4448
|
+
extraneous.forEach((key) => problems.push(`"${env}:${componentName}": "${key}" is not declared in the config (or filtered out by --key)`));
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
if (requireComplete) {
|
|
4452
|
+
for (const { env, componentName, keys } of scoped) {
|
|
4453
|
+
const provided = Object.keys((_b = (_a = document === null || document === void 0 ? void 0 : document[componentName]) === null || _a === void 0 ? void 0 : _a[env]) !== null && _b !== void 0 ? _b : {});
|
|
4454
|
+
keys
|
|
4455
|
+
.filter((key) => !provided.includes(key))
|
|
4456
|
+
.forEach((key) => problems.push(`"${env}:${componentName}": "${key}" has not been provided`));
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
return problems;
|
|
4460
|
+
};
|
|
4461
|
+
exports.checkSecretsDocument = checkSecretsDocument;
|
|
4462
|
+
/**
|
|
4463
|
+
* turns a (validated) document into writes. FILL_ME placeholders and
|
|
4464
|
+
* empty (null) values are skipped, so an untouched placeholder can
|
|
4465
|
+
* never end up as a live secret value.
|
|
4466
|
+
*/
|
|
4467
|
+
const collectSecretsWrites = (document, scoped) => {
|
|
4468
|
+
var _a, _b;
|
|
4469
|
+
const writes = [];
|
|
4470
|
+
const skipped = [];
|
|
4471
|
+
for (const { env, componentName, keys } of scoped) {
|
|
4472
|
+
const provided = (_b = (_a = document === null || document === void 0 ? void 0 : document[componentName]) === null || _a === void 0 ? void 0 : _a[env]) !== null && _b !== void 0 ? _b : {};
|
|
4473
|
+
const secrets = {};
|
|
4474
|
+
for (const key of keys) {
|
|
4475
|
+
if (!(key in provided)) {
|
|
4476
|
+
continue;
|
|
4477
|
+
}
|
|
4478
|
+
const value = provided[key];
|
|
4479
|
+
if (value === exports.FILL_ME || value === null || value === undefined) {
|
|
4480
|
+
skipped.push(`${env}:${componentName} ${key}`);
|
|
4481
|
+
continue;
|
|
4482
|
+
}
|
|
4483
|
+
secrets[key] = value;
|
|
4484
|
+
}
|
|
4485
|
+
if (Object.keys(secrets).length > 0) {
|
|
4486
|
+
writes.push({ env, componentName, secrets });
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
return { writes, skipped };
|
|
4490
|
+
};
|
|
4491
|
+
exports.collectSecretsWrites = collectSecretsWrites;
|
|
4492
|
+
/**
|
|
4493
|
+
* writes secrets to the vault (the source of truth) and mirrors them
|
|
4494
|
+
* to every enabled CI backend — which backends exist is invisible to
|
|
4495
|
+
* the caller
|
|
4496
|
+
*/
|
|
4497
|
+
const writeSecretsAndMirror = async (io, writes) => {
|
|
4498
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
4499
|
+
if (!config) {
|
|
4500
|
+
throw new Error("no catladder config found");
|
|
4501
|
+
}
|
|
4502
|
+
io.log("");
|
|
4503
|
+
io.log("writing secrets to the vault, please wait...");
|
|
4504
|
+
io.log("");
|
|
4505
|
+
for (const { env, componentName, secrets } of writes) {
|
|
4506
|
+
io.log("writing " + env + ":" + componentName + "...\n");
|
|
4507
|
+
await (await io.getVaultManager()).writeSecrets(env, componentName, secrets);
|
|
4508
|
+
io.log("");
|
|
4509
|
+
io.log("✅ " + env + ":" + componentName);
|
|
4510
|
+
io.log("--------------------------------\n");
|
|
4511
|
+
}
|
|
4512
|
+
await mirrorSecretsToCiBackends(io, config, writes);
|
|
4513
|
+
};
|
|
4514
|
+
exports.writeSecretsAndMirror = writeSecretsAndMirror;
|
|
4515
|
+
/**
|
|
4516
|
+
* the vault is the source of truth; every enabled CI backend receives
|
|
4517
|
+
* a mirrored copy of the written secrets (gitlab variables, github
|
|
4518
|
+
* secrets), so all CI systems stay in sync
|
|
4519
|
+
*/
|
|
4520
|
+
const mirrorSecretsToCiBackends = async (io, config, writes) => {
|
|
4521
|
+
const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
|
|
4522
|
+
// gitlab mirror (unless gitlab is the vault itself, then it is
|
|
4523
|
+
// already written)
|
|
4524
|
+
if ((0, pipeline_1.getVaultConfig)(config).type !== "gitlab" && enabled.includes("gitlab")) {
|
|
4525
|
+
for (const { env, componentName, secrets } of writes) {
|
|
4526
|
+
await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName);
|
|
4527
|
+
}
|
|
4528
|
+
io.log("✅ mirrored to gitlab");
|
|
4529
|
+
}
|
|
4530
|
+
if (!enabled.includes("github")) {
|
|
4531
|
+
return;
|
|
4532
|
+
}
|
|
4533
|
+
const kinds = new Map();
|
|
4534
|
+
for (const { env, componentName } of writes) {
|
|
4535
|
+
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
4536
|
+
[
|
|
4537
|
+
...secretEnvVarKeys,
|
|
4538
|
+
...jobOnlyVars.build.secretEnvVarKeys,
|
|
4539
|
+
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
4540
|
+
].forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
4541
|
+
}
|
|
4542
|
+
const secrets = writes.flatMap(({ env, componentName, secrets }) => Object.entries(secrets).map(([key, value]) => {
|
|
4543
|
+
var _a;
|
|
4544
|
+
const name = (0, pipeline_1.getSecretVarName)(env, componentName, key);
|
|
4545
|
+
return {
|
|
4546
|
+
name,
|
|
4547
|
+
value: typeof value === "string" ? value : JSON.stringify(value !== null && value !== void 0 ? value : ""),
|
|
4548
|
+
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
|
|
4549
|
+
};
|
|
4550
|
+
}));
|
|
4551
|
+
if (secrets.length === 0) {
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4554
|
+
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
4555
|
+
io.log("⚠️ github pipeline is enabled, but the github cli (gh) is not authenticated — run `project secrets-sync-github` later to mirror the secrets");
|
|
4556
|
+
return;
|
|
4557
|
+
}
|
|
4558
|
+
const repo = await (0, commandSecretsSyncGithub_1.getConfiguredGithubRepo)();
|
|
4559
|
+
if (!repo) {
|
|
4560
|
+
io.log("⚠️ github pipeline is enabled, but no github repository was found — run `project secrets-sync-github` later to mirror the secrets");
|
|
4561
|
+
return;
|
|
4562
|
+
}
|
|
4563
|
+
io.log(`mirroring ${secrets.length} secrets to github ('${repo}')...`);
|
|
4564
|
+
await (0, commandSecretsSyncGithub_1.pushSecretsToGithub)(io, repo, secrets, await (0, commandSecretsSyncGithub_1.collectSecretTargets)(config));
|
|
4565
|
+
};
|
|
4566
|
+
//# sourceMappingURL=document.js.map
|
|
4567
|
+
|
|
4568
|
+
/***/ }),
|
|
4569
|
+
|
|
4570
|
+
/***/ 55443:
|
|
4571
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
4572
|
+
|
|
4573
|
+
"use strict";
|
|
4574
|
+
|
|
4575
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4576
|
+
exports.parseKeysInput = void 0;
|
|
4577
|
+
/** parses a comma-separated `--key` input into a list of keys */
|
|
4578
|
+
const parseKeysInput = (input) => {
|
|
4579
|
+
const keys = input === null || input === void 0 ? void 0 : input.split(",").map((key) => key.trim()).filter(Boolean);
|
|
4580
|
+
return keys && keys.length > 0 ? keys : undefined;
|
|
4581
|
+
};
|
|
4582
|
+
exports.parseKeysInput = parseKeysInput;
|
|
4583
|
+
//# sourceMappingURL=parseKeysInput.js.map
|
|
4584
|
+
|
|
4585
|
+
/***/ }),
|
|
4586
|
+
|
|
4587
|
+
/***/ 17712:
|
|
4588
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4589
|
+
|
|
4590
|
+
"use strict";
|
|
4591
|
+
|
|
4592
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4593
|
+
exports.formatScope = exports.getScopedSecretKeys = exports.getDeclaredSecretKeys = exports.secretsScopeChoices = exports.resolveSecretsScope = void 0;
|
|
4594
|
+
const getProjectConfig_1 = __nccwpck_require__(50001);
|
|
4595
|
+
/**
|
|
4596
|
+
* resolves a scope expression to component → envs:
|
|
4597
|
+
* - (empty): all components, all envs
|
|
4598
|
+
* - `env:component`: one env of one component
|
|
4599
|
+
* - `env` / `env:`: one env, every component that has it
|
|
4600
|
+
* - `:component`: every env of one component
|
|
4601
|
+
*/
|
|
4602
|
+
const resolveSecretsScope = async (scope) => {
|
|
4603
|
+
const all = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
4604
|
+
if (Object.keys(all).length === 0) {
|
|
4605
|
+
throw new Error("no catladder config found");
|
|
4606
|
+
}
|
|
4607
|
+
if (!scope) {
|
|
4608
|
+
return all;
|
|
4609
|
+
}
|
|
4610
|
+
const [env, componentName] = scope.split(":").map((x) => x || null);
|
|
4611
|
+
if (componentName && !(componentName in all)) {
|
|
4612
|
+
throw new Error(`unknown component "${componentName}" — components: ${Object.keys(all).join(", ")}`);
|
|
4613
|
+
}
|
|
4614
|
+
const scoped = Object.fromEntries(Object.entries(all)
|
|
4615
|
+
.filter(([name]) => !componentName || name === componentName)
|
|
4616
|
+
.map(([name, envs]) => [
|
|
4617
|
+
name,
|
|
4618
|
+
env ? envs.filter((e) => e === env) : envs,
|
|
4619
|
+
])
|
|
4620
|
+
.filter(([, envs]) => envs.length > 0));
|
|
4621
|
+
if (Object.keys(scoped).length === 0) {
|
|
4622
|
+
const allEnvs = [...new Set(Object.values(all).flat())];
|
|
4623
|
+
throw new Error(`no component has the environment "${env}" — environments: ${allEnvs.join(", ")}`);
|
|
4624
|
+
}
|
|
4625
|
+
return scoped;
|
|
4626
|
+
};
|
|
4627
|
+
exports.resolveSecretsScope = resolveSecretsScope;
|
|
4628
|
+
/**
|
|
4629
|
+
* all valid scope expressions, for autocompletion: `env:component`
|
|
4630
|
+
* pairs plus the `env:` (one env, all components) and `:component`
|
|
4631
|
+
* (one component, all envs) forms
|
|
4632
|
+
*/
|
|
4633
|
+
const secretsScopeChoices = async () => {
|
|
4634
|
+
const all = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
4635
|
+
const pairs = Object.entries(all).flatMap(([componentName, envs]) => envs.map((env) => `${env}:${componentName}`));
|
|
4636
|
+
const envs = [...new Set(Object.values(all).flat())];
|
|
4637
|
+
return [
|
|
4638
|
+
...pairs,
|
|
4639
|
+
...envs.map((env) => `${env}:`),
|
|
4640
|
+
...Object.keys(all).map((componentName) => `:${componentName}`),
|
|
4641
|
+
];
|
|
4642
|
+
};
|
|
4643
|
+
exports.secretsScopeChoices = secretsScopeChoices;
|
|
4644
|
+
/** the secret keys declared in the config for one env of one component */
|
|
4645
|
+
const getDeclaredSecretKeys = async (env, componentName) => {
|
|
4646
|
+
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
4647
|
+
return [
|
|
4648
|
+
...jobOnlyVars.build.secretEnvVarKeys,
|
|
4649
|
+
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
4650
|
+
...secretEnvVarKeys,
|
|
4651
|
+
]
|
|
4652
|
+
.filter((k) => !k.hidden)
|
|
4653
|
+
.map((k) => k.key);
|
|
4654
|
+
};
|
|
4655
|
+
exports.getDeclaredSecretKeys = getDeclaredSecretKeys;
|
|
4656
|
+
/**
|
|
4657
|
+
* expands a scope to its declared secret keys, optionally filtered to
|
|
4658
|
+
* `onlyKeys`. Throws when a requested key is not declared anywhere in
|
|
4659
|
+
* the scope (typo protection); env/component pairs without matching
|
|
4660
|
+
* keys are dropped.
|
|
4661
|
+
*/
|
|
4662
|
+
const getScopedSecretKeys = async (scope, onlyKeys) => {
|
|
4663
|
+
const scoped = [];
|
|
4664
|
+
const declaredAnywhere = new Set();
|
|
4665
|
+
for (const [componentName, envs] of Object.entries(scope)) {
|
|
4666
|
+
for (const env of envs) {
|
|
4667
|
+
const declared = await (0, exports.getDeclaredSecretKeys)(env, componentName);
|
|
4668
|
+
declared.forEach((key) => declaredAnywhere.add(key));
|
|
4669
|
+
const keys = onlyKeys
|
|
4670
|
+
? declared.filter((key) => onlyKeys.includes(key))
|
|
4671
|
+
: declared;
|
|
4672
|
+
if (keys.length > 0) {
|
|
4673
|
+
scoped.push({ env, componentName, keys });
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
}
|
|
4677
|
+
const unknownKeys = (onlyKeys !== null && onlyKeys !== void 0 ? onlyKeys : []).filter((key) => !declaredAnywhere.has(key));
|
|
4678
|
+
if (unknownKeys.length > 0) {
|
|
4679
|
+
throw new Error(`these secrets are not declared in this scope: ${unknownKeys.join(", ")}` +
|
|
4680
|
+
`\ndeclared secrets: ${[...declaredAnywhere].join(", ")}`);
|
|
4681
|
+
}
|
|
4682
|
+
if (scoped.length === 0) {
|
|
4683
|
+
throw new Error("there are no secrets to configure in this scope");
|
|
4684
|
+
}
|
|
4685
|
+
return scoped;
|
|
4686
|
+
};
|
|
4687
|
+
exports.getScopedSecretKeys = getScopedSecretKeys;
|
|
4688
|
+
/** human-readable one-line-per-component summary of a scope */
|
|
4689
|
+
const formatScope = (scoped) => {
|
|
4690
|
+
var _a;
|
|
4691
|
+
const byComponent = new Map();
|
|
4692
|
+
for (const { env, componentName } of scoped) {
|
|
4693
|
+
byComponent.set(componentName, [
|
|
4694
|
+
...((_a = byComponent.get(componentName)) !== null && _a !== void 0 ? _a : []),
|
|
4695
|
+
env,
|
|
4696
|
+
]);
|
|
4697
|
+
}
|
|
4698
|
+
return [...byComponent.entries()]
|
|
4699
|
+
.map(([componentName, envs]) => `- ${componentName}: ${envs.join(", ")}`)
|
|
4700
|
+
.join("\n");
|
|
4701
|
+
};
|
|
4702
|
+
exports.formatScope = formatScope;
|
|
4703
|
+
//# sourceMappingURL=scope.js.map
|
|
4704
|
+
|
|
4705
|
+
/***/ }),
|
|
4706
|
+
|
|
4251
4707
|
/***/ 45498:
|
|
4252
4708
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4253
4709
|
|
|
@@ -6515,6 +6971,26 @@ exports.delay = delay;
|
|
|
6515
6971
|
|
|
6516
6972
|
/***/ }),
|
|
6517
6973
|
|
|
6974
|
+
/***/ 185:
|
|
6975
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
6976
|
+
|
|
6977
|
+
"use strict";
|
|
6978
|
+
|
|
6979
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6980
|
+
exports.readStdin = void 0;
|
|
6981
|
+
/** reads the whole stdin stream (for piped input in non-interactive use) */
|
|
6982
|
+
const readStdin = async () => {
|
|
6983
|
+
const chunks = [];
|
|
6984
|
+
for await (const chunk of process.stdin) {
|
|
6985
|
+
chunks.push(chunk);
|
|
6986
|
+
}
|
|
6987
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
6988
|
+
};
|
|
6989
|
+
exports.readStdin = readStdin;
|
|
6990
|
+
//# sourceMappingURL=readStdin.js.map
|
|
6991
|
+
|
|
6992
|
+
/***/ }),
|
|
6993
|
+
|
|
6518
6994
|
/***/ 45381:
|
|
6519
6995
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6520
6996
|
|