@catladder/cli 5.0.1 → 5.1.0
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/apps/cli/src/apps/cli/commands/project/doctor/checkGithub.js +3 -3
- package/dist/apps/cli/src/apps/cli/commands/project/doctor/checkGithub.js.map +1 -1
- package/dist/apps/cli/src/apps/cli/commands/project/setup/setupAccessTokens.js +2 -2
- package/dist/apps/cli/src/apps/cli/commands/project/setup/setupAccessTokens.js.map +1 -1
- package/dist/apps/cli/src/apps/cli/commands/project/setup/setupGithub.js +2 -2
- package/dist/apps/cli/src/apps/cli/commands/project/setup/setupGithub.js.map +1 -1
- package/dist/apps/cli/src/apps/cli/commands/project/setup/setupKubernetes.js +23 -7
- package/dist/apps/cli/src/apps/cli/commands/project/setup/setupKubernetes.js.map +1 -1
- package/dist/apps/cli/src/commands/index.d.ts +1 -0
- package/dist/apps/cli/src/commands/index.js +4 -1
- package/dist/apps/cli/src/commands/index.js.map +1 -1
- package/dist/apps/cli/src/commands/project/commandConfigSecrets.js +2 -1
- package/dist/apps/cli/src/commands/project/commandConfigSecrets.js.map +1 -1
- package/dist/apps/cli/src/commands/project/commandMrPin.d.ts +21 -0
- package/dist/apps/cli/src/commands/project/commandMrPin.js +119 -0
- package/dist/apps/cli/src/commands/project/commandMrPin.js.map +1 -0
- package/dist/apps/cli/src/commands/project/commandSecretsSyncGithub.d.ts +1 -42
- package/dist/apps/cli/src/commands/project/commandSecretsSyncGithub.js +5 -124
- package/dist/apps/cli/src/commands/project/commandSecretsSyncGithub.js.map +1 -1
- package/dist/apps/cli/src/commands/project/secrets/commandSecretsPush.js +2 -1
- package/dist/apps/cli/src/commands/project/secrets/commandSecretsPush.js.map +1 -1
- package/dist/apps/cli/src/commands/project/secrets/commandSecretsSet.js +2 -2
- package/dist/apps/cli/src/commands/project/secrets/commandSecretsSet.js.map +1 -1
- package/dist/apps/cli/src/commands/project/secrets/document.d.ts +1 -12
- package/dist/apps/cli/src/commands/project/secrets/document.js +1 -79
- package/dist/apps/cli/src/commands/project/secrets/document.js.map +1 -1
- package/dist/apps/cli/src/gcloud/serviceAccounts.js +15 -4
- package/dist/apps/cli/src/gcloud/serviceAccounts.js.map +1 -1
- package/dist/apps/cli/src/secrets/github.d.ts +41 -0
- package/dist/apps/cli/src/secrets/github.js +127 -0
- package/dist/apps/cli/src/secrets/github.js.map +1 -0
- package/dist/apps/cli/src/secrets/index.d.ts +2 -0
- package/dist/apps/cli/src/secrets/index.js +19 -0
- package/dist/apps/cli/src/secrets/index.js.map +1 -0
- package/dist/apps/cli/src/secrets/writeSecrets.d.ts +18 -0
- package/dist/apps/cli/src/secrets/writeSecrets.js +88 -0
- package/dist/apps/cli/src/secrets/writeSecrets.js.map +1 -0
- package/dist/apps/cli/src/utils/gitlab.d.ts +10 -0
- package/dist/apps/cli/src/utils/gitlab.js +30 -5
- package/dist/apps/cli/src/utils/gitlab.js.map +1 -1
- package/dist/apps/cli/src/vault/BitwardenVault.d.ts +6 -0
- package/dist/apps/cli/src/vault/BitwardenVault.js +11 -1
- package/dist/apps/cli/src/vault/BitwardenVault.js.map +1 -1
- package/dist/apps/cli/src/vault/GitlabVault.d.ts +2 -2
- package/dist/apps/cli/src/vault/GitlabVault.js +3 -2
- package/dist/apps/cli/src/vault/GitlabVault.js.map +1 -1
- package/dist/apps/cli/src/vault/VaultManager.d.ts +2 -2
- package/dist/apps/cli/src/vault/VaultManager.js +2 -2
- package/dist/apps/cli/src/vault/VaultManager.js.map +1 -1
- package/dist/apps/cli/src/vault/types.d.ts +16 -2
- package/dist/bundles/catenv/index.js +115 -13
- package/dist/bundles/cli/index.js +749 -431
- package/dist/bundles/skills/catladder-cli/references/commands.md +13 -0
- package/dist/bundles/skills/catladder-deploys/SKILL.md +7 -0
- package/dist/bundles/skills/catladder-migrate-ci-backend/SKILL.md +7 -2
- package/dist/bundles/skills/catladder-pipelines/SKILL.md +27 -1
- package/dist/bundles/skills/catladder-secrets/SKILL.md +16 -0
- package/dist/packages/pipeline/src/autoStop.d.ts +22 -0
- package/dist/packages/pipeline/src/autoStop.js +30 -0
- package/dist/packages/pipeline/src/autoStop.js.map +1 -0
- package/dist/packages/pipeline/src/backends/gitlab/GitlabBackend.js +2 -0
- package/dist/packages/pipeline/src/backends/gitlab/GitlabBackend.js.map +1 -1
- package/dist/packages/pipeline/src/backends/gitlab/createGitlabPipeline.d.ts +4 -1
- package/dist/packages/pipeline/src/backends/gitlab/createGitlabPipeline.js +21 -1
- package/dist/packages/pipeline/src/backends/gitlab/createGitlabPipeline.js.map +1 -1
- package/dist/packages/pipeline/src/deploy/base/deploy.js +8 -2
- package/dist/packages/pipeline/src/deploy/base/deploy.js.map +1 -1
- package/dist/packages/pipeline/src/index.d.ts +1 -0
- package/dist/packages/pipeline/src/index.js +1 -0
- package/dist/packages/pipeline/src/index.js.map +1 -1
- package/dist/packages/pipeline/src/types/config.d.ts +32 -0
- package/dist/skills/catladder-cli/references/commands.md +13 -0
- package/dist/skills/catladder-deploys/SKILL.md +7 -0
- package/dist/skills/catladder-migrate-ci-backend/SKILL.md +7 -2
- package/dist/skills/catladder-pipelines/SKILL.md +27 -1
- package/dist/skills/catladder-secrets/SKILL.md +16 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/apps/cli/commands/project/doctor/checkGithub.ts +1 -1
- package/src/apps/cli/commands/project/setup/setupAccessTokens.ts +3 -2
- package/src/apps/cli/commands/project/setup/setupGithub.ts +1 -1
- package/src/apps/cli/commands/project/setup/setupKubernetes.ts +31 -20
- package/src/commands/index.ts +1 -0
- package/src/commands/project/commandConfigSecrets.ts +1 -1
- package/src/commands/project/commandMrPin.ts +184 -0
- package/src/commands/project/commandSecretsSyncGithub.ts +7 -154
- package/src/commands/project/secrets/commandSecretsPush.ts +2 -5
- package/src/commands/project/secrets/commandSecretsSet.ts +2 -2
- package/src/commands/project/secrets/document.ts +2 -127
- package/src/gcloud/serviceAccounts.ts +16 -7
- package/src/secrets/__tests__/writeSecrets.test.ts +147 -0
- package/src/secrets/github.ts +157 -0
- package/src/secrets/index.ts +2 -0
- package/src/secrets/writeSecrets.ts +138 -0
- package/src/utils/gitlab.ts +34 -7
- package/src/vault/BitwardenVault.ts +10 -1
- package/src/vault/GitlabVault.ts +9 -2
- package/src/vault/VaultManager.ts +3 -2
- package/src/vault/__tests__/BitwardenVault.test.ts +88 -0
- package/src/vault/types.ts +17 -1
|
@@ -616,7 +616,7 @@ exports.checkCloudRun = checkCloudRun;
|
|
|
616
616
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
617
617
|
exports.checkGithub = void 0;
|
|
618
618
|
const pipeline_1 = __nccwpck_require__(53695);
|
|
619
|
-
const
|
|
619
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
620
620
|
const concurrency_1 = __nccwpck_require__(59723);
|
|
621
621
|
const github_1 = __nccwpck_require__(41353);
|
|
622
622
|
const githubMergeGating_1 = __nccwpck_require__(14966);
|
|
@@ -637,14 +637,14 @@ const checkGithub = async (report, config) => {
|
|
|
637
637
|
report.warn("github cli (gh) not authenticated — github checks skipped", "run: gh auth login");
|
|
638
638
|
return;
|
|
639
639
|
}
|
|
640
|
-
const repo = await (0,
|
|
640
|
+
const repo = await (0, secrets_1.getConfiguredGithubRepo)();
|
|
641
641
|
if (!repo) {
|
|
642
642
|
report.fail(`no github repository found on the '${(0, pipeline_1.getPipelineGitRemote)(config, "github")}' remote`);
|
|
643
643
|
return;
|
|
644
644
|
}
|
|
645
645
|
let targets;
|
|
646
646
|
try {
|
|
647
|
-
targets = await (0,
|
|
647
|
+
targets = await (0, secrets_1.collectSecretTargets)(config);
|
|
648
648
|
}
|
|
649
649
|
catch (e) {
|
|
650
650
|
report.warn(`could not generate the github workflows to derive secret references (${e.message})`);
|
|
@@ -1260,10 +1260,10 @@ const setupAccessTokens = async (instance) => {
|
|
|
1260
1260
|
await (0, gitlab_1.doGitlabRequest)(instance, `projects/${projectId}/variables/GL_TOKEN`, { value: newToken.token }, "PUT");
|
|
1261
1261
|
}
|
|
1262
1262
|
catch (e) {
|
|
1263
|
-
if (e
|
|
1263
|
+
if (!(e instanceof gitlab_1.GitlabNotFoundError)) {
|
|
1264
1264
|
throw e;
|
|
1265
1265
|
}
|
|
1266
|
-
// not
|
|
1266
|
+
// the variable does not exist yet: create it
|
|
1267
1267
|
await (0, gitlab_1.doGitlabRequest)(instance, `projects/${projectId}/variables`, {
|
|
1268
1268
|
key: "GL_TOKEN",
|
|
1269
1269
|
value: newToken.token,
|
|
@@ -1566,7 +1566,7 @@ const promises_1 = __nccwpck_require__(91943);
|
|
|
1566
1566
|
const os_1 = __nccwpck_require__(70857);
|
|
1567
1567
|
const path_1 = __nccwpck_require__(16928);
|
|
1568
1568
|
const util_1 = __nccwpck_require__(39023);
|
|
1569
|
-
const
|
|
1569
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
1570
1570
|
const github_1 = __nccwpck_require__(41353);
|
|
1571
1571
|
const githubMergeGating_1 = __nccwpck_require__(14966);
|
|
1572
1572
|
const execFile = (0, util_1.promisify)(child_process_1.execFile);
|
|
@@ -1600,7 +1600,7 @@ const setupGithub = async (instance, config) => {
|
|
|
1600
1600
|
instance.log("⚠️ github cli (gh) not authenticated — skipping github merge-gating setup (run: gh auth login)");
|
|
1601
1601
|
return;
|
|
1602
1602
|
}
|
|
1603
|
-
const repo = await (0,
|
|
1603
|
+
const repo = await (0, secrets_1.getConfiguredGithubRepo)();
|
|
1604
1604
|
if (!repo) {
|
|
1605
1605
|
instance.log(`⚠️ no github repository found on the '${(0, pipeline_1.getPipelineGitRemote)(config, "github")}' remote — skipping github merge-gating setup`);
|
|
1606
1606
|
return;
|
|
@@ -1770,15 +1770,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
1770
1770
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
1771
1771
|
exports.setupKubernetes = void 0;
|
|
1772
1772
|
const pipeline_1 = __nccwpck_require__(53695);
|
|
1773
|
+
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
1773
1774
|
const child_process_promise_1 = __nccwpck_require__(11542);
|
|
1775
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
1774
1776
|
const cluster_1 = __nccwpck_require__(8034);
|
|
1775
1777
|
const gitlab_1 = __nccwpck_require__(17697);
|
|
1776
1778
|
const ensureNamespace_1 = __importDefault(__nccwpck_require__(308));
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1779
|
+
/**
|
|
1780
|
+
* the cluster pulls the images from the gitlab container registry, and
|
|
1781
|
+
* a deploy token is how it authenticates there. Nothing to do when the
|
|
1782
|
+
* project has no gitlab pipeline (the images live elsewhere then).
|
|
1783
|
+
*/
|
|
1784
|
+
const ensureGitlabDeployToken = async (instance, config) => {
|
|
1785
|
+
if (!config || !(0, pipeline_1.getEnabledPipelineTypes)(config).includes("gitlab")) {
|
|
1786
|
+
return;
|
|
1782
1787
|
}
|
|
1783
1788
|
const { id: projectId } = await (0, gitlab_1.getProjectInfo)(instance);
|
|
1784
1789
|
const deploy_tokens = await (0, gitlab_1.doGitlabRequest)(instance, `projects/${projectId}/deploy_tokens`);
|
|
@@ -1790,6 +1795,14 @@ const setupKubernetes = async (instance, context) => {
|
|
|
1790
1795
|
scopes: ["read_registry"],
|
|
1791
1796
|
}, "POST");
|
|
1792
1797
|
}
|
|
1798
|
+
};
|
|
1799
|
+
const setupKubernetes = async (instance, context) => {
|
|
1800
|
+
var _a;
|
|
1801
|
+
const deployConfig = (_a = context.deploy) === null || _a === void 0 ? void 0 : _a.config;
|
|
1802
|
+
if (!(0, pipeline_1.isOfDeployType)(deployConfig, "kubernetes")) {
|
|
1803
|
+
throw new Error("cannot run setupKubernetes on non-kubernetes deployments");
|
|
1804
|
+
}
|
|
1805
|
+
await ensureGitlabDeployToken(instance, await (0, getProjectConfig_1.getProjectConfig)());
|
|
1793
1806
|
const fullName = (0, pipeline_1.getFullKubernetesClusterName)(deployConfig.cluster);
|
|
1794
1807
|
instance.log(`cluster: ${fullName}`);
|
|
1795
1808
|
await (0, cluster_1.connectToCluster)(fullName);
|
|
@@ -1872,8 +1885,11 @@ EOF
|
|
|
1872
1885
|
}
|
|
1873
1886
|
instance.log("service accounts created / updated!");
|
|
1874
1887
|
instance.log("");
|
|
1875
|
-
instance.log("
|
|
1876
|
-
await (0,
|
|
1888
|
+
instance.log("storing the cluster credentials...");
|
|
1889
|
+
await (0, secrets_1.writeSecretsAndMirror)(instance, [{ env: context.env, componentName: context.name, secrets: vars }],
|
|
1890
|
+
// the service account token is recreated on every run — the
|
|
1891
|
+
// previous one is worth nothing
|
|
1892
|
+
{ backup: false });
|
|
1877
1893
|
instance.log("done!");
|
|
1878
1894
|
};
|
|
1879
1895
|
exports.setupKubernetes = setupKubernetes;
|
|
@@ -2719,7 +2735,7 @@ exports.commandKubeStopPortforward = (0, defineCommand_1.defineCommand)({
|
|
|
2719
2735
|
"use strict";
|
|
2720
2736
|
|
|
2721
2737
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2722
|
-
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;
|
|
2738
|
+
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.commandMrUnpin = exports.commandMrPin = 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;
|
|
2723
2739
|
// General commands
|
|
2724
2740
|
var commandKubeCurrentContext_1 = __nccwpck_require__(78034);
|
|
2725
2741
|
Object.defineProperty(exports, "commandKubeCurrentContext", ({ enumerable: true, get: function () { return commandKubeCurrentContext_1.commandKubeCurrentContext; } }));
|
|
@@ -2779,6 +2795,9 @@ var commandProjectRestoreDb_1 = __nccwpck_require__(69233);
|
|
|
2779
2795
|
Object.defineProperty(exports, "commandProjectRestoreDb", ({ enumerable: true, get: function () { return commandProjectRestoreDb_1.commandProjectRestoreDb; } }));
|
|
2780
2796
|
var commandSecurityEvaluate_1 = __nccwpck_require__(86851);
|
|
2781
2797
|
Object.defineProperty(exports, "commandSecurityEvaluate", ({ enumerable: true, get: function () { return commandSecurityEvaluate_1.commandSecurityEvaluate; } }));
|
|
2798
|
+
var commandMrPin_1 = __nccwpck_require__(31318);
|
|
2799
|
+
Object.defineProperty(exports, "commandMrPin", ({ enumerable: true, get: function () { return commandMrPin_1.commandMrPin; } }));
|
|
2800
|
+
Object.defineProperty(exports, "commandMrUnpin", ({ enumerable: true, get: function () { return commandMrPin_1.commandMrUnpin; } }));
|
|
2782
2801
|
// Project k8s commands
|
|
2783
2802
|
var commandNamespace_1 = __nccwpck_require__(25918);
|
|
2784
2803
|
Object.defineProperty(exports, "commandNamespace", ({ enumerable: true, get: function () { return commandNamespace_1.commandNamespace; } }));
|
|
@@ -3175,6 +3194,7 @@ const common_tags_1 = __nccwpck_require__(110);
|
|
|
3175
3194
|
const defineCommand_1 = __nccwpck_require__(19096);
|
|
3176
3195
|
const editAsFile_1 = __nccwpck_require__(3072);
|
|
3177
3196
|
const promise_1 = __nccwpck_require__(23161);
|
|
3197
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
3178
3198
|
const document_1 = __nccwpck_require__(96716);
|
|
3179
3199
|
const scope_1 = __nccwpck_require__(8513);
|
|
3180
3200
|
const parseKeysInput_1 = __nccwpck_require__(93560);
|
|
@@ -3237,7 +3257,7 @@ exports.commandConfigSecrets = (0, defineCommand_1.defineCommand)({
|
|
|
3237
3257
|
ctx.log("⏭️ these secrets are still unset and will not be written:");
|
|
3238
3258
|
skipped.forEach((entry) => ctx.log(` - ${entry}`));
|
|
3239
3259
|
}
|
|
3240
|
-
await (0,
|
|
3260
|
+
await (0, secrets_1.writeSecretsAndMirror)(ctx, writes);
|
|
3241
3261
|
ctx.log("done! 😻");
|
|
3242
3262
|
ctx.log("");
|
|
3243
3263
|
},
|
|
@@ -3442,6 +3462,132 @@ exports.commandCiJobLog = (0, defineCommand_1.defineCommand)({
|
|
|
3442
3462
|
|
|
3443
3463
|
/***/ }),
|
|
3444
3464
|
|
|
3465
|
+
/***/ 31318:
|
|
3466
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
3467
|
+
|
|
3468
|
+
"use strict";
|
|
3469
|
+
|
|
3470
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
3471
|
+
exports.commandMrUnpin = exports.commandMrPin = void 0;
|
|
3472
|
+
const child_process_promise_1 = __nccwpck_require__(11542);
|
|
3473
|
+
const pipeline_1 = __nccwpck_require__(53695);
|
|
3474
|
+
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
3475
|
+
const defineCommand_1 = __nccwpck_require__(19096);
|
|
3476
|
+
const gitlab_1 = __nccwpck_require__(17697);
|
|
3477
|
+
const PIN_LABEL_COLOR = "#428fdc";
|
|
3478
|
+
/**
|
|
3479
|
+
* the configured pin label — errors when the project cannot pin
|
|
3480
|
+
* (github-only, or pinning disabled)
|
|
3481
|
+
*/
|
|
3482
|
+
const getPinLabel = async () => {
|
|
3483
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
3484
|
+
if (!config) {
|
|
3485
|
+
throw new Error("no catladder config found");
|
|
3486
|
+
}
|
|
3487
|
+
if (!(0, pipeline_1.getEnabledPipelineTypes)(config).includes("gitlab")) {
|
|
3488
|
+
throw new Error("pinning review apps needs the gitlab pipeline — github has no auto-stop, review apps live until the pull request is closed");
|
|
3489
|
+
}
|
|
3490
|
+
const { pinLabel } = (0, pipeline_1.getAutoStopConfig)(config);
|
|
3491
|
+
if (pinLabel === false) {
|
|
3492
|
+
throw new Error("review-app pinning is disabled in this project (autoStop.pinLabel: false)");
|
|
3493
|
+
}
|
|
3494
|
+
return pinLabel;
|
|
3495
|
+
};
|
|
3496
|
+
const findMr = async (io, projectId, mrIid) => {
|
|
3497
|
+
if (mrIid) {
|
|
3498
|
+
return (0, gitlab_1.doGitlabRequest)(io, `projects/${projectId}/merge_requests/${mrIid}`);
|
|
3499
|
+
}
|
|
3500
|
+
const branch = (await (0, child_process_promise_1.exec)("git rev-parse --abbrev-ref HEAD")).stdout.trim();
|
|
3501
|
+
const mrs = await (0, gitlab_1.doGitlabRequest)(io, `projects/${projectId}/merge_requests?state=opened&source_branch=${encodeURIComponent(branch)}`);
|
|
3502
|
+
if (!(mrs === null || mrs === void 0 ? void 0 : mrs.length)) {
|
|
3503
|
+
throw new Error(`no open merge request found for branch '${branch}' — pass one with --mr <iid>`);
|
|
3504
|
+
}
|
|
3505
|
+
return mrs[0];
|
|
3506
|
+
};
|
|
3507
|
+
const ensurePinLabelExists = async (io, projectId, pinLabel) => {
|
|
3508
|
+
const existing = await (0, gitlab_1.doGitlabRequest)(io, `projects/${projectId}/labels?search=${encodeURIComponent(pinLabel)}`);
|
|
3509
|
+
if (existing === null || existing === void 0 ? void 0 : existing.some((label) => label.name === pinLabel)) {
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
await (0, gitlab_1.doGitlabRequest)(io, `projects/${projectId}/labels`, {
|
|
3513
|
+
name: pinLabel,
|
|
3514
|
+
color: PIN_LABEL_COLOR,
|
|
3515
|
+
description: "review apps of this MR are pinned — deploys use auto_stop_in: never (managed by catladder)",
|
|
3516
|
+
}, "POST");
|
|
3517
|
+
io.log(`created the '${pinLabel}' label in the project`);
|
|
3518
|
+
};
|
|
3519
|
+
exports.commandMrPin = (0, defineCommand_1.defineCommand)({
|
|
3520
|
+
name: "mr pin",
|
|
3521
|
+
description: "pin the review apps of a merge request (disable their auto-stop) by adding the pin label; merging or closing the MR still stops them",
|
|
3522
|
+
group: "mr",
|
|
3523
|
+
inputs: {
|
|
3524
|
+
mr: {
|
|
3525
|
+
type: "number",
|
|
3526
|
+
message: "merge request IID (defaults to the open MR of the current branch)",
|
|
3527
|
+
positional: true,
|
|
3528
|
+
required: false,
|
|
3529
|
+
},
|
|
3530
|
+
pipeline: {
|
|
3531
|
+
type: "boolean",
|
|
3532
|
+
message: "trigger a merge-request pipeline so the pin takes effect immediately",
|
|
3533
|
+
required: false,
|
|
3534
|
+
},
|
|
3535
|
+
},
|
|
3536
|
+
execute: async (ctx) => {
|
|
3537
|
+
var _a, _b;
|
|
3538
|
+
const pinLabel = await getPinLabel();
|
|
3539
|
+
const { id: projectId } = await (0, gitlab_1.getProjectInfo)(ctx);
|
|
3540
|
+
const mr = await findMr(ctx, projectId, await ctx.get("mr"));
|
|
3541
|
+
await ensurePinLabelExists(ctx, projectId, pinLabel);
|
|
3542
|
+
if ((_a = mr.labels) === null || _a === void 0 ? void 0 : _a.includes(pinLabel)) {
|
|
3543
|
+
ctx.log(`already pinned: mr!${mr.iid} carries the '${pinLabel}' label`);
|
|
3544
|
+
}
|
|
3545
|
+
else {
|
|
3546
|
+
await (0, gitlab_1.doGitlabRequest)(ctx, `projects/${projectId}/merge_requests/${mr.iid}`, { add_labels: pinLabel }, "PUT");
|
|
3547
|
+
ctx.log(`📌 pinned mr!${mr.iid} "${mr.title}" — label '${pinLabel}' added`);
|
|
3548
|
+
}
|
|
3549
|
+
// the label only affects pipelines created after it was set, so
|
|
3550
|
+
// trigger one — otherwise the currently deployed review apps keep
|
|
3551
|
+
// their old auto-stop timer until the next push
|
|
3552
|
+
if ((_b = (await ctx.get("pipeline"))) !== null && _b !== void 0 ? _b : true) {
|
|
3553
|
+
const pipeline = await (0, gitlab_1.doGitlabRequest)(ctx, `projects/${projectId}/merge_requests/${mr.iid}/pipelines`, {}, "POST");
|
|
3554
|
+
ctx.log(`🚀 triggered a pipeline so the pin takes effect now: ${pipeline.web_url}`);
|
|
3555
|
+
}
|
|
3556
|
+
else {
|
|
3557
|
+
ctx.log("the pin takes effect with the next pipeline of the MR");
|
|
3558
|
+
}
|
|
3559
|
+
},
|
|
3560
|
+
});
|
|
3561
|
+
exports.commandMrUnpin = (0, defineCommand_1.defineCommand)({
|
|
3562
|
+
name: "mr unpin",
|
|
3563
|
+
description: "unpin the review apps of a merge request — the auto-stop timer re-arms with the next deploy",
|
|
3564
|
+
group: "mr",
|
|
3565
|
+
inputs: {
|
|
3566
|
+
mr: {
|
|
3567
|
+
type: "number",
|
|
3568
|
+
message: "merge request IID (defaults to the open MR of the current branch)",
|
|
3569
|
+
positional: true,
|
|
3570
|
+
required: false,
|
|
3571
|
+
},
|
|
3572
|
+
},
|
|
3573
|
+
execute: async (ctx) => {
|
|
3574
|
+
var _a;
|
|
3575
|
+
const pinLabel = await getPinLabel();
|
|
3576
|
+
const { id: projectId } = await (0, gitlab_1.getProjectInfo)(ctx);
|
|
3577
|
+
const mr = await findMr(ctx, projectId, await ctx.get("mr"));
|
|
3578
|
+
if (!((_a = mr.labels) === null || _a === void 0 ? void 0 : _a.includes(pinLabel))) {
|
|
3579
|
+
ctx.log(`mr!${mr.iid} is not pinned (no '${pinLabel}' label)`);
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3582
|
+
await (0, gitlab_1.doGitlabRequest)(ctx, `projects/${projectId}/merge_requests/${mr.iid}`, { remove_labels: pinLabel }, "PUT");
|
|
3583
|
+
ctx.log(`unpinned mr!${mr.iid} — label '${pinLabel}' removed`);
|
|
3584
|
+
ctx.log("the deployed review apps stay pinned until the next deploy re-arms their auto-stop timer");
|
|
3585
|
+
},
|
|
3586
|
+
});
|
|
3587
|
+
//# sourceMappingURL=commandMrPin.js.map
|
|
3588
|
+
|
|
3589
|
+
/***/ }),
|
|
3590
|
+
|
|
3445
3591
|
/***/ 30119:
|
|
3446
3592
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
3447
3593
|
|
|
@@ -3874,131 +4020,12 @@ exports.commandSecretsClearBackups = (0, defineCommand_1.defineCommand)({
|
|
|
3874
4020
|
"use strict";
|
|
3875
4021
|
|
|
3876
4022
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
3877
|
-
exports.commandSecretsSyncGithub =
|
|
4023
|
+
exports.commandSecretsSyncGithub = void 0;
|
|
3878
4024
|
const pipeline_1 = __nccwpck_require__(53695);
|
|
3879
4025
|
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
3880
4026
|
const defineCommand_1 = __nccwpck_require__(19096);
|
|
4027
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
3881
4028
|
const github_1 = __nccwpck_require__(41353);
|
|
3882
|
-
/**
|
|
3883
|
-
* all secrets declared in the config, with their values read from the
|
|
3884
|
-
* vault (github secrets are write-only and can never act as a source)
|
|
3885
|
-
*/
|
|
3886
|
-
const collectSecretsFromVault = async (io, envFilter) => {
|
|
3887
|
-
const envAndComponents = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
3888
|
-
const kinds = new Map();
|
|
3889
|
-
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
3890
|
-
for (const env of envs) {
|
|
3891
|
-
if (envFilter && !envFilter.includes(env)) {
|
|
3892
|
-
continue;
|
|
3893
|
-
}
|
|
3894
|
-
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
3895
|
-
const keys = [
|
|
3896
|
-
...secretEnvVarKeys,
|
|
3897
|
-
...jobOnlyVars.build.secretEnvVarKeys,
|
|
3898
|
-
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
3899
|
-
];
|
|
3900
|
-
keys.forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
3901
|
-
}
|
|
3902
|
-
}
|
|
3903
|
-
const names = [...kinds.keys()];
|
|
3904
|
-
const values = await (await io.getVaultManager()).readSecrets(names, io);
|
|
3905
|
-
const secrets = names
|
|
3906
|
-
.filter((name) => values[name] !== undefined)
|
|
3907
|
-
.map((name) => {
|
|
3908
|
-
var _a;
|
|
3909
|
-
return ({
|
|
3910
|
-
name,
|
|
3911
|
-
value: values[name],
|
|
3912
|
-
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
|
|
3913
|
-
});
|
|
3914
|
-
});
|
|
3915
|
-
const missing = names.filter((name) => values[name] === undefined);
|
|
3916
|
-
return { secrets, missing };
|
|
3917
|
-
};
|
|
3918
|
-
exports.collectSecretsFromVault = collectSecretsFromVault;
|
|
3919
|
-
/** marker for repo-level (environment-less) targets */
|
|
3920
|
-
const REPO_LEVEL = "";
|
|
3921
|
-
/**
|
|
3922
|
-
* derives which github environment(s) each secret/variable must live in
|
|
3923
|
-
* by scanning the GENERATED workflows: a `${{ secrets.X }}` / `${{
|
|
3924
|
-
* vars.X }}` reference in a job's env targets that job's environment
|
|
3925
|
-
* (or the repo level when the job has none). Deriving from the real
|
|
3926
|
-
* output means the sync can never drift from what the workflows expect.
|
|
3927
|
-
*
|
|
3928
|
-
* Environment secrets are the answer to github's cap of 100 secrets
|
|
3929
|
-
* per REPO (a multi-env project easily exceeds it): the cap applies
|
|
3930
|
-
* per environment instead.
|
|
3931
|
-
*/
|
|
3932
|
-
const collectSecretTargets = async (config) => {
|
|
3933
|
-
var _a;
|
|
3934
|
-
const workflows = await new pipeline_1.GithubBackend().createWorkflows(config);
|
|
3935
|
-
const targets = new Map();
|
|
3936
|
-
for (const workflow of Object.values(workflows)) {
|
|
3937
|
-
for (const job of Object.values(workflow.jobs)) {
|
|
3938
|
-
const environment = typeof job.environment === "object"
|
|
3939
|
-
? job.environment.name
|
|
3940
|
-
: job.environment;
|
|
3941
|
-
for (const value of Object.values((_a = job.env) !== null && _a !== void 0 ? _a : {})) {
|
|
3942
|
-
if (typeof value !== "string")
|
|
3943
|
-
continue;
|
|
3944
|
-
for (const match of value.matchAll(/\$\{\{\s*(?:secrets|vars)\.([A-Za-z0-9_]+)\s*\}\}/g)) {
|
|
3945
|
-
const name = match[1];
|
|
3946
|
-
if (!targets.has(name)) {
|
|
3947
|
-
targets.set(name, new Set());
|
|
3948
|
-
}
|
|
3949
|
-
targets.get(name).add(environment !== null && environment !== void 0 ? environment : REPO_LEVEL);
|
|
3950
|
-
}
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
}
|
|
3954
|
-
return targets;
|
|
3955
|
-
};
|
|
3956
|
-
exports.collectSecretTargets = collectSecretTargets;
|
|
3957
|
-
/**
|
|
3958
|
-
* pushes vault values to github via the gh cli: sensitive ones as
|
|
3959
|
-
* secrets (masked), "variable"-kind ones as variables (plain) — each
|
|
3960
|
-
* into the environment(s) whose jobs reference them
|
|
3961
|
-
*/
|
|
3962
|
-
const pushSecretsToGithub = async (io, repo, secrets, targets) => {
|
|
3963
|
-
const environments = [
|
|
3964
|
-
...new Set([...targets.values()].flatMap((envs) => [...envs].filter((env) => env !== REPO_LEVEL))),
|
|
3965
|
-
];
|
|
3966
|
-
for (const environment of environments) {
|
|
3967
|
-
await (0, github_1.ensureGithubEnvironment)(repo, environment);
|
|
3968
|
-
io.log(`🌍 environment ${environment}`);
|
|
3969
|
-
}
|
|
3970
|
-
for (const { name, value, kind } of secrets) {
|
|
3971
|
-
const envs = targets.get(name);
|
|
3972
|
-
if (!envs) {
|
|
3973
|
-
io.log(`⏭️ ${name} (not referenced by any generated workflow)`);
|
|
3974
|
-
continue;
|
|
3975
|
-
}
|
|
3976
|
-
for (const environment of envs) {
|
|
3977
|
-
const suffix = environment === REPO_LEVEL ? "" : ` → ${environment}`;
|
|
3978
|
-
if (kind === "variable") {
|
|
3979
|
-
await (0, github_1.setGithubVariable)(repo, name, value, environment || undefined);
|
|
3980
|
-
io.log(`📖 ${name} (variable)${suffix}`);
|
|
3981
|
-
}
|
|
3982
|
-
else {
|
|
3983
|
-
await (0, github_1.setGithubSecret)(repo, name, value, environment || undefined);
|
|
3984
|
-
io.log(`✅ ${name}${suffix}`);
|
|
3985
|
-
}
|
|
3986
|
-
}
|
|
3987
|
-
}
|
|
3988
|
-
};
|
|
3989
|
-
exports.pushSecretsToGithub = pushSecretsToGithub;
|
|
3990
|
-
/**
|
|
3991
|
-
* resolves the github repository from the configured git remote
|
|
3992
|
-
* (`pipelines.github.gitRemote`, defaults to origin)
|
|
3993
|
-
*/
|
|
3994
|
-
const getConfiguredGithubRepo = async () => {
|
|
3995
|
-
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
3996
|
-
if (!config) {
|
|
3997
|
-
return undefined;
|
|
3998
|
-
}
|
|
3999
|
-
return (0, github_1.getGithubRepoFromRemote)((0, pipeline_1.getPipelineGitRemote)(config, "github"));
|
|
4000
|
-
};
|
|
4001
|
-
exports.getConfiguredGithubRepo = getConfiguredGithubRepo;
|
|
4002
4029
|
/**
|
|
4003
4030
|
* copies the catladder secrets from the vault to github actions
|
|
4004
4031
|
* repository secrets, keeping the exact same names, so the github
|
|
@@ -4035,12 +4062,12 @@ exports.commandSecretsSyncGithub = (0, defineCommand_1.defineCommand)({
|
|
|
4035
4062
|
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
4036
4063
|
throw new Error("the github cli (gh) is not installed or not authenticated — run `gh auth login` first");
|
|
4037
4064
|
}
|
|
4038
|
-
const repo = (_a = (await ctx.get("repo"))) !== null && _a !== void 0 ? _a : (await (0,
|
|
4065
|
+
const repo = (_a = (await ctx.get("repo"))) !== null && _a !== void 0 ? _a : (await (0, secrets_1.getConfiguredGithubRepo)());
|
|
4039
4066
|
if (!repo) {
|
|
4040
4067
|
throw new Error(`no github repository found on the '${(0, pipeline_1.getPipelineGitRemote)(config, "github")}' remote — pass it as owner/name or configure pipelines.github.gitRemote`);
|
|
4041
4068
|
}
|
|
4042
4069
|
const envFilter = (_b = (await ctx.get("env"))) === null || _b === void 0 ? void 0 : _b.split(",").map((e) => e.trim());
|
|
4043
|
-
const { secrets, missing } = await (0,
|
|
4070
|
+
const { secrets, missing } = await (0, secrets_1.collectSecretsFromVault)(ctx, envFilter);
|
|
4044
4071
|
if (missing.length > 0) {
|
|
4045
4072
|
ctx.log(`⚠️ ${missing.length} secrets are not set in the vault and will be skipped:`);
|
|
4046
4073
|
missing.forEach((name) => ctx.log(` - ${name}`));
|
|
@@ -4057,7 +4084,7 @@ exports.commandSecretsSyncGithub = (0, defineCommand_1.defineCommand)({
|
|
|
4057
4084
|
if (!confirmed) {
|
|
4058
4085
|
throw new Error("abort");
|
|
4059
4086
|
}
|
|
4060
|
-
await (0,
|
|
4087
|
+
await (0, secrets_1.pushSecretsToGithub)(ctx, repo, secrets, await (0, secrets_1.collectSecretTargets)(config));
|
|
4061
4088
|
ctx.log("");
|
|
4062
4089
|
ctx.log("done! 😻 the github pipeline can use them as ${{ secrets.<NAME> }}");
|
|
4063
4090
|
},
|
|
@@ -4621,6 +4648,7 @@ const fs_extra_1 = __nccwpck_require__(20925);
|
|
|
4621
4648
|
const yaml_1 = __nccwpck_require__(99292);
|
|
4622
4649
|
const defineCommand_1 = __nccwpck_require__(19096);
|
|
4623
4650
|
const readStdin_1 = __nccwpck_require__(89973);
|
|
4651
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
4624
4652
|
const document_1 = __nccwpck_require__(96716);
|
|
4625
4653
|
const scope_1 = __nccwpck_require__(8513);
|
|
4626
4654
|
const parseKeysInput_1 = __nccwpck_require__(93560);
|
|
@@ -4683,7 +4711,7 @@ exports.commandSecretsPush = (0, defineCommand_1.defineCommand)({
|
|
|
4683
4711
|
if (!confirmed) {
|
|
4684
4712
|
throw new Error("abort");
|
|
4685
4713
|
}
|
|
4686
|
-
await (0,
|
|
4714
|
+
await (0, secrets_1.writeSecretsAndMirror)(ctx, writes);
|
|
4687
4715
|
ctx.log("done! 😻");
|
|
4688
4716
|
},
|
|
4689
4717
|
});
|
|
@@ -4701,7 +4729,7 @@ exports.commandSecretsSet = void 0;
|
|
|
4701
4729
|
const fs_extra_1 = __nccwpck_require__(20925);
|
|
4702
4730
|
const defineCommand_1 = __nccwpck_require__(19096);
|
|
4703
4731
|
const readStdin_1 = __nccwpck_require__(89973);
|
|
4704
|
-
const
|
|
4732
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
4705
4733
|
const scope_1 = __nccwpck_require__(8513);
|
|
4706
4734
|
const resolveValue = async (io, value, valueFile) => {
|
|
4707
4735
|
if (valueFile) {
|
|
@@ -4772,7 +4800,7 @@ exports.commandSecretsSet = (0, defineCommand_1.defineCommand)({
|
|
|
4772
4800
|
componentName,
|
|
4773
4801
|
secrets: { [key]: value },
|
|
4774
4802
|
}));
|
|
4775
|
-
await (0,
|
|
4803
|
+
await (0, secrets_1.writeSecretsAndMirror)(ctx, writes);
|
|
4776
4804
|
ctx.log("done! 😻");
|
|
4777
4805
|
},
|
|
4778
4806
|
});
|
|
@@ -4786,12 +4814,8 @@ exports.commandSecretsSet = (0, defineCommand_1.defineCommand)({
|
|
|
4786
4814
|
"use strict";
|
|
4787
4815
|
|
|
4788
4816
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4789
|
-
exports.
|
|
4817
|
+
exports.collectSecretsWrites = exports.checkSecretsDocument = exports.buildSecretsDocument = exports.FILL_ME = void 0;
|
|
4790
4818
|
const pipeline_1 = __nccwpck_require__(53695);
|
|
4791
|
-
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
4792
|
-
const github_1 = __nccwpck_require__(41353);
|
|
4793
|
-
const gitlab_1 = __nccwpck_require__(17697);
|
|
4794
|
-
const commandSecretsSyncGithub_1 = __nccwpck_require__(27565);
|
|
4795
4819
|
/** placeholder for secrets that have no value in the vault yet */
|
|
4796
4820
|
exports.FILL_ME = "🚨 FILL ME";
|
|
4797
4821
|
/* for convenience, parse json values. that makes it easier to edit secrets that are objects */
|
|
@@ -4889,123 +4913,49 @@ const collectSecretsWrites = (document, scoped) => {
|
|
|
4889
4913
|
return { writes, skipped };
|
|
4890
4914
|
};
|
|
4891
4915
|
exports.collectSecretsWrites = collectSecretsWrites;
|
|
4916
|
+
//# sourceMappingURL=document.js.map
|
|
4917
|
+
|
|
4918
|
+
/***/ }),
|
|
4919
|
+
|
|
4920
|
+
/***/ 93560:
|
|
4921
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
4922
|
+
|
|
4923
|
+
"use strict";
|
|
4924
|
+
|
|
4925
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4926
|
+
exports.parseKeysInput = void 0;
|
|
4927
|
+
/** parses a comma-separated `--key` input into a list of keys */
|
|
4928
|
+
const parseKeysInput = (input) => {
|
|
4929
|
+
const keys = input === null || input === void 0 ? void 0 : input.split(",").map((key) => key.trim()).filter(Boolean);
|
|
4930
|
+
return keys && keys.length > 0 ? keys : undefined;
|
|
4931
|
+
};
|
|
4932
|
+
exports.parseKeysInput = parseKeysInput;
|
|
4933
|
+
//# sourceMappingURL=parseKeysInput.js.map
|
|
4934
|
+
|
|
4935
|
+
/***/ }),
|
|
4936
|
+
|
|
4937
|
+
/***/ 8513:
|
|
4938
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4939
|
+
|
|
4940
|
+
"use strict";
|
|
4941
|
+
|
|
4942
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4943
|
+
exports.formatScope = exports.getScopedSecretKeys = exports.getDeclaredSecretKeys = exports.secretsScopeChoices = exports.resolveSecretsScope = void 0;
|
|
4944
|
+
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
4892
4945
|
/**
|
|
4893
|
-
*
|
|
4894
|
-
*
|
|
4895
|
-
*
|
|
4946
|
+
* resolves a scope expression to component → envs:
|
|
4947
|
+
* - (empty): all components, all envs
|
|
4948
|
+
* - `env:component`: one env of one component
|
|
4949
|
+
* - `env` / `env:`: one env, every component that has it
|
|
4950
|
+
* - `:component`: every env of one component
|
|
4896
4951
|
*/
|
|
4897
|
-
const
|
|
4898
|
-
const
|
|
4899
|
-
if (
|
|
4952
|
+
const resolveSecretsScope = async (scope) => {
|
|
4953
|
+
const all = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
4954
|
+
if (Object.keys(all).length === 0) {
|
|
4900
4955
|
throw new Error("no catladder config found");
|
|
4901
4956
|
}
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
io.log("");
|
|
4905
|
-
for (const { env, componentName, secrets } of writes) {
|
|
4906
|
-
io.log("writing " + env + ":" + componentName + "...\n");
|
|
4907
|
-
await (await io.getVaultManager()).writeSecrets(env, componentName, secrets);
|
|
4908
|
-
io.log("");
|
|
4909
|
-
io.log("✅ " + env + ":" + componentName);
|
|
4910
|
-
io.log("--------------------------------\n");
|
|
4911
|
-
}
|
|
4912
|
-
await mirrorSecretsToCiBackends(io, config, writes);
|
|
4913
|
-
};
|
|
4914
|
-
exports.writeSecretsAndMirror = writeSecretsAndMirror;
|
|
4915
|
-
/**
|
|
4916
|
-
* the vault is the source of truth; every enabled CI backend receives
|
|
4917
|
-
* a mirrored copy of the written secrets (gitlab variables, github
|
|
4918
|
-
* secrets), so all CI systems stay in sync
|
|
4919
|
-
*/
|
|
4920
|
-
const mirrorSecretsToCiBackends = async (io, config, writes) => {
|
|
4921
|
-
const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
|
|
4922
|
-
// gitlab mirror (unless gitlab is the vault itself, then it is
|
|
4923
|
-
// already written)
|
|
4924
|
-
if ((0, pipeline_1.getVaultConfig)(config).type !== "gitlab" && enabled.includes("gitlab")) {
|
|
4925
|
-
for (const { env, componentName, secrets } of writes) {
|
|
4926
|
-
await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName);
|
|
4927
|
-
}
|
|
4928
|
-
io.log("✅ mirrored to gitlab");
|
|
4929
|
-
}
|
|
4930
|
-
if (!enabled.includes("github")) {
|
|
4931
|
-
return;
|
|
4932
|
-
}
|
|
4933
|
-
const kinds = new Map();
|
|
4934
|
-
for (const { env, componentName } of writes) {
|
|
4935
|
-
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
4936
|
-
[
|
|
4937
|
-
...secretEnvVarKeys,
|
|
4938
|
-
...jobOnlyVars.build.secretEnvVarKeys,
|
|
4939
|
-
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
4940
|
-
].forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
4941
|
-
}
|
|
4942
|
-
const secrets = writes.flatMap(({ env, componentName, secrets }) => Object.entries(secrets).map(([key, value]) => {
|
|
4943
|
-
var _a;
|
|
4944
|
-
const name = (0, pipeline_1.getSecretVarName)(env, componentName, key);
|
|
4945
|
-
return {
|
|
4946
|
-
name,
|
|
4947
|
-
value: typeof value === "string" ? value : JSON.stringify(value !== null && value !== void 0 ? value : ""),
|
|
4948
|
-
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
|
|
4949
|
-
};
|
|
4950
|
-
}));
|
|
4951
|
-
if (secrets.length === 0) {
|
|
4952
|
-
return;
|
|
4953
|
-
}
|
|
4954
|
-
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
4955
|
-
io.log("⚠️ github pipeline is enabled, but the github cli (gh) is not authenticated — run `project secrets-sync-github` later to mirror the secrets");
|
|
4956
|
-
return;
|
|
4957
|
-
}
|
|
4958
|
-
const repo = await (0, commandSecretsSyncGithub_1.getConfiguredGithubRepo)();
|
|
4959
|
-
if (!repo) {
|
|
4960
|
-
io.log("⚠️ github pipeline is enabled, but no github repository was found — run `project secrets-sync-github` later to mirror the secrets");
|
|
4961
|
-
return;
|
|
4962
|
-
}
|
|
4963
|
-
io.log(`mirroring ${secrets.length} secrets to github ('${repo}')...`);
|
|
4964
|
-
await (0, commandSecretsSyncGithub_1.pushSecretsToGithub)(io, repo, secrets, await (0, commandSecretsSyncGithub_1.collectSecretTargets)(config));
|
|
4965
|
-
};
|
|
4966
|
-
//# sourceMappingURL=document.js.map
|
|
4967
|
-
|
|
4968
|
-
/***/ }),
|
|
4969
|
-
|
|
4970
|
-
/***/ 93560:
|
|
4971
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
4972
|
-
|
|
4973
|
-
"use strict";
|
|
4974
|
-
|
|
4975
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4976
|
-
exports.parseKeysInput = void 0;
|
|
4977
|
-
/** parses a comma-separated `--key` input into a list of keys */
|
|
4978
|
-
const parseKeysInput = (input) => {
|
|
4979
|
-
const keys = input === null || input === void 0 ? void 0 : input.split(",").map((key) => key.trim()).filter(Boolean);
|
|
4980
|
-
return keys && keys.length > 0 ? keys : undefined;
|
|
4981
|
-
};
|
|
4982
|
-
exports.parseKeysInput = parseKeysInput;
|
|
4983
|
-
//# sourceMappingURL=parseKeysInput.js.map
|
|
4984
|
-
|
|
4985
|
-
/***/ }),
|
|
4986
|
-
|
|
4987
|
-
/***/ 8513:
|
|
4988
|
-
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
4989
|
-
|
|
4990
|
-
"use strict";
|
|
4991
|
-
|
|
4992
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
4993
|
-
exports.formatScope = exports.getScopedSecretKeys = exports.getDeclaredSecretKeys = exports.secretsScopeChoices = exports.resolveSecretsScope = void 0;
|
|
4994
|
-
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
4995
|
-
/**
|
|
4996
|
-
* resolves a scope expression to component → envs:
|
|
4997
|
-
* - (empty): all components, all envs
|
|
4998
|
-
* - `env:component`: one env of one component
|
|
4999
|
-
* - `env` / `env:`: one env, every component that has it
|
|
5000
|
-
* - `:component`: every env of one component
|
|
5001
|
-
*/
|
|
5002
|
-
const resolveSecretsScope = async (scope) => {
|
|
5003
|
-
const all = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
5004
|
-
if (Object.keys(all).length === 0) {
|
|
5005
|
-
throw new Error("no catladder config found");
|
|
5006
|
-
}
|
|
5007
|
-
if (!scope) {
|
|
5008
|
-
return all;
|
|
4957
|
+
if (!scope) {
|
|
4958
|
+
return all;
|
|
5009
4959
|
}
|
|
5010
4960
|
const [env, componentName] = scope.split(":").map((x) => x || null);
|
|
5011
4961
|
if (componentName && !(componentName in all)) {
|
|
@@ -6060,7 +6010,7 @@ const hash = (str, length) => {
|
|
|
6060
6010
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6061
6011
|
exports.upsertGcloudServiceAccountAndSaveSecret = exports.accountExists = void 0;
|
|
6062
6012
|
const child_process_promise_1 = __nccwpck_require__(11542);
|
|
6063
|
-
const
|
|
6013
|
+
const secrets_1 = __nccwpck_require__(85200);
|
|
6064
6014
|
const serviceAccountNames_1 = __nccwpck_require__(67851);
|
|
6065
6015
|
const accountExists = async (fullIdentifier) => {
|
|
6066
6016
|
try {
|
|
@@ -6097,9 +6047,20 @@ const upsertGcloudServiceAccount = async (context, account) => {
|
|
|
6097
6047
|
const upsertGcloudServiceAccountAndSaveSecret = async (instance, context, account, secretName) => {
|
|
6098
6048
|
instance.log("upserting service account " + account.name + "...");
|
|
6099
6049
|
const key = await upsertGcloudServiceAccount(context, account);
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6050
|
+
// through the vault (and from there to every enabled ci backend) —
|
|
6051
|
+
// the key is a secret like any other, the deploy jobs read it under
|
|
6052
|
+
// its declared name. Writing it to gitlab directly would break every
|
|
6053
|
+
// project that has no gitlab.
|
|
6054
|
+
await (0, secrets_1.writeSecretsAndMirror)(instance, [
|
|
6055
|
+
{
|
|
6056
|
+
env: context.env,
|
|
6057
|
+
componentName: context.name,
|
|
6058
|
+
secrets: { [secretName]: key },
|
|
6059
|
+
},
|
|
6060
|
+
],
|
|
6061
|
+
// a fresh key is created on every run, the previous one is deleted
|
|
6062
|
+
// at google — a backup copy of it would only be a dead secret
|
|
6063
|
+
{ backup: false });
|
|
6103
6064
|
instance.log("done!");
|
|
6104
6065
|
};
|
|
6105
6066
|
exports.upsertGcloudServiceAccountAndSaveSecret = upsertGcloudServiceAccountAndSaveSecret;
|
|
@@ -6176,23 +6137,338 @@ const getGitRemoteHostAndPath = async (remoteName = "origin") => {
|
|
|
6176
6137
|
if (!(gitRemoteHost === null || gitRemoteHost === void 0 ? void 0 : gitRemoteHost.length) || !(gitRemotePath === null || gitRemotePath === void 0 ? void 0 : gitRemotePath.length)) {
|
|
6177
6138
|
throw new Error(`Failed to parse git remote hostname and path from git configs remote.${remoteName}.url! ${remoteUrl}`);
|
|
6178
6139
|
}
|
|
6179
|
-
return { gitRemoteHost, gitRemotePath };
|
|
6180
|
-
};
|
|
6181
|
-
exports.getGitRemoteHostAndPath = getGitRemoteHostAndPath;
|
|
6182
|
-
const gitProjectInformation = async () => {
|
|
6183
|
-
const [{ gitRemoteHost, gitRemotePath }, projectRootPath] = await Promise.all([(0, exports.getGitRemoteHostAndPath)(), (0, exports.getProjectRootPath)()]);
|
|
6184
|
-
return {
|
|
6185
|
-
gitRemoteHost,
|
|
6186
|
-
gitRemotePath,
|
|
6187
|
-
projectRootPath,
|
|
6188
|
-
};
|
|
6140
|
+
return { gitRemoteHost, gitRemotePath };
|
|
6141
|
+
};
|
|
6142
|
+
exports.getGitRemoteHostAndPath = getGitRemoteHostAndPath;
|
|
6143
|
+
const gitProjectInformation = async () => {
|
|
6144
|
+
const [{ gitRemoteHost, gitRemotePath }, projectRootPath] = await Promise.all([(0, exports.getGitRemoteHostAndPath)(), (0, exports.getProjectRootPath)()]);
|
|
6145
|
+
return {
|
|
6146
|
+
gitRemoteHost,
|
|
6147
|
+
gitRemotePath,
|
|
6148
|
+
projectRootPath,
|
|
6149
|
+
};
|
|
6150
|
+
};
|
|
6151
|
+
exports.gitProjectInformation = gitProjectInformation;
|
|
6152
|
+
//# sourceMappingURL=gitProjectInformation.js.map
|
|
6153
|
+
|
|
6154
|
+
/***/ }),
|
|
6155
|
+
|
|
6156
|
+
/***/ 77721:
|
|
6157
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
6158
|
+
|
|
6159
|
+
"use strict";
|
|
6160
|
+
|
|
6161
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6162
|
+
if (k2 === undefined) k2 = k;
|
|
6163
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6164
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6165
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
6166
|
+
}
|
|
6167
|
+
Object.defineProperty(o, k2, desc);
|
|
6168
|
+
}) : (function(o, m, k, k2) {
|
|
6169
|
+
if (k2 === undefined) k2 = k;
|
|
6170
|
+
o[k2] = m[k];
|
|
6171
|
+
}));
|
|
6172
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
6173
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
6174
|
+
};
|
|
6175
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6176
|
+
__exportStar(__nccwpck_require__(40403), exports);
|
|
6177
|
+
__exportStar(__nccwpck_require__(86884), exports);
|
|
6178
|
+
__exportStar(__nccwpck_require__(3328), exports);
|
|
6179
|
+
//# sourceMappingURL=index.js.map
|
|
6180
|
+
|
|
6181
|
+
/***/ }),
|
|
6182
|
+
|
|
6183
|
+
/***/ 32839:
|
|
6184
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6185
|
+
|
|
6186
|
+
"use strict";
|
|
6187
|
+
|
|
6188
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6189
|
+
exports.getk8sApiBatchBeta = exports.getk8sApiBatch = exports.getk8sApi = void 0;
|
|
6190
|
+
const client_node_1 = __nccwpck_require__(67235);
|
|
6191
|
+
const getKubeConfig = () => {
|
|
6192
|
+
const kc = new client_node_1.KubeConfig();
|
|
6193
|
+
kc.loadFromDefault();
|
|
6194
|
+
return kc;
|
|
6195
|
+
};
|
|
6196
|
+
/**
|
|
6197
|
+
* get kubernetes client. avoid reusing the instance when context get changed
|
|
6198
|
+
* @returns kuberenetes client
|
|
6199
|
+
*/
|
|
6200
|
+
const getk8sApi = () => {
|
|
6201
|
+
const kc = getKubeConfig();
|
|
6202
|
+
return kc.makeApiClient(client_node_1.CoreV1Api);
|
|
6203
|
+
};
|
|
6204
|
+
exports.getk8sApi = getk8sApi;
|
|
6205
|
+
const getk8sApiBatch = () => {
|
|
6206
|
+
const kc = getKubeConfig();
|
|
6207
|
+
return kc.makeApiClient(client_node_1.BatchV1Api);
|
|
6208
|
+
};
|
|
6209
|
+
exports.getk8sApiBatch = getk8sApiBatch;
|
|
6210
|
+
const getk8sApiBatchBeta = () => {
|
|
6211
|
+
const kc = getKubeConfig();
|
|
6212
|
+
return kc.makeApiClient(client_node_1.BatchV1beta1Api);
|
|
6213
|
+
};
|
|
6214
|
+
exports.getk8sApiBatchBeta = getk8sApiBatchBeta;
|
|
6215
|
+
//# sourceMappingURL=index.js.map
|
|
6216
|
+
|
|
6217
|
+
/***/ }),
|
|
6218
|
+
|
|
6219
|
+
/***/ 79107:
|
|
6220
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6221
|
+
|
|
6222
|
+
"use strict";
|
|
6223
|
+
|
|
6224
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6225
|
+
exports.getProjectPodNames = exports.getProjectPvcs = exports.getProjectPods = void 0;
|
|
6226
|
+
const parseChoice_1 = __nccwpck_require__(70769);
|
|
6227
|
+
const k8sApi_1 = __nccwpck_require__(32839);
|
|
6228
|
+
const projects_1 = __nccwpck_require__(20575);
|
|
6229
|
+
const getProjectPods = async (envComponent) => {
|
|
6230
|
+
const namespace = await (0, projects_1.getProjectNamespace)(envComponent);
|
|
6231
|
+
const k8sApi = (0, k8sApi_1.getk8sApi)();
|
|
6232
|
+
const res = await k8sApi.listNamespacedPod(namespace);
|
|
6233
|
+
const { componentName } = (0, parseChoice_1.parseChoice)(envComponent);
|
|
6234
|
+
return res.body.items.filter((item) => { var _a, _b; return componentName ? (_b = (_a = item.metadata) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.includes(componentName + "-") : true; });
|
|
6235
|
+
};
|
|
6236
|
+
exports.getProjectPods = getProjectPods;
|
|
6237
|
+
const getProjectPvcs = async (envComponent) => {
|
|
6238
|
+
const namespace = await (0, projects_1.getProjectNamespace)(envComponent);
|
|
6239
|
+
const k8sApi = (0, k8sApi_1.getk8sApi)();
|
|
6240
|
+
const res = await k8sApi.listNamespacedPersistentVolumeClaim(namespace);
|
|
6241
|
+
return res.body.items;
|
|
6242
|
+
};
|
|
6243
|
+
exports.getProjectPvcs = getProjectPvcs;
|
|
6244
|
+
const getProjectPodNames = async (envComponent) => {
|
|
6245
|
+
const pods = await (0, exports.getProjectPods)(envComponent);
|
|
6246
|
+
return pods.map((n) => n.metadata.name);
|
|
6247
|
+
};
|
|
6248
|
+
exports.getProjectPodNames = getProjectPodNames;
|
|
6249
|
+
//# sourceMappingURL=index.js.map
|
|
6250
|
+
|
|
6251
|
+
/***/ }),
|
|
6252
|
+
|
|
6253
|
+
/***/ 14178:
|
|
6254
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6255
|
+
|
|
6256
|
+
"use strict";
|
|
6257
|
+
|
|
6258
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6259
|
+
exports.openGoogleCloudKubernetesDashboard = exports.openGoogleCloudLogs = void 0;
|
|
6260
|
+
const pipeline_1 = __nccwpck_require__(53695);
|
|
6261
|
+
const openDashboard_1 = __nccwpck_require__(74241);
|
|
6262
|
+
const openGoogleCloudLogs = async (instance, context) => {
|
|
6263
|
+
var _a;
|
|
6264
|
+
const deployConfig = (_a = context.deploy) === null || _a === void 0 ? void 0 : _a.config;
|
|
6265
|
+
if (!(0, pipeline_1.isOfDeployType)(deployConfig, "kubernetes")) {
|
|
6266
|
+
throw new Error("context is not of type kubernetes");
|
|
6267
|
+
}
|
|
6268
|
+
if (!deployConfig.cluster || deployConfig.cluster.type !== "gcloud") {
|
|
6269
|
+
throw new Error("no gcloud custer configured");
|
|
6270
|
+
}
|
|
6271
|
+
const namespace = context.environment.envVars.KUBE_NAMESPACE;
|
|
6272
|
+
const cluster = deployConfig.cluster;
|
|
6273
|
+
const resource = `k8s_container/cluster_name/${cluster.name}${namespace ? `/namespace_name/${namespace}` : ""}`;
|
|
6274
|
+
await (0, openDashboard_1.openGoogleCloudDashboard)(instance, "logs/viewer", {
|
|
6275
|
+
project: cluster.projectId,
|
|
6276
|
+
resource: resource,
|
|
6277
|
+
});
|
|
6278
|
+
};
|
|
6279
|
+
exports.openGoogleCloudLogs = openGoogleCloudLogs;
|
|
6280
|
+
const openGoogleCloudKubernetesDashboard = async (instance, context) => {
|
|
6281
|
+
var _a;
|
|
6282
|
+
const deployConfig = (_a = context.deploy) === null || _a === void 0 ? void 0 : _a.config;
|
|
6283
|
+
if (!(0, pipeline_1.isOfDeployType)(deployConfig, "kubernetes")) {
|
|
6284
|
+
throw new Error("context is not of type kubernetes");
|
|
6285
|
+
}
|
|
6286
|
+
if (!deployConfig.cluster || deployConfig.cluster.type !== "gcloud") {
|
|
6287
|
+
throw new Error("no gcloud custer configured");
|
|
6288
|
+
}
|
|
6289
|
+
const namespace = context.environment.envVars.KUBE_NAMESPACE;
|
|
6290
|
+
const cluster = deployConfig.cluster;
|
|
6291
|
+
const pageState = `("savedViews":("c":["gke/${cluster.region}/${cluster.name}"],"n":["${namespace}"],"i":"4e42e0b9cd6147f8a4fba7516752ec48"))`;
|
|
6292
|
+
await (0, openDashboard_1.openGoogleCloudDashboard)(instance, "kubernetes/workload", {
|
|
6293
|
+
project: cluster.projectId,
|
|
6294
|
+
pageState: pageState,
|
|
6295
|
+
});
|
|
6296
|
+
};
|
|
6297
|
+
exports.openGoogleCloudKubernetesDashboard = openGoogleCloudKubernetesDashboard;
|
|
6298
|
+
//# sourceMappingURL=openKubernetesDashboards.js.map
|
|
6299
|
+
|
|
6300
|
+
/***/ }),
|
|
6301
|
+
|
|
6302
|
+
/***/ 76775:
|
|
6303
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6304
|
+
|
|
6305
|
+
"use strict";
|
|
6306
|
+
|
|
6307
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6308
|
+
exports.startKubePortForward = void 0;
|
|
6309
|
+
const portForwards_1 = __nccwpck_require__(5368);
|
|
6310
|
+
const startKubePortForward = async (podname, localPort, remotePort, namespace) => {
|
|
6311
|
+
const name = `kube/${namespace}/${podname}/${localPort}:${remotePort}`;
|
|
6312
|
+
await (0, portForwards_1.startPortForwardCommand)(name, `kubectl port-forward ${podname} ${localPort}:${remotePort} -n ${namespace}`);
|
|
6313
|
+
};
|
|
6314
|
+
exports.startKubePortForward = startKubePortForward;
|
|
6315
|
+
//# sourceMappingURL=portForward.js.map
|
|
6316
|
+
|
|
6317
|
+
/***/ }),
|
|
6318
|
+
|
|
6319
|
+
/***/ 55689:
|
|
6320
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
6321
|
+
|
|
6322
|
+
"use strict";
|
|
6323
|
+
|
|
6324
|
+
// we can't import the package.json directly, because the bundling process will inline it
|
|
6325
|
+
// but the version is only set during deployement, when its already bundled
|
|
6326
|
+
// instead we need to use require.main.path to get the path of the main module, which is actually the file in the bin
|
|
6327
|
+
// this will point to the root package.json
|
|
6328
|
+
var _a;
|
|
6329
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6330
|
+
const path = ((_a = require.main) === null || _a === void 0 ? void 0 : _a.path) + "/../package.json";
|
|
6331
|
+
const ownPkg = require(path);
|
|
6332
|
+
exports["default"] = ownPkg;
|
|
6333
|
+
//# sourceMappingURL=packageInfos.js.map
|
|
6334
|
+
|
|
6335
|
+
/***/ }),
|
|
6336
|
+
|
|
6337
|
+
/***/ 97245:
|
|
6338
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6339
|
+
|
|
6340
|
+
"use strict";
|
|
6341
|
+
|
|
6342
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6343
|
+
exports.getConfiguredGithubRepo = exports.pushSecretsToGithub = exports.collectSecretTargets = exports.collectSecretsFromVault = void 0;
|
|
6344
|
+
const pipeline_1 = __nccwpck_require__(53695);
|
|
6345
|
+
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
6346
|
+
const github_1 = __nccwpck_require__(41353);
|
|
6347
|
+
/**
|
|
6348
|
+
* all secrets declared in the config, with their values read from the
|
|
6349
|
+
* vault (github secrets are write-only and can never act as a source)
|
|
6350
|
+
*/
|
|
6351
|
+
const collectSecretsFromVault = async (io, envFilter) => {
|
|
6352
|
+
const envAndComponents = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
6353
|
+
const kinds = new Map();
|
|
6354
|
+
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
6355
|
+
for (const env of envs) {
|
|
6356
|
+
if (envFilter && !envFilter.includes(env)) {
|
|
6357
|
+
continue;
|
|
6358
|
+
}
|
|
6359
|
+
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
6360
|
+
const keys = [
|
|
6361
|
+
...secretEnvVarKeys,
|
|
6362
|
+
...jobOnlyVars.build.secretEnvVarKeys,
|
|
6363
|
+
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
6364
|
+
];
|
|
6365
|
+
keys.forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
6366
|
+
}
|
|
6367
|
+
}
|
|
6368
|
+
const names = [...kinds.keys()];
|
|
6369
|
+
const values = await (await io.getVaultManager()).readSecrets(names, io);
|
|
6370
|
+
const secrets = names
|
|
6371
|
+
.filter((name) => values[name] !== undefined)
|
|
6372
|
+
.map((name) => {
|
|
6373
|
+
var _a;
|
|
6374
|
+
return ({
|
|
6375
|
+
name,
|
|
6376
|
+
value: values[name],
|
|
6377
|
+
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
|
|
6378
|
+
});
|
|
6379
|
+
});
|
|
6380
|
+
const missing = names.filter((name) => values[name] === undefined);
|
|
6381
|
+
return { secrets, missing };
|
|
6382
|
+
};
|
|
6383
|
+
exports.collectSecretsFromVault = collectSecretsFromVault;
|
|
6384
|
+
/** marker for repo-level (environment-less) targets */
|
|
6385
|
+
const REPO_LEVEL = "";
|
|
6386
|
+
/**
|
|
6387
|
+
* derives which github environment(s) each secret/variable must live in
|
|
6388
|
+
* by scanning the GENERATED workflows: a `${{ secrets.X }}` / `${{
|
|
6389
|
+
* vars.X }}` reference in a job's env targets that job's environment
|
|
6390
|
+
* (or the repo level when the job has none). Deriving from the real
|
|
6391
|
+
* output means the sync can never drift from what the workflows expect.
|
|
6392
|
+
*
|
|
6393
|
+
* Environment secrets are the answer to github's cap of 100 secrets
|
|
6394
|
+
* per REPO (a multi-env project easily exceeds it): the cap applies
|
|
6395
|
+
* per environment instead.
|
|
6396
|
+
*/
|
|
6397
|
+
const collectSecretTargets = async (config) => {
|
|
6398
|
+
var _a;
|
|
6399
|
+
const workflows = await new pipeline_1.GithubBackend().createWorkflows(config);
|
|
6400
|
+
const targets = new Map();
|
|
6401
|
+
for (const workflow of Object.values(workflows)) {
|
|
6402
|
+
for (const job of Object.values(workflow.jobs)) {
|
|
6403
|
+
const environment = typeof job.environment === "object"
|
|
6404
|
+
? job.environment.name
|
|
6405
|
+
: job.environment;
|
|
6406
|
+
for (const value of Object.values((_a = job.env) !== null && _a !== void 0 ? _a : {})) {
|
|
6407
|
+
if (typeof value !== "string")
|
|
6408
|
+
continue;
|
|
6409
|
+
for (const match of value.matchAll(/\$\{\{\s*(?:secrets|vars)\.([A-Za-z0-9_]+)\s*\}\}/g)) {
|
|
6410
|
+
const name = match[1];
|
|
6411
|
+
if (!targets.has(name)) {
|
|
6412
|
+
targets.set(name, new Set());
|
|
6413
|
+
}
|
|
6414
|
+
targets.get(name).add(environment !== null && environment !== void 0 ? environment : REPO_LEVEL);
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
return targets;
|
|
6420
|
+
};
|
|
6421
|
+
exports.collectSecretTargets = collectSecretTargets;
|
|
6422
|
+
/**
|
|
6423
|
+
* pushes vault values to github via the gh cli: sensitive ones as
|
|
6424
|
+
* secrets (masked), "variable"-kind ones as variables (plain) — each
|
|
6425
|
+
* into the environment(s) whose jobs reference them
|
|
6426
|
+
*/
|
|
6427
|
+
const pushSecretsToGithub = async (io, repo, secrets, targets) => {
|
|
6428
|
+
const environments = [
|
|
6429
|
+
...new Set([...targets.values()].flatMap((envs) => [...envs].filter((env) => env !== REPO_LEVEL))),
|
|
6430
|
+
];
|
|
6431
|
+
for (const environment of environments) {
|
|
6432
|
+
await (0, github_1.ensureGithubEnvironment)(repo, environment);
|
|
6433
|
+
io.log(`🌍 environment ${environment}`);
|
|
6434
|
+
}
|
|
6435
|
+
for (const { name, value, kind } of secrets) {
|
|
6436
|
+
const envs = targets.get(name);
|
|
6437
|
+
if (!envs) {
|
|
6438
|
+
io.log(`⏭️ ${name} (not referenced by any generated workflow)`);
|
|
6439
|
+
continue;
|
|
6440
|
+
}
|
|
6441
|
+
for (const environment of envs) {
|
|
6442
|
+
const suffix = environment === REPO_LEVEL ? "" : ` → ${environment}`;
|
|
6443
|
+
if (kind === "variable") {
|
|
6444
|
+
await (0, github_1.setGithubVariable)(repo, name, value, environment || undefined);
|
|
6445
|
+
io.log(`📖 ${name} (variable)${suffix}`);
|
|
6446
|
+
}
|
|
6447
|
+
else {
|
|
6448
|
+
await (0, github_1.setGithubSecret)(repo, name, value, environment || undefined);
|
|
6449
|
+
io.log(`✅ ${name}${suffix}`);
|
|
6450
|
+
}
|
|
6451
|
+
}
|
|
6452
|
+
}
|
|
6453
|
+
};
|
|
6454
|
+
exports.pushSecretsToGithub = pushSecretsToGithub;
|
|
6455
|
+
/**
|
|
6456
|
+
* resolves the github repository from the configured git remote
|
|
6457
|
+
* (`pipelines.github.gitRemote`, defaults to origin)
|
|
6458
|
+
*/
|
|
6459
|
+
const getConfiguredGithubRepo = async () => {
|
|
6460
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
6461
|
+
if (!config) {
|
|
6462
|
+
return undefined;
|
|
6463
|
+
}
|
|
6464
|
+
return (0, github_1.getGithubRepoFromRemote)((0, pipeline_1.getPipelineGitRemote)(config, "github"));
|
|
6189
6465
|
};
|
|
6190
|
-
exports.
|
|
6191
|
-
//# sourceMappingURL=
|
|
6466
|
+
exports.getConfiguredGithubRepo = getConfiguredGithubRepo;
|
|
6467
|
+
//# sourceMappingURL=github.js.map
|
|
6192
6468
|
|
|
6193
6469
|
/***/ }),
|
|
6194
6470
|
|
|
6195
|
-
/***/
|
|
6471
|
+
/***/ 85200:
|
|
6196
6472
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
6197
6473
|
|
|
6198
6474
|
"use strict";
|
|
@@ -6212,164 +6488,104 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
6212
6488
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
6213
6489
|
};
|
|
6214
6490
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6215
|
-
__exportStar(__nccwpck_require__(
|
|
6216
|
-
__exportStar(__nccwpck_require__(
|
|
6217
|
-
__exportStar(__nccwpck_require__(3328), exports);
|
|
6491
|
+
__exportStar(__nccwpck_require__(97245), exports);
|
|
6492
|
+
__exportStar(__nccwpck_require__(31298), exports);
|
|
6218
6493
|
//# sourceMappingURL=index.js.map
|
|
6219
6494
|
|
|
6220
6495
|
/***/ }),
|
|
6221
6496
|
|
|
6222
|
-
/***/
|
|
6497
|
+
/***/ 31298:
|
|
6223
6498
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6224
6499
|
|
|
6225
6500
|
"use strict";
|
|
6226
6501
|
|
|
6227
6502
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6228
|
-
exports.
|
|
6229
|
-
const
|
|
6230
|
-
const
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
};
|
|
6503
|
+
exports.writeSecretsAndMirror = void 0;
|
|
6504
|
+
const pipeline_1 = __nccwpck_require__(53695);
|
|
6505
|
+
const getProjectConfig_1 = __nccwpck_require__(70478);
|
|
6506
|
+
const github_1 = __nccwpck_require__(41353);
|
|
6507
|
+
const gitlab_1 = __nccwpck_require__(17697);
|
|
6508
|
+
const github_2 = __nccwpck_require__(97245);
|
|
6235
6509
|
/**
|
|
6236
|
-
*
|
|
6237
|
-
*
|
|
6510
|
+
* the one door for writing secret values: they go into the vault (the
|
|
6511
|
+
* source of truth) and are mirrored to every enabled CI backend —
|
|
6512
|
+
* which vault and which backends exist is invisible to the caller.
|
|
6513
|
+
*
|
|
6514
|
+
* Everything that produces a secret value must come through here: the
|
|
6515
|
+
* secrets commands, but also the credentials `project setup`
|
|
6516
|
+
* provisions (gcloud service account keys, kubernetes tokens).
|
|
6238
6517
|
*/
|
|
6239
|
-
const
|
|
6240
|
-
const
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
exports.getk8sApi = getk8sApi;
|
|
6244
|
-
const getk8sApiBatch = () => {
|
|
6245
|
-
const kc = getKubeConfig();
|
|
6246
|
-
return kc.makeApiClient(client_node_1.BatchV1Api);
|
|
6247
|
-
};
|
|
6248
|
-
exports.getk8sApiBatch = getk8sApiBatch;
|
|
6249
|
-
const getk8sApiBatchBeta = () => {
|
|
6250
|
-
const kc = getKubeConfig();
|
|
6251
|
-
return kc.makeApiClient(client_node_1.BatchV1beta1Api);
|
|
6252
|
-
};
|
|
6253
|
-
exports.getk8sApiBatchBeta = getk8sApiBatchBeta;
|
|
6254
|
-
//# sourceMappingURL=index.js.map
|
|
6255
|
-
|
|
6256
|
-
/***/ }),
|
|
6257
|
-
|
|
6258
|
-
/***/ 79107:
|
|
6259
|
-
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6260
|
-
|
|
6261
|
-
"use strict";
|
|
6262
|
-
|
|
6263
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6264
|
-
exports.getProjectPodNames = exports.getProjectPvcs = exports.getProjectPods = void 0;
|
|
6265
|
-
const parseChoice_1 = __nccwpck_require__(70769);
|
|
6266
|
-
const k8sApi_1 = __nccwpck_require__(32839);
|
|
6267
|
-
const projects_1 = __nccwpck_require__(20575);
|
|
6268
|
-
const getProjectPods = async (envComponent) => {
|
|
6269
|
-
const namespace = await (0, projects_1.getProjectNamespace)(envComponent);
|
|
6270
|
-
const k8sApi = (0, k8sApi_1.getk8sApi)();
|
|
6271
|
-
const res = await k8sApi.listNamespacedPod(namespace);
|
|
6272
|
-
const { componentName } = (0, parseChoice_1.parseChoice)(envComponent);
|
|
6273
|
-
return res.body.items.filter((item) => { var _a, _b; return componentName ? (_b = (_a = item.metadata) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.includes(componentName + "-") : true; });
|
|
6274
|
-
};
|
|
6275
|
-
exports.getProjectPods = getProjectPods;
|
|
6276
|
-
const getProjectPvcs = async (envComponent) => {
|
|
6277
|
-
const namespace = await (0, projects_1.getProjectNamespace)(envComponent);
|
|
6278
|
-
const k8sApi = (0, k8sApi_1.getk8sApi)();
|
|
6279
|
-
const res = await k8sApi.listNamespacedPersistentVolumeClaim(namespace);
|
|
6280
|
-
return res.body.items;
|
|
6281
|
-
};
|
|
6282
|
-
exports.getProjectPvcs = getProjectPvcs;
|
|
6283
|
-
const getProjectPodNames = async (envComponent) => {
|
|
6284
|
-
const pods = await (0, exports.getProjectPods)(envComponent);
|
|
6285
|
-
return pods.map((n) => n.metadata.name);
|
|
6286
|
-
};
|
|
6287
|
-
exports.getProjectPodNames = getProjectPodNames;
|
|
6288
|
-
//# sourceMappingURL=index.js.map
|
|
6289
|
-
|
|
6290
|
-
/***/ }),
|
|
6291
|
-
|
|
6292
|
-
/***/ 14178:
|
|
6293
|
-
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6294
|
-
|
|
6295
|
-
"use strict";
|
|
6296
|
-
|
|
6297
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6298
|
-
exports.openGoogleCloudKubernetesDashboard = exports.openGoogleCloudLogs = void 0;
|
|
6299
|
-
const pipeline_1 = __nccwpck_require__(53695);
|
|
6300
|
-
const openDashboard_1 = __nccwpck_require__(74241);
|
|
6301
|
-
const openGoogleCloudLogs = async (instance, context) => {
|
|
6302
|
-
var _a;
|
|
6303
|
-
const deployConfig = (_a = context.deploy) === null || _a === void 0 ? void 0 : _a.config;
|
|
6304
|
-
if (!(0, pipeline_1.isOfDeployType)(deployConfig, "kubernetes")) {
|
|
6305
|
-
throw new Error("context is not of type kubernetes");
|
|
6518
|
+
const writeSecretsAndMirror = async (io, writes, options = {}) => {
|
|
6519
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
6520
|
+
if (!config) {
|
|
6521
|
+
throw new Error("no catladder config found");
|
|
6306
6522
|
}
|
|
6307
|
-
|
|
6308
|
-
|
|
6523
|
+
io.log("");
|
|
6524
|
+
io.log("writing secrets to the vault, please wait...");
|
|
6525
|
+
io.log("");
|
|
6526
|
+
for (const { env, componentName, secrets } of writes) {
|
|
6527
|
+
io.log("writing " + env + ":" + componentName + "...\n");
|
|
6528
|
+
await (await io.getVaultManager()).writeSecrets(env, componentName, secrets, io, options);
|
|
6529
|
+
io.log("");
|
|
6530
|
+
io.log("✅ " + env + ":" + componentName);
|
|
6531
|
+
io.log("--------------------------------\n");
|
|
6309
6532
|
}
|
|
6310
|
-
|
|
6311
|
-
const cluster = deployConfig.cluster;
|
|
6312
|
-
const resource = `k8s_container/cluster_name/${cluster.name}${namespace ? `/namespace_name/${namespace}` : ""}`;
|
|
6313
|
-
await (0, openDashboard_1.openGoogleCloudDashboard)(instance, "logs/viewer", {
|
|
6314
|
-
project: cluster.projectId,
|
|
6315
|
-
resource: resource,
|
|
6316
|
-
});
|
|
6533
|
+
await mirrorSecretsToCiBackends(io, config, writes, options);
|
|
6317
6534
|
};
|
|
6318
|
-
exports.
|
|
6319
|
-
|
|
6535
|
+
exports.writeSecretsAndMirror = writeSecretsAndMirror;
|
|
6536
|
+
/**
|
|
6537
|
+
* the vault is the source of truth; every enabled CI backend receives
|
|
6538
|
+
* a mirrored copy of the written secrets (gitlab variables, github
|
|
6539
|
+
* secrets), so all CI systems stay in sync
|
|
6540
|
+
*/
|
|
6541
|
+
const mirrorSecretsToCiBackends = async (io, config, writes, options) => {
|
|
6320
6542
|
var _a;
|
|
6321
|
-
const
|
|
6322
|
-
|
|
6323
|
-
|
|
6543
|
+
const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
|
|
6544
|
+
// gitlab mirror (unless gitlab is the vault itself, then it is
|
|
6545
|
+
// already written)
|
|
6546
|
+
if ((0, pipeline_1.getVaultConfig)(config).type !== "gitlab" && enabled.includes("gitlab")) {
|
|
6547
|
+
for (const { env, componentName, secrets } of writes) {
|
|
6548
|
+
await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName, (_a = options.backup) !== null && _a !== void 0 ? _a : true);
|
|
6549
|
+
}
|
|
6550
|
+
io.log("✅ mirrored to gitlab");
|
|
6324
6551
|
}
|
|
6325
|
-
if (!
|
|
6326
|
-
|
|
6552
|
+
if (!enabled.includes("github")) {
|
|
6553
|
+
return;
|
|
6327
6554
|
}
|
|
6328
|
-
const
|
|
6329
|
-
const
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
};
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6555
|
+
const kinds = new Map();
|
|
6556
|
+
for (const { env, componentName } of writes) {
|
|
6557
|
+
const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
6558
|
+
[
|
|
6559
|
+
...secretEnvVarKeys,
|
|
6560
|
+
...jobOnlyVars.build.secretEnvVarKeys,
|
|
6561
|
+
...jobOnlyVars.deploy.secretEnvVarKeys,
|
|
6562
|
+
].forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
6563
|
+
}
|
|
6564
|
+
const secrets = writes.flatMap(({ env, componentName, secrets }) => Object.entries(secrets).map(([key, value]) => {
|
|
6565
|
+
var _a;
|
|
6566
|
+
const name = (0, pipeline_1.getSecretVarName)(env, componentName, key);
|
|
6567
|
+
return {
|
|
6568
|
+
name,
|
|
6569
|
+
value: typeof value === "string" ? value : JSON.stringify(value !== null && value !== void 0 ? value : ""),
|
|
6570
|
+
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
|
|
6571
|
+
};
|
|
6572
|
+
}));
|
|
6573
|
+
if (secrets.length === 0) {
|
|
6574
|
+
return;
|
|
6575
|
+
}
|
|
6576
|
+
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
6577
|
+
io.log("⚠️ github pipeline is enabled, but the github cli (gh) is not authenticated — run `project secrets-sync-github` later to mirror the secrets");
|
|
6578
|
+
return;
|
|
6579
|
+
}
|
|
6580
|
+
const repo = await (0, github_2.getConfiguredGithubRepo)();
|
|
6581
|
+
if (!repo) {
|
|
6582
|
+
io.log("⚠️ github pipeline is enabled, but no github repository was found — run `project secrets-sync-github` later to mirror the secrets");
|
|
6583
|
+
return;
|
|
6584
|
+
}
|
|
6585
|
+
io.log(`mirroring ${secrets.length} secrets to github ('${repo}')...`);
|
|
6586
|
+
await (0, github_2.pushSecretsToGithub)(io, repo, secrets, await (0, github_2.collectSecretTargets)(config));
|
|
6352
6587
|
};
|
|
6353
|
-
|
|
6354
|
-
//# sourceMappingURL=portForward.js.map
|
|
6355
|
-
|
|
6356
|
-
/***/ }),
|
|
6357
|
-
|
|
6358
|
-
/***/ 55689:
|
|
6359
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
6360
|
-
|
|
6361
|
-
"use strict";
|
|
6362
|
-
|
|
6363
|
-
// we can't import the package.json directly, because the bundling process will inline it
|
|
6364
|
-
// but the version is only set during deployement, when its already bundled
|
|
6365
|
-
// instead we need to use require.main.path to get the path of the main module, which is actually the file in the bin
|
|
6366
|
-
// this will point to the root package.json
|
|
6367
|
-
var _a;
|
|
6368
|
-
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6369
|
-
const path = ((_a = require.main) === null || _a === void 0 ? void 0 : _a.path) + "/../package.json";
|
|
6370
|
-
const ownPkg = require(path);
|
|
6371
|
-
exports["default"] = ownPkg;
|
|
6372
|
-
//# sourceMappingURL=packageInfos.js.map
|
|
6588
|
+
//# sourceMappingURL=writeSecrets.js.map
|
|
6373
6589
|
|
|
6374
6590
|
/***/ }),
|
|
6375
6591
|
|
|
@@ -6910,7 +7126,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6910
7126
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6911
7127
|
};
|
|
6912
7128
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6913
|
-
exports.upsertAllVariables = exports.clearBackups = exports.getVariableValueByRawName = exports.getAllVariables = exports.getProjectInfo = exports.doGitlabRequestAllPages = exports.doGitlabRequest = exports.getGitlabToken = exports.setupGitlabToken = exports.hasGitlabToken = void 0;
|
|
7129
|
+
exports.upsertAllVariables = exports.clearBackups = exports.getVariableValueByRawName = exports.getAllVariables = exports.getProjectInfo = exports.doGitlabRequestAllPages = exports.doGitlabRequest = exports.GitlabNotFoundError = exports.getGitlabToken = exports.setupGitlabToken = exports.hasGitlabToken = void 0;
|
|
6914
7130
|
const pipeline_1 = __nccwpck_require__(53695);
|
|
6915
7131
|
const lodash_es_1 = __nccwpck_require__(50210);
|
|
6916
7132
|
const memoizee_1 = __importDefault(__nccwpck_require__(6575));
|
|
@@ -6962,6 +7178,20 @@ const getGitlabToken = async (io) => {
|
|
|
6962
7178
|
return (0, preferences_1.getPreference)(TOKEN_KEY);
|
|
6963
7179
|
};
|
|
6964
7180
|
exports.getGitlabToken = getGitlabToken;
|
|
7181
|
+
/**
|
|
7182
|
+
* a gitlab api call that came back 404. Carries the path so a caller
|
|
7183
|
+
* that wants to treat "does not exist yet" as normal can say so
|
|
7184
|
+
* (`instanceof`) instead of matching on a message.
|
|
7185
|
+
*/
|
|
7186
|
+
class GitlabNotFoundError extends Error {
|
|
7187
|
+
constructor(path, host) {
|
|
7188
|
+
super(`gitlab api: ${path} not found on ${host}`);
|
|
7189
|
+
this.path = path;
|
|
7190
|
+
this.host = host;
|
|
7191
|
+
this.name = "GitlabNotFoundError";
|
|
7192
|
+
}
|
|
7193
|
+
}
|
|
7194
|
+
exports.GitlabNotFoundError = GitlabNotFoundError;
|
|
6965
7195
|
const doGitlabRequest = async (io, path, data = undefined, method = "GET") => {
|
|
6966
7196
|
const [rootToken, { gitRemoteHost }] = await Promise.all([
|
|
6967
7197
|
(0, exports.getGitlabToken)(io),
|
|
@@ -6983,7 +7213,7 @@ const doGitlabRequest = async (io, path, data = undefined, method = "GET") => {
|
|
|
6983
7213
|
return null;
|
|
6984
7214
|
}
|
|
6985
7215
|
if (result.status === 404) {
|
|
6986
|
-
throw new
|
|
7216
|
+
throw new GitlabNotFoundError(path, gitRemoteHost);
|
|
6987
7217
|
}
|
|
6988
7218
|
throw new Error(`Could not send request to gitlab api ${path}: ${result.status} "${result.statusText}".\nResponse: ${JSON.stringify(await result.json(), null, 2)}`);
|
|
6989
7219
|
};
|
|
@@ -7009,9 +7239,20 @@ const doGitlabRequestAllPages = async (io, path) => {
|
|
|
7009
7239
|
};
|
|
7010
7240
|
exports.doGitlabRequestAllPages = doGitlabRequestAllPages;
|
|
7011
7241
|
const getProjectInfo = async (io) => {
|
|
7012
|
-
const { gitRemotePath } = await (0, gitProjectInformation_1.getGitRemoteHostAndPath)();
|
|
7013
|
-
|
|
7014
|
-
|
|
7242
|
+
const { gitRemoteHost, gitRemotePath } = await (0, gitProjectInformation_1.getGitRemoteHostAndPath)();
|
|
7243
|
+
try {
|
|
7244
|
+
return await (0, exports.doGitlabRequest)(io, `projects/${encodeURIComponent(gitRemotePath)}`);
|
|
7245
|
+
}
|
|
7246
|
+
catch (e) {
|
|
7247
|
+
if (e instanceof GitlabNotFoundError) {
|
|
7248
|
+
// the classic: the remote is not a gitlab at all (a github one,
|
|
7249
|
+
// say), so the request goes to a host without /api/v4 and every
|
|
7250
|
+
// path answers 404
|
|
7251
|
+
throw new Error(`no gitlab project '${gitRemotePath}' on '${gitRemoteHost}'. ` +
|
|
7252
|
+
"Check the git remote and `pipelines` in catladder.ts — this command talks to the gitlab api.");
|
|
7253
|
+
}
|
|
7254
|
+
throw e;
|
|
7255
|
+
}
|
|
7015
7256
|
};
|
|
7016
7257
|
exports.getProjectInfo = getProjectInfo;
|
|
7017
7258
|
exports.getAllVariables = (0, memoizee_1.default)(async (io, n = 5) => {
|
|
@@ -7566,7 +7807,14 @@ class BitwardenVault {
|
|
|
7566
7807
|
}
|
|
7567
7808
|
return secrets;
|
|
7568
7809
|
}
|
|
7810
|
+
/**
|
|
7811
|
+
* upserts into the item's yaml note. The note is rewritten as a
|
|
7812
|
+
* whole, so the values that are not part of this write have to be
|
|
7813
|
+
* carried over — a single-key write (`secrets-set`, a credential
|
|
7814
|
+
* provisioned by `project setup`) must not drop the rest.
|
|
7815
|
+
*/
|
|
7569
7816
|
async writeSecrets(io, env, componentName, secrets) {
|
|
7817
|
+
var _a;
|
|
7570
7818
|
const { config, collectionName } = this;
|
|
7571
7819
|
const bwSession = await this.session(io);
|
|
7572
7820
|
const collection = await findCollection(bwSession, collectionName);
|
|
@@ -7579,7 +7827,10 @@ class BitwardenVault {
|
|
|
7579
7827
|
"--search",
|
|
7580
7828
|
name,
|
|
7581
7829
|
])).find((item) => item.name === name);
|
|
7582
|
-
const
|
|
7830
|
+
const previous = (existing === null || existing === void 0 ? void 0 : existing.notes)
|
|
7831
|
+
? ((_a = (0, yaml_1.parse)(existing.notes)) !== null && _a !== void 0 ? _a : {})
|
|
7832
|
+
: {};
|
|
7833
|
+
const notes = (0, yaml_1.stringify)({ ...previous, ...secrets });
|
|
7583
7834
|
if (existing) {
|
|
7584
7835
|
await (0, bw_1.runBw)(bwSession, [
|
|
7585
7836
|
"edit",
|
|
@@ -7633,8 +7884,9 @@ class GitlabVault {
|
|
|
7633
7884
|
const variables = await (0, gitlab_1.getAllVariables)(io);
|
|
7634
7885
|
return Object.fromEntries(variables.map((v) => [v.key, v.value]));
|
|
7635
7886
|
}
|
|
7636
|
-
async writeSecrets(io, env, componentName, secrets) {
|
|
7637
|
-
|
|
7887
|
+
async writeSecrets(io, env, componentName, secrets, options = {}) {
|
|
7888
|
+
var _a;
|
|
7889
|
+
await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName, (_a = options.backup) !== null && _a !== void 0 ? _a : true);
|
|
7638
7890
|
}
|
|
7639
7891
|
}
|
|
7640
7892
|
exports.GitlabVault = GitlabVault;
|
|
@@ -7720,11 +7972,11 @@ class VaultManager {
|
|
|
7720
7972
|
* writes secrets of one env/component to the vault and updates the
|
|
7721
7973
|
* local cache (write-through, "local" env only)
|
|
7722
7974
|
*/
|
|
7723
|
-
async writeSecrets(env, componentName, secrets, io = this.io) {
|
|
7975
|
+
async writeSecrets(env, componentName, secrets, io = this.io, options = {}) {
|
|
7724
7976
|
if (!io) {
|
|
7725
7977
|
throw new Error("writing to the vault requires an interactive context");
|
|
7726
7978
|
}
|
|
7727
|
-
await this.vault.writeSecrets(io, env, componentName, secrets);
|
|
7979
|
+
await this.vault.writeSecrets(io, env, componentName, secrets, options);
|
|
7728
7980
|
if (env === CACHED_ENV) {
|
|
7729
7981
|
await (0, cache_1.updateSecretsCache)(this.vault.id, env, componentName, Object.fromEntries(Object.entries(secrets).map(([key, value]) => [
|
|
7730
7982
|
key,
|
|
@@ -8723,6 +8975,43 @@ exports.getAgentSkillTargets = getAgentSkillTargets;
|
|
|
8723
8975
|
|
|
8724
8976
|
/***/ }),
|
|
8725
8977
|
|
|
8978
|
+
/***/ 72792:
|
|
8979
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
8980
|
+
|
|
8981
|
+
"use strict";
|
|
8982
|
+
|
|
8983
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
8984
|
+
exports.getPinLabelRegexSource = exports.getAutoStopConfig = exports.DEFAULT_PIN_LABEL = exports.DEFAULT_DEV_AUTO_STOP = exports.DEFAULT_REVIEW_AUTO_STOP = exports.REVIEW_AUTO_STOP_VARIABLE = void 0;
|
|
8985
|
+
const lodash_es_1 = __nccwpck_require__(50210);
|
|
8986
|
+
/**
|
|
8987
|
+
* pipeline-level variable holding the `auto_stop_in` of review
|
|
8988
|
+
* environments. Review deploy jobs reference it instead of a literal,
|
|
8989
|
+
* so the pin label's workflow rule can override it to `never` for the
|
|
8990
|
+
* whole pipeline (all components at once).
|
|
8991
|
+
*/
|
|
8992
|
+
exports.REVIEW_AUTO_STOP_VARIABLE = "CL_REVIEW_AUTO_STOP";
|
|
8993
|
+
exports.DEFAULT_REVIEW_AUTO_STOP = "1 week";
|
|
8994
|
+
exports.DEFAULT_DEV_AUTO_STOP = "4 weeks";
|
|
8995
|
+
exports.DEFAULT_PIN_LABEL = "catladder::pin-review";
|
|
8996
|
+
const getAutoStopConfig = (config) => {
|
|
8997
|
+
var _a, _b, _c, _d, _e, _f;
|
|
8998
|
+
return ({
|
|
8999
|
+
review: (_b = (_a = config.autoStop) === null || _a === void 0 ? void 0 : _a.review) !== null && _b !== void 0 ? _b : exports.DEFAULT_REVIEW_AUTO_STOP,
|
|
9000
|
+
dev: (_d = (_c = config.autoStop) === null || _c === void 0 ? void 0 : _c.dev) !== null && _d !== void 0 ? _d : exports.DEFAULT_DEV_AUTO_STOP,
|
|
9001
|
+
pinLabel: (_f = (_e = config.autoStop) === null || _e === void 0 ? void 0 : _e.pinLabel) !== null && _f !== void 0 ? _f : exports.DEFAULT_PIN_LABEL,
|
|
9002
|
+
});
|
|
9003
|
+
};
|
|
9004
|
+
exports.getAutoStopConfig = getAutoStopConfig;
|
|
9005
|
+
/**
|
|
9006
|
+
* matches the pin label inside `$CI_MERGE_REQUEST_LABELS`
|
|
9007
|
+
* (comma-separated) — anchored so `pin` never matches `no-pin`
|
|
9008
|
+
*/
|
|
9009
|
+
const getPinLabelRegexSource = (pinLabel) => `(^|,)${(0, lodash_es_1.escapeRegExp)(pinLabel).replaceAll("/", "\\/")}(,|$)`;
|
|
9010
|
+
exports.getPinLabelRegexSource = getPinLabelRegexSource;
|
|
9011
|
+
//# sourceMappingURL=autoStop.js.map
|
|
9012
|
+
|
|
9013
|
+
/***/ }),
|
|
9014
|
+
|
|
8726
9015
|
/***/ 48476:
|
|
8727
9016
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
8728
9017
|
|
|
@@ -10101,6 +10390,7 @@ exports.GitlabBackend = void 0;
|
|
|
10101
10390
|
const promises_1 = __nccwpck_require__(91943);
|
|
10102
10391
|
const rules_1 = __nccwpck_require__(78503);
|
|
10103
10392
|
const config_1 = __nccwpck_require__(75591);
|
|
10393
|
+
const autoStop_1 = __nccwpck_require__(72792);
|
|
10104
10394
|
const createAllJobs_1 = __nccwpck_require__(83477);
|
|
10105
10395
|
const jobImagesPlan_1 = __nccwpck_require__(59623);
|
|
10106
10396
|
const shippedCatci_1 = __nccwpck_require__(27967);
|
|
@@ -10286,6 +10576,7 @@ class GitlabBackend {
|
|
|
10286
10576
|
// per-pipeline-type variables (pipelines.gitlab.runnerVariables)
|
|
10287
10577
|
...(0, index_1.getPipelineOptions)(config, this.type).runnerVariables,
|
|
10288
10578
|
},
|
|
10579
|
+
autoStop: (0, autoStop_1.getAutoStopConfig)(config),
|
|
10289
10580
|
});
|
|
10290
10581
|
}
|
|
10291
10582
|
}
|
|
@@ -10730,6 +11021,7 @@ function getGitlabNeedsForWorkspaceJob(context, { needs }, allJobs) {
|
|
|
10730
11021
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
10731
11022
|
exports.createGitlabPipelineWithDefaults = void 0;
|
|
10732
11023
|
const bash_1 = __nccwpck_require__(94143);
|
|
11024
|
+
const autoStop_1 = __nccwpck_require__(72792);
|
|
10733
11025
|
const rules_1 = __nccwpck_require__(78503);
|
|
10734
11026
|
/**
|
|
10735
11027
|
* gitlab requires a top-level default image for jobs that don't set their
|
|
@@ -10738,7 +11030,8 @@ const rules_1 = __nccwpck_require__(78503);
|
|
|
10738
11030
|
* build-free image (a catladder job image would drag in a build job).
|
|
10739
11031
|
*/
|
|
10740
11032
|
const DEFAULT_PIPELINE_IMAGE = "node:22";
|
|
10741
|
-
const createGitlabPipelineWithDefaults = ({ image, variables, before_script, ...config }) => {
|
|
11033
|
+
const createGitlabPipelineWithDefaults = ({ image, variables, before_script, autoStop, ...config }) => {
|
|
11034
|
+
const pinLabel = autoStop && autoStop.pinLabel;
|
|
10742
11035
|
return {
|
|
10743
11036
|
image: image !== null && image !== void 0 ? image : DEFAULT_PIPELINE_IMAGE,
|
|
10744
11037
|
variables: {
|
|
@@ -10747,6 +11040,10 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, ...
|
|
|
10747
11040
|
CACHE_COMPRESSION_LEVEL: "fast", // same as above, but for caches
|
|
10748
11041
|
TRANSFER_METER_FREQUENCY: "5s", // how often we should update the transfer meter for cache upload/download
|
|
10749
11042
|
GIT_DEPTH: "1", // no need the full depth
|
|
11043
|
+
// review env lifetime — the pin-label workflow rule below
|
|
11044
|
+
// overrides this to "never" (workflow rule variables take
|
|
11045
|
+
// precedence over pipeline-level variables)
|
|
11046
|
+
...(pinLabel ? { [autoStop_1.REVIEW_AUTO_STOP_VARIABLE]: autoStop.review } : {}),
|
|
10750
11047
|
...(variables !== null && variables !== void 0 ? variables : {}),
|
|
10751
11048
|
},
|
|
10752
11049
|
before_script: [
|
|
@@ -10763,6 +11060,20 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, ...
|
|
|
10763
11060
|
PIPELINE_NAME: "Thinking...",
|
|
10764
11061
|
},
|
|
10765
11062
|
},
|
|
11063
|
+
// pinned MRs (rules stop at the first match, so this must come
|
|
11064
|
+
// before the plain merge-request rule)
|
|
11065
|
+
...(pinLabel
|
|
11066
|
+
? [
|
|
11067
|
+
{
|
|
11068
|
+
if: `${rules_1.RULE_IS_MERGE_REQUEST.if} && $CI_MERGE_REQUEST_LABELS =~ /${(0, autoStop_1.getPinLabelRegexSource)(pinLabel)}/`,
|
|
11069
|
+
variables: {
|
|
11070
|
+
PIPELINE_ICON: "🐱📌",
|
|
11071
|
+
PIPELINE_NAME: "mr$CI_MERGE_REQUEST_IID - $CI_MERGE_REQUEST_TITLE",
|
|
11072
|
+
[autoStop_1.REVIEW_AUTO_STOP_VARIABLE]: "never",
|
|
11073
|
+
},
|
|
11074
|
+
},
|
|
11075
|
+
]
|
|
11076
|
+
: []),
|
|
10766
11077
|
{
|
|
10767
11078
|
if: rules_1.RULE_IS_MERGE_REQUEST.if,
|
|
10768
11079
|
variables: {
|
|
@@ -14477,6 +14788,7 @@ const docker_1 = __nccwpck_require__(12354);
|
|
|
14477
14788
|
const context_1 = __nccwpck_require__(73938);
|
|
14478
14789
|
const jobs_1 = __nccwpck_require__(98521);
|
|
14479
14790
|
const utils_1 = __nccwpck_require__(71286);
|
|
14791
|
+
const autoStop_1 = __nccwpck_require__(72792);
|
|
14480
14792
|
const stop_1 = __nccwpck_require__(35937);
|
|
14481
14793
|
const variables_1 = __nccwpck_require__(54768);
|
|
14482
14794
|
exports.DEPLOY_JOB_NAME = "🚀 Deploy";
|
|
@@ -14485,10 +14797,15 @@ class DeployJob extends jobs_1.CatladderJob {
|
|
|
14485
14797
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
14486
14798
|
const hasDocker = (0, docker_1.requiresDockerBuild)(context);
|
|
14487
14799
|
const isStoppable = (0, utils_1.contextIsStoppable)(context);
|
|
14800
|
+
const autoStopConfig = (0, autoStop_1.getAutoStopConfig)(context.fullConfig);
|
|
14488
14801
|
const autoStop = context.environment.envType === "review"
|
|
14489
|
-
?
|
|
14802
|
+
? // review envs read the lifetime from a pipeline variable, so
|
|
14803
|
+
// the pin label's workflow rule can override it to "never"
|
|
14804
|
+
autoStopConfig.pinLabel === false
|
|
14805
|
+
? autoStopConfig.review
|
|
14806
|
+
: `$${autoStop_1.REVIEW_AUTO_STOP_VARIABLE}`
|
|
14490
14807
|
: context.environment.envType === "dev"
|
|
14491
|
-
?
|
|
14808
|
+
? autoStopConfig.dev
|
|
14492
14809
|
: undefined;
|
|
14493
14810
|
const deployConfig = (_a = context.deploy) === null || _a === void 0 ? void 0 : _a.config;
|
|
14494
14811
|
// if auto or manual is configured explicitly, use that
|
|
@@ -17317,6 +17634,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
17317
17634
|
};
|
|
17318
17635
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
17319
17636
|
__exportStar(__nccwpck_require__(46734), exports);
|
|
17637
|
+
__exportStar(__nccwpck_require__(72792), exports);
|
|
17320
17638
|
__exportStar(__nccwpck_require__(62853), exports);
|
|
17321
17639
|
__exportStar(__nccwpck_require__(63557), exports);
|
|
17322
17640
|
__exportStar(__nccwpck_require__(78503), exports);
|