@catladder/cli 0.0.0-next-aea5d3ad → 0.0.0-next-2b60440e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/bundles/cli/index.js +705 -229
  2. package/dist/bundles/runner-images/semantic-release/Dockerfile +15 -12
  3. package/dist/bundles/runner-images/semantic-release/scripts/semanticRelease +10 -1
  4. package/dist/bundles/skills/catladder-cli/references/commands.md +37 -2
  5. package/dist/bundles/skills/catladder-secrets/SKILL.md +42 -9
  6. package/dist/cli/src/commands/index.d.ts +4 -0
  7. package/dist/cli/src/commands/index.js +9 -1
  8. package/dist/cli/src/commands/index.js.map +1 -1
  9. package/dist/cli/src/commands/project/commandConfigSecrets.d.ts +6 -1
  10. package/dist/cli/src/commands/project/commandConfigSecrets.js +56 -15
  11. package/dist/cli/src/commands/project/commandConfigSecrets.js.map +1 -1
  12. package/dist/cli/src/commands/project/secrets/commandSecretsList.d.ts +24 -0
  13. package/dist/cli/src/commands/project/secrets/commandSecretsList.js +64 -0
  14. package/dist/cli/src/commands/project/secrets/commandSecretsList.js.map +1 -0
  15. package/dist/cli/src/commands/project/secrets/commandSecretsPull.d.ts +19 -0
  16. package/dist/cli/src/commands/project/secrets/commandSecretsPull.js +48 -0
  17. package/dist/cli/src/commands/project/secrets/commandSecretsPull.js.map +1 -0
  18. package/dist/cli/src/commands/project/secrets/commandSecretsPush.d.ts +19 -0
  19. package/dist/cli/src/commands/project/secrets/commandSecretsPush.js +74 -0
  20. package/dist/cli/src/commands/project/secrets/commandSecretsPush.js.map +1 -0
  21. package/dist/cli/src/commands/project/secrets/commandSecretsSet.d.ts +24 -0
  22. package/dist/cli/src/commands/project/secrets/commandSecretsSet.js +82 -0
  23. package/dist/cli/src/commands/project/secrets/commandSecretsSet.js.map +1 -0
  24. package/dist/cli/src/commands/project/secrets/document.d.ts +47 -0
  25. package/dist/cli/src/commands/project/secrets/document.js +180 -0
  26. package/dist/cli/src/commands/project/secrets/document.js.map +1 -0
  27. package/dist/cli/src/commands/project/secrets/parseKeysInput.d.ts +2 -0
  28. package/dist/cli/src/commands/project/secrets/parseKeysInput.js +10 -0
  29. package/dist/cli/src/commands/project/secrets/parseKeysInput.js.map +1 -0
  30. package/dist/cli/src/commands/project/secrets/scope.d.ts +35 -0
  31. package/dist/cli/src/commands/project/secrets/scope.js +113 -0
  32. package/dist/cli/src/commands/project/secrets/scope.js.map +1 -0
  33. package/dist/cli/src/utils/readStdin.d.ts +2 -0
  34. package/dist/cli/src/utils/readStdin.js +13 -0
  35. package/dist/cli/src/utils/readStdin.js.map +1 -0
  36. package/dist/runner-images/semantic-release/Dockerfile +15 -12
  37. package/dist/runner-images/semantic-release/scripts/semanticRelease +10 -1
  38. package/dist/skills/catladder-cli/references/commands.md +37 -2
  39. package/dist/skills/catladder-secrets/SKILL.md +42 -9
  40. package/dist/tsconfig.tsbuildinfo +1 -1
  41. package/package.json +1 -1
  42. package/src/commands/index.ts +4 -0
  43. package/src/commands/project/commandConfigSecrets.ts +76 -15
  44. package/src/commands/project/secrets/__tests__/document.test.ts +122 -0
  45. package/src/commands/project/secrets/commandSecretsList.ts +75 -0
  46. package/src/commands/project/secrets/commandSecretsPull.ts +55 -0
  47. package/src/commands/project/secrets/commandSecretsPush.ts +100 -0
  48. package/src/commands/project/secrets/commandSecretsSet.ts +102 -0
  49. package/src/commands/project/secrets/document.ts +269 -0
  50. package/src/commands/project/secrets/parseKeysInput.ts +8 -0
  51. package/src/commands/project/secrets/scope.ts +151 -0
  52. package/src/utils/readStdin.ts +8 -0
  53. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.d.ts +0 -2
  54. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js +0 -206
  55. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js.map +0 -1
  56. package/src/apps/cli/commands/project/commandConfigSecrets.ts +0 -322
