@kitsy/cnos 1.1.1 → 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.
@@ -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 path2 from "path";
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 ? "" : path2.posix.join("workspaces", graph.workspace.workspaceId);
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: path2.posix.join(basePath, "values", graph.profile, "app.yml"),
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: path2.posix.join(basePath, "secrets", graph.profile, "app.yml"),
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 = path2.resolve(options.to);
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 = path2.join(root, file.path);
340
- await mkdir(path2.dirname(destination), { recursive: true });
341
- await writeFile(destination, file.content, "utf8");
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,118 +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, readdir, 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 && (value.vault === void 0 && true || typeof value.vault === "string" && value.vault.trim().length > 0) && Object.keys(value).every((key) => ["provider", "ref", "vault"].includes(key));
371
- }
372
- function resolveSecretStoreRoot(processEnv = process.env) {
373
- return path3.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
374
- }
375
- function resolveSecretVaultFile(storeRoot, vault = "default") {
376
- return path3.join(storeRoot, "vaults", `${vault}.json`);
377
- }
378
- function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
379
- return path3.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
380
- }
381
- function deriveKey(passphrase, salt) {
382
- return scryptSync(passphrase, salt, 32);
383
- }
384
- function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
385
- const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
386
- return processEnv[`CNOS_SECRET_PASSPHRASE_${vaultToken}`] ?? processEnv.CNOS_SECRET_PASSPHRASE;
387
- }
388
- function encryptDocument(value, passphrase) {
389
- const salt = randomBytes(16);
390
- const iv = randomBytes(12);
391
- const key = deriveKey(passphrase, salt);
392
- const cipher = createCipheriv("aes-256-gcm", key, iv);
393
- const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
394
- const tag = cipher.getAuthTag();
395
- return {
396
- version: 1,
397
- algorithm: "aes-256-gcm",
398
- salt: salt.toString("base64"),
399
- iv: iv.toString("base64"),
400
- tag: tag.toString("base64"),
401
- ciphertext: ciphertext.toString("base64")
402
- };
403
- }
404
- function decryptDocument(document, passphrase) {
405
- const salt = Buffer.from(document.salt, "base64");
406
- const iv = Buffer.from(document.iv, "base64");
407
- const tag = Buffer.from(document.tag, "base64");
408
- const ciphertext = Buffer.from(document.ciphertext, "base64");
409
- const key = deriveKey(passphrase, salt);
410
- const decipher = createDecipheriv("aes-256-gcm", key, iv);
411
- decipher.setAuthTag(tag);
412
- const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
413
- return plaintext.toString("utf8");
414
- }
415
- async function createSecretVault(storeRoot, vault, passphrase) {
416
- const normalizedVault = vault.trim() || "default";
417
- const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
418
- await mkdir2(path3.dirname(filePath), { recursive: true });
419
- const document = {
420
- version: 1,
421
- name: normalizedVault,
422
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
423
- verifier: encryptDocument(`cnos-vault:${normalizedVault}`, passphrase)
424
- };
425
- await writeFile2(filePath, JSON.stringify(document, null, 2), "utf8");
426
- return filePath;
427
- }
428
- async function ensureSecretVault(storeRoot, vault, passphrase) {
429
- const normalizedVault = vault.trim() || "default";
430
- const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
431
- try {
432
- await readFile(filePath, "utf8");
433
- return filePath;
434
- } catch (error) {
435
- if (error.code !== "ENOENT") {
436
- throw error;
437
- }
438
- }
439
- return createSecretVault(storeRoot, normalizedVault, passphrase);
440
- }
441
- async function listSecretVaults(storeRoot) {
442
- const vaultRoot = path3.join(storeRoot, "vaults");
443
- try {
444
- const entries = await readdir(vaultRoot, { withFileTypes: true });
445
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((left, right) => left.localeCompare(right));
446
- } catch {
447
- return [];
448
- }
449
- }
450
- async function writeLocalSecret(storeRoot, ref, value, passphrase, vault = "default") {
451
- await ensureSecretVault(storeRoot, vault, passphrase);
452
- const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
453
- await mkdir2(path3.dirname(filePath), { recursive: true });
454
- await writeFile2(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
455
- return filePath;
456
- }
457
- async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
458
- if (!passphrase) {
459
- throw new CnosManifestError(
460
- `Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
461
- );
462
- }
463
- const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
464
- const source = await readFile(filePath, "utf8");
465
- const document = JSON.parse(source);
466
- 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") {
467
- throw new CnosManifestError("Invalid local secret document", filePath);
468
- }
469
- return decryptDocument(document, passphrase);
470
- }
471
-
472
465
  // ../core/src/validation/envMapping.ts
473
- function fallbackLogicalKeyToEnvVar2(key) {
466
+ function fallbackLogicalKeyToEnvVar(key) {
474
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();
475
468
  }
476
469
  function validateEnvMappingCollisions(manifest, graph) {
@@ -485,7 +478,7 @@ function validateEnvMappingCollisions(manifest, graph) {
485
478
  if (key.startsWith("meta.")) {
486
479
  continue;
487
480
  }
488
- const envVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? (key.startsWith("value.") || key.startsWith("secret.") ? fallbackLogicalKeyToEnvVar2(key) : void 0);
481
+ const envVar = logicalKeyToEnvVar(key, manifest.envMapping) ?? (key.startsWith("value.") || key.startsWith("secret.") ? fallbackLogicalKeyToEnvVar(key) : void 0);
489
482
  if (!envVar) {
490
483
  continue;
491
484
  }
@@ -1593,13 +1586,6 @@ export {
1593
1586
  parseYaml,
1594
1587
  stringifyYaml,
1595
1588
  applySchemaRules,
1596
- envVarToLogicalKey,
1597
- toEnv,
1598
- toPublicEnv,
1599
- createCnos,
1600
- planDump,
1601
- writeDump,
1602
- flattenObject,
1603
1589
  isSecretReference,
1604
1590
  resolveSecretStoreRoot,
1605
1591
  resolveSecretVaultFile,
@@ -1608,5 +1594,12 @@ export {
1608
1594
  listSecretVaults,
1609
1595
  writeLocalSecret,
1610
1596
  readLocalSecret,
1597
+ toEnv,
1598
+ envVarToLogicalKey,
1599
+ toPublicEnv,
1600
+ createCnos,
1601
+ planDump,
1602
+ writeDump,
1603
+ flattenObject,
1611
1604
  validateRuntime
1612
1605
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  envVarToLogicalKey
3
- } from "./chunk-JPJ3S3CO.js";
3
+ } from "./chunk-33ZDYDQJ.js";
4
4
 
5
5
  // ../../plugins/process-env/src/index.ts
6
6
  var PROCESS_ENV_PLUGIN_ID = "@kitsy/cnos/plugins/process-env";
@@ -6,7 +6,7 @@ import {
6
6
  resolveSecretPassphrase,
7
7
  resolveSecretStoreRoot,
8
8
  toPortablePath
9
- } from "./chunk-JPJ3S3CO.js";
9
+ } from "./chunk-33ZDYDQJ.js";
10
10
 
11
11
  // ../../plugins/filesystem/src/helpers.ts
12
12
  import { readdir } from "fs/promises";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  joinConfigPath
3
- } from "./chunk-JPJ3S3CO.js";
3
+ } from "./chunk-33ZDYDQJ.js";
4
4
 
5
5
  // ../../plugins/cli-args/src/index.ts
6
6
  var CLI_ARGS_PLUGIN_ID = "@kitsy/cnos/plugins/cli-args";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  toEnv,
3
3
  toPublicEnv
4
- } from "./chunk-JPJ3S3CO.js";
4
+ } from "./chunk-33ZDYDQJ.js";
5
5
 
6
6
  // ../../plugins/env-export/src/index.ts
7
7
  function createEnvExportPlugin() {
@@ -2,7 +2,7 @@ import {
2
2
  envVarToLogicalKey,
3
3
  resolveWorkspaceScopedPath,
4
4
  toPortablePath
5
- } from "./chunk-JPJ3S3CO.js";
5
+ } from "./chunk-33ZDYDQJ.js";
6
6
 
7
7
  // ../../plugins/dotenv/src/index.ts
8
8
  import { readFile } from "fs/promises";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  applySchemaRules
3
- } from "./chunk-JPJ3S3CO.js";
3
+ } from "./chunk-33ZDYDQJ.js";
4
4
 
5
5
  // ../../plugins/basic-schema/src/index.ts
6
6
  function createBasicSchemaPlugin() {
package/dist/index.cjs CHANGED
@@ -1003,6 +1003,90 @@ function requireValue(graph, key) {
1003
1003
  return value;
1004
1004
  }
1005
1005
 
1006
+ // ../core/src/utils/secretStore.ts
1007
+ var import_node_crypto = require("crypto");
1008
+ var import_promises6 = require("fs/promises");
1009
+ var import_node_path6 = __toESM(require("path"), 1);
1010
+ function isObject(value) {
1011
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1012
+ }
1013
+ function isSecretReference(value) {
1014
+ 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));
1015
+ }
1016
+ function resolveSecretStoreRoot(processEnv = process.env) {
1017
+ return import_node_path6.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
1018
+ }
1019
+ function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
1020
+ return import_node_path6.default.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
1021
+ }
1022
+ function deriveKey(passphrase, salt) {
1023
+ return (0, import_node_crypto.scryptSync)(passphrase, salt, 32);
1024
+ }
1025
+ function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
1026
+ const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1027
+ return processEnv[`CNOS_SECRET_PASSPHRASE_${vaultToken}`] ?? processEnv.CNOS_SECRET_PASSPHRASE;
1028
+ }
1029
+ function decryptDocument(document, passphrase) {
1030
+ const salt = Buffer.from(document.salt, "base64");
1031
+ const iv = Buffer.from(document.iv, "base64");
1032
+ const tag = Buffer.from(document.tag, "base64");
1033
+ const ciphertext = Buffer.from(document.ciphertext, "base64");
1034
+ const key = deriveKey(passphrase, salt);
1035
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", key, iv);
1036
+ decipher.setAuthTag(tag);
1037
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
1038
+ return plaintext.toString("utf8");
1039
+ }
1040
+ async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
1041
+ if (!passphrase) {
1042
+ throw new CnosManifestError(
1043
+ `Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
1044
+ );
1045
+ }
1046
+ const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
1047
+ const source = await (0, import_promises6.readFile)(filePath, "utf8");
1048
+ const document = JSON.parse(source);
1049
+ 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") {
1050
+ throw new CnosManifestError("Invalid local secret document", filePath);
1051
+ }
1052
+ return decryptDocument(document, passphrase);
1053
+ }
1054
+
1055
+ // ../core/src/runtime/toEnv.ts
1056
+ function normalizeEnvValue(value) {
1057
+ if (value === void 0 || value === null) {
1058
+ return "";
1059
+ }
1060
+ if (typeof value === "string") {
1061
+ return value;
1062
+ }
1063
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
1064
+ return String(value);
1065
+ }
1066
+ return JSON.stringify(value);
1067
+ }
1068
+ function toEnv(graph, manifest, options = {}) {
1069
+ const includeSecrets = options.includeSecrets ?? true;
1070
+ const output = {};
1071
+ const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
1072
+ ([left], [right]) => left.localeCompare(right)
1073
+ );
1074
+ for (const [envVar, logicalKey] of mappedEntries) {
1075
+ const entry = graph.entries.get(logicalKey);
1076
+ if (!entry) {
1077
+ continue;
1078
+ }
1079
+ if (entry.namespace === "secret" && !includeSecrets) {
1080
+ continue;
1081
+ }
1082
+ if (isSecretReference(entry.value)) {
1083
+ continue;
1084
+ }
1085
+ output[envVar] = normalizeEnvValue(entry.value);
1086
+ }
1087
+ return output;
1088
+ }
1089
+
1006
1090
  // ../core/src/utils/envNaming.ts
