@kitsy/cnos 1.1.0 → 1.1.2
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/README.md +14 -0
- package/dist/{chunk-K2T4R5WH.js → chunk-33ZDYDQJ.js} +165 -125
- package/dist/{chunk-CGTFH4QQ.js → chunk-53HXUSM6.js} +1 -1
- package/dist/{chunk-KG6OZX5C.js → chunk-7FBRVJD6.js} +6 -3
- package/dist/{chunk-GGYIRIGU.js → chunk-HOS4E7XO.js} +1 -1
- package/dist/{chunk-ASZ7I3JJ.js → chunk-IHSV5AFX.js} +1 -1
- package/dist/{chunk-44JOQPSN.js → chunk-IQOUWY6T.js} +1 -1
- package/dist/{chunk-H65FPTDM.js → chunk-JQGGSNCL.js} +1 -1
- package/dist/index.cjs +100 -100
- package/dist/index.js +10 -9
- package/dist/internal.cjs +89 -38
- package/dist/internal.d.cts +7 -2
- package/dist/internal.d.ts +7 -2
- package/dist/internal.js +9 -1
- package/dist/plugin/basic-schema.cjs +3 -3
- package/dist/plugin/basic-schema.js +2 -2
- package/dist/plugin/cli-args.cjs +3 -3
- package/dist/plugin/cli-args.js +2 -2
- package/dist/plugin/dotenv.cjs +5 -5
- package/dist/plugin/dotenv.js +2 -2
- package/dist/plugin/env-export.cjs +46 -47
- package/dist/plugin/env-export.js +2 -2
- package/dist/plugin/filesystem.cjs +21 -15
- package/dist/plugin/filesystem.js +2 -2
- package/dist/plugin/process-env.cjs +5 -5
- package/dist/plugin/process-env.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,4 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
Developer-friendly CNOS runtime assembly. It bundles the core engine plus the official built-in plugins, exposes the main `createCnos(...)` entry point for app code, and re-exports the built-ins under `@kitsy/cnos/plugins/*`.
|
|
4
4
|
|
|
5
|
+
Current runtime surface includes:
|
|
6
|
+
- `createCnos()`
|
|
7
|
+
- `read`, `require`, `readOr`
|
|
8
|
+
- `value`, `secret`, `meta`
|
|
9
|
+
- `inspect`
|
|
10
|
+
- `toObject`, `toNamespace`
|
|
11
|
+
- `toEnv`, `toPublicEnv`
|
|
12
|
+
|
|
13
|
+
CLI-oriented storage/export rules to be aware of:
|
|
14
|
+
- user-defined values and secrets remain private by default
|
|
15
|
+
- public/browser exposure comes from `public.promote`
|
|
16
|
+
- shell env export comes from explicit `envMapping.explicit`
|
|
17
|
+
- local secret material lives outside the repo in encrypted vault storage under `~/.cnos/secrets`
|
|
18
|
+
|
|
5
19
|
Use `@kitsy/cnos-vite` for Vite projects and `@kitsy/cnos-next` for Next.js projects when you want CNOS public values projected into framework-native env surfaces.
|
|
@@ -120,6 +120,151 @@ function stringifyYaml(value) {
|
|
|
120
120
|
return stringify(value);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// ../core/src/utils/secretStore.ts
|
|
124
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
|
|
125
|
+
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
126
|
+
import path2 from "path";
|
|
127
|
+
function isObject(value) {
|
|
128
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
129
|
+
}
|
|
130
|
+
function isSecretReference(value) {
|
|
131
|
+
return isObject(value) && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.ref === "string" && value.ref.trim().length > 0 && (value.vault === void 0 && true || typeof value.vault === "string" && value.vault.trim().length > 0) && Object.keys(value).every((key) => ["provider", "ref", "vault"].includes(key));
|
|
132
|
+
}
|
|
133
|
+
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
134
|
+
return path2.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
135
|
+
}
|
|
136
|
+
function resolveSecretVaultFile(storeRoot, vault = "default") {
|
|
137
|
+
return path2.join(storeRoot, "vaults", `${vault}.json`);
|
|
138
|
+
}
|
|
139
|
+
function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
|
|
140
|
+
return path2.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
|
|
141
|
+
}
|
|
142
|
+
function deriveKey(passphrase, salt) {
|
|
143
|
+
return scryptSync(passphrase, salt, 32);
|
|
144
|
+
}
|
|
145
|
+
function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
|
|
146
|
+
const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
147
|
+
return processEnv[`CNOS_SECRET_PASSPHRASE_${vaultToken}`] ?? processEnv.CNOS_SECRET_PASSPHRASE;
|
|
148
|
+
}
|
|
149
|
+
function encryptDocument(value, passphrase) {
|
|
150
|
+
const salt = randomBytes(16);
|
|
151
|
+
const iv = randomBytes(12);
|
|
152
|
+
const key = deriveKey(passphrase, salt);
|
|
153
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
154
|
+
const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
|
|
155
|
+
const tag = cipher.getAuthTag();
|
|
156
|
+
return {
|
|
157
|
+
version: 1,
|
|
158
|
+
algorithm: "aes-256-gcm",
|
|
159
|
+
salt: salt.toString("base64"),
|
|
160
|
+
iv: iv.toString("base64"),
|
|
161
|
+
tag: tag.toString("base64"),
|
|
162
|
+
ciphertext: ciphertext.toString("base64")
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function decryptDocument(document, passphrase) {
|
|
166
|
+
const salt = Buffer.from(document.salt, "base64");
|
|
167
|
+
const iv = Buffer.from(document.iv, "base64");
|
|
168
|
+
const tag = Buffer.from(document.tag, "base64");
|
|
169
|
+
const ciphertext = Buffer.from(document.ciphertext, "base64");
|
|
170
|
+
const key = deriveKey(passphrase, salt);
|
|
171
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
172
|
+
decipher.setAuthTag(tag);
|
|
173
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
174
|
+
return plaintext.toString("utf8");
|
|
175
|
+
}
|
|
176
|
+
async function createSecretVault(storeRoot, vault, passphrase) {
|
|
177
|
+
const normalizedVault = vault.trim() || "default";
|
|
178
|
+
const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
|
|
179
|
+
await mkdir(path2.dirname(filePath), { recursive: true });
|
|
180
|
+
const document = {
|
|
181
|
+
version: 1,
|
|
182
|
+
name: normalizedVault,
|
|
183
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
184
|
+
verifier: encryptDocument(`cnos-vault:${normalizedVault}`, passphrase)
|
|
185
|
+
};
|
|
186
|
+
await writeFile(filePath, JSON.stringify(document, null, 2), "utf8");
|
|
187
|
+
return filePath;
|
|
188
|
+
}
|
|
189
|
+
async function ensureSecretVault(storeRoot, vault, passphrase) {
|
|
190
|
+
const normalizedVault = vault.trim() || "default";
|
|
191
|
+
const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
|
|
192
|
+
try {
|
|
193
|
+
await readFile(filePath, "utf8");
|
|
194
|
+
return filePath;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error.code !== "ENOENT") {
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return createSecretVault(storeRoot, normalizedVault, passphrase);
|
|
201
|
+
}
|
|
202
|
+
async function listSecretVaults(storeRoot) {
|
|
203
|
+
const vaultRoot = path2.join(storeRoot, "vaults");
|
|
204
|
+
try {
|
|
205
|
+
const entries = await readdir(vaultRoot, { withFileTypes: true });
|
|
206
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((left, right) => left.localeCompare(right));
|
|
207
|
+
} catch {
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function writeLocalSecret(storeRoot, ref, value, passphrase, vault = "default") {
|
|
212
|
+
await ensureSecretVault(storeRoot, vault, passphrase);
|
|
213
|
+
const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
|
|
214
|
+
await mkdir(path2.dirname(filePath), { recursive: true });
|
|
215
|
+
await writeFile(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
|
|
216
|
+
return filePath;
|
|
217
|
+
}
|
|
218
|
+
async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
|
|
219
|
+
if (!passphrase) {
|
|
220
|
+
throw new CnosManifestError(
|
|
221
|
+
`Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
|
|
225
|
+
const source = await readFile(filePath, "utf8");
|
|
226
|
+
const document = JSON.parse(source);
|
|
227
|
+
if (document.version !== 1 || document.algorithm !== "aes-256-gcm" || typeof document.salt !== "string" || typeof document.iv !== "string" || typeof document.tag !== "string" || typeof document.ciphertext !== "string") {
|
|
228
|
+
throw new CnosManifestError("Invalid local secret document", filePath);
|
|
229
|
+
}
|
|
230
|
+
return decryptDocument(document, passphrase);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ../core/src/runtime/toEnv.ts
|
|
234
|
+
function normalizeEnvValue(value) {
|
|
235
|
+
if (value === void 0 || value === null) {
|
|
236
|
+
return "";
|
|
237
|
+
}
|
|
238
|
+
if (typeof value === "string") {
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
242
|
+
return String(value);
|
|
243
|
+
}
|
|
244
|
+
return JSON.stringify(value);
|
|
245
|
+
}
|
|
246
|
+
function toEnv(graph, manifest, options = {}) {
|
|
247
|
+
const includeSecrets = options.includeSecrets ?? true;
|
|
248
|
+
const output = {};
|
|
249
|
+
const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
|
|
250
|
+
([left], [right]) => left.localeCompare(right)
|
|
251
|
+
);
|
|
252
|
+
for (const [envVar, logicalKey] of mappedEntries) {
|
|
253
|
+
const entry = graph.entries.get(logicalKey);
|
|
254
|
+
if (!entry) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (entry.namespace === "secret" && !includeSecrets) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (isSecretReference(entry.value)) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
output[envVar] = normalizeEnvValue(entry.value);
|
|
264
|
+
}
|
|
265
|
+
return output;
|
|
266
|
+
}
|
|
267
|
+
|
|
123
268
|
// ../core/src/utils/envNaming.ts
|
|
124
269
|
function normalizeMappingConfig(config = {}) {
|
|
125
270
|
return {
|
|
@@ -175,48 +320,6 @@ function envVarToLogicalKey(envVar, config = {}) {
|
|
|
175
320
|
return `value.${fromScreamingSnake(envVar)}`;
|
|
176
321
|
}
|
|
177
322
|
|
|
178
|
-
// ../core/src/runtime/toEnv.ts
|
|
179
|
-
function fallbackLogicalKeyToEnvVar(key) {
|
|
180
|
-
if (key.startsWith("value.")) {
|
|
181
|
-
return key.slice("value.".length).replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
182
|
-
}
|
|
183
|
-
if (key.startsWith("secret.")) {
|
|
184
|
-
const normalized = key.slice("secret.".length).replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
185
|
-
return `SECRET_${normalized}`;
|
|
186
|
-
}
|
|
187
|
-
return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
188
|
-
}
|
|
189
|
-
function normalizeEnvValue(value) {
|
|
190
|
-
if (value === void 0 || value === null) {
|
|
191
|
-
return "";
|
|
192
|
-
}
|
|
193
|
-
if (typeof value === "string") {
|
|
194
|
-
return value;
|
|
195
|
-
}
|
|
196
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
197
|
-
return String(value);
|
|
198
|
-
}
|
|
199
|
-
return JSON.stringify(value);
|
|
200
|
-
}
|
|
201
|
-
function toEnv(graph, manifest, options = {}) {
|
|
202
|
-
const includeSecrets = options.includeSecrets ?? true;
|
|
203
|
-
const output = {};
|
|
204
|
-
const resolvedEntries = Array.from(graph.entries.values()).sort(
|
|
205
|
-
(left, right) => left.key.localeCompare(right.key)
|
|
206
|
-
);
|
|
207
|
-
for (const entry of resolvedEntries) {
|
|
208
|
-
if (entry.namespace === "meta") {
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
if (!includeSecrets && entry.namespace === "secret") {
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
const envVar = logicalKeyToEnvVar(entry.key, manifest.envMapping) ?? fallbackLogicalKeyToEnvVar(entry.key);
|
|
215
|
-
output[envVar] = normalizeEnvValue(entry.value);
|
|
216
|
-
}
|
|
217
|
-
return output;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
323
|
// ../core/src/runtime/toPublicEnv.ts
|
|
221
324
|
function fallbackValueEnvVar(key) {
|
|
222
325
|
return key.replace(/^value\./, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
@@ -269,8 +372,8 @@ function toPublicEnv(graph, manifest, options = {}) {
|
|
|
269
372
|
}
|
|
270
373
|
|
|
271
374
|
// ../core/src/runtime/dump.ts
|
|
272
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
273
|
-
import
|
|
375
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
376
|
+
import path3 from "path";
|
|
274
377
|
|
|
275
378
|
// ../core/src/runtime/projection.ts
|
|
276
379
|
function setNestedValue(target, pathSegments, value) {
|
|
@@ -304,20 +407,20 @@ function toNamespaceObject(graph, namespace) {
|
|
|
304
407
|
|
|
305
408
|
// ../core/src/runtime/dump.ts
|
|
306
409
|
function buildDumpFiles(graph, options = {}) {
|
|
307
|
-
const basePath = options.flatten ? "" :
|
|
410
|
+
const basePath = options.flatten ? "" : path3.posix.join("workspaces", graph.workspace.workspaceId);
|
|
308
411
|
const values = toNamespaceObject(graph, "value");
|
|
309
412
|
const secrets = toNamespaceObject(graph, "secret");
|
|
310
413
|
const files = [];
|
|
311
414
|
if (Object.keys(values).length > 0) {
|
|
312
415
|
files.push({
|
|
313
|
-
path:
|
|
416
|
+
path: path3.posix.join(basePath, "values", graph.profile, "app.yml"),
|
|
314
417
|
namespace: "value",
|
|
315
418
|
content: stringifyYaml(values)
|
|
316
419
|
});
|
|
317
420
|
}
|
|
318
421
|
if (Object.keys(secrets).length > 0) {
|
|
319
422
|
files.push({
|
|
320
|
-
path:
|
|
423
|
+
path: path3.posix.join(basePath, "secrets", graph.profile, "app.yml"),
|
|
321
424
|
namespace: "secret",
|
|
322
425
|
content: stringifyYaml(secrets)
|
|
323
426
|
});
|
|
@@ -333,12 +436,12 @@ function planDump(graph, options = {}) {
|
|
|
333
436
|
};
|
|
334
437
|
}
|
|
335
438
|
async function writeDump(graph, options) {
|
|
336
|
-
const root =
|
|
439
|
+
const root = path3.resolve(options.to);
|
|
337
440
|
const plan = planDump(graph, options);
|
|
338
441
|
for (const file of plan.files) {
|
|
339
|
-
const destination =
|
|
340
|
-
await
|
|
341
|
-
await
|
|
442
|
+
const destination = path3.join(root, file.path);
|
|
443
|
+
await mkdir2(path3.dirname(destination), { recursive: true });
|
|
444
|
+
await writeFile2(destination, file.content, "utf8");
|
|
342
445
|
}
|
|
343
446
|
return {
|
|
344
447
|
...plan,
|
|
@@ -359,75 +462,8 @@ function flattenObject(value, prefix = "") {
|
|
|
359
462
|
}, {});
|
|
360
463
|
}
|
|
361
464
|
|
|
362
|
-
// ../core/src/utils/secretStore.ts
|
|
363
|
-
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
|
|
364
|
-
import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
|
|
365
|
-
import path3 from "path";
|
|
366
|
-
function isObject(value) {
|
|
367
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
368
|
-
}
|
|
369
|
-
function isSecretReference(value) {
|
|
370
|
-
return isObject(value) && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.ref === "string" && value.ref.trim().length > 0 && Object.keys(value).every((key) => ["provider", "ref"].includes(key));
|
|
371
|
-
}
|
|
372
|
-
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
373
|
-
return path3.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
374
|
-
}
|
|
375
|
-
function resolveSecretStoreFile(storeRoot, ref) {
|
|
376
|
-
return path3.join(storeRoot, "store", ...ref.split("/")).concat(".json");
|
|
377
|
-
}
|
|
378
|
-
function deriveKey(passphrase, salt) {
|
|
379
|
-
return scryptSync(passphrase, salt, 32);
|
|
380
|
-
}
|
|
381
|
-
function encryptDocument(value, passphrase) {
|
|
382
|
-
const salt = randomBytes(16);
|
|
383
|
-
const iv = randomBytes(12);
|
|
384
|
-
const key = deriveKey(passphrase, salt);
|
|
385
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
386
|
-
const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
|
|
387
|
-
const tag = cipher.getAuthTag();
|
|
388
|
-
return {
|
|
389
|
-
version: 1,
|
|
390
|
-
algorithm: "aes-256-gcm",
|
|
391
|
-
salt: salt.toString("base64"),
|
|
392
|
-
iv: iv.toString("base64"),
|
|
393
|
-
tag: tag.toString("base64"),
|
|
394
|
-
ciphertext: ciphertext.toString("base64")
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
function decryptDocument(document, passphrase) {
|
|
398
|
-
const salt = Buffer.from(document.salt, "base64");
|
|
399
|
-
const iv = Buffer.from(document.iv, "base64");
|
|
400
|
-
const tag = Buffer.from(document.tag, "base64");
|
|
401
|
-
const ciphertext = Buffer.from(document.ciphertext, "base64");
|
|
402
|
-
const key = deriveKey(passphrase, salt);
|
|
403
|
-
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
404
|
-
decipher.setAuthTag(tag);
|
|
405
|
-
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
406
|
-
return plaintext.toString("utf8");
|
|
407
|
-
}
|
|
408
|
-
async function writeLocalSecret(storeRoot, ref, value, passphrase) {
|
|
409
|
-
const filePath = resolveSecretStoreFile(storeRoot, ref);
|
|
410
|
-
await mkdir2(path3.dirname(filePath), { recursive: true });
|
|
411
|
-
await writeFile2(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
|
|
412
|
-
return filePath;
|
|
413
|
-
}
|
|
414
|
-
async function readLocalSecret(storeRoot, ref, passphrase) {
|
|
415
|
-
if (!passphrase) {
|
|
416
|
-
throw new CnosManifestError(
|
|
417
|
-
`Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
const filePath = resolveSecretStoreFile(storeRoot, ref);
|
|
421
|
-
const source = await readFile(filePath, "utf8");
|
|
422
|
-
const document = JSON.parse(source);
|
|
423
|
-
if (document.version !== 1 || document.algorithm !== "aes-256-gcm" || typeof document.salt !== "string" || typeof document.iv !== "string" || typeof document.tag !== "string" || typeof document.ciphertext !== "string") {
|
|
424
|
-
throw new CnosManifestError("Invalid local secret document", filePath);
|
|
425
|
-
}
|
|
426
|
-
return decryptDocument(document, passphrase);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
465
|
// ../core/src/validation/envMapping.ts
|
|
430
|
-
function
|
|
466
|
+
function fallbackLogicalKeyToEnvVar(key) {
|
|
431
467
|
return key.replace(/^(value|secret)\./, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
432
468
|
}
|
|
433
469
|
function validateEnvMappingCollisions(manifest, graph) {
|
|
@@ -442,7 +478,7 @@ function validateEnvMappingCollisions(manifest, graph) {
|
|
|
442
478
|
if (key.startsWith("meta.")) {
|
|
443
479
|
continue;
|
|
444
480
|
}
|
|
445
|
-
const envVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? (key.startsWith("value.") || key.startsWith("secret.") ?
|
|
481
|
+
const envVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? (key.startsWith("value.") || key.startsWith("secret.") ? fallbackLogicalKeyToEnvVar(key) : void 0);
|
|
446
482
|
if (!envVar) {
|
|
447
483
|
continue;
|
|
448
484
|
}
|
|
@@ -1550,16 +1586,20 @@ export {
|
|
|
1550
1586
|
parseYaml,
|
|
1551
1587
|
stringifyYaml,
|
|
1552
1588
|
applySchemaRules,
|
|
1553
|
-
|
|
1589
|
+
isSecretReference,
|
|
1590
|
+
resolveSecretStoreRoot,
|
|
1591
|
+
resolveSecretVaultFile,
|
|
1592
|
+
resolveSecretPassphrase,
|
|
1593
|
+
createSecretVault,
|
|
1594
|
+
listSecretVaults,
|
|
1595
|
+
writeLocalSecret,
|
|
1596
|
+
readLocalSecret,
|
|
1554
1597
|
toEnv,
|
|
1598
|
+
envVarToLogicalKey,
|
|
1555
1599
|
toPublicEnv,
|
|
1556
1600
|
createCnos,
|
|
1557
1601
|
planDump,
|
|
1558
1602
|
writeDump,
|
|
1559
1603
|
flattenObject,
|
|
1560
|
-
isSecretReference,
|
|
1561
|
-
resolveSecretStoreRoot,
|
|
1562
|
-
writeLocalSecret,
|
|
1563
|
-
readLocalSecret,
|
|
1564
1604
|
validateRuntime
|
|
1565
1605
|
};
|
|
@@ -3,9 +3,10 @@ import {
|
|
|
3
3
|
isSecretReference,
|
|
4
4
|
parseYaml,
|
|
5
5
|
readLocalSecret,
|
|
6
|
+
resolveSecretPassphrase,
|
|
6
7
|
resolveSecretStoreRoot,
|
|
7
8
|
toPortablePath
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-33ZDYDQJ.js";
|
|
9
10
|
|
|
10
11
|
// ../../plugins/filesystem/src/helpers.ts
|
|
11
12
|
import { readdir } from "fs/promises";
|
|
@@ -102,13 +103,15 @@ async function resolveSecretValue(value, processEnv) {
|
|
|
102
103
|
return value;
|
|
103
104
|
}
|
|
104
105
|
if (value.provider === "local") {
|
|
105
|
-
|
|
106
|
+
const passphrase = resolveSecretPassphrase(value.vault, processEnv);
|
|
107
|
+
if (!passphrase) {
|
|
106
108
|
return value;
|
|
107
109
|
}
|
|
108
110
|
return readLocalSecret(
|
|
109
111
|
resolveSecretStoreRoot(processEnv),
|
|
110
112
|
value.ref,
|
|
111
|
-
|
|
113
|
+
passphrase,
|
|
114
|
+
value.vault
|
|
112
115
|
);
|
|
113
116
|
}
|
|
114
117
|
if (value.provider === "env") {
|