@@ -0,0 +1,24 @@
1
+ export declare const commandSecretsSet: import("../../../core/types").CommandDef<{
2
+ readonly envComponent: {
3
+ readonly type: "string";
4
+ readonly message: "scope: env:component, env:, or :component";
5
+ readonly positional: true;
6
+ readonly choices: () => Promise<string[]>;
7
+ };
8
+ readonly key: {
9
+ readonly type: "string";
10
+ readonly message: "which secret?";
11
+ readonly positional: true;
12
+ readonly choices: (ctx: any) => Promise<string[]>;
13
+ };
14
+ readonly value: {
15
+ readonly type: "string";
16
+ readonly message: "the secret value (prefer --value-file or stdin over shell history)";
17
+ readonly required: false;
18
+ };
19
+ readonly valueFile: {
20
+ readonly type: "string";
21
+ readonly message: "read the secret value from this file";
22
+ readonly required: false;
23
+ };
24
+ }>;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.commandSecretsSet = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const defineCommand_1 = require("../../../core/defineCommand");
6
+ const readStdin_1 = require("../../../utils/readStdin");
7
+ const document_1 = require("./document");
8
+ const scope_1 = require("./scope");
9
+ const resolveValue = async (io, value, valueFile) => {
10
+ if (valueFile) {
11
+ // a trailing newline is almost never part of the secret
12
+ return (await (0, fs_extra_1.readFile)(valueFile)).toString("utf-8").replace(/\n$/, "");
13
+ }
14
+ if (value !== undefined) {
15
+ return value;
16
+ }
17
+ if (!process.stdin.isTTY) {
18
+ return (await (0, readStdin_1.readStdin)()).replace(/\n$/, "");
19
+ }
20
+ return io.promptDirect({
21
+ name: "value",
22
+ type: "string",
23
+ message: "value",
24
+ });
25
+ };
26
+ exports.commandSecretsSet = (0, defineCommand_1.defineCommand)({
27
+ name: "project secrets-set",
28
+ description: "sets one secret — in one env (dev:web), one env everywhere (dev:), or all envs of a component (:web); value via --value, --value-file or stdin",
29
+ group: "project",
30
+ inputs: {
31
+ envComponent: {
32
+ type: "string",
33
+ message: "scope: env:component, env:, or :component",
34
+ positional: true,
35
+ choices: async () => (0, scope_1.secretsScopeChoices)(),
36
+ },
37
+ key: {
38
+ type: "string",
39
+ message: "which secret?",
40
+ positional: true,
41
+ choices: async (ctx) => {
42
+ const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
43
+ const scoped = await (0, scope_1.getScopedSecretKeys)(scope);
44
+ return [...new Set(scoped.flatMap(({ keys }) => keys))];
45
+ },
46
+ },
47
+ value: {
48
+ type: "string",
49
+ message: "the secret value (prefer --value-file or stdin over shell history)",
50
+ required: false,
51
+ },
52
+ valueFile: {
53
+ type: "string",
54
+ message: "read the secret value from this file",
55
+ required: false,
56
+ },
57
+ },
58
+ execute: async (ctx) => {
59
+ const scope = await (0, scope_1.resolveSecretsScope)(await ctx.get("envComponent"));
60
+ const key = await ctx.get("key");
61
+ // drops env/component pairs where the key is not declared and
62
+ // throws when it is declared nowhere in the scope
63
+ const scoped = await (0, scope_1.getScopedSecretKeys)(scope, [key]);
64
+ const value = await resolveValue(ctx, await ctx.get("value"), await ctx.get("valueFile"));
65
+ const targets = scoped.map(({ env, componentName }) => `${env}:${componentName}`);
66
+ ctx.log(`setting ${key} in: ${targets.join(", ")}`);
67
+ if (targets.length > 1) {
68
+ const confirmed = await ctx.confirm(`write the same value to ${targets.length} environments? 🤔`);
69
+ if (!confirmed) {
70
+ throw new Error("abort");
71
+ }
72
+ }
73
+ const writes = scoped.map(({ env, componentName }) => ({
74
+ env,
75
+ componentName,
76
+ secrets: { [key]: value },
77
+ }));
78
+ await (0, document_1.writeSecretsAndMirror)(ctx, writes);
79
+ ctx.log("done! 😻");
80
+ },
81
+ });
82
+ //# sourceMappingURL=commandSecretsSet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandSecretsSet.js","sourceRoot":"","sources":["../../../../../../src/commands/project/secrets/commandSecretsSet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { IO } from "../../../core/types";
2
+ import type { ScopedSecretKeys } from "./scope";
3
+ /** placeholder for secrets that have no value in the vault yet */
4
+ export declare const FILL_ME = "\uD83D\uDEA8 FILL ME";
5
+ /**
6
+ * component → env → key → value: the document shape shared by the
7
+ * editor, `secrets-pull` and `secrets-push`
8
+ */
9
+ export type SecretsDocument = {
10
+ [componentName: string]: {
11
+ [env: string]: Record<string, unknown>;
12
+ };
13
+ };
14
+ /** secrets of one env of one component, ready to be written */
15
+ export type SecretsWrite = {
16
+ env: string;
17
+ componentName: string;
18
+ secrets: Record<string, unknown>;
19
+ };
20
+ /**
21
+ * builds the document for the given scope with the current values from
22
+ * the vault; unset secrets appear as the FILL_ME placeholder
23
+ */
24
+ export declare const buildSecretsDocument: (io: IO, scoped: ScopedSecretKeys) => Promise<SecretsDocument>;
25
+ /**
26
+ * validates a document against the scope. Undeclared components, envs
27
+ * or keys are always problems; missing keys only when `requireComplete`
28
+ * (the guided editor flow) — pushes may be partial.
29
+ */
30
+ export declare const checkSecretsDocument: (document: SecretsDocument, scoped: ScopedSecretKeys, { requireComplete }: {
31
+ requireComplete: boolean;
32
+ }) => string[];
33
+ /**
34
+ * turns a (validated) document into writes. FILL_ME placeholders and
35
+ * empty (null) values are skipped, so an untouched placeholder can
36
+ * never end up as a live secret value.
37
+ */
38
+ export declare const collectSecretsWrites: (document: SecretsDocument, scoped: ScopedSecretKeys) => {
39
+ writes: SecretsWrite[];
40
+ skipped: string[];
41
+ };
42
+ /**
43
+ * writes secrets to the vault (the source of truth) and mirrors them
44
+ * to every enabled CI backend — which backends exist is invisible to
45
+ * the caller
46
+ */
47
+ export declare const writeSecretsAndMirror: (io: IO, writes: SecretsWrite[]) => Promise<void>;
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeSecretsAndMirror = exports.collectSecretsWrites = exports.checkSecretsDocument = exports.buildSecretsDocument = exports.FILL_ME = void 0;
4
+ const pipeline_1 = require("../../../../../pipeline/src/index.js");
5
+ const getProjectConfig_1 = require("../../../config/getProjectConfig");
6
+ const github_1 = require("../../../utils/github");
7
+ const gitlab_1 = require("../../../utils/gitlab");
8
+ const commandSecretsSyncGithub_1 = require("../commandSecretsSyncGithub");
9
+ /** placeholder for secrets that have no value in the vault yet */
10
+ exports.FILL_ME = "🚨 FILL ME";
11
+ /* for convenience, parse json values. that makes it easier to edit secrets that are objects */
12
+ const parseJsonValue = (value) => {
13
+ try {
14
+ return JSON.parse(value);
15
+ }
16
+ catch (e) {
17
+ return value;
18
+ }
19
+ };
20
+ /**
21
+ * builds the document for the given scope with the current values from
22
+ * the vault; unset secrets appear as the FILL_ME placeholder
23
+ */
24
+ const buildSecretsDocument = async (io, scoped) => {
25
+ var _a;
26
+ const names = scoped.flatMap(({ env, componentName, keys }) => keys.map((key) => (0, pipeline_1.getSecretVarName)(env, componentName, key)));
27
+ const values = await (await io.getVaultManager()).readSecrets(names, io);
28
+ const document = {};
29
+ for (const { env, componentName, keys } of scoped) {
30
+ (_a = document[componentName]) !== null && _a !== void 0 ? _a : (document[componentName] = {});
31
+ document[componentName][env] = Object.fromEntries(keys.map((key) => {
32
+ const value = values[(0, pipeline_1.getSecretVarName)(env, componentName, key)];
33
+ return [key, value === undefined ? exports.FILL_ME : parseJsonValue(value)];
34
+ }));
35
+ }
36
+ return document;
37
+ };
38
+ exports.buildSecretsDocument = buildSecretsDocument;
39
+ /**
40
+ * validates a document against the scope. Undeclared components, envs
41
+ * or keys are always problems; missing keys only when `requireComplete`
42
+ * (the guided editor flow) — pushes may be partial.
43
+ */
44
+ const checkSecretsDocument = (document, scoped, { requireComplete }) => {
45
+ var _a, _b;
46
+ const problems = [];
47
+ const scopedKeys = new Map();
48
+ scoped.forEach(({ env, componentName, keys }) => scopedKeys.set(`${env}:${componentName}`, keys));
49
+ const scopedComponents = new Set(scoped.map((s) => s.componentName));
50
+ for (const [componentName, envs] of Object.entries(document !== null && document !== void 0 ? document : {})) {
51
+ if (!scopedComponents.has(componentName)) {
52
+ problems.push(`"${componentName}" is not a component in this scope — remove it or widen the scope`);
53
+ continue;
54
+ }
55
+ for (const [env, secrets] of Object.entries(envs !== null && envs !== void 0 ? envs : {})) {
56
+ const keys = scopedKeys.get(`${env}:${componentName}`);
57
+ if (!keys) {
58
+ problems.push(`"${env}:${componentName}" is not in this scope — remove it or widen the scope`);
59
+ continue;
60
+ }
61
+ const extraneous = Object.keys(secrets !== null && secrets !== void 0 ? secrets : {}).filter((key) => !keys.includes(key));
62
+ extraneous.forEach((key) => problems.push(`"${env}:${componentName}": "${key}" is not declared in the config (or filtered out by --key)`));
63
+ }
64
+ }
65
+ if (requireComplete) {
66
+ for (const { env, componentName, keys } of scoped) {
67
+ const provided = Object.keys((_b = (_a = document === null || document === void 0 ? void 0 : document[componentName]) === null || _a === void 0 ? void 0 : _a[env]) !== null && _b !== void 0 ? _b : {});
68
+ keys
69
+ .filter((key) => !provided.includes(key))
70
+ .forEach((key) => problems.push(`"${env}:${componentName}": "${key}" has not been provided`));
71
+ }
72
+ }
73
+ return problems;
74
+ };
75
+ exports.checkSecretsDocument = checkSecretsDocument;
76
+ /**
77
+ * turns a (validated) document into writes. FILL_ME placeholders and
78
+ * empty (null) values are skipped, so an untouched placeholder can
79
+ * never end up as a live secret value.
80
+ */
81
+ const collectSecretsWrites = (document, scoped) => {
82
+ var _a, _b;
83
+ const writes = [];
84
+ const skipped = [];
85
+ for (const { env, componentName, keys } of scoped) {
86
+ const provided = (_b = (_a = document === null || document === void 0 ? void 0 : document[componentName]) === null || _a === void 0 ? void 0 : _a[env]) !== null && _b !== void 0 ? _b : {};
87
+ const secrets = {};
88
+ for (const key of keys) {
89
+ if (!(key in provided)) {
90
+ continue;
91
+ }
92
+ const value = provided[key];
93
+ if (value === exports.FILL_ME || value === null || value === undefined) {
94
+ skipped.push(`${env}:${componentName} ${key}`);
95
+ continue;
96
+ }
97
+ secrets[key] = value;
98
+ }
99
+ if (Object.keys(secrets).length > 0) {
100
+ writes.push({ env, componentName, secrets });
101
+ }
102
+ }
103
+ return { writes, skipped };
104
+ };
105
+ exports.collectSecretsWrites = collectSecretsWrites;
106
+ /**
107
+ * writes secrets to the vault (the source of truth) and mirrors them
108
+ * to every enabled CI backend — which backends exist is invisible to
109
+ * the caller
110
+ */
111
+ const writeSecretsAndMirror = async (io, writes) => {
112
+ const config = await (0, getProjectConfig_1.getProjectConfig)();
113
+ if (!config) {
114
+ throw new Error("no catladder config found");
115
+ }
116
+ io.log("");
117
+ io.log("writing secrets to the vault, please wait...");
118
+ io.log("");
119
+ for (const { env, componentName, secrets } of writes) {
120
+ io.log("writing " + env + ":" + componentName + "...\n");
121
+ await (await io.getVaultManager()).writeSecrets(env, componentName, secrets);
122
+ io.log("");
123
+ io.log("✅ " + env + ":" + componentName);
124
+ io.log("--------------------------------\n");
125
+ }
126
+ await mirrorSecretsToCiBackends(io, config, writes);
127
+ };
128
+ exports.writeSecretsAndMirror = writeSecretsAndMirror;
129
+ /**
130
+ * the vault is the source of truth; every enabled CI backend receives
131
+ * a mirrored copy of the written secrets (gitlab variables, github
132
+ * secrets), so all CI systems stay in sync
133
+ */
134
+ const mirrorSecretsToCiBackends = async (io, config, writes) => {
135
+ const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
136
+ // gitlab mirror (unless gitlab is the vault itself, then it is
137
+ // already written)
138
+ if ((0, pipeline_1.getVaultConfig)(config).type !== "gitlab" && enabled.includes("gitlab")) {
139
+ for (const { env, componentName, secrets } of writes) {
140
+ await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName);
141
+ }
142
+ io.log("✅ mirrored to gitlab");
143
+ }
144
+ if (!enabled.includes("github")) {
145
+ return;
146
+ }
147
+ const kinds = new Map();
148
+ for (const { env, componentName } of writes) {
149
+ const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
150
+ [
151
+ ...secretEnvVarKeys,
152
+ ...jobOnlyVars.build.secretEnvVarKeys,
153
+ ...jobOnlyVars.deploy.secretEnvVarKeys,
154
+ ].forEach(({ key, kind }) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
155
+ }
156
+ const secrets = writes.flatMap(({ env, componentName, secrets }) => Object.entries(secrets).map(([key, value]) => {
157
+ var _a;
158
+ const name = (0, pipeline_1.getSecretVarName)(env, componentName, key);
159
+ return {
160
+ name,
161
+ value: typeof value === "string" ? value : JSON.stringify(value !== null && value !== void 0 ? value : ""),
162
+ kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret",
163
+ };
164
+ }));
165
+ if (secrets.length === 0) {
166
+ return;
167
+ }
168
+ if (!(await (0, github_1.isGhAuthenticated)())) {
169
+ io.log("⚠️ github pipeline is enabled, but the github cli (gh) is not authenticated — run `project secrets-sync-github` later to mirror the secrets");
170
+ return;
171
+ }
172
+ const repo = await (0, commandSecretsSyncGithub_1.getConfiguredGithubRepo)();
173
+ if (!repo) {
174
+ io.log("⚠️ github pipeline is enabled, but no github repository was found — run `project secrets-sync-github` later to mirror the secrets");
175
+ return;
176
+ }
177
+ io.log(`mirroring ${secrets.length} secrets to github ('${repo}')...`);
178
+ await (0, commandSecretsSyncGithub_1.pushSecretsToGithub)(io, repo, secrets, await (0, commandSecretsSyncGithub_1.collectSecretTargets)(config));
179
+ };
180
+ //# sourceMappingURL=document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.js","sourceRoot":"","sources":["../../../../../../src/commands/project/secrets/document.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** parses a comma-separated `--key` input into a list of keys */
2
+ export declare const parseKeysInput: (input?: string) => string[] | undefined;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseKeysInput = void 0;
4
+ /** parses a comma-separated `--key` input into a list of keys */
5
+ const parseKeysInput = (input) => {
6
+ const keys = input === null || input === void 0 ? void 0 : input.split(",").map((key) => key.trim()).filter(Boolean);
7
+ return keys && keys.length > 0 ? keys : undefined;
8
+ };
9
+ exports.parseKeysInput = parseKeysInput;
10
+ //# sourceMappingURL=parseKeysInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseKeysInput.js","sourceRoot":"","sources":["../../../../../../src/commands/project/secrets/parseKeysInput.ts"],"names":[],"mappings":";;;AAAA,iEAAiE;AAC1D,MAAM,cAAc,GAAG,CAAC,KAAc,EAAwB,EAAE;IACrE,MAAM,IAAI,GAAG,KAAK,aAAL,KAAK,uBAAL,KAAK,CACd,KAAK,CAAC,GAAG,EACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,EACvB,MAAM,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC,CAAC;AANW,QAAA,cAAc,kBAMzB"}
@@ -0,0 +1,35 @@
1
+ /** which envs of which components a secrets command operates on */
2
+ export type SecretsScope = {
3
+ [componentName: string]: string[];
4
+ };
5
+ /**
6
+ * resolves a scope expression to component → envs:
7
+ * - (empty): all components, all envs
8
+ * - `env:component`: one env of one component
9
+ * - `env` / `env:`: one env, every component that has it
10
+ * - `:component`: every env of one component
11
+ */
12
+ export declare const resolveSecretsScope: (scope?: string) => Promise<SecretsScope>;
13
+ /**
14
+ * all valid scope expressions, for autocompletion: `env:component`
15
+ * pairs plus the `env:` (one env, all components) and `:component`
16
+ * (one component, all envs) forms
17
+ */
18
+ export declare const secretsScopeChoices: () => Promise<string[]>;
19
+ /** one env of one component together with its (filtered) secret keys */
20
+ export type ScopedSecretKeys = Array<{
21
+ env: string;
22
+ componentName: string;
23
+ keys: string[];
24
+ }>;
25
+ /** the secret keys declared in the config for one env of one component */
26
+ export declare const getDeclaredSecretKeys: (env: string, componentName: string) => Promise<string[]>;
27
+ /**
28
+ * expands a scope to its declared secret keys, optionally filtered to
29
+ * `onlyKeys`. Throws when a requested key is not declared anywhere in
30
+ * the scope (typo protection); env/component pairs without matching
31
+ * keys are dropped.
32
+ */
33
+ export declare const getScopedSecretKeys: (scope: SecretsScope, onlyKeys?: string[]) => Promise<ScopedSecretKeys>;
34
+ /** human-readable one-line-per-component summary of a scope */
35
+ export declare const formatScope: (scoped: ScopedSecretKeys) => string;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatScope = exports.getScopedSecretKeys = exports.getDeclaredSecretKeys = exports.secretsScopeChoices = exports.resolveSecretsScope = void 0;
4
+ const getProjectConfig_1 = require("../../../config/getProjectConfig");
5
+ /**
6
+ * resolves a scope expression to component → envs:
7
+ * - (empty): all components, all envs
8
+ * - `env:component`: one env of one component
9
+ * - `env` / `env:`: one env, every component that has it
10
+ * - `:component`: every env of one component
11
+ */
12
+ const resolveSecretsScope = async (scope) => {
13
+ const all = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
14
+ if (Object.keys(all).length === 0) {
15
+ throw new Error("no catladder config found");
16
+ }
17
+ if (!scope) {
18
+ return all;
19
+ }
20
+ const [env, componentName] = scope.split(":").map((x) => x || null);
21
+ if (componentName && !(componentName in all)) {
22
+ throw new Error(`unknown component "${componentName}" — components: ${Object.keys(all).join(", ")}`);
23
+ }
24
+ const scoped = Object.fromEntries(Object.entries(all)
25
+ .filter(([name]) => !componentName || name === componentName)
26
+ .map(([name, envs]) => [
27
+ name,
28
+ env ? envs.filter((e) => e === env) : envs,
29
+ ])
30
+ .filter(([, envs]) => envs.length > 0));
31
+ if (Object.keys(scoped).length === 0) {
32
+ const allEnvs = [...new Set(Object.values(all).flat())];
33
+ throw new Error(`no component has the environment "${env}" — environments: ${allEnvs.join(", ")}`);
34
+ }
35
+ return scoped;
36
+ };
37
+ exports.resolveSecretsScope = resolveSecretsScope;
38
+ /**
39
+ * all valid scope expressions, for autocompletion: `env:component`
40
+ * pairs plus the `env:` (one env, all components) and `:component`
41
+ * (one component, all envs) forms
42
+ */
43
+ const secretsScopeChoices = async () => {
44
+ const all = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
45
+ const pairs = Object.entries(all).flatMap(([componentName, envs]) => envs.map((env) => `${env}:${componentName}`));
46
+ const envs = [...new Set(Object.values(all).flat())];
47
+ return [
48
+ ...pairs,
49
+ ...envs.map((env) => `${env}:`),
50
+ ...Object.keys(all).map((componentName) => `:${componentName}`),
51
+ ];
52
+ };
53
+ exports.secretsScopeChoices = secretsScopeChoices;
54
+ /** the secret keys declared in the config for one env of one component */
55
+ const getDeclaredSecretKeys = async (env, componentName) => {
56
+ const { secretEnvVarKeys, jobOnlyVars } = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
57
+ return [
58
+ ...jobOnlyVars.build.secretEnvVarKeys,
59
+ ...jobOnlyVars.deploy.secretEnvVarKeys,
60
+ ...secretEnvVarKeys,
61
+ ]
62
+ .filter((k) => !k.hidden)
63
+ .map((k) => k.key);
64
+ };
65
+ exports.getDeclaredSecretKeys = getDeclaredSecretKeys;
66
+ /**
67
+ * expands a scope to its declared secret keys, optionally filtered to
68
+ * `onlyKeys`. Throws when a requested key is not declared anywhere in
69
+ * the scope (typo protection); env/component pairs without matching
70
+ * keys are dropped.
71
+ */
72
+ const getScopedSecretKeys = async (scope, onlyKeys) => {
73
+ const scoped = [];
74
+ const declaredAnywhere = new Set();
75
+ for (const [componentName, envs] of Object.entries(scope)) {
76
+ for (const env of envs) {
77
+ const declared = await (0, exports.getDeclaredSecretKeys)(env, componentName);
78
+ declared.forEach((key) => declaredAnywhere.add(key));
79
+ const keys = onlyKeys
80
+ ? declared.filter((key) => onlyKeys.includes(key))
81
+ : declared;
82
+ if (keys.length > 0) {
83
+ scoped.push({ env, componentName, keys });
84
+ }
85
+ }
86
+ }
87
+ const unknownKeys = (onlyKeys !== null && onlyKeys !== void 0 ? onlyKeys : []).filter((key) => !declaredAnywhere.has(key));
88
+ if (unknownKeys.length > 0) {
89
+ throw new Error(`these secrets are not declared in this scope: ${unknownKeys.join(", ")}` +
90
+ `\ndeclared secrets: ${[...declaredAnywhere].join(", ")}`);
91
+ }
92
+ if (scoped.length === 0) {
93
+ throw new Error("there are no secrets to configure in this scope");
94
+ }
95
+ return scoped;
96
+ };
97
+ exports.getScopedSecretKeys = getScopedSecretKeys;
98
+ /** human-readable one-line-per-component summary of a scope */
99
+ const formatScope = (scoped) => {
100
+ var _a;
101
+ const byComponent = new Map();
102
+ for (const { env, componentName } of scoped) {
103
+ byComponent.set(componentName, [
104
+ ...((_a = byComponent.get(componentName)) !== null && _a !== void 0 ? _a : []),
105
+ env,
106
+ ]);
107
+ }
108
+ return [...byComponent.entries()]
109
+ .map(([componentName, envs]) => `- ${componentName}: ${envs.join(", ")}`)
110
+ .join("\n");
111
+ };
112
+ exports.formatScope = formatScope;
113
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../../../../../src/commands/project/secrets/scope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** reads the whole stdin stream (for piped input in non-interactive use) */
2
+ export declare const readStdin: () => Promise<string>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readStdin = void 0;
4
+ /** reads the whole stdin stream (for piped input in non-interactive use) */
5
+ const readStdin = async () => {
6
+ const chunks = [];
7
+ for await (const chunk of process.stdin) {
8
+ chunks.push(chunk);
9
+ }
10
+ return Buffer.concat(chunks).toString("utf-8");
11
+ };
12
+ exports.readStdin = readStdin;
13
+ //# sourceMappingURL=readStdin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readStdin.js","sourceRoot":"","sources":["../../../../src/utils/readStdin.ts"],"names":[],"mappings":";;;AAAA,4EAA4E;AACrE,MAAM,SAAS,GAAG,KAAK,IAAqB,EAAE;IACnD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC,CAAC;AANW,QAAA,SAAS,aAMpB"}
@@ -1,24 +1,27 @@
1
1
  # job images are addressed by a content hash of this directory — the
