@catladder/cli 0.0.0-next-aea5d3ad → 0.0.0-next-1c65899f

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 (52) hide show
  1. package/dist/bundles/cli/index.js +705 -229
  2. package/dist/bundles/skills/catladder-cli/references/commands.md +37 -2
  3. package/dist/bundles/skills/catladder-secrets/SKILL.md +42 -9
  4. package/dist/cli/src/commands/index.d.ts +4 -0
  5. package/dist/cli/src/commands/index.js +9 -1
  6. package/dist/cli/src/commands/index.js.map +1 -1
  7. package/dist/cli/src/commands/project/commandConfigSecrets.d.ts +6 -1
  8. package/dist/cli/src/commands/project/commandConfigSecrets.js +56 -15
  9. package/dist/cli/src/commands/project/commandConfigSecrets.js.map +1 -1
  10. package/dist/cli/src/commands/project/secrets/commandSecretsList.d.ts +24 -0
  11. package/dist/cli/src/commands/project/secrets/commandSecretsList.js +64 -0
  12. package/dist/cli/src/commands/project/secrets/commandSecretsList.js.map +1 -0
  13. package/dist/cli/src/commands/project/secrets/commandSecretsPull.d.ts +19 -0
  14. package/dist/cli/src/commands/project/secrets/commandSecretsPull.js +48 -0
  15. package/dist/cli/src/commands/project/secrets/commandSecretsPull.js.map +1 -0
  16. package/dist/cli/src/commands/project/secrets/commandSecretsPush.d.ts +19 -0
  17. package/dist/cli/src/commands/project/secrets/commandSecretsPush.js +74 -0
  18. package/dist/cli/src/commands/project/secrets/commandSecretsPush.js.map +1 -0
  19. package/dist/cli/src/commands/project/secrets/commandSecretsSet.d.ts +24 -0
  20. package/dist/cli/src/commands/project/secrets/commandSecretsSet.js +82 -0
  21. package/dist/cli/src/commands/project/secrets/commandSecretsSet.js.map +1 -0
  22. package/dist/cli/src/commands/project/secrets/document.d.ts +47 -0
  23. package/dist/cli/src/commands/project/secrets/document.js +180 -0
  24. package/dist/cli/src/commands/project/secrets/document.js.map +1 -0
  25. package/dist/cli/src/commands/project/secrets/parseKeysInput.d.ts +2 -0
  26. package/dist/cli/src/commands/project/secrets/parseKeysInput.js +10 -0
  27. package/dist/cli/src/commands/project/secrets/parseKeysInput.js.map +1 -0
  28. package/dist/cli/src/commands/project/secrets/scope.d.ts +35 -0
  29. package/dist/cli/src/commands/project/secrets/scope.js +113 -0
  30. package/dist/cli/src/commands/project/secrets/scope.js.map +1 -0
  31. package/dist/cli/src/utils/readStdin.d.ts +2 -0
  32. package/dist/cli/src/utils/readStdin.js +13 -0
  33. package/dist/cli/src/utils/readStdin.js.map +1 -0
  34. package/dist/skills/catladder-cli/references/commands.md +37 -2
  35. package/dist/skills/catladder-secrets/SKILL.md +42 -9
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +1 -1
  38. package/src/commands/index.ts +4 -0
  39. package/src/commands/project/commandConfigSecrets.ts +76 -15
  40. package/src/commands/project/secrets/__tests__/document.test.ts +122 -0
  41. package/src/commands/project/secrets/commandSecretsList.ts +75 -0
  42. package/src/commands/project/secrets/commandSecretsPull.ts +55 -0
  43. package/src/commands/project/secrets/commandSecretsPush.ts +100 -0
  44. package/src/commands/project/secrets/commandSecretsSet.ts +102 -0
  45. package/src/commands/project/secrets/document.ts +269 -0
  46. package/src/commands/project/secrets/parseKeysInput.ts +8 -0
  47. package/src/commands/project/secrets/scope.ts +151 -0
  48. package/src/utils/readStdin.ts +8 -0
  49. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.d.ts +0 -2
  50. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js +0 -206
  51. package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js.map +0 -1
  52. package/src/apps/cli/commands/project/commandConfigSecrets.ts +0 -322
@@ -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"}
@@ -107,9 +107,10 @@ restores a project db from one source to another target
107
107
 
108
108
  ## `catladder project config-secrets [envComponent]`
109
109
 
110
- setup/update secrets stored in pass
110
+ setup/update secrets in the vault via your editor
111
111
 
112
- - `envComponent` (positional): environment:component
112
+ - `envComponent` (positional): scope: env:component, env:, :component or empty for everything
113
+ - `--key <value>`: only edit these secrets (comma-separated keys)
113
114
 
114
115
  ## `catladder project doctor [component]`
115
116
 
@@ -226,6 +227,40 @@ clears all backups
226
227
 
227
228
  - `--keep <value>`: How many backups should we keep? (default: 1)
228
229
 
230
+ ## `catladder project secrets-list [envComponent]`
231
+
232
+ lists the declared secrets of a scope with their set/unset status (values only with --reveal)
233
+
234
+ - `envComponent` (positional): scope: env:component, env:, :component or empty for everything
235
+ - `--key <value>`: only these secrets (comma-separated keys)
236
+ - `--reveal`: also print the secret values (default: false)
237
+ - `--check`: exit with an error when any secret is unset (for CI/agents) (default: false)
238
+
239
+ ## `catladder project secrets-pull [envComponent]`
240
+
241
+ prints the current secrets of a scope as yaml (unset ones as a placeholder) — edit and feed to secrets-push
242
+
243
+ - `envComponent` (positional): scope: env:component, env:, :component or empty for everything
244
+ - `--key <value>`: only these secrets (comma-separated keys)
245
+ - `--out <value>`: write the yaml to this file instead of stdout
246
+
247
+ ## `catladder project secrets-push [envComponent]`
248
+
249
+ writes secrets from a yaml document (secrets-pull format, --file or stdin) to the vault; may be partial
250
+
251
+ - `envComponent` (positional): scope: env:component, env:, :component or empty for everything
252
+ - `--key <value>`: only write these secrets (comma-separated keys)
253
+ - `--file <value>`: yaml file to push (component → env → key: value); stdin when omitted
254
+
255
+ ## `catladder project secrets-set [envComponent] [key]`
256
+
257
+ 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
258
+
259
+ - `envComponent` (positional): scope: env:component, env:, or :component
260
+ - `key` (positional): which secret?
261
+ - `--value <value>`: the secret value (prefer --value-file or stdin over shell history)
262
+ - `--value-file <value>`: read the secret value from this file
263
+
229
264
  ## `catladder project secrets-sync-github [repo] [env]`
230
265
 
231
266
  copies all secrets from the vault to github repo secrets (same names), for the github pipeline