1007
1091
  function normalizeMappingConfig(config = {}) {
1008
1092
  return {
@@ -1058,48 +1142,6 @@ function envVarToLogicalKey(envVar, config = {}) {
1058
1142
  return `value.${fromScreamingSnake(envVar)}`;
1059
1143
  }
1060
1144
 
1061
- // ../core/src/runtime/toEnv.ts
1062
- function fallbackLogicalKeyToEnvVar(key) {
1063
- if (key.startsWith("value.")) {
1064
- 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();
1065
- }
1066
- if (key.startsWith("secret.")) {
1067
- 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();
1068
- return `SECRET_${normalized}`;
1069
- }
1070
- return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1071
- }
1072
- function normalizeEnvValue(value) {
1073
- if (value === void 0 || value === null) {
1074
- return "";
1075
- }
1076
- if (typeof value === "string") {
1077
- return value;
1078
- }
1079
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
1080
- return String(value);
1081
- }
1082
- return JSON.stringify(value);
1083
- }
1084
- function toEnv(graph, manifest, options = {}) {
1085
- const includeSecrets = options.includeSecrets ?? true;
1086
- const output = {};
1087
- const resolvedEntries = Array.from(graph.entries.values()).sort(
1088
- (left, right) => left.key.localeCompare(right.key)
1089
- );
1090
- for (const entry of resolvedEntries) {
1091
- if (entry.namespace === "meta") {
1092
- continue;
1093
- }
1094
- if (!includeSecrets && entry.namespace === "secret") {
1095
- continue;
1096
- }
1097
- const envVar = logicalKeyToEnvVar(entry.key, manifest.envMapping) ?? fallbackLogicalKeyToEnvVar(entry.key);
1098
- output[envVar] = normalizeEnvValue(entry.value);
1099
- }
1100
- return output;
1101
- }
1102
-
1103
1145
  // ../core/src/runtime/toPublicEnv.ts
1104
1146
  function fallbackValueEnvVar(key) {
1105
1147
  return key.replace(/^value\./, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
@@ -1338,23 +1380,23 @@ async function createCnos(options = {}) {
1338
1380
  }
1339
1381
 
1340
1382
  // ../core/src/runtime/dump.ts
1341
- var import_promises6 = require("fs/promises");
1342
- var import_node_path6 = __toESM(require("path"), 1);
1383
+ var import_promises7 = require("fs/promises");
1384
+ var import_node_path7 = __toESM(require("path"), 1);
1343
1385
  function buildDumpFiles(graph, options = {}) {
1344
- const basePath = options.flatten ? "" : import_node_path6.default.posix.join("workspaces", graph.workspace.workspaceId);
1386
+ const basePath = options.flatten ? "" : import_node_path7.default.posix.join("workspaces", graph.workspace.workspaceId);
1345
1387
  const values = toNamespaceObject(graph, "value");
1346
1388
  const secrets = toNamespaceObject(graph, "secret");
1347
1389
  const files = [];
1348
1390
  if (Object.keys(values).length > 0) {
1349
1391
  files.push({
1350
- path: import_node_path6.default.posix.join(basePath, "values", graph.profile, "app.yml"),
1392
+ path: import_node_path7.default.posix.join(basePath, "values", graph.profile, "app.yml"),
1351
1393
  namespace: "value",
1352
1394
  content: stringifyYaml(values)
1353
1395
  });
1354
1396
  }
1355
1397
  if (Object.keys(secrets).length > 0) {
1356
1398
  files.push({
1357
- path: import_node_path6.default.posix.join(basePath, "secrets", graph.profile, "app.yml"),
1399
+ path: import_node_path7.default.posix.join(basePath, "secrets", graph.profile, "app.yml"),
1358
1400
  namespace: "secret",
1359
1401
  content: stringifyYaml(secrets)
1360
1402
  });
@@ -1370,12 +1412,12 @@ function planDump(graph, options = {}) {
1370
1412
  };
1371
1413
  }
1372
1414
  async function writeDump(graph, options) {
1373
- const root = import_node_path6.default.resolve(options.to);
1415
+ const root = import_node_path7.default.resolve(options.to);
1374
1416
  const plan = planDump(graph, options);
1375
1417
  for (const file of plan.files) {
1376
- const destination = import_node_path6.default.join(root, file.path);
1377
- await (0, import_promises6.mkdir)(import_node_path6.default.dirname(destination), { recursive: true });
1378
- await (0, import_promises6.writeFile)(destination, file.content, "utf8");
1418
+ const destination = import_node_path7.default.join(root, file.path);
1419
+ await (0, import_promises7.mkdir)(import_node_path7.default.dirname(destination), { recursive: true });
1420
+ await (0, import_promises7.writeFile)(destination, file.content, "utf8");
1379
1421
  }
1380
1422
  return {
1381
1423
  ...plan,
@@ -1383,59 +1425,10 @@ async function writeDump(graph, options) {
1383
1425
  };
1384
1426
  }
1385
1427
 
1386
- // ../core/src/utils/secretStore.ts
1387
- var import_node_crypto = require("crypto");
1388
- var import_promises7 = require("fs/promises");
1389
- var import_node_path7 = __toESM(require("path"), 1);
1390
- function isObject(value) {
1391
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1392
- }
1393
- function isSecretReference(value) {
1394
- 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));
1395
- }
1396
- function resolveSecretStoreRoot(processEnv = process.env) {
1397
- return import_node_path7.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
1398
- }
1399
- function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
1400
- return import_node_path7.default.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
1401
- }
1402
- function deriveKey(passphrase, salt) {
1403
- return (0, import_node_crypto.scryptSync)(passphrase, salt, 32);
1404
- }
1405
- function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
1406
- const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1407
- return processEnv[`CNOS_SECRET_PASSPHRASE_${vaultToken}`] ?? processEnv.CNOS_SECRET_PASSPHRASE;
1408
- }
1409
- function decryptDocument(document, passphrase) {
1410
- const salt = Buffer.from(document.salt, "base64");
1411
- const iv = Buffer.from(document.iv, "base64");
1412
- const tag = Buffer.from(document.tag, "base64");
1413
- const ciphertext = Buffer.from(document.ciphertext, "base64");
1414
- const key = deriveKey(passphrase, salt);
1415
- const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", key, iv);
1416
- decipher.setAuthTag(tag);
1417
- const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
1418
- return plaintext.toString("utf8");
1419
- }
1420
- async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
1421
- if (!passphrase) {
1422
- throw new CnosManifestError(
1423
- `Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
1424
- );
1425
- }
1426
- const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
1427
- const source = await (0, import_promises7.readFile)(filePath, "utf8");
1428
- const document = JSON.parse(source);
1429
- 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") {
1430
- throw new CnosManifestError("Invalid local secret document", filePath);
1431
- }
1432
- return decryptDocument(document, passphrase);
1433
- }
1434
-
1435
1428
  // package.json
1436
1429
  var package_default = {
1437
1430
  name: "@kitsy/cnos",
1438
- version: "1.1.1",
1431
+ version: "1.1.2",
1439
1432
  description: "Batteries-included CNOS runtime package wired with the official plugins.",
1440
1433
  type: "module",
1441
1434
  main: "./dist/index.cjs",
package/dist/index.js CHANGED
@@ -1,23 +1,23 @@
1
1
  import {
2
2
  createBasicSchemaPlugin
3
- } from "./chunk-L3HOQHCH.js";
3
+ } from "./chunk-JQGGSNCL.js";
4
4
  import {
5
5
  createCliArgsPlugin
6
- } from "./chunk-M4S6PYM5.js";
6
+ } from "./chunk-HOS4E7XO.js";
7
7
  import {
8
8
  createDotenvPlugin
9
- } from "./chunk-7GNXYEO6.js";
9
+ } from "./chunk-IQOUWY6T.js";
10
10
  import {
11
11
  createEnvExportPlugin,
12
12
  createPublicEnvExportPlugin
13
- } from "./chunk-PBU5NAX4.js";
13
+ } from "./chunk-IHSV5AFX.js";
14
14
  import {
15
15
  createFilesystemSecretsPlugin,
16
16
  createFilesystemValuesPlugin
17
- } from "./chunk-QKJ6QLRS.js";
17
+ } from "./chunk-7FBRVJD6.js";
18
18
  import {
19
19
  createProcessEnvPlugin
20
- } from "./chunk-X4GOXEKX.js";
20
+ } from "./chunk-53HXUSM6.js";
21
21
  import {
22
22
  createCnos,
23
23
  createProvenanceInspector,
@@ -25,12 +25,12 @@ import {
25
25
  toEnv,
26
26
  toPublicEnv,
27
27
  writeDump
28
- } from "./chunk-JPJ3S3CO.js";
28
+ } from "./chunk-33ZDYDQJ.js";
29
29
 
30
30
  // package.json
31
31
  var package_default = {
32
32
  name: "@kitsy/cnos",
33
- version: "1.1.1",
33
+ version: "1.1.2",
34
34
  description: "Batteries-included CNOS runtime package wired with the official plugins.",
35
35
  type: "module",
36
36
  main: "./dist/index.cjs",
package/dist/internal.cjs CHANGED
@@ -95,66 +95,18 @@ var import_node_path4 = __toESM(require("path"), 1);
95
95
  var import_promises5 = require("fs/promises");
96
96
  var import_node_path5 = __toESM(require("path"), 1);
97
97
 
98
- // ../core/src/utils/envNaming.ts
99
- function normalizeMappingConfig(config = {}) {
100
- return {
101
- convention: config.convention,
102
- explicit: config.explicit ?? {}
103
- };
104
- }
105
- function toScreamingSnakeSegment(segment) {
106
- return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
107
- }
108
- function toScreamingSnake(path8) {
109
- return path8.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
110
- }
111
- function logicalKeyToEnvVar(key, config = {}) {
112
- const normalized = normalizeMappingConfig(config);
113
- const explicitEntry = Object.entries(normalized.explicit).find(([, logicalKey]) => logicalKey === key);
114
- if (explicitEntry) {
115
- return explicitEntry[0];
116
- }
117
- if (normalized.convention !== "SCREAMING_SNAKE") {
118
- return void 0;
119
- }
120
- if (key.startsWith("value.")) {
121
- return toScreamingSnake(key.slice("value.".length));
122
- }
123
- if (key.startsWith("secret.")) {
124
- return `SECRET_${toScreamingSnake(key.slice("secret.".length))}`;
125
- }
126
- return void 0;
127
- }
128
-
129
- // ../core/src/runtime/dump.ts
130
- var import_promises6 = require("fs/promises");
131
- var import_node_path6 = __toESM(require("path"), 1);
132
-
133
- // ../core/src/utils/flatten.ts
134
- function flattenObject(value, prefix = "") {
135
- return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
136
- const nextKey = prefix ? `${prefix}.${key}` : key;
137
- if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue)) {
138
- Object.assign(accumulator, flattenObject(nestedValue, nextKey));
139
- return accumulator;
140
- }
141
- accumulator[nextKey] = nestedValue;
142
- return accumulator;
143
- }, {});
144
- }
145
-
146
98
  // ../core/src/utils/secretStore.ts
147
99
  var import_node_crypto = require("crypto");
148
- var import_promises7 = require("fs/promises");
149
- var import_node_path7 = __toESM(require("path"), 1);
100
+ var import_promises6 = require("fs/promises");
101
+ var import_node_path6 = __toESM(require("path"), 1);
150
102
  function resolveSecretStoreRoot(processEnv = process.env) {
151
- return import_node_path7.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
103
+ return import_node_path6.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
152
104
  }
153
105
  function resolveSecretVaultFile(storeRoot, vault = "default") {
154
- return import_node_path7.default.join(storeRoot, "vaults", `${vault}.json`);
106
+ return import_node_path6.default.join(storeRoot, "vaults", `${vault}.json`);
155
107
  }
156
108
  function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
157
- return import_node_path7.default.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
109
+ return import_node_path6.default.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
158
110
  }
159
111
  function deriveKey(passphrase, salt) {
160
112
  return (0, import_node_crypto.scryptSync)(passphrase, salt, 32);
@@ -182,21 +134,21 @@ function encryptDocument(value, passphrase) {
182
134
  async function createSecretVault(storeRoot, vault, passphrase) {
183
135
  const normalizedVault = vault.trim() || "default";
184
136
  const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
185
- await (0, import_promises7.mkdir)(import_node_path7.default.dirname(filePath), { recursive: true });
137
+ await (0, import_promises6.mkdir)(import_node_path6.default.dirname(filePath), { recursive: true });
186
138
  const document = {
187
139
  version: 1,
188
140
  name: normalizedVault,
189
141
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
190
142
  verifier: encryptDocument(`cnos-vault:${normalizedVault}`, passphrase)
191
143
  };
192
- await (0, import_promises7.writeFile)(filePath, JSON.stringify(document, null, 2), "utf8");
144
+ await (0, import_promises6.writeFile)(filePath, JSON.stringify(document, null, 2), "utf8");
193
145
  return filePath;
194
146
  }
195
147
  async function ensureSecretVault(storeRoot, vault, passphrase) {
196
148
  const normalizedVault = vault.trim() || "default";
197
149
  const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
198
150
  try {
199
- await (0, import_promises7.readFile)(filePath, "utf8");
151
+ await (0, import_promises6.readFile)(filePath, "utf8");
200
152
  return filePath;
201
153
  } catch (error) {
202
154
  if (error.code !== "ENOENT") {
@@ -206,9 +158,9 @@ async function ensureSecretVault(storeRoot, vault, passphrase) {
206
158
  return createSecretVault(storeRoot, normalizedVault, passphrase);
207
159
  }
208
160
  async function listSecretVaults(storeRoot) {
209
- const vaultRoot = import_node_path7.default.join(storeRoot, "vaults");
161
+ const vaultRoot = import_node_path6.default.join(storeRoot, "vaults");
210
162
  try {
211
- const entries = await (0, import_promises7.readdir)(vaultRoot, { withFileTypes: true });
163
+ const entries = await (0, import_promises6.readdir)(vaultRoot, { withFileTypes: true });
212
164
  return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((left, right) => left.localeCompare(right));
213
165
  } catch {
214
166
  return [];
@@ -217,11 +169,59 @@ async function listSecretVaults(storeRoot) {
217
169
  async function writeLocalSecret(storeRoot, ref, value, passphrase, vault = "default") {
218
170
  await ensureSecretVault(storeRoot, vault, passphrase);
219
171
  const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
220
- await (0, import_promises7.mkdir)(import_node_path7.default.dirname(filePath), { recursive: true });
221
- await (0, import_promises7.writeFile)(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
172
+ await (0, import_promises6.mkdir)(import_node_path6.default.dirname(filePath), { recursive: true });
173
+ await (0, import_promises6.writeFile)(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
222
174
  return filePath;
223
175
  }
224
176
 
177
+ // ../core/src/utils/envNaming.ts
178
+ function normalizeMappingConfig(config = {}) {
179
+ return {
180
+ convention: config.convention,
181
+ explicit: config.explicit ?? {}
182
+ };
183
+ }
184
+ function toScreamingSnakeSegment(segment) {
185
+ return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
186
+ }
187
+ function toScreamingSnake(path8) {
188
+ return path8.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
189
+ }
190
+ function logicalKeyToEnvVar(key, config = {}) {
191
+ const normalized = normalizeMappingConfig(config);
192
+ const explicitEntry = Object.entries(normalized.explicit).find(([, logicalKey]) => logicalKey === key);
193
+ if (explicitEntry) {
194
+ return explicitEntry[0];
195
+ }
196
+ if (normalized.convention !== "SCREAMING_SNAKE") {
197
+ return void 0;
198
+ }
199
+ if (key.startsWith("value.")) {
200
+ return toScreamingSnake(key.slice("value.".length));
201
+ }
202
+ if (key.startsWith("secret.")) {
203
+ return `SECRET_${toScreamingSnake(key.slice("secret.".length))}`;
204
+ }
205
+ return void 0;
206
+ }
207
+
208
+ // ../core/src/runtime/dump.ts
209
+ var import_promises7 = require("fs/promises");
210
+ var import_node_path7 = __toESM(require("path"), 1);
211
+
212
+ // ../core/src/utils/flatten.ts
213
+ function flattenObject(value, prefix = "") {
214
+ return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
215
+ const nextKey = prefix ? `${prefix}.${key}` : key;
216
+ if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue)) {
217
+ Object.assign(accumulator, flattenObject(nestedValue, nextKey));
218
+ return accumulator;
219
+ }
220
+ accumulator[nextKey] = nestedValue;
221
+ return accumulator;
222
+ }, {});
223
+ }
224
+
225
225
  // ../core/src/validation/envMapping.ts
226
226
  function fallbackLogicalKeyToEnvVar(key) {
227
227
  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();
package/dist/internal.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  stringifyYaml,
11
11
  validateRuntime,
12
12
  writeLocalSecret
13
- } from "./chunk-JPJ3S3CO.js";
13
+ } from "./chunk-33ZDYDQJ.js";
14
14
  export {
15
15
  createSecretVault,
16
16
  flattenObject,
@@ -205,12 +205,12 @@ function applySchemaRules(graph, schema) {
205
205
  };
206
206
  }
207
207
 
208
- // ../core/src/runtime/dump.ts
208
+ // ../core/src/utils/secretStore.ts
209
+ var import_node_crypto = require("crypto");
209
210
  var import_promises6 = require("fs/promises");
210
211
  var import_node_path6 = __toESM(require("path"), 1);
211
212
 
212
- // ../core/src/utils/secretStore.ts
213
- var import_node_crypto = require("crypto");
213
+ // ../core/src/runtime/dump.ts
214
214
  var import_promises7 = require("fs/promises");
215
215
  var import_node_path7 = __toESM(require("path"), 1);
216
216
 
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createBasicSchemaPlugin
3
- } from "../chunk-L3HOQHCH.js";
4
- import "../chunk-JPJ3S3CO.js";
3
+ } from "../chunk-JQGGSNCL.js";
4
+ import "../chunk-33ZDYDQJ.js";
5
5
  export {
6
6
  createBasicSchemaPlugin
7
7
  };
@@ -63,12 +63,12 @@ var import_node_path4 = __toESM(require("path"), 1);
63
63
  var import_promises5 = require("fs/promises");
64
64
  var import_node_path5 = __toESM(require("path"), 1);
65
65
 
66
- // ../core/src/runtime/dump.ts
66
+ // ../core/src/utils/secretStore.ts
67
+ var import_node_crypto = require("crypto");
67
68
  var import_promises6 = require("fs/promises");
68
69
  var import_node_path6 = __toESM(require("path"), 1);
69
70
 
70
- // ../core/src/utils/secretStore.ts
71
- var import_node_crypto = require("crypto");
71
+ // ../core/src/runtime/dump.ts
72
72
  var import_promises7 = require("fs/promises");
73
73
  var import_node_path7 = __toESM(require("path"), 1);
74
74
 
@@ -2,8 +2,8 @@ import {
2
2
  cliArgEntriesFromArgs,
3
3
  createCliArgsPlugin,
4
4
  parseCliArgs
5
- } from "../chunk-M4S6PYM5.js";
6
- import "../chunk-JPJ3S3CO.js";
5
+ } from "../chunk-HOS4E7XO.js";
6
+ import "../chunk-33ZDYDQJ.js";
7
7
  export {
8
8
  cliArgEntriesFromArgs,
9
9
  createCliArgsPlugin,
@@ -89,6 +89,11 @@ var import_node_path4 = __toESM(require("path"), 1);
89
89
  var import_promises5 = require("fs/promises");
90
90
  var import_node_path5 = __toESM(require("path"), 1);
91
91
 
92
+ // ../core/src/utils/secretStore.ts
93
+ var import_node_crypto = require("crypto");
94
+ var import_promises6 = require("fs/promises");
95
+ var import_node_path6 = __toESM(require("path"), 1);
96
+
92
97
  // ../core/src/utils/envNaming.ts
93
98
  function normalizeMappingConfig(config = {}) {
94
99
  return {
@@ -122,11 +127,6 @@ function envVarToLogicalKey(envVar, config = {}) {
122
127
  }
123
128
 
124
129
  // ../core/src/runtime/dump.ts
125
- var import_promises6 = require("fs/promises");
126
- var import_node_path6 = __toESM(require("path"), 1);
127
-
128
- // ../core/src/utils/secretStore.ts
129
- var import_node_crypto = require("crypto");
130
130
  var import_promises7 = require("fs/promises");
131
131
  var import_node_path7 = __toESM(require("path"), 1);
132
132
 
@@ -2,8 +2,8 @@ import {
2
2
  createDotenvPlugin,
3
3
  dotenvEntriesFromObject,
4
4
  parseDotenv
5
- } from "../chunk-7GNXYEO6.js";
6
- import "../chunk-JPJ3S3CO.js";
5
+ } from "../chunk-IQOUWY6T.js";
6
+ import "../chunk-33ZDYDQJ.js";
7
7
  export {
8
8
  createDotenvPlugin,
9
9
  dotenvEntriesFromObject,
@@ -76,6 +76,52 @@ var import_node_path4 = __toESM(require("path"), 1);
76
76
  var import_promises5 = require("fs/promises");
77
77
  var import_node_path5 = __toESM(require("path"), 1);
78
78
 
79
+ // ../core/src/utils/secretStore.ts
80
+ var import_node_crypto = require("crypto");
81
+ var import_promises6 = require("fs/promises");
82
+ var import_node_path6 = __toESM(require("path"), 1);
83
+ function isObject(value) {
84
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
85
+ }
86
+ function isSecretReference(value) {
87
+ 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));
88
+ }
89
+
90
+ // ../core/src/runtime/toEnv.ts
91
+ function normalizeEnvValue(value) {
92
+ if (value === void 0 || value === null) {
93
+ return "";
94
+ }
95
+ if (typeof value === "string") {
96
+ return value;
97
+ }
98
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
99
+ return String(value);
100
+ }
101
+ return JSON.stringify(value);
102
+ }
103
+ function toEnv(graph, manifest, options = {}) {
104
+ const includeSecrets = options.includeSecrets ?? true;
105
+ const output = {};
106
+ const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
107
+ ([left], [right]) => left.localeCompare(right)
108
+ );
109
+ for (const [envVar, logicalKey] of mappedEntries) {
110
+ const entry = graph.entries.get(logicalKey);
111
+ if (!entry) {
112
+ continue;
113
+ }
114
+ if (entry.namespace === "secret" && !includeSecrets) {
115
+ continue;
116
+ }
117
+ if (isSecretReference(entry.value)) {
118
+ continue;
119
+ }
120
+ output[envVar] = normalizeEnvValue(entry.value);
121
+ }
122
+ return output;
123
+ }
124
+
79
125
  // ../core/src/utils/envNaming.ts
80
126
  function normalizeMappingConfig(config = {}) {
81
127
  return {
@@ -107,48 +153,6 @@ function logicalKeyToEnvVar(key, config = {}) {
107
153
  return void 0;
108
154
  }
109
155
 
110
- // ../core/src/runtime/toEnv.ts
111
- function fallbackLogicalKeyToEnvVar(key) {
112
- if (key.startsWith("value.")) {
113
- 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();
114
- }
115
- if (key.startsWith("secret.")) {
116
- 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();
117
- return `SECRET_${normalized}`;
118
- }
119
- return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
120
- }
121
- function normalizeEnvValue(value) {
122
- if (value === void 0 || value === null) {
123
- return "";
124
- }
125
- if (typeof value === "string") {
126
- return value;
127
- }
128
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
129
- return String(value);
130
- }
131
- return JSON.stringify(value);
132
- }
133
- function toEnv(graph, manifest, options = {}) {
134
- const includeSecrets = options.includeSecrets ?? true;
135
- const output = {};
136
- const resolvedEntries = Array.from(graph.entries.values()).sort(
137
- (left, right) => left.key.localeCompare(right.key)
138
- );
139
- for (const entry of resolvedEntries) {
140
- if (entry.namespace === "meta") {
141
- continue;
142
- }
143
- if (!includeSecrets && entry.namespace === "secret") {
144
- continue;
145
- }
146
- const envVar = logicalKeyToEnvVar(entry.key, manifest.envMapping) ?? fallbackLogicalKeyToEnvVar(entry.key);
147
- output[envVar] = normalizeEnvValue(entry.value);
148
- }
149
- return output;
150
- }
151
-
152
156
  // ../core/src/runtime/toPublicEnv.ts
153
157
  function fallbackValueEnvVar(key) {
154
158
  return key.replace(/^value\./, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
@@ -201,11 +205,6 @@ function toPublicEnv(graph, manifest, options = {}) {
201
205
  }
202
206
 
203
207
  // ../core/src/runtime/dump.ts
204
- var import_promises6 = require("fs/promises");
205
- var import_node_path6 = __toESM(require("path"), 1);
206
-
207
- // ../core/src/utils/secretStore.ts
208
- var import_node_crypto = require("crypto");
209
208
  var import_promises7 = require("fs/promises");
210
209
  var import_node_path7 = __toESM(require("path"), 1);
211
210
 
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createEnvExportPlugin,
3
3
  createPublicEnvExportPlugin
4
- } from "../chunk-PBU5NAX4.js";
4
+ } from "../chunk-IHSV5AFX.js";
5
5
  import {
6
6
  toEnv,
7
7
  toPublicEnv
8
- } from "../chunk-JPJ3S3CO.js";
8
+ } from "../chunk-33ZDYDQJ.js";
9
9
  export {
10
10
  createEnvExportPlugin,
11
11
  createPublicEnvExportPlugin,
@@ -100,14 +100,10 @@ var import_node_path4 = __toESM(require("path"), 1);
100
100
  var import_promises5 = require("fs/promises");
101
101
  var import_node_path5 = __toESM(require("path"), 1);
102
102
 
103
- // ../core/src/runtime/dump.ts
104
- var import_promises6 = require("fs/promises");
105
- var import_node_path6 = __toESM(require("path"), 1);
106
-
107
103
  // ../core/src/utils/secretStore.ts
108
104
  var import_node_crypto = require("crypto");
109
- var import_promises7 = require("fs/promises");
110
- var import_node_path7 = __toESM(require("path"), 1);
105
+ var import_promises6 = require("fs/promises");
106
+ var import_node_path6 = __toESM(require("path"), 1);
111
107
  function isObject(value) {
112
108
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
113
109
  }
@@ -115,10 +111,10 @@ function isSecretReference(value) {
115
111
  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));
116
112
  }
117
113
  function resolveSecretStoreRoot(processEnv = process.env) {
118
- return import_node_path7.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
114
+ return import_node_path6.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
119
115
  }
120
116
  function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
121
- return import_node_path7.default.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
117
+ return import_node_path6.default.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
122
118
  }
123
119
  function deriveKey(passphrase, salt) {
124
120
  return (0, import_node_crypto.scryptSync)(passphrase, salt, 32);
@@ -145,7 +141,7 @@ async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
145
141
  );
146
142
  }
147
143
  const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
148
- const source = await (0, import_promises7.readFile)(filePath, "utf8");
144
+ const source = await (0, import_promises6.readFile)(filePath, "utf8");
149
145
  const document = JSON.parse(source);
150
146
  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") {
151
147
  throw new CnosManifestError("Invalid local secret document", filePath);
@@ -153,6 +149,10 @@ async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
153
149
  return decryptDocument(document, passphrase);
154
150
  }
155
151
 
152
+ // ../core/src/runtime/dump.ts
153
+ var import_promises7 = require("fs/promises");
154
+ var import_node_path7 = __toESM(require("path"), 1);
155
+
156
156
  // ../../plugins/filesystem/src/helpers.ts
157
157
  var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
158
158
  var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
@@ -5,8 +5,8 @@ import {
5
5
  filesystemSecretsReader,
6
6
  filesystemValuesReader,
7
7
  yamlObjectToEntries
8
- } from "../chunk-QKJ6QLRS.js";
9
- import "../chunk-JPJ3S3CO.js";
8
+ } from "../chunk-7FBRVJD6.js";
9
+ import "../chunk-33ZDYDQJ.js";
10
10
  export {
11
11
  collectFilesystemLayerFiles,
12
12
  createFilesystemSecretsPlugin,
@@ -59,6 +59,11 @@ var import_node_path4 = __toESM(require("path"), 1);
59
59
  var import_promises5 = require("fs/promises");
60
60
  var import_node_path5 = __toESM(require("path"), 1);
61
61
 
62
+ // ../core/src/utils/secretStore.ts
63
+ var import_node_crypto = require("crypto");
64
+ var import_promises6 = require("fs/promises");
65
+ var import_node_path6 = __toESM(require("path"), 1);
66
+
62
67
  // ../core/src/utils/envNaming.ts
63
68
  function normalizeMappingConfig(config = {}) {
64
69
  return {
@@ -92,11 +97,6 @@ function envVarToLogicalKey(envVar, config = {}) {
92
97
  }
93
98
 
94
99
  // ../core/src/runtime/dump.ts
95
- var import_promises6 = require("fs/promises");
96
- var import_node_path6 = __toESM(require("path"), 1);
97
-
98
- // ../core/src/utils/secretStore.ts
99
- var import_node_crypto = require("crypto");
100
100
  var import_promises7 = require("fs/promises");
101
101
  var import_node_path7 = __toESM(require("path"), 1);
102
102
 
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createProcessEnvPlugin,
3
3
  processEnvEntriesFromObject
4
- } from "../chunk-X4GOXEKX.js";
5
- import "../chunk-JPJ3S3CO.js";
4
+ } from "../chunk-53HXUSM6.js";
5
+ import "../chunk-33ZDYDQJ.js";
6
6
  export {
7
7
  createProcessEnvPlugin,
8
8
  processEnvEntriesFromObject
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitsy/cnos",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Batteries-included CNOS runtime package wired with the official plugins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",