@catladder/cli 0.0.0-next-16388362 → 0.0.0-next-8b9ad5ca

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/bundles/catenv/index.js +1209 -28
  2. package/dist/bundles/cli/index.js +1406 -30
  3. package/dist/cli/src/adapters/baseContext.d.ts +4 -0
  4. package/dist/cli/src/adapters/baseContext.js +5 -0
  5. package/dist/cli/src/adapters/baseContext.js.map +1 -1
  6. package/dist/cli/src/adapters/nonInteractive.d.ts +9 -0
  7. package/dist/cli/src/adapters/nonInteractive.js +32 -0
  8. package/dist/cli/src/adapters/nonInteractive.js.map +1 -0
  9. package/dist/cli/src/adapters/programmatic.d.ts +1 -0
  10. package/dist/cli/src/adapters/programmatic.js +6 -1
  11. package/dist/cli/src/adapters/programmatic.js.map +1 -1
  12. package/dist/cli/src/adapters/terminal.d.ts +1 -0
  13. package/dist/cli/src/adapters/terminal.js +10 -1
  14. package/dist/cli/src/adapters/terminal.js.map +1 -1
  15. package/dist/cli/src/adapters/vaultManagerAccess.d.ts +8 -0
  16. package/dist/cli/src/adapters/vaultManagerAccess.js +26 -0
  17. package/dist/cli/src/adapters/vaultManagerAccess.js.map +1 -0
  18. package/dist/cli/src/apps/catenv/catenv.d.ts +2 -0
  19. package/dist/cli/src/apps/catenv/catenv.js +8 -1
  20. package/dist/cli/src/apps/catenv/catenv.js.map +1 -1
  21. package/dist/cli/src/apps/catenv/printVariables.d.ts +2 -2
  22. package/dist/cli/src/apps/catenv/printVariables.js +4 -4
  23. package/dist/cli/src/apps/catenv/printVariables.js.map +1 -1
  24. package/dist/cli/src/apps/catenv/types.d.ts +9 -0
  25. package/dist/cli/src/apps/catenv/writeDotEnvFiles.d.ts +2 -2
  26. package/dist/cli/src/apps/catenv/writeDotEnvFiles.js +1 -1
  27. package/dist/cli/src/apps/catenv/writeDotEnvFiles.js.map +1 -1
  28. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js +52 -3
  29. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js.map +1 -1
  30. package/dist/cli/src/catenv.js +3 -2
  31. package/dist/cli/src/catenv.js.map +1 -1
  32. package/dist/cli/src/commands/index.d.ts +1 -0
  33. package/dist/cli/src/commands/index.js +8 -1
  34. package/dist/cli/src/commands/index.js.map +1 -1
  35. package/dist/cli/src/commands/project/commandSecretsSyncGithub.d.ts +37 -0
  36. package/dist/cli/src/commands/project/commandSecretsSyncGithub.js +127 -0
  37. package/dist/cli/src/commands/project/commandSecretsSyncGithub.js.map +1 -0
  38. package/dist/cli/src/config/getProjectConfig.d.ts +1 -1
  39. package/dist/cli/src/config/getProjectConfig.js +12 -2
  40. package/dist/cli/src/config/getProjectConfig.js.map +1 -1
  41. package/dist/cli/src/core/types.d.ts +15 -0
  42. package/dist/cli/src/core/types.js +8 -1
  43. package/dist/cli/src/core/types.js.map +1 -1
  44. package/dist/cli/src/git/gitProjectInformation.d.ts +1 -1
  45. package/dist/cli/src/git/gitProjectInformation.js +3 -3
  46. package/dist/cli/src/git/gitProjectInformation.js.map +1 -1
  47. package/dist/cli/src/utils/github.d.ts +15 -0
  48. package/dist/cli/src/utils/github.js +54 -0
  49. package/dist/cli/src/utils/github.js.map +1 -0
  50. package/dist/cli/src/vault/BitwardenVault.d.ts +24 -0
  51. package/dist/cli/src/vault/BitwardenVault.js +107 -0
  52. package/dist/cli/src/vault/BitwardenVault.js.map +1 -0
  53. package/dist/cli/src/vault/GitlabVault.d.ts +11 -0
  54. package/dist/cli/src/vault/GitlabVault.js +24 -0
  55. package/dist/cli/src/vault/GitlabVault.js.map +1 -0
  56. package/dist/cli/src/vault/VaultManager.d.ts +43 -0
  57. package/dist/cli/src/vault/VaultManager.js +131 -0
  58. package/dist/cli/src/vault/VaultManager.js.map +1 -0
  59. package/dist/cli/src/vault/bw.d.ts +15 -0
  60. package/dist/cli/src/vault/bw.js +89 -0
  61. package/dist/cli/src/vault/bw.js.map +1 -0
  62. package/dist/cli/src/vault/cache.d.ts +38 -0
  63. package/dist/cli/src/vault/cache.js +53 -0
  64. package/dist/cli/src/vault/cache.js.map +1 -0
  65. package/dist/cli/src/vault/index.d.ts +5 -0
  66. package/dist/cli/src/vault/index.js +48 -0
  67. package/dist/cli/src/vault/index.js.map +1 -0
  68. package/dist/cli/src/vault/types.d.ts +33 -0
  69. package/dist/cli/src/vault/types.js +5 -0
  70. package/dist/cli/src/vault/types.js.map +1 -0
  71. package/dist/pipeline/src/backends/github/GithubBackend.d.ts +12 -0
  72. package/dist/pipeline/src/backends/github/GithubBackend.js +170 -0
  73. package/dist/pipeline/src/backends/github/GithubBackend.js.map +1 -0
  74. package/dist/pipeline/src/backends/github/ciVariables.d.ts +14 -0
  75. package/dist/pipeline/src/backends/github/ciVariables.js +31 -0
  76. package/dist/pipeline/src/backends/github/ciVariables.js.map +1 -0
  77. package/dist/pipeline/src/backends/github/createGithubJobs.d.ts +17 -0
  78. package/dist/pipeline/src/backends/github/createGithubJobs.js +208 -0
  79. package/dist/pipeline/src/backends/github/createGithubJobs.js.map +1 -0
  80. package/dist/pipeline/src/backends/github/githubReleaseJobs.d.ts +15 -0
  81. package/dist/pipeline/src/backends/github/githubReleaseJobs.js +65 -0
  82. package/dist/pipeline/src/backends/github/githubReleaseJobs.js.map +1 -0
  83. package/dist/pipeline/src/backends/github/index.d.ts +2 -0
  84. package/dist/pipeline/src/backends/github/index.js +26 -0
  85. package/dist/pipeline/src/backends/github/index.js.map +1 -0
  86. package/dist/pipeline/src/backends/github/scriptFunctions.d.ts +6 -0
  87. package/dist/pipeline/src/backends/github/scriptFunctions.js +30 -0
  88. package/dist/pipeline/src/backends/github/scriptFunctions.js.map +1 -0
  89. package/dist/pipeline/src/backends/gitlab/GitlabBackend.d.ts +1 -0
  90. package/dist/pipeline/src/backends/gitlab/GitlabBackend.js +7 -0
  91. package/dist/pipeline/src/backends/gitlab/GitlabBackend.js.map +1 -1
  92. package/dist/pipeline/src/backends/index.d.ts +18 -1
  93. package/dist/pipeline/src/backends/index.js +37 -2
  94. package/dist/pipeline/src/backends/index.js.map +1 -1
  95. package/dist/pipeline/src/backends/types.d.ts +7 -3
  96. package/dist/pipeline/src/bash/ciVariables.js +4 -2
  97. package/dist/pipeline/src/bash/ciVariables.js.map +1 -1
  98. package/dist/pipeline/src/constants.js +1 -1
  99. package/dist/pipeline/src/context/getReviewSlug.js +3 -1
  100. package/dist/pipeline/src/context/getReviewSlug.js.map +1 -1
  101. package/dist/pipeline/src/deploy/cloudRun/index.js +11 -4
  102. package/dist/pipeline/src/deploy/cloudRun/index.js.map +1 -1
  103. package/dist/pipeline/src/pipeline/generatePipelineFiles.js +2 -5
  104. package/dist/pipeline/src/pipeline/generatePipelineFiles.js.map +1 -1
  105. package/dist/pipeline/src/types/config.d.ts +37 -3
  106. package/dist/pipeline/src/types/github-types.d.ts +47 -0
  107. package/dist/pipeline/src/types/github-types.js +9 -0
  108. package/dist/pipeline/src/types/github-types.js.map +1 -0
  109. package/dist/pipeline/src/types/pipeline.d.ts +4 -3
  110. package/dist/tsconfig.tsbuildinfo +1 -1
  111. package/package.json +1 -1
  112. package/src/adapters/baseContext.ts +10 -0
  113. package/src/adapters/nonInteractive.ts +30 -0
  114. package/src/adapters/programmatic.ts +7 -1
  115. package/src/adapters/terminal.ts +9 -1
  116. package/src/adapters/vaultManagerAccess.ts +25 -0
  117. package/src/apps/catenv/catenv.ts +5 -1
  118. package/src/apps/catenv/printVariables.ts +16 -6
  119. package/src/apps/catenv/types.ts +9 -0
  120. package/src/apps/catenv/writeDotEnvFiles.ts +3 -3
  121. package/src/apps/cli/commands/project/commandConfigSecrets.ts +94 -9
  122. package/src/catenv.ts +22 -2
  123. package/src/commands/index.ts +1 -0
  124. package/src/commands/project/commandSecretsSyncGithub.ts +149 -0
  125. package/src/config/getProjectConfig.ts +21 -7
  126. package/src/core/types.ts +23 -0
  127. package/src/git/gitProjectInformation.ts +5 -3
  128. package/src/utils/github.ts +59 -0
  129. package/src/vault/BitwardenVault.ts +161 -0
  130. package/src/vault/GitlabVault.ts +25 -0
  131. package/src/vault/VaultManager.ts +211 -0
  132. package/src/vault/bw.ts +110 -0
  133. package/src/vault/cache.ts +80 -0
  134. package/src/vault/index.ts +5 -0
  135. package/src/vault/types.ts +42 -0