2
2
  # build must be reproducible, so every dependency is pinned exactly.
3
- # (@semantic-release/changelog@7 went ESM-only and broke overnight under
4
- # the CJS semantic-release@19 while the hash claimed "unchanged".)
5
- FROM node:22-alpine
3
+ # node:24 satisfies the newer plugins' engine requirements
4
+ # (@semantic-release/git and @semantic-release/changelog need node >=24.15).
5
+ FROM node:24-alpine
6
6
 
7
7
  RUN apk add --no-cache bash git git-lfs
8
8
 
9
9
  # add semantic release
10
- # NOTE: keep every plugin pinned to a major that is compatible with
11
- # semantic-release@19 (they declare `semantic-release` as a peer dependency).
12
- # Unpinned plugins drift to their latest major on image rebuild, which now
13
- # requires semantic-release>=20 and fails with "plugins configuration is invalid".
10
+ # NOTE: pin every dependency exactly. These are the semantic-release@25 line
11
+ # (all ESM — v25 loads plugins via dynamic import, so changelog@7/git@11 are
12
+ # fine). Every plugin declares `semantic-release` as a peer dependency, so a
13
+ # plugin major that outpaces the semantic-release major fails the release job
14
+ # with "plugins configuration is invalid" — bump them together. Upstream
15
+ # @semantic-release/git replaces the old panter fork; see
16
+ # scripts/semanticRelease for why the commit message is hardcoded.
14
17
  RUN yarn global add \
