@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.
- package/dist/bundles/cli/index.js +705 -229
- package/dist/bundles/skills/catladder-cli/references/commands.md +37 -2
- package/dist/bundles/skills/catladder-secrets/SKILL.md +42 -9
- package/dist/cli/src/commands/index.d.ts +4 -0
- package/dist/cli/src/commands/index.js +9 -1
- package/dist/cli/src/commands/index.js.map +1 -1
- package/dist/cli/src/commands/project/commandConfigSecrets.d.ts +6 -1
- package/dist/cli/src/commands/project/commandConfigSecrets.js +56 -15
- package/dist/cli/src/commands/project/commandConfigSecrets.js.map +1 -1
- package/dist/cli/src/commands/project/secrets/commandSecretsList.d.ts +24 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsList.js +64 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsList.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPull.d.ts +19 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPull.js +48 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPull.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPush.d.ts +19 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPush.js +74 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsPush.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsSet.d.ts +24 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsSet.js +82 -0
- package/dist/cli/src/commands/project/secrets/commandSecretsSet.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/document.d.ts +47 -0
- package/dist/cli/src/commands/project/secrets/document.js +180 -0
- package/dist/cli/src/commands/project/secrets/document.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/parseKeysInput.d.ts +2 -0
- package/dist/cli/src/commands/project/secrets/parseKeysInput.js +10 -0
- package/dist/cli/src/commands/project/secrets/parseKeysInput.js.map +1 -0
- package/dist/cli/src/commands/project/secrets/scope.d.ts +35 -0
- package/dist/cli/src/commands/project/secrets/scope.js +113 -0
- package/dist/cli/src/commands/project/secrets/scope.js.map +1 -0
- package/dist/cli/src/utils/readStdin.d.ts +2 -0
- package/dist/cli/src/utils/readStdin.js +13 -0
- package/dist/cli/src/utils/readStdin.js.map +1 -0
- package/dist/skills/catladder-cli/references/commands.md +37 -2
- package/dist/skills/catladder-secrets/SKILL.md +42 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/commands/index.ts +4 -0
- package/src/commands/project/commandConfigSecrets.ts +76 -15
- package/src/commands/project/secrets/__tests__/document.test.ts +122 -0
- package/src/commands/project/secrets/commandSecretsList.ts +75 -0
- package/src/commands/project/secrets/commandSecretsPull.ts +55 -0
- package/src/commands/project/secrets/commandSecretsPush.ts +100 -0
- package/src/commands/project/secrets/commandSecretsSet.ts +102 -0
- package/src/commands/project/secrets/document.ts +269 -0
- package/src/commands/project/secrets/parseKeysInput.ts +8 -0
- package/src/commands/project/secrets/scope.ts +151 -0
- package/src/utils/readStdin.ts +8 -0
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.d.ts +0 -2
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js +0 -206
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js.map +0 -1
- package/src/apps/cli/commands/project/commandConfigSecrets.ts +0 -322
|
@@ -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,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,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
|
|
110
|
+
setup/update secrets in the vault via your editor
|
|
111
111
|
|
|
112
|
-
- `envComponent` (positional):
|
|
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
|