@@ -1,6 +1,78 @@
1
1
  /******/ (() => { // webpackBootstrap
2
2
  /******/ var __webpack_modules__ = ({
3
3
 
4
+ /***/ 1917:
5
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
6
+
7
+ "use strict";
8
+
9
+
10
+ Object.defineProperty(exports, "__esModule", ({
11
+ value: true
12
+ }));
13
+ exports.createNonInteractiveIO = void 0;
14
+ const types_1 = __nccwpck_require__(2284);
15
+ const vaultManagerAccess_1 = __nccwpck_require__(7881);
16
+ /**
17
+ * the context of non-interactive runs (catenv via direnv): logging
18
+ * goes to stderr, any required interaction fails with a clear error.
19
+ */
20
+ function createNonInteractiveIO(options = {}) {
21
+ const io = {
22
+ interactive: false,
23
+ getVaultManager: (0, vaultManagerAccess_1.createVaultManagerGetter)(() => io, {
24
+ mode: options.vaultMode
25
+ }),
26
+ log(message) {
27
+ // stderr: stdout may be evaluated (direnv)
28
+ console.error(message);
29
+ },
30
+ async confirm(message) {
31
+ throw new types_1.NonInteractiveError(`confirmation ("${message}")`);
32
+ },
33
+ async promptDirect(spec) {
34
+ throw new types_1.NonInteractiveError(`input "${spec.name}"`);
35
+ }
36
+ };
37
+ return io;
38
+ }
39
+ exports.createNonInteractiveIO = createNonInteractiveIO;
40
+
41
+ /***/ }),
42
+
43
+ /***/ 7881:
44
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
45
+
46
+ "use strict";
47
+
48
+
49
+ Object.defineProperty(exports, "__esModule", ({
50
+ value: true
51
+ }));
52
+ exports.createVaultManagerGetter = void 0;
53
+ const getProjectConfig_1 = __nccwpck_require__(1);
54
+ const VaultManager_1 = __nccwpck_require__(5771);
55
+ /**
56
+ * lazily creates the vault manager of a context (once per context),
57
+ * loading the project config on first use
58
+ */
59
+ const createVaultManagerGetter = (io, options = {}) => {
60
+ let managerPromise;
61
+ return () => managerPromise !== null && managerPromise !== void 0 ? managerPromise : managerPromise = (async () => {
62
+ const config = await (0, getProjectConfig_1.getProjectConfig)();
63
+ if (!config) {
64
+ throw new Error("no catladder config found — the secrets vault needs a project config");
65
+ }
66
+ return new VaultManager_1.VaultManager(config, {
67
+ ...options,
68
+ io: io()
69
+ });
70
+ })();
71
+ };
72
+ exports.createVaultManagerGetter = createVaultManagerGetter;
73
+
74
+ /***/ }),
75
+
4
76
  /***/ 6057:
5
77
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
6
78
 
@@ -16,12 +88,19 @@ const verboseBanner_1 = __nccwpck_require__(5472);
16
88
  const writeDotEnvFiles_1 = __nccwpck_require__(5614);
17
89
  const writeEnvDTs_1 = __nccwpck_require__(8832);
18
90
  const pipeline_1 = __nccwpck_require__(241);