15
- semantic-release@19.0.5 \
18
+ semantic-release@25.0.8 \
16
19
  @semantic-release/commit-analyzer@13.0.1 \
17
20
  @semantic-release/release-notes-generator@14.1.1 \
18
- https://github.com/panter/git.git#b4037626cc583d3e9f7995ea0604b23730d0a22e \
19
- @semantic-release/changelog@6.0.3 \
20
- @semantic-release/gitlab@9.5.1 \
21
- @semantic-release/exec@6.0.3
21
+ @semantic-release/git@11.0.0 \
22
+ @semantic-release/changelog@7.0.0 \
23
+ @semantic-release/gitlab@13.3.3 \
24
+ @semantic-release/exec@7.1.0
22
25
 
23
26
  RUN mkdir -p /scripts
24
27
  COPY ./scripts/* /scripts/
@@ -77,8 +77,17 @@ if [ ! -e .releaserc ]; then
77
77
  ],
78
78
  "@semantic-release/release-notes-generator",
79
79
  "@semantic-release/changelog",
80
+ # message prefix hardcoded to "release" on purpose. Ideally this would be
81
+ # "chore(\${branch.type})", but upstream @semantic-release/git passes the
82
+ # branch *name* (not the object) into the template, so \${branch.type} is
83
+ # never available (see https://github.com/semantic-release/git/pull/213,
84
+ # open/ignored since 2020 — the README documents branch.type but the code
85
+ # never wired it up; the old panter fork existed only to patch this). On the
86
+ # default branch branch.type is always "release", and the pipeline
87
+ # loop-prevention rule keys on the literal "chore(release)" prefix, so keep
88
+ # this literal. Don't "fix" it back to \${branch.type}.
80
89
  ["@semantic-release/git", {
81
- "message": "chore(\${branch.type}): \${nextRelease.version}\n\n\${nextRelease.notes}"
90
+ "message": "chore(release): \${nextRelease.version}\n\n\${nextRelease.notes}"
82
91
  }]${PUBLISH_PLUGIN}
83
92
  ],
84
93
  "branches": [