91
+ const nonInteractive_1 = __nccwpck_require__(1917);
19
92
  exports["default"] = async (choice, options) => {
20
93
  const config = await (0, getProjectConfig_1.getProjectConfig)();
21
94
  if (!config) {
22
95
  return;
23
96
  }
24
- const context = (0, pipeline_1.createCatenvContext)(config);
97
+ const io = (0, nonInteractive_1.createNonInteractiveIO)({
98
+ vaultMode: options === null || options === void 0 ? void 0 : options.vaultMode
99
+ });
100
+ const context = {
101
+ ...(0, pipeline_1.createCatenvContext)(config),
102
+ io
103
+ };
25
104
  if (options === null || options === void 0 ? void 0 : options.verbose) {
26
105
  (0, verboseBanner_1.printVerboseBanner)();
27
106
  }
@@ -42,19 +121,19 @@ Object.defineProperty(exports, "__esModule", ({
42
121
  exports.printVariables = void 0;
43
122
  const getProjectConfig_1 = __nccwpck_require__(1);
44
123
  const utils_1 = __nccwpck_require__(1909);
45
- const getAllVariablesToPrint = async (config, choice) => {
124
+ const getAllVariablesToPrint = async (io, config, choice) => {
46
125
  const {
47
126
  env,
48
127
  currentComponent
49
128
  } = await (0, utils_1.getCurrentComponentAndEnvFromChoice)(config, choice);
50
129
  if (currentComponent) {
51
- return await (0, getProjectConfig_1.getEnvVarsResolved)(null, env, currentComponent);
130
+ return await (0, getProjectConfig_1.getEnvVarsResolved)(io, env, currentComponent);
52
131
  } else {
53
132
  // when in a monorep and not in a subapp, merge all env vars.
54
133
  // this is not 100% correct, but better than not exporting any vars at all
55
134
  // so we also add prefixed variants
56
135
  return await Object.keys(config.components).reduce(async (acc, componentName) => {
57
- const subappvars = await (0, getProjectConfig_1.getEnvVarsResolved)(null, env, componentName);
136
+ const subappvars = await (0, getProjectConfig_1.getEnvVarsResolved)(io, env, componentName);
58
137
  delete subappvars["_ALL_ENV_VAR_KEYS"];
59
138
  return {
60
139
  ...(await acc),
@@ -66,7 +145,7 @@ const getAllVariablesToPrint = async (config, choice) => {
66
145
  }
67
146
  };
68
147
  const printVariables = async (context, choice) => {
69
- const variables = await getAllVariablesToPrint(context.config, choice);
148
+ const variables = await getAllVariablesToPrint(context.io, context.config, choice);
70
149
  console.log(makeExportKeyValuestring(variables));
71
150
  };
72
151
  exports.printVariables = printVariables;
@@ -185,7 +264,7 @@ const writeDotEnvFiles = async (context, choice) => {
185
264
  const componentsToActuallyWriteDotEnvNow = currentComponent ? componentsWithEnabledDotEnvWrite.includes(currentComponent) ? [currentComponent] : [] : componentsWithEnabledDotEnvWrite;
186
265
  const gitRoot = await (0, projects_1.getGitRoot)();
187
266
  for (const componentName of componentsToActuallyWriteDotEnvNow) {
188
- const variables = await (0, getProjectConfig_1.getEnvVarsResolved)(null, env, componentName);
267
+ const variables = await (0, getProjectConfig_1.getEnvVarsResolved)(context.io, env, componentName);
189
268
  delete variables["_ALL_ENV_VAR_KEYS"];
190
269
  const componentDir = (0, utils_1.getComponentFullPath)(gitRoot, context.config, componentName);
191
270
  const filePath = (0, path_1.join)(componentDir, ".env");
@@ -279,11 +358,12 @@ const catenv_1 = __importDefault(__nccwpck_require__(6057));
279
358
  const parseChoice_1 = __nccwpck_require__(4272);
280
359
  const packageInfos_1 = __importDefault(__nccwpck_require__(3568));
281
360
  const program = new commander_1.Command();
282
- program.name("catenv").description("Environment variable and pipeline generation via direnv").version(packageInfos_1.default.version).argument("[envComponent]", "env or env:component").option("-v, --verbose", "verbose output").option("-p, --print-variables", "print variables").action((envComponent, opts) => {
361
+ program.name("catenv").description("Environment variable and pipeline generation via direnv").version(packageInfos_1.default.version).argument("[envComponent]", "env or env:component").option("-v, --verbose", "verbose output").option("-p, --print-variables", "print variables").addOption(new commander_1.Option("--vault-mode <mode>", ["how to interact with the secrets vault:", "auto: contact the vault when cached secrets are missing (may prompt to unlock)", "no-prompt: like auto, but fail instead of prompting", "offline: never contact the vault, use only locally cached secrets", "refresh: ignore the local cache once and refresh it from the vault"].join("\n")).choices(["auto", "no-prompt", "offline", "refresh"]).default("auto")).action((envComponent, opts) => {
283
362
  var _a, _b;
284
363
  (0, catenv_1.default)(envComponent ? (0, parseChoice_1.parseChoice)(envComponent) : null, {
285
364
  verbose: (_a = opts.verbose) !== null && _a !== void 0 ? _a : false,
286
- printVariables: (_b = opts.printVariables) !== null && _b !== void 0 ? _b : false
365
+ printVariables: (_b = opts.printVariables) !== null && _b !== void 0 ? _b : false,
366
+ vaultMode: opts.vaultMode
287
367
  }).then(() => {
288
368
  // we have to exit manually, because we have some file watches
289
369
  process.exit();
@@ -403,14 +483,24 @@ const getGitlabVar = async (io, env, componentName, variableName) => {
403
483
  };
404
484
  exports.getGitlabVar = getGitlabVar;
405
485
  const resolveSecrets = async (io, varSets) => {
406
- const allVariablesInGitlab = await (0, gitlab_1.getAllVariables)(io);
486
+ // the secret variables actually referenced by the env var values —
487
+ // when they are all in the local cache, the vault is not contacted
488
+ const referencedNames = [...new Set(varSets.flatMap(({
489
+ envVars
490
+ }) => Object.values(envVars).flatMap(value => {
491
+ var _a;
492
+ return (_a = `${value}`.match(/\$CL_\w+/g)) !== null && _a !== void 0 ? _a : [];
493
+ })))].map(reference => reference.slice(1));
494
+ const vaultManager = await io.getVaultManager();
495
+ const secrets = await vaultManager.readSecrets(referencedNames, io);
496
+ const secretEntries = Object.entries(secrets);
407
497
  return Object.fromEntries(varSets.flatMap(({
408
498
  envVars,
409
499
  secretEnvVarKeys
410
500
  }) => Object.entries(envVars).filter(([key, value]) => {
411
501
  var _a;
412
502
  return value !== undefined && value !== null && !((_a = secretEnvVarKeys.find(k => k.key === key)) === null || _a === void 0 ? void 0 : _a.hidden);
413
- }).map(([key, value]) => [key, allVariablesInGitlab.reduce((acc, curr) => acc.replace(new RegExp("\\$" + curr.key, "g"), curr.value), `${value}`)])));
503
+ }).map(([key, value]) => [key, secretEntries.reduce((acc, [name, secretValue]) => acc.replace(new RegExp("\\$" + name, "g"), secretValue), `${value}`)])));
414
504
  };
415
505
  const getEnvVarsResolved = async (io, env, componentName) => {
416
506
  if (!componentName) {
@@ -464,6 +554,36 @@ exports.parseChoice = parseChoice;
464
554
 
465
555
  /***/ }),
466
556
 
557
+ /***/ 2284:
558
+ /***/ ((__unused_webpack_module, exports) => {
559
+
560
+ "use strict";
561
+
562
+
563
+ Object.defineProperty(exports, "__esModule", ({
564
+ value: true
565
+ }));
566
+ exports.MissingInputError = exports.NonInteractiveError = void 0;
567
+ // ─── Errors ──────────────────────────────────────────────────────────
568
+ class NonInteractiveError extends Error {
569
+ constructor(interaction) {
570
+ super(`${interaction} requires an interactive terminal, but this context is not interactive`);
571
+ this.name = "NonInteractiveError";
572
+ }
573
+ }
574
+ exports.NonInteractiveError = NonInteractiveError;
575
+ class MissingInputError extends Error {
576
+ constructor(inputName, promptMessage) {
577
+ super(`Missing required input: "${inputName}" (${promptMessage}). ` + `Provide it via --${inputName}=<value> or --inputs='{"${inputName}": ...}'`);
578
+ this.inputName = inputName;
579
+ this.promptMessage = promptMessage;
580
+ this.name = "MissingInputError";
581
+ }
582
+ }
583
+ exports.MissingInputError = MissingInputError;
584
+
585
+ /***/ }),
586
+
467
587
  /***/ 6636:
468
588
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
469
589
 
@@ -518,14 +638,14 @@ exports.getProjectRootPath = getProjectRootPath;
518
638
  /**
519
639
  * Get the git remote hostname and project path from the git config.
520
640
  */
521
- const getGitRemoteHostAndPath = async () => {
641
+ const getGitRemoteHostAndPath = async (remoteName = "origin") => {
522
642
  var _a;
523
- const remoteUrl = await (0, gitConfig_1.gitConfigGet)("remote.origin.url");
643
+ const remoteUrl = await (0, gitConfig_1.gitConfigGet)(`remote.${remoteName}.url`);
524
644
  const remoteReg = /(https:\/\/|git@)([^:/]+)[:/]([^.]*)(\.git)?/;
525
645
  const match = (_a = remoteUrl.match(remoteReg)) !== null && _a !== void 0 ? _a : [];
526
646
  const [,, gitRemoteHost, gitRemotePath] = match;
527
647
  if (!(gitRemoteHost === null || gitRemoteHost === void 0 ? void 0 : gitRemoteHost.length) || !(gitRemotePath === null || gitRemotePath === void 0 ? void 0 : gitRemotePath.length)) {
528
- throw new Error(`Failed to parse git remote hostname and path from git configs remote.origin.url! ${remoteUrl}`);
648
+ throw new Error(`Failed to parse git remote hostname and path from git configs remote.${remoteName}.url! ${remoteUrl}`);
529
649
  }
530
650
  return {
531
651
  gitRemoteHost,
@@ -947,6 +1067,1017 @@ exports.getProjectNamespace = getProjectNamespace;
947
1067
 
948
1068
  /***/ }),
949
1069
 
1070
+ /***/ 3510:
1071
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1072
+
1073
+ "use strict";
1074
+
1075
+
1076
+ Object.defineProperty(exports, "__esModule", ({
1077
+ value: true
1078
+ }));
1079
+ exports.BitwardenVault = void 0;
1080
+ const pipeline_1 = __nccwpck_require__(241);
1081
+ const yaml_1 = __nccwpck_require__(6637);
1082
+ const bw_1 = __nccwpck_require__(2211);
1083
+ const DEFAULT_COLLECTION = "catladder";
1084
+ const SECURE_NOTE_TYPE = 2;
1085
+ /**
1086
+ * one yaml note per env and component:
1087
+ * `<customerName>/<appName>/<env>/<componentName>/secrets.yml`
1088
+ */
1089
+ const itemName = (config, env, componentName) => `${config.customerName}/${config.appName}/${env}/${componentName}/secrets.yml`;
1090
+ const itemPrefix = config => `${config.customerName}/${config.appName}/`;
1091
+ /**
1092
+ * parses env and componentName back out of an item name
1093
+ */
1094
+ const parseItemName = (config, name) => {
1095
+ const match = name.slice(itemPrefix(config).length).match(/^([^/]+)\/([^/]+)\/secrets\.yml$/);
1096
+ return match ? {
1097
+ env: match[1],
1098
+ componentName: match[2]
1099
+ } : null;
1100
+ };
1101
+ const findCollection = async (session, collectionName) => {
1102
+ const collections = await (0, bw_1.runBwJson)(session, ["list", "collections", "--search", collectionName]);
1103
+ const collection = collections.find(c => c.name === collectionName);
1104
+ if (!collection) {
1105
+ throw new Error(`bitwarden collection '${collectionName}' not found — create it and make sure you have access`);
1106
+ }
1107
+ return collection;
1108
+ };
1109
+ const encodePayload = payload => Buffer.from(JSON.stringify(payload), "utf-8").toString("base64");
1110
+ class BitwardenVault {
1111
+ constructor(config, options,
1112
+ /**
1113
+ * whether a locked bitwarden may be unlocked interactively
1114
+ * (false with catenv --vault-mode no-prompt)
1115
+ */
1116
+ allowPrompt) {
1117
+ var _a;
1118
+ this.config = config;
1119
+ this.allowPrompt = allowPrompt;
1120
+ this.collectionName = (_a = options.collection) !== null && _a !== void 0 ? _a : DEFAULT_COLLECTION;
1121
+ this.id = `bitwarden:${this.collectionName}`;
1122
+ }
1123
+ session(io) {
1124
+ return (0, bw_1.getBwSession)(io, {
1125
+ allowPrompt: this.allowPrompt
1126
+ });
1127
+ }
1128
+ async readAllSecrets(io) {
1129
+ const {
1130
+ config,
1131
+ collectionName
1132
+ } = this;
1133
+ const bwSession = await this.session(io);
1134
+ const collection = await findCollection(bwSession, collectionName);
1135
+ const items = await (0, bw_1.runBwJson)(bwSession, ["list", "items", "--collectionid", collection.id]);
1136
+ const secrets = {};
1137
+ for (const item of items) {
1138
+ const parsed = parseItemName(config, item.name);
1139
+ if (!parsed || !item.notes) {
1140
+ continue;
1141
+ }
1142
+ const values = (0, yaml_1.parse)(item.notes);
1143
+ Object.entries(values !== null && values !== void 0 ? values : {}).forEach(([key, value]) => {
1144
+ secrets[(0, pipeline_1.getSecretVarName)(parsed.env, parsed.componentName, key)] = typeof value === "string" ? value : JSON.stringify(value);
1145
+ });
1146
+ }
1147
+ return secrets;
1148
+ }
1149
+ async writeSecrets(io, env, componentName, secrets) {
1150
+ const {
1151
+ config,
1152
+ collectionName
1153
+ } = this;
1154
+ const bwSession = await this.session(io);
1155
+ const collection = await findCollection(bwSession, collectionName);
1156
+ const name = itemName(config, env, componentName);
1157
+ const existing = (await (0, bw_1.runBwJson)(bwSession, ["list", "items", "--collectionid", collection.id, "--search", name])).find(item => item.name === name);
1158
+ const notes = (0, yaml_1.stringify)(secrets);
1159
+ if (existing) {
1160
+ await (0, bw_1.runBw)(bwSession, ["edit", "item", existing.id, encodePayload({
1161
+ ...existing,
1162
+ notes
1163
+ })]);
1164
+ } else {
1165
+ await (0, bw_1.runBw)(bwSession, ["create", "item", encodePayload({
1166
+ type: SECURE_NOTE_TYPE,
1167
+ secureNote: {
1168
+ type: 0
1169
+ },
1170
+ name,
1171
+ notes,
1172
+ ...(collection.organizationId ? {
1173
+ organizationId: collection.organizationId,
1174
+ collectionIds: [collection.id]
1175
+ } : {})
1176
+ })]);
1177
+ }
1178
+ }
1179
+ }
1180
+ exports.BitwardenVault = BitwardenVault;
1181
+
1182
+ /***/ }),
1183
+
1184
+ /***/ 1107:
1185
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1186
+
1187
+ "use strict";
1188
+
1189
+
1190
+ Object.defineProperty(exports, "__esModule", ({
1191
+ value: true
1192
+ }));
1193
+ exports.GitlabVault = void 0;
1194
+ const gitlab_1 = __nccwpck_require__(4508);
1195
+ /**
1196
+ * the legacy (and default) vault: the gitlab project variables double
1197
+ * as the secret store
1198
+ */
1199
+ class GitlabVault {
1200
+ constructor() {
1201
+ this.id = "gitlab";
1202
+ }
1203
+ async readAllSecrets(io) {
1204
+ const variables = await (0, gitlab_1.getAllVariables)(io);
1205
+ return Object.fromEntries(variables.map(v => [v.key, v.value]));
1206
+ }
1207
+ async writeSecrets(io, env, componentName, secrets) {
1208
+ await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName);
1209
+ }
1210
+ }
1211
+ exports.GitlabVault = GitlabVault;
1212
+
1213
+ /***/ }),
1214
+
1215
+ /***/ 5771:
1216
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1217
+
1218
+ "use strict";
1219
+
1220
+
1221
+ Object.defineProperty(exports, "__esModule", ({
1222
+ value: true
1223
+ }));
1224
+ exports.VaultManager = void 0;
1225
+ const pipeline_1 = __nccwpck_require__(241);
1226
+ const BitwardenVault_1 = __nccwpck_require__(3510);
1227
+ const cache_1 = __nccwpck_require__(4236);
1228
+ const GitlabVault_1 = __nccwpck_require__(1107);
1229
+ /**
1230
+ * only secrets of this env are cached locally — the other envs'
1231
+ * secrets have no business sitting on developer machines
1232
+ */
1233
+ const CACHED_ENV = "local";
1234
+ /**
1235
+ * owns the configured vault, the secrets mode and the local cache.
1236
+ * The vault is the readable source of truth for secrets; CI backends
1237
+ * only receive mirrored copies.
1238
+ */
1239
+ class VaultManager {
1240
+ constructor(config, options = {}) {
1241
+ var _a, _b;
1242
+ this.config = config;
1243
+ /** refresh mode bypasses the cache only once per manager */
1244
+ this.refreshed = false;
1245
+ this.mode = (_a = options.mode) !== null && _a !== void 0 ? _a : "auto";
1246
+ this.io = (_b = options.io) !== null && _b !== void 0 ? _b : null;
1247
+ this.vault = this.createVault();
1248
+ }
1249
+ createVault() {
1250
+ const vaultConfig = (0, pipeline_1.getVaultConfig)(this.config);
1251
+ switch (vaultConfig.type) {
1252
+ case "gitlab":
1253
+ return new GitlabVault_1.GitlabVault();
1254
+ case "bitwarden":
1255
+ return new BitwardenVault_1.BitwardenVault(this.config, vaultConfig, this.mode === "auto" || this.mode === "refresh");
1256
+ }
1257
+ }
1258
+ /**
1259
+ * the vault secrets, served from the local cache when it contains
1260
+ * all required names; otherwise (depending on the mode) refreshed
1261
+ * from the vault. Only the "local" env is (re-)cached.
1262
+ */
1263
+ async readSecrets(requiredNames, io = this.io) {
1264
+ const bypassCache = this.mode === "refresh" && !this.refreshed;
1265
+ const cache = bypassCache ? null : await (0, cache_1.readSecretsCache)();
1266
+ // known entries include recorded misses (null values), so declared
1267
+ // but intentionally unset secrets don't force a vault refresh
1268
+ const known = (cache === null || cache === void 0 ? void 0 : cache.vaultId) === this.vault.id ? flattenSecrets(cache.secrets) : undefined;
1269
+ const missing = requiredNames.filter(name => !(name in (known !== null && known !== void 0 ? known : {})));
1270
+ // nothing missing (or nothing required at all): don't touch the vault
1271
+ if (missing.length === 0 && (known || requiredNames.length === 0)) {
1272
+ return withoutMisses(known !== null && known !== void 0 ? known : {});
1273
+ }
1274
+ if (this.mode === "offline") {
1275
+ if (missing.length > 0) {
1276
+ io === null || io === void 0 ? void 0 : io.log(`⚠️ vault is offline (--vault-mode offline) and ${missing.length} secrets are not in the local cache: ${missing.join(", ")}`);
1277
+ }
1278
+ return withoutMisses(known !== null && known !== void 0 ? known : {});
1279
+ }
1280
+ const secrets = await this.vault.readAllSecrets(io);
1281
+ this.refreshed = true;
1282
+ await (0, cache_1.writeSecretsCache)(this.vault.id, await this.cacheableSubset(secrets));
1283
+ return secrets;
1284
+ }
1285
+ /**
1286
+ * writes secrets of one env/component to the vault and updates the
1287
+ * local cache (write-through, "local" env only)
1288
+ */
1289
+ async writeSecrets(env, componentName, secrets, io = this.io) {
1290
+ if (!io) {
1291
+ throw new Error("writing to the vault requires an interactive context");
1292
+ }
1293
+ await this.vault.writeSecrets(io, env, componentName, secrets);
1294
+ if (env === CACHED_ENV) {
1295
+ await (0, cache_1.updateSecretsCache)(this.vault.id, env, componentName, Object.fromEntries(Object.entries(secrets).map(([key, value]) => [key, typeof value === "string" ? value : JSON.stringify(value)])));
1296
+ }
1297
+ }
1298
+ /**
1299
+ * the subset of the vault secrets that may be cached: the declared
1300
+ * secrets of the "local" env, per component, as a hierarchy
1301
+ */
1302
+ async cacheableSubset(flatSecrets) {
1303
+ const local = {};
1304
+ for (const componentName of Object.keys(this.config.components)) {
1305
+ const keys = await this.declaredSecretKeys(componentName);
1306
+ const values = Object.fromEntries(keys.map(key => {
1307
+ var _a;
1308
+ return [key,
1309
+ // null records "absent in the vault" (a known miss)
1310
+ (_a = flatSecrets[(0, pipeline_1.getSecretVarName)(CACHED_ENV, componentName, key)]) !== null && _a !== void 0 ? _a : null];
1311
+ }));
1312
+ if (Object.keys(values).length > 0) {
1313
+ local[componentName] = values;
1314
+ }
1315
+ }
1316
+ return Object.keys(local).length > 0 ? {
1317
+ [CACHED_ENV]: local
1318
+ } : {};
1319
+ }
1320
+ async declaredSecretKeys(componentName) {
1321
+ try {
1322
+ const {
1323
+ secretEnvVarKeys,
1324
+ jobOnlyVars
1325
+ } = await (0, pipeline_1.getEnvironment)({
1326
+ config: this.config,
1327
+ componentName,
1328
+ env: CACHED_ENV
1329
+ });
1330
+ return [...secretEnvVarKeys, ...jobOnlyVars.build.secretEnvVarKeys, ...jobOnlyVars.deploy.secretEnvVarKeys].map(({
1331
+ key
1332
+ }) => key);
1333
+ } catch (_a) {
1334
+ // components without a local env simply have nothing to cache
1335
+ return [];
1336
+ }
1337
+ }
1338
+ }
1339
+ exports.VaultManager = VaultManager;
1340
+ /**
1341
+ * the cache hierarchy as a flat map of raw secret variable names
1342
+ * (null values = recorded misses)
1343
+ */
1344
+ const flattenSecrets = secrets => Object.fromEntries(Object.entries(secrets).flatMap(([env, components]) => Object.entries(components).flatMap(([componentName, values]) => Object.entries(values).map(([key, value]) => [(0, pipeline_1.getSecretVarName)(env, componentName, key), value]))));
1345
+ /**
1346
+ * only actual values — recorded misses stay unresolved, like any other
1347
+ * unset variable
1348
+ */
1349
+ const withoutMisses = known => Object.fromEntries(Object.entries(known).filter(entry => entry[1] !== null));
1350
+
1351
+ /***/ }),
1352
+
1353
+ /***/ 2211:
1354
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1355
+
1356
+ "use strict";
1357
+
1358
+
1359
+ Object.defineProperty(exports, "__esModule", ({
1360
+ value: true
1361
+ }));
1362
+ exports.runBwJson = exports.runBw = exports.getBwSession = void 0;
1363
+ const child_process_1 = __nccwpck_require__(5317);
1364
+ const util_1 = __nccwpck_require__(9023);
1365
+ const preferences_1 = __nccwpck_require__(6261);
1366
+ const execFile = (0, util_1.promisify)(child_process_1.execFile);
1367
+ const SESSION_PREFERENCE = "bwsession";
1368
+ class BitwardenLockedError extends Error {
1369
+ constructor() {
1370
+ super("bitwarden is locked and prompting is disabled — run `bw unlock` or catenv without --vault-mode no-prompt");
1371
+ }
1372
+ }
1373
+ /**
1374
+ * runs an interactive bw command that prints a session key on stdout
1375
+ * (login/unlock) while the user types the password on the terminal
1376
+ */
1377
+ const interactiveSessionCommand = args => new Promise((resolve, reject) => {
1378
+ var _a;
1379
+ const child = (0, child_process_1.spawn)("bw", [...args, "--raw"], {
1380
+ stdio: ["inherit", "pipe", "inherit"]
1381
+ });
1382
+ let session = "";
1383
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", data => session += data.toString("utf-8"));
1384
+ child.on("error", reject);
1385
+ child.on("close", code => code === 0 && session.trim() ? resolve(session.trim()) : reject(new Error(`bw ${args[0]} failed`)));
1386
+ });
1387
+ const getBwStatus = async session => {
1388
+ try {
1389
+ const {
1390
+ stdout
1391
+ } = await execFile("bw", ["status"], {
1392
+ env: {
1393
+ ...process.env,
1394
+ ...(session ? {
1395
+ BW_SESSION: session
1396
+ } : {})
1397
+ }
1398
+ });
1399
+ return JSON.parse(stdout).status;
1400
+ } catch (_a) {
1401
+ return "unauthenticated";
1402
+ }
1403
+ };
1404
+ /**
1405
+ * a working bw session: reuses the cached one, otherwise unlocks (or
1406
+ * logs in) interactively — unless prompting is disabled
1407
+ */
1408
+ const getBwSession = async (io, {
1409
+ allowPrompt
1410
+ }) => {
1411
+ const cached = (await (0, preferences_1.hasPreference)(SESSION_PREFERENCE)) ? String(await (0, preferences_1.getPreference)(SESSION_PREFERENCE)) : null;
1412
+ const status = await getBwStatus(cached);
1413
+ if (status === "unlocked" && cached) {
1414
+ return cached;
1415
+ }
1416
+ if (!allowPrompt) {
1417
+ throw new BitwardenLockedError();
1418
+ }
1419
+ io === null || io === void 0 ? void 0 : io.log("");
1420
+ io === null || io === void 0 ? void 0 : io.log(status === "unauthenticated" ? "# Please login to Bitwarden:" : "# Bitwarden is locked, please unlock:");
1421
+ io === null || io === void 0 ? void 0 : io.log("");
1422
+ const session = await interactiveSessionCommand([status === "unauthenticated" ? "login" : "unlock"]);
1423
+ await (0, preferences_1.setPreference)(SESSION_PREFERENCE, session);
1424
+ await (0, exports.runBw)(session, ["sync"]);
1425
+ return session;
1426
+ };
1427
+ exports.getBwSession = getBwSession;
1428
+ /**
1429
+ * runs a bw command with the given session and returns stdout
1430
+ */
1431
+ const runBw = async (session, args) => {
1432
+ const {
1433
+ stdout
1434
+ } = await execFile("bw", [...args, "--raw", "--nointeraction"], {
1435
+ env: {
1436
+ ...process.env,
1437
+ BW_SESSION: session
1438
+ },
1439
+ maxBuffer: 50 * 1024 * 1024
1440
+ });
1441
+ return stdout;
1442
+ };
1443
+ exports.runBw = runBw;
1444
+ const runBwJson = async (session, args) => JSON.parse(await (0, exports.runBw)(session, args));
1445
+ exports.runBwJson = runBwJson;
1446
+
1447
+ /***/ }),
1448
+
1449
+ /***/ 4236:
1450
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1451
+
1452
+ "use strict";
1453
+
1454
+
1455
+ Object.defineProperty(exports, "__esModule", ({
1456
+ value: true
1457
+ }));
1458
+ exports.updateSecretsCache = exports.writeSecretsCache = exports.readSecretsCache = void 0;
1459
+ const promises_1 = __nccwpck_require__(1943);
1460
+ const path_1 = __nccwpck_require__(6928);
1461
+ const gitProjectInformation_1 = __nccwpck_require__(1111);
1462
+ const getCacheFolder = async () => (0, path_1.join)(await (0, gitProjectInformation_1.getProjectRootPath)(), ".catladder");
1463
+ const getCachePath = async () => (0, path_1.join)(await getCacheFolder(), "secrets.json");
1464
+ const readSecretsCache = async () => {
1465
+ try {
1466
+ return JSON.parse(await (0, promises_1.readFile)(await getCachePath(), "utf-8"));
1467
+ } catch (_a) {
1468
+ return null;
1469
+ }
1470
+ };
1471
+ exports.readSecretsCache = readSecretsCache;
1472
+ const writeSecretsCache = async (vaultId, secrets) => {
1473
+ const folder = await getCacheFolder();
1474
+ await (0, promises_1.mkdir)(folder, {
1475
+ recursive: true
1476
+ });
1477
+ // the folder ignores itself, so the cache can never be committed
1478
+ await (0, promises_1.writeFile)((0, path_1.join)(folder, ".gitignore"), "*\n");
1479
+ const cache = {
1480
+ vaultId,
1481
+ updatedAt: new Date().toISOString(),
1482
+ secrets
1483
+ };
1484
+ await (0, promises_1.writeFile)(await getCachePath(), JSON.stringify(cache, null, 2));
1485
+ };
1486
+ exports.writeSecretsCache = writeSecretsCache;
1487
+ /**
1488
+ * merges freshly written secrets of one env/component into the cache
1489
+ * (write-through from config-secrets), so the next catenv run doesn't
1490
+ * need the vault
1491
+ */
1492
+ const updateSecretsCache = async (vaultId, env, componentName, values) => {
1493
+ var _a;
1494
+ const existing = await (0, exports.readSecretsCache)();
1495
+ const secrets = (existing === null || existing === void 0 ? void 0 : existing.vaultId) === vaultId ? existing.secrets : {};
1496
+ secrets[env] = {
1497
+ ...secrets[env],
1498
+ [componentName]: {
1499
+ ...((_a = secrets[env]) === null || _a === void 0 ? void 0 : _a[componentName]),
1500
+ ...values
1501
+ }
1502
+ };
1503
+ await (0, exports.writeSecretsCache)(vaultId, secrets);
1504
+ };
1505
+ exports.updateSecretsCache = updateSecretsCache;
1506
+
1507
+ /***/ }),
1508
+
1509
+ /***/ 4038:
1510
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1511
+
1512
+ "use strict";
1513
+
1514
+
1515
+ Object.defineProperty(exports, "__esModule", ({
1516
+ value: true
1517
+ }));
1518
+ exports.GithubBackend = void 0;
1519
+ const promises_1 = __nccwpck_require__(1943);
1520
+ const path_1 = __nccwpck_require__(6928);
1521
+ const createAllJobs_1 = __nccwpck_require__(3671);
1522
+ const config_1 = __nccwpck_require__(6925);
1523
+ const ciVariables_1 = __nccwpck_require__(3093);
1524
+ const createGithubJobs_1 = __nccwpck_require__(4016);
1525
+ const githubReleaseJobs_1 = __nccwpck_require__(5611);
1526
+ const WORKFLOWS_FOLDER = ".github/workflows";
1527
+ /**
1528
+ * generated workflow files are prefixed so that cleanup never touches
1529
+ * user-maintained workflows in the same folder
1530
+ */
1531
+ const GENERATED_FILE_PREFIX = "catladder-";
1532
+ const TRIGGER_WORKFLOWS = {
1533
+ mr: {
1534
+ name: "catladder review",
1535
+ on: {
1536
+ pull_request: {
1537
+ types: ["opened", "synchronize", "reopened"]
1538
+ }
1539
+ },
1540
+ concurrency: {
1541
+ group: "catladder-review-${{ github.event.number }}",
1542
+ "cancel-in-progress": true
1543
+ }
1544
+ },
1545
+ mainBranch: {
1546
+ name: "catladder main",
1547
+ // TODO: make the default branch configurable
1548
+ on: {
1549
+ push: {
1550
+ branches: ["main"]
1551
+ }
1552
+ }
1553
+ },
1554
+ taggedRelease: {
1555
+ name: "catladder release",
1556
+ on: {
1557
+ push: {
1558
+ tags: ["v*"]
1559
+ }
1560
+ }
1561
+ }
1562
+ };
1563
+ class GithubBackend {
1564
+ constructor() {
1565
+ this.type = "github";
1566
+ }
1567
+ async cleanup() {
1568
+ const entries = await (0, promises_1.readdir)(WORKFLOWS_FOLDER).catch(() => []);
1569
+ await Promise.all(entries.filter(file => file.startsWith(GENERATED_FILE_PREFIX)).map(file => (0, promises_1.unlink)((0, path_1.join)(WORKFLOWS_FOLDER, file))));
1570
+ }
1571
+ async createFiles(config) {
1572
+ const workflows = await this.createWorkflows(config);
1573
+ return Object.entries(workflows).map(([fileName, workflow]) => ({
1574
+ path: (0, path_1.join)(WORKFLOWS_FOLDER, fileName),
1575
+ content: workflow
1576
+ }));
1577
+ }
1578
+ /**
1579
+ * all workflows keyed by file name, mainly for testing purposes
1580
+ */
1581
+ async createWorkflows(config) {
1582
+ const workflows = {};
1583
+ const reviewStopJobs = {};
1584
+ const manualJobs = {};
1585
+ for (const trigger of config_1.ALL_PIPELINE_TRIGGERS) {
1586
+ const allJobs = await (0, createAllJobs_1.createAllJobs)({
1587
+ config,
1588
+ trigger,
1589
+ pipelineType: this.type
1590
+ });
1591
+ const uploadProviderIds = (0, createGithubJobs_1.getUploadProviderIds)(allJobs);
1592
+ const jobs = {};
1593
+ // NOTE: agent jobs are gitlab-only and skipped on github
1594
+ [...allJobs.workspaces, ...allJobs.components].forEach(({
1595
+ context,
1596
+ jobs: contextJobs
1597
+ }) => contextJobs.forEach(job => {
1598
+ const [id, githubJob] = (0, createGithubJobs_1.makeGithubJob)(context, job, allJobs, uploadProviderIds);
1599
+ if (isReviewStopJob(context, job)) {
1600
+ reviewStopJobs[id] = githubJob;
1601
+ } else if (isManualTaskJob(job)) {
1602
+ manualJobs[id] = githubJob;
1603
+ } else {
1604
+ jobs[id] = githubJob;
1605
+ }
1606
+ }));
1607
+ if (trigger === "mainBranch") {
1608
+ const releaseJobs = (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs));
1609
+ Object.assign(jobs, releaseJobs.main);
1610
+ Object.assign(manualJobs, releaseJobs.manual);
1611
+ }
1612
+ if (Object.keys(jobs).length > 0) {
1613
+ workflows[`${GENERATED_FILE_PREFIX}${workflowFileName(trigger)}`] = {
1614
+ ...TRIGGER_WORKFLOWS[trigger],
1615
+ env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
1616
+ jobs
1617
+ };
1618
+ }
1619
+ }
1620
+ if (Object.keys(reviewStopJobs).length > 0) {
1621
+ workflows[`${GENERATED_FILE_PREFIX}review-stop.yml`] = {
1622
+ name: "catladder review stop",
1623
+ on: {
1624
+ pull_request: {
1625
+ types: ["closed"]
1626
+ }
1627
+ },
1628
+ env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
1629
+ jobs: reviewStopJobs
1630
+ };
1631
+ }
1632
+ if (Object.keys(manualJobs).length > 0) {
1633
+ workflows[`${GENERATED_FILE_PREFIX}manual.yml`] = {
1634
+ name: "catladder manual tasks",
1635
+ on: {
1636
+ workflow_dispatch: {
1637
+ inputs: {
1638
+ job: {
1639
+ description: "the task to run",
1640
+ required: true,
1641
+ type: "choice",
1642
+ options: Object.keys(manualJobs)
1643
+ }
1644
+ }
1645
+ }
1646
+ },
1647
+ env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
1648
+ jobs: Object.fromEntries(Object.entries(manualJobs).map(([id, job]) => [id, {
1649
+ ...job,
1650
+ if: `\${{ inputs.job == '${id}' }}`
1651
+ }]))
1652
+ };
1653
+ }
1654
+ return workflows;
1655
+ }
1656
+ }
1657
+ exports.GithubBackend = GithubBackend;
1658
+ const workflowFileName = trigger => {
1659
+ switch (trigger) {
1660
+ case "mr":
1661
+ return "review.yml";
1662
+ case "mainBranch":
1663
+ return "main.yml";
1664
+ case "taggedRelease":
1665
+ return "release.yml";
1666
+ }
1667
+ throw new Error(`${trigger} is not supported`);
1668
+ };
1669
+ /**
1670
+ * stop jobs of review environments run in their own workflow when the
1671
+ * pull request is closed (the counterpart of gitlab's on_stop wiring)
1672
+ */
1673
+ const isReviewStopJob = (context, job) => {
1674
+ var _a;
1675
+ return ((_a = job.environment) === null || _a === void 0 ? void 0 : _a.action) === "stop" && context.type === "component" && context.environment.envType === "review";
1676
+ };
1677
+ /**
1678
+ * stop/rollback jobs of non-review environments have no automatic
1679
+ * trigger; they are collected in a workflow_dispatch workflow
1680
+ * (gitlab runs them as manual jobs inside the pipeline)
1681
+ */
1682
+ const isManualTaskJob = job => job.stage === "stop" || job.stage === "rollback";
1683
+
1684
+ /***/ }),
1685
+
1686
+ /***/ 3093:
1687
+ /***/ ((__unused_webpack_module, exports) => {
1688
+
1689
+ "use strict";
1690
+
1691
+
1692
+ Object.defineProperty(exports, "__esModule", ({
1693
+ value: true
1694
+ }));
1695
+ exports.GITHUB_INJECTED_WORKFLOW_ENV = exports.GITHUB_CI_VARIABLES = void 0;
1696
+ /**
1697
+ * how the github backend names the predefined CI variables.
1698
+ *
1699
+ * GITHUB_* variables are provided by github actions natively; the CL_*
1700
+ * variables are injected by the {@link GithubBackend} itself (workflow or
1701
+ * job level), because github has no direct counterpart.
1702
+ */
1703
+ exports.GITHUB_CI_VARIABLES = {
1704
+ commitSha: "GITHUB_SHA",
1705
+ jobToken: "CL_JOB_TOKEN",
1706
+ jobImage: "CL_JOB_IMAGE",
1707
+ registry: "CL_REGISTRY",
1708
+ registryImage: "CL_REGISTRY_IMAGE"
1709
+ };
1710
+ /**
1711
+ * the workflow-level env the backend injects to provide the CL_*
1712
+ * variables referenced by {@link GITHUB_CI_VARIABLES}
1713
+ */
1714
+ exports.GITHUB_INJECTED_WORKFLOW_ENV = {
1715
+ CL_JOB_TOKEN: "${{ github.token }}",
1716
+ CL_REGISTRY: "ghcr.io",
1717
+ CL_REGISTRY_IMAGE: "ghcr.io/${{ github.repository }}",
1718
+ // empty outside of pull request events
1719
+ CL_PR_NUMBER: "${{ github.event.number }}"
1720
+ };
1721
+
1722
+ /***/ }),
1723
+
1724
+ /***/ 4016:
1725
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1726
+
1727
+ "use strict";
1728
+
1729
+
1730
+ Object.defineProperty(exports, "__esModule", ({
1731
+ value: true
1732
+ }));
1733
+ exports.getUploadProviderIds = exports.makeGithubJob = exports.resolveGithubNeeds = exports.githubJobId = void 0;
1734
+ const lodash_es_1 = __nccwpck_require__(4284);
1735
+ const getInjectVarsScript_1 = __nccwpck_require__(436);
1736
+ const createJobCache_1 = __nccwpck_require__(5644);
1737
+ const getEnvironmentVariables_1 = __nccwpck_require__(5855);
1738
+ const utils_1 = __nccwpck_require__(595);
1739
+ const gitlab_1 = __nccwpck_require__(3468);
1740
+ const scriptFunctions_1 = __nccwpck_require__(5759);
1741
+ /**
1742
+ * runner variables that only make sense on gitlab runners and must not
1743
+ * leak into github jobs (docker-in-docker daemon config, kubernetes
1744
+ * executor resource requests, gitlab clone strategy)
1745
+ */
1746
+ const GITLAB_ONLY_RUNNER_VARIABLES = new Set(["DOCKER_HOST", "DOCKER_TLS_CERTDIR", "DOCKER_DRIVER", "KUBERNETES_CPU_REQUEST", "KUBERNETES_MEMORY_REQUEST", "KUBERNETES_CPU_LIMIT", "KUBERNETES_MEMORY_LIMIT", "GIT_STRATEGY"]);
1747
+ /**
1748
+ * github runs docker natively on its runners, gitlab needs a
1749
+ * docker-in-docker service for it
1750
+ */
1751
+ const isDindService = image => /(^|\/)docker:.*dind/.test(image);
1752
+ const slug = value => {
1753
+ const slugged = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1754
+ // job ids must start with a letter or _
1755
+ return /^[a-z_]/.test(slugged) ? slugged : `job-${slugged}`;
1756
+ };
1757
+ const githubJobId = (context, jobName) => slug(`${context.type === "workspace" ? "ws-" : ""}${context.name}-${jobName}-${context.env}`);
1758
+ exports.githubJobId = githubJobId;
1759
+ const githubJobName = (context, jobName) => `${context.name} ${jobName} | ${context.env}`;
1760
+ const resolveNeed = (context, need, allJobs) => {
1761
+ var _a;
1762
+ const env = context.env;
1763
+ const findComponentJob = (componentName, jobName) => {
1764
+ const provider = allJobs.components.find(c => c.context.name === componentName && c.context.env === env);
1765
+ const job = provider === null || provider === void 0 ? void 0 : provider.jobs.find(j => j.name === jobName);
1766
+ if (!provider || !job) {
1767
+ throw new Error(`unknown job referenced: '${jobName}' from '${env}:${componentName}'`);
1768
+ }
1769
+ return (0, exports.githubJobId)(provider.context, jobName);
1770
+ };
1771
+ const findWorkspaceJob = (workspaceName, jobName) => {
1772
+ const provider = allJobs.workspaces.find(w => w.context.name === workspaceName && w.context.env === env);
1773
+ const job = provider === null || provider === void 0 ? void 0 : provider.jobs.find(j => j.name === jobName);
1774
+ if (!provider || !job) {
1775
+ throw new Error(`unknown job referenced: '${jobName}' from workspace '${env}:${workspaceName}'`);
1776
+ }
1777
+ return (0, exports.githubJobId)(provider.context, jobName);
1778
+ };
1779
+ if ((0, lodash_es_1.isObject)(need)) {
1780
+ if ("workspaceName" in need && need.workspaceName) {
1781
+ return {
1782
+ id: findWorkspaceJob(need.workspaceName, need.job),
1783
+ artifacts: need.artifacts
1784
+ };
1785
+ }
1786
+ return {
1787
+ id: findComponentJob((_a = "componentName" in need ? need.componentName : undefined) !== null && _a !== void 0 ? _a : context.name, need.job),
1788
+ artifacts: need.artifacts
1789
+ };
1790
+ }
1791
+ return {
1792
+ id: context.type === "workspace" ? findWorkspaceJob(context.name, need) : findComponentJob(context.name, need),
1793
+ // plain string needs download artifacts by default (gitlab semantics)
1794
+ artifacts: true
1795
+ };
1796
+ };
1797
+ const resolveGithubNeeds = (context, job, allJobs) => {
1798
+ var _a;
1799
+ const resolved = ((_a = job.needs) !== null && _a !== void 0 ? _a : []).map(need => resolveNeed(context, need, allJobs));
1800
+ // deduplicate by provider id, explicit entries win (they come last)
1801
+ return [...new Map(resolved.map(n => [n.id, n])).values()].sort((a, b) => a.id.localeCompare(b.id));
1802
+ };
1803
+ exports.resolveGithubNeeds = resolveGithubNeeds;
1804
+ const createCacheSteps = (context, job) => {
1805
+ var _a, _b;
1806
+ if (!((_a = job.caches) === null || _a === void 0 ? void 0 : _a.length)) {
1807
+ return [];
1808
+ }
1809
+ const lowered = (_b = (0, createJobCache_1.createJobCacheFromCacheConfigs)(context, job.caches)) !== null && _b !== void 0 ? _b : [];
1810
+ return (0, utils_1.ensureArray)(lowered).map(cache => {
1811
+ var _a, _b, _c, _d, _e, _f;
1812
+ const paths = (0, utils_1.ensureArray)((_a = cache.paths) !== null && _a !== void 0 ? _a : []);
1813
+ const key = cache.key;
1814
+ const {
1815
+ cacheKey,
1816
+ restoreKeyPrefix,
1817
+ label
1818
+ } = typeof key === "string" || key === undefined ? {
1819
+ // unique key per run so the cache is re-saved, restored via prefix
1820
+ cacheKey: `${key !== null && key !== void 0 ? key : "cache"}-\${{ github.run_id }}`,
1821
+ restoreKeyPrefix: `${key !== null && key !== void 0 ? key : "cache"}-`,
1822
+ label: key !== null && key !== void 0 ? key : "cache"
1823
+ } : {
1824
+ cacheKey: `${(_b = key.prefix) !== null && _b !== void 0 ? _b : "files"}-\${{ hashFiles(${((_c = key.files) !== null && _c !== void 0 ? _c : []).map(f => `'${f}'`).join(", ")}) }}`,
1825
+ restoreKeyPrefix: `${(_d = key.prefix) !== null && _d !== void 0 ? _d : "files"}-`,
1826
+ label: (_e = key.prefix) !== null && _e !== void 0 ? _e : ((_f = key.files) !== null && _f !== void 0 ? _f : []).join(",")
1827
+ };
1828
+ return {
1829
+ name: `Cache ${label}`,
1830
+ // pull-only caches are restored but never saved
1831
+ uses: cache.policy === "pull" ? "actions/cache/restore@v4" : "actions/cache@v4",
1832
+ with: {
1833
+ path: paths.join("\n"),
1834
+ key: cacheKey,
1835
+ "restore-keys": restoreKeyPrefix
1836
+ }
1837
+ };
1838
+ });
1839
+ };
1840
+ const getSecretsEnv = context => {
1841
+ var _a, _b;
1842
+ const keys = [...context.environment.secretEnvVarKeys, ...((_a = context.environment.jobOnlyVars.build.secretEnvVarKeys) !== null && _a !== void 0 ? _a : []), ...((_b = context.environment.jobOnlyVars.deploy.secretEnvVarKeys) !== null && _b !== void 0 ? _b : [])];
1843
+ return Object.fromEntries(keys.map(({
1844
+ key
1845
+ }) => {
1846
+ const name = (0, getEnvironmentVariables_1.getSecretVarName)(context.env, context.name, key);
1847
+ return [name, `\${{ secrets.${name} }}`];
1848
+ }));
1849
+ };
1850
+ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
1851
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1852
+ const id = (0, exports.githubJobId)(context, job.name);
1853
+ const isComponent = context.type === "component";
1854
+ const createsJobEnv = !!job.environment && isComponent && (!job.environment.action || job.environment.action === "start");
1855
+ const skipCheckout = ((_a = job.runnerVariables) === null || _a === void 0 ? void 0 : _a.GIT_STRATEGY) === "none";
1856
+ const needs = (0, exports.resolveGithubNeeds)(context, job, allJobs);
1857
+ const image = typeof job.image === "string" ? job.image : Array.isArray(job.image) ? job.image[0] : (_b = job.image) === null || _b === void 0 ? void 0 : _b.name;
1858
+ const runScript = [...(0, scriptFunctions_1.getGithubScriptFunctionDefinitions)(), ...(0, gitlab_1.collapseableSection)("injectvars", "Injecting variables")((0, getInjectVarsScript_1.getInjectVarsScript)((_c = job.variables) !== null && _c !== void 0 ? _c : {})), ...((_e = (_d = job.script) === null || _d === void 0 ? void 0 : _d.filter(utils_1.notNil)) !== null && _e !== void 0 ? _e : []), ...(createsJobEnv ? [`echo "url=$ROOT_URL" >> "$GITHUB_OUTPUT"`] : [])].join("\n");
1859
+ const artifactPaths = (_g = (_f = job.artifacts) === null || _f === void 0 ? void 0 : _f.paths) !== null && _g !== void 0 ? _g : [];
1860
+ const services = Object.fromEntries(((_h = job.services) !== null && _h !== void 0 ? _h : []).map(service => typeof service === "string" ? {
1861
+ name: service
1862
+ } : service).filter(service => !isDindService(service.name)).map(service => [slug("alias" in service && service.alias ? service.alias : service.name), {
1863
+ image: service.name,
1864
+ ...("variables" in service && service.variables ? {
1865
+ env: service.variables
1866
+ } : {})
1867
+ }]));
1868
+ const env = {
1869
+ ...Object.fromEntries(Object.entries((_j = job.runnerVariables) !== null && _j !== void 0 ? _j : {}).filter(([key]) => !GITLAB_ONLY_RUNNER_VARIABLES.has(key))),
1870
+ ...(isComponent ? getSecretsEnv(context) : {}),
1871
+ CL_JOB_IMAGE: image !== null && image !== void 0 ? image : "runner"
1872
+ };
1873
+ const githubJob = {
1874
+ name: githubJobName(context, job.name),
1875
+ "runs-on": "ubuntu-latest",
1876
+ ...(needs.length > 0 ? {
1877
+ needs: needs.map(n => n.id)
1878
+ } : {}),
1879
+ ...(image ? {
1880
+ container: {
1881
+ image
1882
+ }
1883
+ } : {}),
1884
+ ...(Object.keys(services).length > 0 ? {
1885
+ services
1886
+ } : {}),
1887
+ ...(job.environment && isComponent ? {
1888
+ environment: {
1889
+ name: context.environment.envType === "review" ? `review-pr\${{ github.event.number }}-${context.name}` : `${context.env}-${context.name}`,
1890
+ ...(createsJobEnv ? {
1891
+ url: "${{ steps.main.outputs.url }}"
1892
+ } : {})
1893
+ }
1894
+ } : {}),
1895
+ env,
1896
+ steps: [...(skipCheckout ? [] : [{
1897
+ name: "Checkout",
1898
+ uses: "actions/checkout@v4"
1899
+ }]), ...createCacheSteps(context, job), ...needs.filter(n => n.artifacts).map(n => ({
1900
+ name: `Download artifacts from ${n.id}`,
1901
+ uses: "actions/download-artifact@v4",
1902
+ with: {
1903
+ name: n.id
1904
+ }
1905
+ })), {
1906
+ name: job.name,
1907
+ id: "main",
1908
+ run: runScript,
1909
+ shell: "bash"
1910
+ }, ...(uploadProviderIds.has(id) || artifactPaths.length > 0 ? artifactPaths.length > 0 ? [{
1911
+ name: "Upload artifacts",
1912
+ uses: "actions/upload-artifact@v4",
1913
+ with: {
1914
+ name: id,
1915
+ path: artifactPaths.join("\n"),
1916
+ "if-no-files-found": "warn"
1917
+ }
1918
+ }] : [] : [])]
1919
+ };
1920
+ return [id, githubJob];
1921
+ };
1922
+ exports.makeGithubJob = makeGithubJob;
1923
+ /**
1924
+ * the ids of all jobs whose artifacts are consumed by other jobs
1925
+ * (they need an upload step)
1926
+ */
1927
+ const getUploadProviderIds = allJobs => {
1928
+ const ids = new Set();
1929
+ [...allJobs.workspaces, ...allJobs.components].forEach(({
1930
+ context,
1931
+ jobs
1932
+ }) => jobs.forEach(job => (0, exports.resolveGithubNeeds)(context, job, allJobs).filter(n => n.artifacts).forEach(n => ids.add(n.id))));
1933
+ return ids;
1934
+ };
1935
+ exports.getUploadProviderIds = getUploadProviderIds;
1936
+
1937
+ /***/ }),
1938
+
1939
+ /***/ 5611:
1940
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
1941
+
1942
+ "use strict";
1943
+
1944
+
1945
+ Object.defineProperty(exports, "__esModule", ({
1946
+ value: true
1947
+ }));
1948
+ exports.getGithubReleaseJobs = void 0;
1949
+ const runner_1 = __nccwpck_require__(2348);
1950
+ const createReleaseJob = needs => ({
1951
+ name: "create release",
1952
+ "runs-on": "ubuntu-latest",
1953
+ container: {
1954
+ image: (0, runner_1.getRunnerImage)("semantic-release")
1955
+ },
1956
+ // semantic-release pushes the version tag and release commit
1957
+ permissions: {
1958
+ contents: "write"
1959
+ },
1960
+ ...(needs && needs.length > 0 ? {
1961
+ needs
1962
+ } : {}),
1963
+ env: {
1964
+ GITHUB_TOKEN: "${{ github.token }}"
1965
+ },
1966
+ steps: [{
1967
+ name: "Checkout",
1968
+ uses: "actions/checkout@v4",
1969
+ // semantic-release needs the full history to determine the version
1970
+ with: {
1971
+ "fetch-depth": 0
1972
+ }
1973
+ }, {
1974
+ name: "create release",
1975
+ run: "semanticRelease",
1976
+ shell: "bash"
1977
+ }]
1978
+ });
1979
+ /**
1980
+ * the release jobs for the github backend (the counterpart of the
1981
+ * gitlab release jobs):
1982
+ * - releases.when === "auto": the release job runs in the main-branch
1983
+ * workflow after all other jobs; a force variant goes to the manual
1984
+ * tasks workflow
1985
+ * - otherwise (manual, the default): the release job goes to the
1986
+ * manual tasks workflow
1987
+ */
1988
+ const getGithubReleaseJobs = (config, mainWorkflowJobIds) => {
1989
+ var _a;
1990
+ if (((_a = config.releases) === null || _a === void 0 ? void 0 : _a.when) === "auto") {
1991
+ return {
1992
+ main: {
1993
+ "create-release": createReleaseJob(mainWorkflowJobIds)
1994
+ },
1995
+ manual: {
1996
+ "force-create-release": createReleaseJob()
1997
+ }
1998
+ };
1999
+ }
2000
+ return {
2001
+ main: {},
2002
+ manual: {
2003
+ "create-release": createReleaseJob()
2004
+ }
2005
+ };
2006
+ };
2007
+ exports.getGithubReleaseJobs = getGithubReleaseJobs;
2008
+
2009
+ /***/ }),
2010
+
2011
+ /***/ 9635:
2012
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
2013
+
2014
+ "use strict";
2015
+
2016
+
2017
+ var __createBinding = this && this.__createBinding || (Object.create ? function (o, m, k, k2) {
2018
+ if (k2 === undefined) k2 = k;
2019
+ var desc = Object.getOwnPropertyDescriptor(m, k);
2020
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
2021
+ desc = {
2022
+ enumerable: true,
2023
+ get: function () {
2024
+ return m[k];
2025
+ }
2026
+ };
2027
+ }
2028
+ Object.defineProperty(o, k2, desc);
2029
+ } : function (o, m, k, k2) {
2030
+ if (k2 === undefined) k2 = k;
2031
+ o[k2] = m[k];
2032
+ });
2033
+ var __exportStar = this && this.__exportStar || function (m, exports) {
2034
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
2035
+ };
2036
+ Object.defineProperty(exports, "__esModule", ({
2037
+ value: true
2038
+ }));
2039
+ __exportStar(__nccwpck_require__(4038), exports);
2040
+ __exportStar(__nccwpck_require__(3093), exports);
2041
+
2042
+ /***/ }),
2043
+
2044
+ /***/ 5759:
2045
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
2046
+
2047
+ "use strict";
2048
+
2049
+
2050
+ Object.defineProperty(exports, "__esModule", ({
2051
+ value: true
2052
+ }));
2053
+ exports.getGithubScriptFunctionDefinitions = void 0;
2054
+ const globalScriptFunctions_1 = __nccwpck_require__(3891);
2055
+ /**
2056
+ * github variants of the global script functions where the gitlab
2057
+ * implementation uses gitlab-specific mechanics (e.g. collapsible log
2058
+ * sections use gitlab's `section_start` escape codes, github uses
2059
+ * `::group::` workflow commands). All other functions are plain bash
2060
+ * and shared as-is.
2061
+ */
2062
+ const GITHUB_FUNCTION_OVERRIDES = {
2063
+ collapseable_section_start: `local section_title="\${1}"
2064
+ local section_description="\${2:-$section_title}"
2065
+ echo "::group::\${section_description}"`,
2066
+ collapseable_section_end: `echo "::endgroup::"`
2067
+ };
2068
+ /**
2069
+ * the bash function definitions to prepend to every job script.
2070
+ * github has no pipeline-wide before_script like gitlab, so each job
2071
+ * carries its own definitions.
2072
+ */
2073
+ const getGithubScriptFunctionDefinitions = () => [...globalScriptFunctions_1.globalScriptFunctions.values()].map(fn => {
2074
+ const override = GITHUB_FUNCTION_OVERRIDES[fn.name];
2075
+ return override ? `function ${fn.name} () {\n${override.trim()}\n}` : fn.toBashFunction();
2076
+ });
2077
+ exports.getGithubScriptFunctionDefinitions = getGithubScriptFunctionDefinitions;
2078
+
2079
+ /***/ }),
2080
+
950
2081
  /***/ 2278:
951
2082
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
952
2083
 
@@ -957,6 +2088,7 @@ Object.defineProperty(exports, "__esModule", ({
957
2088
  value: true
958
2089
  }));
959
2090
  exports.GitlabBackend = void 0;
2091
+ const promises_1 = __nccwpck_require__(1943);
960
2092
  const rules_1 = __nccwpck_require__(4565);
961
2093
  const config_1 = __nccwpck_require__(6925);
962
2094
  const createAllJobs_1 = __nccwpck_require__(3671);
@@ -972,6 +2104,12 @@ class GitlabBackend {
972
2104
  this.type = "gitlab";
973
2105
  this.generatedFolder = GITLAB_GENERATED_FOLDER;
974
2106
  }
2107
+ async cleanup() {
2108
+ await (0, promises_1.rm)(this.generatedFolder, {
2109
+ force: true,
2110
+ recursive: true
2111
+ });
2112
+ }
975
2113
  async createFiles(config) {
976
2114
  const includes = await this.createIncludes(config);
977
2115
  const mainFile = {
@@ -1686,12 +2824,15 @@ var __exportStar = this && this.__exportStar || function (m, exports) {
1686
2824
  Object.defineProperty(exports, "__esModule", ({
1687
2825
  value: true
1688
2826
  }));
1689
- exports.getEnabledPipelineTypes = exports.getPipelineBackend = void 0;
2827
+ exports.getEnabledPipelineTypes = exports.getVaultConfig = exports.getPipelineGitRemote = exports.getPipelineOptions = exports.getPipelineBackend = void 0;
2828
+ const github_1 = __nccwpck_require__(9635);
1690
2829
  const gitlab_1 = __nccwpck_require__(8475);
1691
2830
  __exportStar(__nccwpck_require__(2474), exports);
1692
2831
  __exportStar(__nccwpck_require__(8475), exports);
2832
+ __exportStar(__nccwpck_require__(9635), exports);
1693
2833
  const BACKENDS = {
1694
- gitlab: () => new gitlab_1.GitlabBackend()
2834
+ gitlab: () => new gitlab_1.GitlabBackend(),
2835
+ github: () => new github_1.GithubBackend()
1695
2836
  };
1696
2837
  const getPipelineBackend = type => {
1697
2838
  const createBackend = BACKENDS[type];
@@ -1701,6 +2842,38 @@ const getPipelineBackend = type => {
1701
2842
  return createBackend();
1702
2843
  };
1703
2844
  exports.getPipelineBackend = getPipelineBackend;
2845
+ /**
2846
+ * the options of an enabled pipeline type (empty object when enabled
2847
+ * with `true`)
2848
+ */
2849
+ const getPipelineOptions = (config, type) => {
2850
+ var _a;
2851
+ const value = (_a = config.pipelines) === null || _a === void 0 ? void 0 : _a[type];
2852
+ return typeof value === "object" ? value : {};
2853
+ };
2854
+ exports.getPipelineOptions = getPipelineOptions;
2855
+ /**
2856
+ * the git remote pointing to the repository of this pipeline type's CI
2857
+ * system (e.g. during a migration, gitlab may be `origin` and github a
2858
+ * second remote)
2859
+ */
2860
+ const getPipelineGitRemote = (config, type) => {
2861
+ var _a;
2862
+ return (_a = (0, exports.getPipelineOptions)(config, type).gitRemote) !== null && _a !== void 0 ? _a : "origin";
2863
+ };
2864
+ exports.getPipelineGitRemote = getPipelineGitRemote;
2865
+ /**
2866
+ * the normalized secrets vault of a config (string shorthands resolved
2867
+ * to their object form; defaults to the legacy gitlab store)
2868
+ */
2869
+ const getVaultConfig = config => {
2870
+ var _a, _b;
2871
+ const vault = (_b = (_a = config.secrets) === null || _a === void 0 ? void 0 : _a.vault) !== null && _b !== void 0 ? _b : "gitlab";
2872
+ return typeof vault === "string" ? {
2873
+ type: vault
2874
+ } : vault;
2875
+ };
2876
+ exports.getVaultConfig = getVaultConfig;
1704
2877
  /**
1705
2878
  * the pipeline types enabled for this config. Multiple types can be
1706
2879
  * enabled at once (parallel generation, e.g. during a CI migration).
@@ -2043,10 +3216,12 @@ Object.defineProperty(exports, "__esModule", ({
2043
3216
  value: true
2044
3217
  }));
2045
3218
  exports.getCiVariable = void 0;
2046
- const ciVariables_1 = __nccwpck_require__(8506);
3219
+ const ciVariables_1 = __nccwpck_require__(3093);
3220
+ const ciVariables_2 = __nccwpck_require__(8506);
2047
3221
  const BashExpression_1 = __nccwpck_require__(5354);
2048
3222
  const CI_VARIABLES_PER_PIPELINE_TYPE = {
2049
- gitlab: ciVariables_1.GITLAB_CI_VARIABLES
3223
+ gitlab: ciVariables_2.GITLAB_CI_VARIABLES,
3224
+ github: ciVariables_1.GITHUB_CI_VARIABLES
2050
3225
  };
2051
3226
  /**
2052
3227
  * resolves a platform-neutral CI variable to a bash expression for the
@@ -3665,7 +4840,7 @@ Object.defineProperty(exports, "__esModule", ({
3665
4840
  value: true
3666
4841
  }));
3667
4842
  exports.DOCKER_REGISTRY = exports.PIPELINE_IMAGE_TAG = void 0;
3668
- exports.PIPELINE_IMAGE_TAG = "next-16388362" || 0;
4843
+ exports.PIPELINE_IMAGE_TAG = "next-8b9ad5ca" || 0;
3669
4844
  exports.DOCKER_REGISTRY = "git.panter.ch:5001/catladder/catladder" || 0;
3670
4845
 
3671
4846
  /***/ }),
@@ -4232,7 +5407,9 @@ const bashExpressionPerPipelineType_1 = __nccwpck_require__(1945);
4232
5407
  const getEnvType_1 = __nccwpck_require__(8254);
4233
5408
  const REVIEW_SLUG = {
4234
5409
  default: "unknown-review-slug",
4235
- gitlab: new BashExpression_1.BashExpression(`$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })`)
5410
+ gitlab: new BashExpression_1.BashExpression(`$([ -n "$CI_MERGE_REQUEST_IID" ] && echo "mr$CI_MERGE_REQUEST_IID" || { [ -n "$CI_COMMIT_REF_SLUG" ] && echo "$CI_COMMIT_REF_SLUG" || echo "unknown"; })`),
5411
+ // CL_PR_NUMBER is injected by the github backend at the workflow level
5412
+ github: new BashExpression_1.BashExpression(`$([ -n "$CL_PR_NUMBER" ] && echo "pr$CL_PR_NUMBER" || echo "unknown")`)
4236
5413
  };
4237
5414
  const getReviewSlug = (envConfig, env, pipelineType) => {
4238
5415
  const envType = (0, getEnvType_1.getEnvType)(env, envConfig);
@@ -5568,13 +6745,15 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
5568
6745
  }
5569
6746
  return {};
5570
6747
  },
5571
- additionalSecretKeys: ctx => [{
6748
+ additionalSecretKeys: ctx => [
6749
+ // deploy-time credentials don't exist for the local env
6750
+ ...(ctx.envType !== "local" ? [{
5572
6751
  key: exports.GCLOUD_DEPLOY_CREDENTIALS_KEY,
5573
6752
  hidden: true
5574
6753
  }, {
5575
6754
  key: exports.GCLOUD_RUN_CANONICAL_HOST_SUFFIX,
5576
6755
  hidden: true
5577
- }, ...(ctx.deployConfigRaw && ctx.deployConfigRaw.cloudSql ? [{
6756
+ }] : []), ...(ctx.deployConfigRaw && ctx.deployConfigRaw.cloudSql ? [{
5578
6757
  key: "DB_PASSWORD"
5579
6758
  }] : [])],
5580
6759
  getAdditionalEnvVars: ctx => {
@@ -5582,7 +6761,8 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
5582
6761
  fullName,
5583
6762
  env,
5584
6763
  componentName,
5585
- deployConfigRaw
6764
+ deployConfigRaw,
6765
+ envType
5586
6766
  } = ctx;
5587
6767
  const HOSTNAME_INTERNAL = (0, BashExpression_1.joinBashExpressions)([fullName, (0, BashExpression_1.getBashVariable)((0, context_1.getSecretVarName)(env, componentName, exports.GCLOUD_RUN_CANONICAL_HOST_SUFFIX))], "-").toLowerCase();
5588
6768
  const jobTriggers = deployConfigRaw && deployConfigRaw.jobs ? Object.fromEntries(Object.entries(deployConfigRaw.jobs).filter(([name, job]) => Boolean(job)).map(([name, job]) => ["CLOUD_RUN_JOB_TRIGGER_URL_" + (0, gitlab_1.sanitizeForBashVariable)(name), (0, cloudRunExecutionUrl_1.getCloudRunJobExecuteUrl)(name, {
@@ -5591,7 +6771,11 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
5591
6771
  region: deployConfigRaw.region
5592
6772
  })])) : {};
5593
6773
  return {
5594
- HOSTNAME_INTERNAL,
6774
+ // references the canonical host suffix secret, which doesn't
6775
+ // exist for the local env
6776
+ ...(envType !== "local" ? {
6777
+ HOSTNAME_INTERNAL
6778
+ } : {}),
5595
6779
  ...getCloudSqlVariables(ctx),
5596
6780
  ...jobTriggers,
5597
6781
  DEPLOY_CLOUD_RUN_SERVICE_NAME: (0, getServiceName_1.getServiceNameForEnvContext)(ctx),
@@ -7422,11 +8606,8 @@ async function generatePipelineFiles(context, pipelineType) {
7422
8606
  exports.generatePipelineFiles = generatePipelineFiles;
7423
8607
  async function generatePipelineFilesForBackend(context, backend) {
7424
8608
  const files = await backend.createFiles(context.config);
7425
- // first clean up the folder
7426
- await (0, promises_1.rm)(backend.generatedFolder, {
7427
- force: true,
7428
- recursive: true
7429
- });
8609
+ // first clean up previously generated files
8610
+ await backend.cleanup();
7430
8611
  // write files
7431
8612
  await Promise.all(files.map(async ({
7432
8613
  path,