@kitsy/cnos 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +3 -3
  2. package/dist/build/index.cjs +1003 -121
  3. package/dist/build/index.d.cts +1 -1
  4. package/dist/build/index.d.ts +1 -1
  5. package/dist/build/index.js +22 -10
  6. package/dist/{chunk-APCTXRUN.js → chunk-APIU4GTB.js} +1012 -195
  7. package/dist/chunk-EQSKV3DP.js +105 -0
  8. package/dist/{chunk-MLQGYCO7.js → chunk-FWJC4Y2D.js} +1 -1
  9. package/dist/{chunk-RD5WMHPM.js → chunk-HMM76UYZ.js} +1 -1
  10. package/dist/{chunk-EIN55XXA.js → chunk-J4K4JUJL.js} +1 -1
  11. package/dist/{chunk-SO5XREEU.js → chunk-JSBVYK2T.js} +32 -11
  12. package/dist/chunk-LJD4SM32.js +189 -0
  13. package/dist/{chunk-SXTMTACL.js → chunk-T6Y57KTT.js} +20 -31
  14. package/dist/chunk-WCHX2QFY.js +115 -0
  15. package/dist/{chunk-ZA74BO47.js → chunk-ZTPSFXWP.js} +1 -1
  16. package/dist/configure/index.cjs +3021 -0
  17. package/dist/configure/index.d.cts +12 -0
  18. package/dist/configure/index.d.ts +12 -0
  19. package/dist/configure/index.js +24 -0
  20. package/dist/{envNaming-CcsqAel3.d.ts → envNaming-Dvm_LP2D.d.ts} +1 -1
  21. package/dist/{envNaming-BTJpH93W.d.cts → envNaming-S4B-dHUx.d.cts} +1 -1
  22. package/dist/index.cjs +1243 -186
  23. package/dist/index.d.cts +2 -13
  24. package/dist/index.d.ts +2 -13
  25. package/dist/index.js +13 -25
  26. package/dist/internal.cjs +1525 -81
  27. package/dist/internal.d.cts +171 -14
  28. package/dist/internal.d.ts +171 -14
  29. package/dist/internal.js +652 -5
  30. package/dist/plugin/basic-schema.cjs +29 -2
  31. package/dist/plugin/basic-schema.d.cts +1 -1
  32. package/dist/plugin/basic-schema.d.ts +1 -1
  33. package/dist/plugin/basic-schema.js +2 -2
  34. package/dist/plugin/cli-args.cjs +29 -2
  35. package/dist/plugin/cli-args.d.cts +1 -1
  36. package/dist/plugin/cli-args.d.ts +1 -1
  37. package/dist/plugin/cli-args.js +2 -2
  38. package/dist/plugin/dotenv.cjs +36 -9
  39. package/dist/plugin/dotenv.d.cts +2 -2
  40. package/dist/plugin/dotenv.d.ts +2 -2
  41. package/dist/plugin/dotenv.js +2 -2
  42. package/dist/plugin/env-export.cjs +31 -2
  43. package/dist/plugin/env-export.d.cts +2 -2
  44. package/dist/plugin/env-export.d.ts +2 -2
  45. package/dist/plugin/env-export.js +2 -2
  46. package/dist/plugin/filesystem.cjs +65 -91
  47. package/dist/plugin/filesystem.d.cts +1 -1
  48. package/dist/plugin/filesystem.d.ts +1 -1
  49. package/dist/plugin/filesystem.js +2 -2
  50. package/dist/plugin/process-env.cjs +105 -11
  51. package/dist/plugin/process-env.d.cts +4 -3
  52. package/dist/plugin/process-env.d.ts +4 -3
  53. package/dist/plugin/process-env.js +6 -4
  54. package/dist/{plugin-DkOIT5uI.d.cts → plugin-B4xwySxw.d.cts} +15 -2
  55. package/dist/{plugin-DkOIT5uI.d.ts → plugin-B4xwySxw.d.ts} +15 -2
  56. package/dist/runtime/index.cjs +1057 -136
  57. package/dist/runtime/index.d.cts +1 -1
  58. package/dist/runtime/index.d.ts +1 -1
  59. package/dist/runtime/index.js +11 -186
  60. package/dist/{toPublicEnv-C9clvXLo.d.ts → toPublicEnv-CvhGAfsB.d.ts} +1 -1
  61. package/dist/{toPublicEnv-DvFeV3qG.d.cts → toPublicEnv-ggmphZFs.d.cts} +1 -1
  62. package/package.json +11 -1
  63. package/dist/chunk-JUHPBAEH.js +0 -20
  64. package/dist/chunk-PQ4KSV76.js +0 -50
  65. package/dist/chunk-WHUGFPE4.js +0 -49
@@ -17,6 +17,11 @@ var CnosSecurityError = class extends CnosError {
17
17
  super(message);
18
18
  }
19
19
  };
20
+ var CnosAuthenticationError = class extends CnosError {
21
+ constructor(message) {
22
+ super(message);
23
+ }
24
+ };
20
25
  var CnosKeyNotFoundError = class extends CnosError {
21
26
  constructor(key) {
22
27
  super(`Missing required CNOS config key: ${key}`);
@@ -58,6 +63,112 @@ function inspectValue(graph, key) {
58
63
  };
59
64
  }
60
65
 
66
+ // ../core/src/keychain/linux.ts
67
+ import { execFile, spawn } from "child_process";
68
+ import { promisify } from "util";
69
+ var execFileAsync = promisify(execFile);
70
+ async function readLinuxKeychain(entry) {
71
+ try {
72
+ const { stdout } = await execFileAsync("secret-tool", ["lookup", "service", "cnos", "account", entry]);
73
+ const value = stdout.trim();
74
+ return value.length > 0 ? value : void 0;
75
+ } catch {
76
+ return void 0;
77
+ }
78
+ }
79
+ async function writeLinuxKeychain(entry, value) {
80
+ await new Promise((resolve, reject) => {
81
+ const child = spawn("secret-tool", ["store", "--label", `CNOS ${entry}`, "service", "cnos", "account", entry], {
82
+ stdio: ["pipe", "ignore", "pipe"]
83
+ });
84
+ let stderr = "";
85
+ child.stdin?.end(value);
86
+ child.stderr?.on("data", (chunk) => {
87
+ stderr += chunk.toString();
88
+ });
89
+ child.on("error", reject);
90
+ child.on("close", (code) => {
91
+ if (code === 0) {
92
+ resolve();
93
+ return;
94
+ }
95
+ reject(new Error(stderr || `secret-tool exited with code ${code ?? 1}`));
96
+ });
97
+ });
98
+ }
99
+
100
+ // ../core/src/keychain/macos.ts
101
+ import { execFile as execFile2 } from "child_process";
102
+ import { promisify as promisify2 } from "util";
103
+ var execFileAsync2 = promisify2(execFile2);
104
+ async function readMacosKeychain(entry) {
105
+ try {
106
+ const { stdout } = await execFileAsync2("security", ["find-generic-password", "-a", "cnos", "-s", entry, "-w"]);
107
+ const value = stdout.trim();
108
+ return value.length > 0 ? value : void 0;
109
+ } catch {
110
+ return void 0;
111
+ }
112
+ }
113
+ async function writeMacosKeychain(entry, value) {
114
+ await execFileAsync2("security", ["add-generic-password", "-a", "cnos", "-s", entry, "-w", value, "-U"]);
115
+ }
116
+
117
+ // ../core/src/keychain/windows.ts
118
+ import { execFile as execFile3 } from "child_process";
119
+ import { promisify as promisify3 } from "util";
120
+ var execFileAsync3 = promisify3(execFile3);
121
+ function wrap(script) {
122
+ return ["-NoProfile", "-Command", script];
123
+ }
124
+ async function readWindowsKeychain(entry) {
125
+ try {
126
+ const { stdout } = await execFileAsync3(
127
+ "powershell",
128
+ wrap(`Add-Type -AssemblyName System.Runtime.WindowsRuntime; [Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] > $null; $vault = New-Object Windows.Security.Credentials.PasswordVault; $credential = $vault.Retrieve('cnos','${entry}'); $credential.RetrievePassword(); Write-Output $credential.Password`)
129
+ );
130
+ const value = stdout.trim();
131
+ return value.length > 0 ? value : void 0;
132
+ } catch {
133
+ return void 0;
134
+ }
135
+ }
136
+ async function writeWindowsKeychain(entry, value) {
137
+ await execFileAsync3(
138
+ "powershell",
139
+ wrap(`Add-Type -AssemblyName System.Runtime.WindowsRuntime; [Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] > $null; $vault = New-Object Windows.Security.Credentials.PasswordVault; try { $existing = $vault.Retrieve('cnos','${entry}'); $vault.Remove($existing) } catch {}; $credential = New-Object Windows.Security.Credentials.PasswordCredential('cnos','${entry}','${value}'); $vault.Add($credential)`)
140
+ );
141
+ }
142
+
143
+ // ../core/src/keychain/index.ts
144
+ async function readKeychain(entry) {
145
+ if (process.platform === "win32") {
146
+ return readWindowsKeychain(entry);
147
+ }
148
+ if (process.platform === "darwin") {
149
+ return readMacosKeychain(entry);
150
+ }
151
+ if (process.platform === "linux") {
152
+ return readLinuxKeychain(entry);
153
+ }
154
+ return void 0;
155
+ }
156
+ async function writeKeychain(entry, value) {
157
+ if (process.platform === "win32") {
158
+ await writeWindowsKeychain(entry, value);
159
+ return;
160
+ }
161
+ if (process.platform === "darwin") {
162
+ await writeMacosKeychain(entry, value);
163
+ return;
164
+ }
165
+ if (process.platform === "linux") {
166
+ await writeLinuxKeychain(entry, value);
167
+ return;
168
+ }
169
+ throw new CnosAuthenticationError(`OS keychain is not supported on platform "${process.platform}".`);
170
+ }
171
+
61
172
  // ../core/src/utils/path.ts
62
173
  import { access } from "fs/promises";
63
174
  import os from "os";
@@ -123,7 +234,7 @@ function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
123
234
  return path.resolve(workspaceRoot, interpolated);
124
235
  }
125
236
  function resolveNamespaceDirectory(workspaceRoot, namespace, profile) {
126
- const rootFolder = namespace === "value" ? "values" : "secrets";
237
+ const rootFolder = namespace === "value" ? "values" : namespace === "secret" ? "secrets" : namespace;
127
238
  if (profile && profile !== "base") {
128
239
  return path.resolve(workspaceRoot, "profiles", profile, rootFolder);
129
240
  }
@@ -192,6 +303,11 @@ var DEFAULT_NAMESPACES = {
192
303
  shareable: false,
193
304
  readonly: true
194
305
  },
306
+ process: {
307
+ kind: "system",
308
+ shareable: false,
309
+ readonly: true
310
+ },
195
311
  public: {
196
312
  kind: "projection",
197
313
  source: "promote",
@@ -246,22 +362,82 @@ function normalizeNamespaces(namespaces) {
246
362
  function normalizeVaults(vaults) {
247
363
  return Object.fromEntries(
248
364
  Object.entries(vaults ?? {}).map(([name, definition]) => {
365
+ const legacyPassphrase = definition.passphrase;
366
+ if (legacyPassphrase !== void 0) {
367
+ throw new CnosManifestError(
368
+ `Vault "${name}" uses legacy passphrase configuration. Use vaults.${name}.auth instead.`
369
+ );
370
+ }
249
371
  const provider = definition.provider?.trim();
250
372
  if (!provider) {
251
373
  throw new CnosManifestError(`Vault "${name}" requires a provider`);
252
374
  }
375
+ const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
376
+ const normalizedMapping = Object.fromEntries(
377
+ Object.entries(definition.mapping ?? {}).filter(
378
+ (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
379
+ ).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
380
+ );
253
381
  return [
254
382
  name,
255
383
  {
256
384
  provider,
257
- ...definition.passphrase?.trim() ? {
258
- passphrase: definition.passphrase.trim()
385
+ auth: normalizedAuth,
386
+ ...Object.keys(normalizedMapping).length > 0 ? {
387
+ mapping: normalizedMapping
259
388
  } : {}
260
389
  }
261
390
  ];
262
391
  })
263
392
  );
264
393
  }
394
+ function normalizeAuthSources(value) {
395
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
396
+ return void 0;
397
+ }
398
+ const sources = Array.isArray(value.from) ? value.from : void 0;
399
+ const normalized = (sources ?? []).map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean);
400
+ return normalized.length > 0 ? normalized : void 0;
401
+ }
402
+ function normalizeVaultAuth(vaultName, provider, auth) {
403
+ if (provider === "local") {
404
+ const passphraseSources = normalizeAuthSources(auth?.passphrase);
405
+ const defaultToken = vaultName.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
406
+ const defaultSources = [
407
+ ...defaultToken ? [`env:CNOS_SECRET_PASSPHRASE_${defaultToken}`] : [],
408
+ "env:CNOS_SECRET_PASSPHRASE",
409
+ `keychain:cnos/${vaultName}`,
410
+ "prompt"
411
+ ];
412
+ return {
413
+ method: auth?.method ?? "passphrase",
414
+ passphrase: {
415
+ from: passphraseSources ?? defaultSources
416
+ },
417
+ ...auth?.config ? { config: auth.config } : {}
418
+ };
419
+ }
420
+ if (provider === "github-secrets") {
421
+ return {
422
+ method: auth?.method ?? "environment",
423
+ ...auth?.config ? { config: auth.config } : {}
424
+ };
425
+ }
426
+ return {
427
+ ...auth?.method ? { method: auth.method } : {},
428
+ ...normalizeAuthSources(auth?.passphrase) ? {
429
+ passphrase: {
430
+ from: normalizeAuthSources(auth?.passphrase) ?? []
431
+ }
432
+ } : {},
433
+ ...normalizeAuthSources(auth?.token) ? {
434
+ token: {
435
+ from: normalizeAuthSources(auth?.token) ?? []
436
+ }
437
+ } : {},
438
+ ...auth?.config ? { config: auth.config } : {}
439
+ };
440
+ }
265
441
  function normalizeManifest(manifest) {
266
442
  const version = manifest.version ?? 1;
267
443
  if (version !== 1) {
@@ -432,60 +608,65 @@ function validateProjectionIssue(manifest, key, target) {
432
608
  }
433
609
  }
434
610
 
435
- // ../core/src/runtime/projection.ts
436
- function setNestedValue(target, pathSegments, value) {
437
- const [head, ...tail] = pathSegments;
438
- if (!head) {
439
- return;
440
- }
441
- if (tail.length === 0) {
442
- target[head] = value;
443
- return;
444
- }
445
- const current = target[head];
446
- const nextTarget = current && typeof current === "object" && !Array.isArray(current) ? current : {};
447
- target[head] = nextTarget;
448
- setNestedValue(nextTarget, tail, value);
611
+ // ../core/src/secrets/sessionStore.ts
612
+ import { mkdir, readFile as readFile2, readdir, rm, writeFile } from "fs/promises";
613
+ import path3 from "path";
614
+ function buildSessionRoot(processEnv = process.env) {
615
+ return path3.join(path3.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
449
616
  }
450
- function toNamespaceObject(graph, namespace) {
451
- const output = {};
452
- const resolvedEntries = Array.from(graph.entries.values()).sort(
453
- (left, right) => left.key.localeCompare(right.key)
454
- );
455
- for (const entry of resolvedEntries) {
456
- if (namespace && entry.namespace !== namespace) {
457
- continue;
617
+ function buildSessionPath(vault, processEnv) {
618
+ return path3.join(buildSessionRoot(processEnv), `${vault}.json`);
619
+ }
620
+ async function writeVaultSessionKey(vault, derivedKey, processEnv) {
621
+ const filePath = buildSessionPath(vault, processEnv);
622
+ await mkdir(path3.dirname(filePath), { recursive: true });
623
+ const document = {
624
+ version: 1,
625
+ vault,
626
+ derivedKey: derivedKey.toString("hex"),
627
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
628
+ };
629
+ await writeFile(filePath, JSON.stringify(document, null, 2), "utf8");
630
+ return filePath;
631
+ }
632
+ async function readVaultSessionKey(vault, processEnv) {
633
+ try {
634
+ const source = await readFile2(buildSessionPath(vault, processEnv), "utf8");
635
+ const document = JSON.parse(source);
636
+ if (document.version !== 1 || typeof document.derivedKey !== "string") {
637
+ return void 0;
458
638
  }
459
- const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
460
- setNestedValue(output, valuePath.split("."), entry.value);
639
+ const key = Buffer.from(document.derivedKey, "hex");
640
+ return key.length > 0 ? key : void 0;
641
+ } catch {
642
+ return void 0;
461
643
  }
462
- return output;
463
644
  }
464
-
465
- // ../core/src/runtime/read.ts
466
- function readValue(graph, key) {
467
- return graph.entries.get(key)?.value;
645
+ async function clearVaultSessionKey(vault, processEnv) {
646
+ await rm(buildSessionPath(vault, processEnv), { force: true });
468
647
  }
469
-
470
- // ../core/src/runtime/readOr.ts
471
- function readOrValue(graph, key, fallback) {
472
- const value = readValue(graph, key);
473
- return value === void 0 ? fallback : value;
474
- }
475
-
476
- // ../core/src/runtime/require.ts
477
- function requireValue(graph, key) {
478
- const value = readValue(graph, key);
479
- if (value === void 0) {
480
- throw new CnosKeyNotFoundError(key);
648
+ async function clearAllVaultSessionKeys(processEnv) {
649
+ const root = buildSessionRoot(processEnv);
650
+ try {
651
+ const entries = await readdir(root);
652
+ await Promise.all(entries.map((entry) => rm(path3.join(root, entry), { force: true })));
653
+ } catch {
481
654
  }
482
- return value;
483
655
  }
484
656
 
485
657
  // ../core/src/utils/secretStore.ts
486
- import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
487
- import { mkdir, readdir, readFile as readFile2, writeFile } from "fs/promises";
488
- import path3 from "path";
658
+ import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from "crypto";
659
+ import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
660
+ import path4 from "path";
661
+ var KEY_LENGTH = 32;
662
+ var SALT_LENGTH = 32;
663
+ var IV_LENGTH = 12;
664
+ var AUTH_TAG_LENGTH = 16;
665
+ var PBKDF2_ITERATIONS = 6e5;
666
+ var KEYSTORE_VERSION = 1;
667
+ var METADATA_VERSION = 1;
668
+ var META_FILENAME = "meta.yml";
669
+ var KEYSTORE_FILENAME = "keystore.enc";
489
670
  function isObject(value) {
490
671
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
491
672
  }
@@ -493,135 +674,657 @@ function isSecretReference(value) {
493
674
  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));
494
675
  }
495
676
  function resolveSecretStoreRoot(processEnv = process.env) {
496
- return path3.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
677
+ return path4.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
497
678
  }
498
- function resolveSecretVaultFile(storeRoot, vault = "default") {
499
- return path3.join(storeRoot, "vaults", `${vault}.json`);
500
- }
501
- function resolveSecretStoreFile(storeRoot, ref, vault = "default") {
502
- return path3.join(storeRoot, "vaults", vault, "store", ...ref.split("/")).concat(".json");
503
- }
504
- function deriveKey(passphrase, salt) {
505
- return scryptSync(passphrase, salt, 32);
506
- }
507
- function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
508
- const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
509
- return processEnv[`CNOS_SECRET_PASSPHRASE_${vaultToken}`] ?? processEnv.CNOS_SECRET_PASSPHRASE;
679
+ function normalizeVaultToken(vault = "default") {
680
+ return vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
510
681
  }
511
682
  function getVaultPassphraseEnvVar(vault = "default") {
512
- const vaultToken = vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
683
+ const vaultToken = normalizeVaultToken(vault);
513
684
  return vaultToken && vaultToken !== "DEFAULT" ? `CNOS_SECRET_PASSPHRASE_${vaultToken}` : "CNOS_SECRET_PASSPHRASE";
514
685
  }
515
686
  function isPassphraseEnvRef(value) {
516
687
  return typeof value === "string" && value.startsWith("env:") && value.length > 4;
517
688
  }
518
- function resolveConfiguredVaultPassphrase(definition, vault = "default", processEnv = process.env) {
519
- if (definition?.provider !== "local") {
689
+ function getVaultSessionKeyEnvVar(vault = "default") {
690
+ const vaultToken = normalizeVaultToken(vault);
691
+ return `__CNOS_VAULT_KEY_${vaultToken || "DEFAULT"}__`;
692
+ }
693
+ function resolveSecretPassphrase(vault = "default", processEnv = process.env) {
694
+ return processEnv[getVaultPassphraseEnvVar(vault)] ?? processEnv.CNOS_SECRET_PASSPHRASE;
695
+ }
696
+ function resolveVaultSessionKey(vault = "default", processEnv = process.env) {
697
+ const encoded = processEnv[getVaultSessionKeyEnvVar(vault)];
698
+ if (!encoded) {
699
+ return readVaultSessionKey(vault, processEnv);
700
+ }
701
+ try {
702
+ const key = Buffer.from(encoded, "hex");
703
+ return key.length === KEY_LENGTH ? key : void 0;
704
+ } catch {
520
705
  return void 0;
521
706
  }
522
- const passphraseRef = definition.passphrase;
523
- if (typeof passphraseRef === "string" && passphraseRef.startsWith("env:") && passphraseRef.length > 4) {
524
- return processEnv[passphraseRef.slice(4)];
707
+ }
708
+ function deriveVaultKey(passphrase, salt, iterations = PBKDF2_ITERATIONS) {
709
+ return pbkdf2Sync(passphrase, salt, iterations, KEY_LENGTH, "sha512");
710
+ }
711
+ function buildMetaPath(storeRoot, vault = "default") {
712
+ return path4.join(storeRoot, "vaults", vault, META_FILENAME);
713
+ }
714
+ function resolveSecretVaultFile(storeRoot, vault = "default") {
715
+ return buildMetaPath(storeRoot, vault);
716
+ }
717
+ function buildKeystorePath(storeRoot, vault = "default") {
718
+ return path4.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
719
+ }
720
+ function buildLegacyVaultFile(storeRoot, vault = "default") {
721
+ return path4.join(storeRoot, "vaults", `${vault}.json`);
722
+ }
723
+ function buildLegacyVaultStoreRoot(storeRoot, vault = "default") {
724
+ return path4.join(storeRoot, "vaults", vault, "store");
725
+ }
726
+ function assertVaultMetadata(value, filePath) {
727
+ if (!isObject(value)) {
728
+ throw new CnosManifestError("Invalid CNOS vault metadata", filePath);
729
+ }
730
+ if (value.version !== METADATA_VERSION || value.algorithm !== "aes-256-gcm" || value.kdf !== "pbkdf2-sha512" || typeof value.iterations !== "number" || typeof value.salt !== "string" || typeof value.createdAt !== "string" || typeof value.secretCount !== "number") {
731
+ throw new CnosManifestError("Invalid CNOS vault metadata", filePath);
525
732
  }
526
- if (passphraseRef) {
527
- return passphraseRef;
733
+ return value;
734
+ }
735
+ async function exists2(targetPath) {
736
+ try {
737
+ await stat(targetPath);
738
+ return true;
739
+ } catch {
740
+ return false;
528
741
  }
529
- return resolveSecretPassphrase(vault, processEnv);
530
742
  }
531
- function resolveVaultDefinition(vaults, vault = "default") {
532
- const definition = vaults?.[vault];
533
- const provider = definition?.provider ?? "local";
534
- return {
535
- name: vault,
536
- provider,
537
- ...definition?.passphrase ? {
538
- passphrase: definition.passphrase
539
- } : {},
540
- requiresPassphrase: provider === "local"
541
- };
743
+ async function detectLegacyVaultFormat(storeRoot, vault = "default") {
744
+ const legacyFile = buildLegacyVaultFile(storeRoot, vault);
745
+ const legacyStore = buildLegacyVaultStoreRoot(storeRoot, vault);
746
+ if (await exists2(legacyFile)) {
747
+ return legacyFile;
748
+ }
749
+ if (await exists2(legacyStore)) {
750
+ return legacyStore;
751
+ }
752
+ return void 0;
542
753
  }
543
- function encryptDocument(value, passphrase) {
544
- const salt = randomBytes(16);
545
- const iv = randomBytes(12);
546
- const key = deriveKey(passphrase, salt);
754
+ async function assertNoLegacyVaultFormat(storeRoot, vault = "default") {
755
+ const legacyPath = await detectLegacyVaultFormat(storeRoot, vault);
756
+ if (!legacyPath) {
757
+ return;
758
+ }
759
+ throw new CnosSecurityError(
760
+ `Legacy CNOS local vault format detected for vault "${vault}" at ${legacyPath}. CNOS 1.4 requires the new keystore format. Remove and recreate the vault.`
761
+ );
762
+ }
763
+ function encryptPayload(payload, key) {
764
+ const iv = randomBytes(IV_LENGTH);
547
765
  const cipher = createCipheriv("aes-256-gcm", key, iv);
548
- const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
766
+ const plaintext = Buffer.from(JSON.stringify(payload), "utf8");
767
+ const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
549
768
  const tag = cipher.getAuthTag();
550
- return {
551
- version: 1,
552
- algorithm: "aes-256-gcm",
553
- salt: salt.toString("base64"),
554
- iv: iv.toString("base64"),
555
- tag: tag.toString("base64"),
556
- ciphertext: ciphertext.toString("base64")
557
- };
769
+ return Buffer.concat([
770
+ Buffer.from(Uint32Array.of(KEYSTORE_VERSION).buffer),
771
+ iv,
772
+ tag,
773
+ ciphertext
774
+ ]);
558
775
  }
559
- function decryptDocument(document, passphrase) {
560
- const salt = Buffer.from(document.salt, "base64");
561
- const iv = Buffer.from(document.iv, "base64");
562
- const tag = Buffer.from(document.tag, "base64");
563
- const ciphertext = Buffer.from(document.ciphertext, "base64");
564
- const key = deriveKey(passphrase, salt);
776
+ function decryptPayload(buffer, key) {
777
+ if (buffer.length < 4 + IV_LENGTH + AUTH_TAG_LENGTH) {
778
+ throw new CnosSecurityError("Invalid CNOS local vault keystore");
779
+ }
780
+ const version = buffer.readUInt32LE(0);
781
+ if (version !== KEYSTORE_VERSION) {
782
+ throw new CnosSecurityError(`Unsupported CNOS local vault keystore version: ${version}`);
783
+ }
784
+ const ivOffset = 4;
785
+ const tagOffset = ivOffset + IV_LENGTH;
786
+ const cipherOffset = tagOffset + AUTH_TAG_LENGTH;
787
+ const iv = buffer.subarray(ivOffset, tagOffset);
788
+ const tag = buffer.subarray(tagOffset, cipherOffset);
789
+ const ciphertext = buffer.subarray(cipherOffset);
565
790
  const decipher = createDecipheriv("aes-256-gcm", key, iv);
566
791
  decipher.setAuthTag(tag);
567
- const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
568
- return plaintext.toString("utf8");
792
+ try {
793
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
794
+ const payload = JSON.parse(plaintext);
795
+ if (!payload || !isObject(payload.secrets) || !isObject(payload.metadata)) {
796
+ throw new Error("invalid");
797
+ }
798
+ return {
799
+ secrets: Object.fromEntries(
800
+ Object.entries(payload.secrets).filter((entry) => typeof entry[1] === "string")
801
+ ),
802
+ metadata: Object.fromEntries(
803
+ Object.entries(payload.metadata).filter(
804
+ (entry) => isObject(entry[1]) && typeof entry[1].createdAt === "string" && typeof entry[1].updatedAt === "string"
805
+ )
806
+ )
807
+ };
808
+ } catch {
809
+ throw new CnosAuthenticationError("Failed to decrypt CNOS local vault. Check vault authentication.");
810
+ }
569
811
  }
570
- async function createSecretVault(storeRoot, vault, passphrase) {
571
- const normalizedVault = vault.trim() || "default";
572
- const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
573
- await mkdir(path3.dirname(filePath), { recursive: true });
574
- const document = {
575
- version: 1,
576
- name: normalizedVault,
577
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
578
- verifier: encryptDocument(`cnos-vault:${normalizedVault}`, passphrase)
812
+ function buildInitialPayload() {
813
+ return {
814
+ secrets: {},
815
+ metadata: {}
579
816
  };
580
- await writeFile(filePath, JSON.stringify(document, null, 2), "utf8");
581
- return filePath;
582
817
  }
583
- async function ensureSecretVault(storeRoot, vault, passphrase) {
584
- const normalizedVault = vault.trim() || "default";
585
- const filePath = resolveSecretVaultFile(storeRoot, normalizedVault);
818
+ async function writeVaultFiles(storeRoot, vault, meta, payload, key) {
819
+ const metaPath = buildMetaPath(storeRoot, vault);
820
+ const keystorePath = buildKeystorePath(storeRoot, vault);
821
+ await mkdir2(path4.dirname(metaPath), { recursive: true });
822
+ await writeFile2(metaPath, stringifyYaml(meta), "utf8");
823
+ await writeFile2(keystorePath, encryptPayload(payload, key));
824
+ }
825
+ async function readVaultMetadata(storeRoot, vault = "default") {
826
+ await assertNoLegacyVaultFormat(storeRoot, vault);
827
+ const metaPath = buildMetaPath(storeRoot, vault);
586
828
  try {
587
- await readFile2(filePath, "utf8");
588
- return filePath;
829
+ const source = await readFile3(metaPath, "utf8");
830
+ return assertVaultMetadata(parseYaml(source), metaPath);
589
831
  } catch (error) {
590
- if (error.code !== "ENOENT") {
591
- throw error;
832
+ if (error.code === "ENOENT") {
833
+ return void 0;
592
834
  }
835
+ throw error;
593
836
  }
594
- return createSecretVault(storeRoot, normalizedVault, passphrase);
595
837
  }
596
838
  async function listSecretVaults(storeRoot) {
597
- const vaultRoot = path3.join(storeRoot, "vaults");
839
+ const vaultRoot = path4.join(storeRoot, "vaults");
598
840
  try {
599
- const entries = await readdir(vaultRoot, { withFileTypes: true });
600
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.replace(/\.json$/, "")).sort((left, right) => left.localeCompare(right));
841
+ const entries = await readdir2(vaultRoot, { withFileTypes: true });
842
+ const vaults = await Promise.all(
843
+ entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists2(path4.join(vaultRoot, entry.name, META_FILENAME)) ? entry.name : void 0)
844
+ );
845
+ return vaults.filter((value) => Boolean(value)).sort((left, right) => left.localeCompare(right));
601
846
  } catch {
602
847
  return [];
603
848
  }
604
849
  }
605
- async function writeLocalSecret(storeRoot, ref, value, passphrase, vault = "default") {
606
- await ensureSecretVault(storeRoot, vault, passphrase);
607
- const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
608
- await mkdir(path3.dirname(filePath), { recursive: true });
609
- await writeFile(filePath, JSON.stringify(encryptDocument(value, passphrase), null, 2), "utf8");
610
- return filePath;
850
+ async function createSecretVault(storeRoot, vault, passphrase) {
851
+ const normalizedVault = vault.trim() || "default";
852
+ await assertNoLegacyVaultFormat(storeRoot, normalizedVault);
853
+ const salt = randomBytes(SALT_LENGTH);
854
+ const key = deriveVaultKey(passphrase, salt, PBKDF2_ITERATIONS);
855
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
856
+ const meta = {
857
+ version: METADATA_VERSION,
858
+ algorithm: "aes-256-gcm",
859
+ kdf: "pbkdf2-sha512",
860
+ iterations: PBKDF2_ITERATIONS,
861
+ salt: salt.toString("base64"),
862
+ createdAt,
863
+ secretCount: 0
864
+ };
865
+ await writeVaultFiles(storeRoot, normalizedVault, meta, buildInitialPayload(), key);
866
+ return buildMetaPath(storeRoot, normalizedVault);
611
867
  }
612
- async function readLocalSecret(storeRoot, ref, passphrase, vault = "default") {
613
- if (!passphrase) {
614
- throw new CnosManifestError(
615
- `Missing CNOS secret passphrase for local secret ref "${ref}". Set CNOS_SECRET_PASSPHRASE or pass processEnv explicitly.`
868
+ async function ensureSecretVault(storeRoot, vault, passphrase) {
869
+ const normalizedVault = vault.trim() || "default";
870
+ const meta = await readVaultMetadata(storeRoot, normalizedVault);
871
+ if (meta) {
872
+ return buildMetaPath(storeRoot, normalizedVault);
873
+ }
874
+ return createSecretVault(storeRoot, normalizedVault, passphrase);
875
+ }
876
+ function resolveConfiguredVaultPassphrase(definition, vault = "default", processEnv = process.env) {
877
+ if (definition?.provider !== "local") {
878
+ return void 0;
879
+ }
880
+ const configuredSources = definition.auth?.passphrase?.from ?? [];
881
+ for (const source of configuredSources) {
882
+ if (source.startsWith("env:")) {
883
+ const value = processEnv[source.slice(4)];
884
+ if (value) {
885
+ return value;
886
+ }
887
+ }
888
+ }
889
+ return resolveSecretPassphrase(vault, processEnv);
890
+ }
891
+ async function resolveVaultAccessKey(storeRoot, definition, vault = "default", processEnv = process.env) {
892
+ if (definition?.provider !== "local") {
893
+ return definition?.provider === "github-secrets" ? {
894
+ method: definition.auth?.method ?? "environment",
895
+ ...definition?.auth?.config ? { config: definition.auth.config } : {}
896
+ } : void 0;
897
+ }
898
+ const sessionKey = await resolveVaultSessionKey(vault, processEnv);
899
+ if (sessionKey) {
900
+ return {
901
+ derivedKey: sessionKey,
902
+ method: "keychain",
903
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
904
+ };
905
+ }
906
+ const passphrase = resolveConfiguredVaultPassphrase(definition, vault, processEnv);
907
+ if (passphrase) {
908
+ return {
909
+ passphrase,
910
+ method: "passphrase",
911
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
912
+ };
913
+ }
914
+ const metadata = await readVaultMetadata(storeRoot, vault);
915
+ if (!metadata) {
916
+ return void 0;
917
+ }
918
+ throw new CnosAuthenticationError(
919
+ `Cannot authenticate to vault "${vault}". Set ${getVaultPassphraseEnvVar(vault)} or run cnos vault auth ${vault}.`
920
+ );
921
+ }
922
+ async function loadVaultPayload(storeRoot, vault, auth) {
923
+ const meta = await readVaultMetadata(storeRoot, vault);
924
+ if (!meta) {
925
+ throw new CnosManifestError(`Missing CNOS vault metadata for "${vault}"`);
926
+ }
927
+ const salt = Buffer.from(meta.salt, "base64");
928
+ const key = auth.derivedKey ?? (auth.passphrase ? deriveVaultKey(auth.passphrase, salt, meta.iterations) : void 0);
929
+ if (!key) {
930
+ throw new CnosAuthenticationError(`Vault "${vault}" requires authentication before access.`);
931
+ }
932
+ const buffer = await readFile3(buildKeystorePath(storeRoot, vault));
933
+ return {
934
+ meta,
935
+ payload: decryptPayload(buffer, key),
936
+ key
937
+ };
938
+ }
939
+ async function writeLocalSecret(storeRoot, ref, value, authOrPassphrase, vault = "default") {
940
+ const auth = typeof authOrPassphrase === "string" ? {
941
+ passphrase: authOrPassphrase,
942
+ method: "passphrase"
943
+ } : authOrPassphrase;
944
+ if (auth.passphrase) {
945
+ await ensureSecretVault(storeRoot, vault, auth.passphrase);
946
+ } else {
947
+ const meta2 = await readVaultMetadata(storeRoot, vault);
948
+ if (!meta2) {
949
+ throw new CnosAuthenticationError(`Vault "${vault}" requires passphrase-based authentication for initial creation.`);
950
+ }
951
+ }
952
+ const { meta, payload, key } = await loadVaultPayload(storeRoot, vault, auth);
953
+ const now = (/* @__PURE__ */ new Date()).toISOString();
954
+ const existing = payload.metadata[ref];
955
+ payload.secrets[ref] = value;
956
+ payload.metadata[ref] = {
957
+ createdAt: existing?.createdAt ?? now,
958
+ updatedAt: now
959
+ };
960
+ const nextMeta = {
961
+ ...meta,
962
+ secretCount: Object.keys(payload.secrets).length
963
+ };
964
+ await writeVaultFiles(storeRoot, vault, nextMeta, payload, key);
965
+ return buildKeystorePath(storeRoot, vault);
966
+ }
967
+ async function deleteLocalSecret(storeRoot, ref, auth, vault = "default") {
968
+ const { meta, payload, key } = await loadVaultPayload(storeRoot, vault, auth);
969
+ if (!(ref in payload.secrets)) {
970
+ return false;
971
+ }
972
+ delete payload.secrets[ref];
973
+ delete payload.metadata[ref];
974
+ const nextMeta = {
975
+ ...meta,
976
+ secretCount: Object.keys(payload.secrets).length
977
+ };
978
+ await writeVaultFiles(storeRoot, vault, nextMeta, payload, key);
979
+ return true;
980
+ }
981
+ async function readLocalSecret(storeRoot, ref, auth, vault = "default") {
982
+ const { payload } = await loadVaultPayload(storeRoot, vault, auth);
983
+ const value = payload.secrets[ref];
984
+ if (value === void 0) {
985
+ throw new CnosManifestError(`Missing local secret ref "${ref}" in vault "${vault}"`);
986
+ }
987
+ return value;
988
+ }
989
+ async function listLocalSecrets(storeRoot, auth, vault = "default") {
990
+ const { payload } = await loadVaultPayload(storeRoot, vault, auth);
991
+ return Object.keys(payload.secrets).sort((left, right) => left.localeCompare(right));
992
+ }
993
+ function resolveVaultDefinition(vaults, vault = "default") {
994
+ const definition = vaults?.[vault];
995
+ const provider = definition?.provider ?? "local";
996
+ return {
997
+ name: vault,
998
+ provider,
999
+ ...definition?.auth ? { auth: definition.auth } : {},
1000
+ ...definition?.mapping ? { mapping: definition.mapping } : {},
1001
+ requiresAuthentication: provider === "local"
1002
+ };
1003
+ }
1004
+ async function removeLocalVaultFiles(storeRoot, vault = "default") {
1005
+ await rm2(path4.join(storeRoot, "vaults", vault), { recursive: true, force: true });
1006
+ }
1007
+
1008
+ // ../core/src/secrets/providers/github.ts
1009
+ var GithubSecretsVaultProvider = class {
1010
+ constructor(vaultId, definition, processEnv = process.env) {
1011
+ this.vaultId = vaultId;
1012
+ this.definition = definition;
1013
+ this.processEnv = processEnv;
1014
+ }
1015
+ vaultId;
1016
+ definition;
1017
+ processEnv;
1018
+ authenticated = false;
1019
+ async authenticate(_authConfig) {
1020
+ void _authConfig;
1021
+ this.authenticated = true;
1022
+ }
1023
+ isAuthenticated() {
1024
+ return this.authenticated;
1025
+ }
1026
+ resolveEnvVar(ref) {
1027
+ if (this.processEnv[ref] !== void 0) {
1028
+ return ref;
1029
+ }
1030
+ return Object.entries(this.definition.mapping ?? {}).find(([, logicalRef]) => logicalRef === ref)?.[0];
1031
+ }
1032
+ async batchGet(refs) {
1033
+ this.authenticated = true;
1034
+ const resolved = /* @__PURE__ */ new Map();
1035
+ for (const ref of Array.from(new Set(refs)).sort((left, right) => left.localeCompare(right))) {
1036
+ const envVar = this.resolveEnvVar(ref);
1037
+ const value = envVar ? this.processEnv[envVar] : void 0;
1038
+ if (value !== void 0) {
1039
+ resolved.set(ref, value);
1040
+ }
1041
+ }
1042
+ return resolved;
1043
+ }
1044
+ async get(ref) {
1045
+ const envVar = this.resolveEnvVar(ref);
1046
+ this.authenticated = true;
1047
+ return envVar ? this.processEnv[envVar] : void 0;
1048
+ }
1049
+ async set(ref, value) {
1050
+ void ref;
1051
+ void value;
1052
+ throw new Error(`Vault "${this.vaultId}" is environment-backed and cannot be written by CNOS.`);
1053
+ }
1054
+ async delete(ref) {
1055
+ void ref;
1056
+ throw new Error(`Vault "${this.vaultId}" is environment-backed and cannot be mutated by CNOS.`);
1057
+ }
1058
+ async list() {
1059
+ return Object.values(this.definition.mapping ?? {}).sort((left, right) => left.localeCompare(right));
1060
+ }
1061
+ };
1062
+
1063
+ // ../core/src/secrets/auditLog.ts
1064
+ import { appendFile, mkdir as mkdir3 } from "fs/promises";
1065
+ import path5 from "path";
1066
+ async function appendAuditEvent(event, processEnv = process.env) {
1067
+ const auditFile = processEnv.CNOS_AUDIT_FILE ?? path5.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
1068
+ await mkdir3(path5.dirname(auditFile), { recursive: true });
1069
+ await appendFile(
1070
+ auditFile,
1071
+ `${JSON.stringify({
1072
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1073
+ ...event
1074
+ })}
1075
+ `,
1076
+ "utf8"
1077
+ );
1078
+ }
1079
+
1080
+ // ../core/src/secrets/providers/local.ts
1081
+ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
1082
+ constructor(vaultId, definition, processEnv = process.env, storeRoot = resolveSecretStoreRoot(processEnv)) {
1083
+ this.vaultId = vaultId;
1084
+ this.processEnv = processEnv;
1085
+ this.storeRoot = storeRoot;
1086
+ this.definition = definition;
1087
+ }
1088
+ vaultId;
1089
+ processEnv;
1090
+ storeRoot;
1091
+ authConfig;
1092
+ definition;
1093
+ static fromVaults(vaults, vaultId, processEnv) {
1094
+ const definition = resolveVaultDefinition(vaults, vaultId);
1095
+ return new _LocalSecretVaultProvider(vaultId, definition, processEnv);
1096
+ }
1097
+ async authenticate(authConfig) {
1098
+ this.authConfig = authConfig;
1099
+ await this.list();
1100
+ }
1101
+ isAuthenticated() {
1102
+ return Boolean(this.authConfig);
1103
+ }
1104
+ async requireAuth() {
1105
+ if (this.authConfig) {
1106
+ return this.authConfig;
1107
+ }
1108
+ const resolved = await resolveVaultAccessKey(this.storeRoot, this.definition, this.vaultId, this.processEnv);
1109
+ if (!resolved) {
1110
+ throw new CnosAuthenticationError(
1111
+ `Cannot authenticate to vault "${this.vaultId}". Set the configured passphrase env var or run cnos vault auth ${this.vaultId}.`
1112
+ );
1113
+ }
1114
+ this.authConfig = resolved;
1115
+ return resolved;
1116
+ }
1117
+ async batchGet(refs) {
1118
+ const auth = await this.requireAuth();
1119
+ const entries = await Promise.all(
1120
+ Array.from(new Set(refs)).sort((left, right) => left.localeCompare(right)).map(async (ref) => [ref, await readLocalSecret(this.storeRoot, ref, auth, this.vaultId)])
1121
+ );
1122
+ return new Map(entries);
1123
+ }
1124
+ async get(ref) {
1125
+ const auth = await this.requireAuth();
1126
+ try {
1127
+ return await readLocalSecret(this.storeRoot, ref, auth, this.vaultId);
1128
+ } catch {
1129
+ return void 0;
1130
+ }
1131
+ }
1132
+ async set(ref, value) {
1133
+ const auth = await this.requireAuth();
1134
+ await writeLocalSecret(this.storeRoot, ref, value, auth, this.vaultId);
1135
+ await appendAuditEvent(
1136
+ {
1137
+ action: "write",
1138
+ vault: this.vaultId,
1139
+ ref,
1140
+ caller: "cli"
1141
+ },
1142
+ this.processEnv
1143
+ );
1144
+ }
1145
+ async delete(ref) {
1146
+ const auth = await this.requireAuth();
1147
+ await deleteLocalSecret(this.storeRoot, ref, auth, this.vaultId);
1148
+ await appendAuditEvent(
1149
+ {
1150
+ action: "delete",
1151
+ vault: this.vaultId,
1152
+ ref,
1153
+ caller: "cli"
1154
+ },
1155
+ this.processEnv
616
1156
  );
617
1157
  }
618
- const filePath = resolveSecretStoreFile(storeRoot, ref, vault);
619
- const source = await readFile2(filePath, "utf8");
620
- const document = JSON.parse(source);
621
- 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") {
622
- throw new CnosManifestError("Invalid local secret document", filePath);
1158
+ async list() {
1159
+ const auth = this.authConfig ?? await resolveVaultAccessKey(this.storeRoot, this.definition, this.vaultId, this.processEnv);
1160
+ if (!auth) {
1161
+ throw new CnosAuthenticationError(
1162
+ `Cannot authenticate to vault "${this.vaultId}". Set the configured passphrase env var or run cnos vault auth ${this.vaultId}.`
1163
+ );
1164
+ }
1165
+ this.authConfig = auth;
1166
+ return listLocalSecrets(this.storeRoot, auth, this.vaultId);
1167
+ }
1168
+ };
1169
+
1170
+ // ../core/src/secrets/providers/registry.ts
1171
+ function createSecretVaultProvider(vaultId, definition, processEnv) {
1172
+ if (definition.provider === "local") {
1173
+ return new LocalSecretVaultProvider(vaultId, definition, processEnv);
1174
+ }
1175
+ if (definition.provider === "github-secrets") {
1176
+ return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
1177
+ }
1178
+ throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
1179
+ }
1180
+
1181
+ // ../core/src/secrets/prompt.ts
1182
+ import readline from "readline";
1183
+ import { Writable } from "stream";
1184
+ async function promptHidden(message) {
1185
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
1186
+ return void 0;
1187
+ }
1188
+ const mutableStdout = new WritableMask();
1189
+ const rl = readline.createInterface({
1190
+ input: process.stdin,
1191
+ output: mutableStdout,
1192
+ terminal: true
1193
+ });
1194
+ try {
1195
+ mutableStdout.muted = true;
1196
+ const value = await new Promise((resolve) => {
1197
+ rl.question(message, resolve);
1198
+ });
1199
+ process.stdout.write("\n");
1200
+ return value;
1201
+ } finally {
1202
+ rl.close();
1203
+ }
1204
+ }
1205
+ var WritableMask = class extends Writable {
1206
+ muted = false;
1207
+ _write(chunk, _encoding, callback) {
1208
+ if (!this.muted) {
1209
+ process.stdout.write(chunk);
1210
+ }
1211
+ callback();
1212
+ }
1213
+ };
1214
+
1215
+ // ../core/src/secrets/resolveAuth.ts
1216
+ function toAuthError(vaultId, sources) {
1217
+ return new CnosAuthenticationError(
1218
+ `Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
1219
+ );
1220
+ }
1221
+ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
1222
+ const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
1223
+ if (sessionKey) {
1224
+ return {
1225
+ derivedKey: sessionKey,
1226
+ method: "keychain",
1227
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
1228
+ };
1229
+ }
1230
+ if (definition.provider === "github-secrets") {
1231
+ return {
1232
+ method: definition.auth?.method ?? "environment",
1233
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
1234
+ };
1235
+ }
1236
+ const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
1237
+ for (const source of sources) {
1238
+ if (source.startsWith("env:")) {
1239
+ const value = processEnv[source.slice(4)];
1240
+ if (value) {
1241
+ return {
1242
+ passphrase: value,
1243
+ method: "passphrase",
1244
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
1245
+ };
1246
+ }
1247
+ }
1248
+ if (source.startsWith("keychain:")) {
1249
+ const value = await readKeychain(source.slice("keychain:".length));
1250
+ if (value) {
1251
+ return {
1252
+ derivedKey: Buffer.from(value, "hex"),
1253
+ method: "keychain",
1254
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
1255
+ };
1256
+ }
1257
+ }
1258
+ if (source === "prompt") {
1259
+ const value = await promptHidden(`Enter passphrase for vault "${vaultId}": `);
1260
+ if (value) {
1261
+ return {
1262
+ passphrase: value,
1263
+ method: "passphrase",
1264
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
1265
+ };
1266
+ }
1267
+ }
1268
+ }
1269
+ const fallback = resolveSecretPassphrase(vaultId, processEnv);
1270
+ if (fallback) {
1271
+ return {
1272
+ passphrase: fallback,
1273
+ method: "passphrase",
1274
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
1275
+ };
1276
+ }
1277
+ throw toAuthError(vaultId, [getVaultSessionKeyEnvVar(vaultId), ...sources]);
1278
+ }
1279
+
1280
+ // ../core/src/runtime/projection.ts
1281
+ function setNestedValue(target, pathSegments, value) {
1282
+ const [head, ...tail] = pathSegments;
1283
+ if (!head) {
1284
+ return;
1285
+ }
1286
+ if (tail.length === 0) {
1287
+ target[head] = value;
1288
+ return;
1289
+ }
1290
+ const current = target[head];
1291
+ const nextTarget = current && typeof current === "object" && !Array.isArray(current) ? current : {};
1292
+ target[head] = nextTarget;
1293
+ setNestedValue(nextTarget, tail, value);
1294
+ }
1295
+ function toNamespaceObject(graph, namespace) {
1296
+ const output = {};
1297
+ const resolvedEntries = Array.from(graph.entries.values()).sort(
1298
+ (left, right) => left.key.localeCompare(right.key)
1299
+ );
1300
+ for (const entry of resolvedEntries) {
1301
+ if (namespace && entry.namespace !== namespace) {
1302
+ continue;
1303
+ }
1304
+ const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
1305
+ setNestedValue(output, valuePath.split("."), entry.value);
1306
+ }
1307
+ return output;
1308
+ }
1309
+
1310
+ // ../core/src/runtime/read.ts
1311
+ function readValue(graph, key) {
1312
+ return graph.entries.get(key)?.value;
1313
+ }
1314
+
1315
+ // ../core/src/runtime/readOr.ts
1316
+ function readOrValue(graph, key, fallback) {
1317
+ const value = readValue(graph, key);
1318
+ return value === void 0 ? fallback : value;
1319
+ }
1320
+
1321
+ // ../core/src/runtime/require.ts
1322
+ function requireValue(graph, key) {
1323
+ const value = readValue(graph, key);
1324
+ if (value === void 0) {
1325
+ throw new CnosKeyNotFoundError(key);
623
1326
  }
624
- return decryptDocument(document, passphrase);
1327
+ return value;
625
1328
  }
626
1329
 
627
1330
  // ../core/src/runtime/toEnv.ts
@@ -705,23 +1408,23 @@ function toPublicEnv(graph, manifest, options = {}) {
705
1408
  }
706
1409
 
707
1410
  // ../core/src/runtime/dump.ts
708
- import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
709
- import path4 from "path";
1411
+ import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
1412
+ import path6 from "path";
710
1413
  function buildDumpFiles(graph, options = {}) {
711
- const basePath = options.flatten ? "" : path4.posix.join("workspaces", graph.workspace.workspaceId);
1414
+ const basePath = options.flatten ? "" : path6.posix.join("workspaces", graph.workspace.workspaceId);
712
1415
  const values = toNamespaceObject(graph, "value");
713
1416
  const secrets = toNamespaceObject(graph, "secret");
714
1417
  const files = [];
715
1418
  if (Object.keys(values).length > 0) {
716
1419
  files.push({
717
- path: path4.posix.join(basePath, "values", graph.profile, "app.yml"),
1420
+ path: path6.posix.join(basePath, "values", graph.profile, "app.yml"),
718
1421
  namespace: "value",
719
1422
  content: stringifyYaml(values)
720
1423
  });
721
1424
  }
722
1425
  if (Object.keys(secrets).length > 0) {
723
1426
  files.push({
724
- path: path4.posix.join(basePath, "secrets", graph.profile, "app.yml"),
1427
+ path: path6.posix.join(basePath, "secrets", graph.profile, "app.yml"),
725
1428
  namespace: "secret",
726
1429
  content: stringifyYaml(secrets)
727
1430
  });
@@ -737,12 +1440,12 @@ function planDump(graph, options = {}) {
737
1440
  };
738
1441
  }
739
1442
  async function writeDump(graph, options) {
740
- const root = path4.resolve(options.to);
1443
+ const root = path6.resolve(options.to);
741
1444
  const plan = planDump(graph, options);
742
1445
  for (const file of plan.files) {
743
- const destination = path4.join(root, file.path);
744
- await mkdir2(path4.dirname(destination), { recursive: true });
745
- await writeFile2(destination, file.content, "utf8");
1446
+ const destination = path6.join(root, file.path);
1447
+ await mkdir4(path6.dirname(destination), { recursive: true });
1448
+ await writeFile3(destination, file.content, "utf8");
746
1449
  }
747
1450
  return {
748
1451
  ...plan,
@@ -773,11 +1476,11 @@ function normalizeMappingConfig(config = {}) {
773
1476
  function toScreamingSnakeSegment(segment) {
774
1477
  return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
775
1478
  }
776
- function toScreamingSnake(path8) {
777
- return path8.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
1479
+ function toScreamingSnake(path10) {
1480
+ return path10.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
778
1481
  }
779
- function fromScreamingSnake(path8) {
780
- return path8.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
1482
+ function fromScreamingSnake(path10) {
1483
+ return path10.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
781
1484
  }
782
1485
  function logicalKeyToEnvVar(key, config = {}) {
783
1486
  const normalized = normalizeMappingConfig(config);
@@ -929,12 +1632,12 @@ function createProvenanceInspector() {
929
1632
  }
930
1633
 
931
1634
  // ../core/src/manifest/loadWorkspaceFile.ts
932
- import { readFile as readFile3 } from "fs/promises";
933
- import path5 from "path";
1635
+ import { readFile as readFile4 } from "fs/promises";
1636
+ import path7 from "path";
934
1637
  async function loadWorkspaceFile(repoRoot) {
935
- const workspaceFilePath = path5.join(repoRoot, ".cnos-workspace.yml");
1638
+ const workspaceFilePath = path7.join(repoRoot, ".cnos-workspace.yml");
936
1639
  try {
937
- const source = await readFile3(workspaceFilePath, "utf8");
1640
+ const source = await readFile4(workspaceFilePath, "utf8");
938
1641
  const parsed = parseYaml(source);
939
1642
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
940
1643
  throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
@@ -957,8 +1660,8 @@ async function loadWorkspaceFile(repoRoot) {
957
1660
  }
958
1661
 
959
1662
  // ../core/src/profiles/expandProfileChain.ts
960
- import { access as access2, readFile as readFile4 } from "fs/promises";
961
- import path6 from "path";
1663
+ import { access as access2, readFile as readFile5 } from "fs/promises";
1664
+ import path8 from "path";
962
1665
  async function fileExists(targetPath) {
963
1666
  try {
964
1667
  await access2(targetPath);
@@ -995,11 +1698,11 @@ async function loadProfileDefinition(profileName, options) {
995
1698
  return normalizeProfileDefinition(profileName, void 0);
996
1699
  }
997
1700
  for (const workspaceRoot of [...workspaceRoots].reverse()) {
998
- const profilePath = path6.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
1701
+ const profilePath = path8.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
999
1702
  if (!await fileExists(profilePath)) {
1000
1703
  continue;
1001
1704
  }
1002
- const document = await readFile4(profilePath, "utf8");
1705
+ const document = await readFile5(profilePath, "utf8");
1003
1706
  const parsed = parseYaml(document);
1004
1707
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1005
1708
  throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
@@ -1007,7 +1710,7 @@ async function loadProfileDefinition(profileName, options) {
1007
1710
  const definition = normalizeProfileDefinition(
1008
1711
  profileName,
1009
1712
  parsed,
1010
- options.manifestRoot ? toPortablePath(path6.relative(path6.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
1713
+ options.manifestRoot ? toPortablePath(path8.relative(path8.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
1011
1714
  );
1012
1715
  if (definition.name !== profileName) {
1013
1716
  throw new CnosManifestError(
@@ -1254,7 +1957,7 @@ function createProfileAwareResolver() {
1254
1957
 
1255
1958
  // ../core/src/workspaces/resolveWorkspaceContext.ts
1256
1959
  import { access as access3 } from "fs/promises";
1257
- import path7 from "path";
1960
+ import path9 from "path";
1258
1961
 
1259
1962
  // ../core/src/workspaces/expandWorkspaceChain.ts
1260
1963
  function expandWorkspaceChain(workspaceId, items) {
@@ -1291,7 +1994,7 @@ function expandWorkspaceChain(workspaceId, items) {
1291
1994
  }
1292
1995
 
1293
1996
  // ../core/src/workspaces/resolveWorkspaceContext.ts
1294
- async function exists2(targetPath) {
1997
+ async function exists3(targetPath) {
1295
1998
  try {
1296
1999
  await access3(targetPath);
1297
2000
  return true;
@@ -1299,15 +2002,18 @@ async function exists2(targetPath) {
1299
2002
  return false;
1300
2003
  }
1301
2004
  }
1302
- async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId) {
1303
- const workspaceRoot = path7.join(manifestRoot, "workspaces", workspaceId);
1304
- if (await exists2(workspaceRoot)) {
2005
+ async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
2006
+ const workspaceRoot = path9.join(manifestRoot, "workspaces", workspaceId);
2007
+ if (await exists3(workspaceRoot)) {
1305
2008
  return workspaceRoot;
1306
2009
  }
1307
- const legacyMarkers = ["values", "secrets", "env", "profiles"].map(
1308
- (segment) => path7.join(manifestRoot, segment)
2010
+ const customDataNamespaceRoots = Object.entries(manifest.namespaces).filter(
2011
+ ([namespace, definition]) => namespace !== "value" && namespace !== "secret" && definition.kind === "data" && !definition.sensitive
2012
+ ).map(([namespace]) => namespace);
2013
+ const legacyMarkers = ["values", "secrets", "env", "profiles", ...customDataNamespaceRoots].map(
2014
+ (segment) => path9.join(manifestRoot, segment)
1309
2015
  );
1310
- if ((await Promise.all(legacyMarkers.map((marker) => exists2(marker)))).some(Boolean)) {
2016
+ if ((await Promise.all(legacyMarkers.map((marker) => exists3(marker)))).some(Boolean)) {
1311
2017
  return manifestRoot;
1312
2018
  }
1313
2019
  return workspaceRoot;
@@ -1347,26 +2053,26 @@ function resolveGlobalRoot(manifest, workspaceFile, options) {
1347
2053
  }
1348
2054
  if (options.globalRoot) {
1349
2055
  return {
1350
- value: path7.resolve(expandHomePath(options.globalRoot)),
2056
+ value: path9.resolve(expandHomePath(options.globalRoot)),
1351
2057
  source: "cli"
1352
2058
  };
1353
2059
  }
1354
2060
  if (workspaceFile?.globalRoot) {
1355
2061
  return {
1356
- value: path7.resolve(expandHomePath(workspaceFile.globalRoot)),
2062
+ value: path9.resolve(expandHomePath(workspaceFile.globalRoot)),
1357
2063
  source: "workspace-file"
1358
2064
  };
1359
2065
  }
1360
2066
  if (manifest.workspaces.global.root) {
1361
2067
  return {
1362
- value: path7.resolve(expandHomePath(manifest.workspaces.global.root)),
2068
+ value: path9.resolve(expandHomePath(manifest.workspaces.global.root)),
1363
2069
  source: "manifest"
1364
2070
  };
1365
2071
  }
1366
2072
  const cnosHome = options.processEnv?.CNOS_HOME;
1367
2073
  if (cnosHome) {
1368
2074
  return {
1369
- value: path7.resolve(expandHomePath(cnosHome)),
2075
+ value: path9.resolve(expandHomePath(cnosHome)),
1370
2076
  source: "CNOS_HOME"
1371
2077
  };
1372
2078
  }
@@ -1383,7 +2089,7 @@ async function resolveWorkspaceContext(manifest, options) {
1383
2089
  workspaceRoots.push({
1384
2090
  scope: "global",
1385
2091
  workspaceId: chainWorkspaceId,
1386
- path: path7.join(globalRoot.value, "workspaces", globalWorkspaceId)
2092
+ path: path9.join(globalRoot.value, "workspaces", globalWorkspaceId)
1387
2093
  });
1388
2094
  }
1389
2095
  }
@@ -1391,7 +2097,7 @@ async function resolveWorkspaceContext(manifest, options) {
1391
2097
  workspaceRoots.push({
1392
2098
  scope: "local",
1393
2099
  workspaceId: chainWorkspaceId,
1394
- path: await resolveLocalWorkspaceRoot(options.manifestRoot, chainWorkspaceId)
2100
+ path: await resolveLocalWorkspaceRoot(options.manifestRoot, chainWorkspaceId, manifest)
1395
2101
  });
1396
2102
  }
1397
2103
  return {
@@ -1556,6 +2262,7 @@ async function runPipeline(options) {
1556
2262
  const collectedEntries = await Promise.all(
1557
2263
  options.plugins.map(
1558
2264
  (plugin) => plugin.load({
2265
+ manifest: options.manifest,
1559
2266
  manifestConfig: {
1560
2267
  ...options.manifest.sources[plugin.id] ?? {},
1561
2268
  envMapping: options.manifest.envMapping
@@ -1573,29 +2280,120 @@ async function runPipeline(options) {
1573
2280
  return collectedEntries.flat();
1574
2281
  }
1575
2282
 
2283
+ // ../core/src/secrets/secretCache.ts
2284
+ var SecretCache = class {
2285
+ cache = /* @__PURE__ */ new Map();
2286
+ authenticated = /* @__PURE__ */ new Set();
2287
+ load(vaultId, secrets) {
2288
+ this.authenticated.add(vaultId);
2289
+ for (const [ref, value] of secrets) {
2290
+ this.cache.set(`${vaultId}:${ref}`, value);
2291
+ }
2292
+ }
2293
+ isVaultAuthenticated(vaultId) {
2294
+ return this.authenticated.has(vaultId);
2295
+ }
2296
+ get(vaultId, ref) {
2297
+ return this.cache.get(`${vaultId}:${ref}`);
2298
+ }
2299
+ clear(vaultId) {
2300
+ if (!vaultId) {
2301
+ this.cache.clear();
2302
+ this.authenticated.clear();
2303
+ return;
2304
+ }
2305
+ this.authenticated.delete(vaultId);
2306
+ for (const key of Array.from(this.cache.keys())) {
2307
+ if (key.startsWith(`${vaultId}:`)) {
2308
+ this.cache.delete(key);
2309
+ }
2310
+ }
2311
+ }
2312
+ };
2313
+
2314
+ // ../core/src/secrets/batchResolve.ts
2315
+ function collectSecretDescriptors(graph) {
2316
+ return Array.from(graph.entries.values()).filter((entry) => entry.namespace === "secret" && isSecretReference(entry.value)).map((entry) => ({
2317
+ logicalKey: entry.key,
2318
+ ref: entry.value
2319
+ }));
2320
+ }
2321
+ async function batchResolveSecrets(graph, manifest, processEnv = process.env) {
2322
+ const cache = new SecretCache();
2323
+ const descriptors = collectSecretDescriptors(graph);
2324
+ const grouped = descriptors.reduce((accumulator, descriptor) => {
2325
+ const vaultId = descriptor.ref.vault ?? "default";
2326
+ const bucket = accumulator.get(vaultId) ?? [];
2327
+ bucket.push(descriptor);
2328
+ accumulator.set(vaultId, bucket);
2329
+ return accumulator;
2330
+ }, /* @__PURE__ */ new Map());
2331
+ for (const [vaultId, refs] of grouped) {
2332
+ const definition = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
2333
+ const provider = createSecretVaultProvider(vaultId, definition, processEnv);
2334
+ const auth = await resolveVaultAuth(vaultId, definition, processEnv);
2335
+ await provider.authenticate(auth);
2336
+ const resolved = await provider.batchGet(refs.map((entry) => entry.ref.ref));
2337
+ cache.load(vaultId, resolved);
2338
+ await appendAuditEvent(
2339
+ {
2340
+ action: "batch_read",
2341
+ vault: vaultId,
2342
+ refs: Array.from(resolved.keys()).sort((left, right) => left.localeCompare(right)),
2343
+ caller: "runtime",
2344
+ workspace: graph.workspace.workspaceId,
2345
+ profile: graph.profile
2346
+ },
2347
+ processEnv
2348
+ );
2349
+ }
2350
+ return cache;
2351
+ }
2352
+ function resolveSecretEntryValue(key, value, cache) {
2353
+ if (!key.startsWith("secret.") || !isSecretReference(value)) {
2354
+ return value;
2355
+ }
2356
+ const vaultId = value.vault ?? "default";
2357
+ return cache.get(vaultId, value.ref) ?? value;
2358
+ }
2359
+
1576
2360
  // ../core/src/orchestrator/runtime.ts
1577
- function createRuntime(manifest, graph, plugins = []) {
2361
+ function createRuntime(manifest, graph, plugins = [], secretCache) {
2362
+ function readLogicalKey(key) {
2363
+ const entry = graph.entries.get(key);
2364
+ if (!entry) {
2365
+ return void 0;
2366
+ }
2367
+ if (!secretCache) {
2368
+ return entry.value;
2369
+ }
2370
+ return resolveSecretEntryValue(key, entry.value, secretCache);
2371
+ }
1578
2372
  return {
1579
2373
  manifest,
1580
2374
  plugins,
1581
2375
  graph,
1582
2376
  read(key) {
1583
- return readValue(graph, key);
2377
+ return readLogicalKey(key);
1584
2378
  },
1585
2379
  require(key) {
1586
- return requireValue(graph, key);
2380
+ const value = readLogicalKey(key);
2381
+ if (value === void 0) {
2382
+ return requireValue(graph, key);
2383
+ }
2384
+ return value;
1587
2385
  },
1588
2386
  readOr(key, fallback) {
1589
2387
  return readOrValue(graph, key, fallback);
1590
2388
  },
1591
- value(path8) {
1592
- return readValue(graph, toLogicalKey("value", path8));
2389
+ value(path10) {
2390
+ return readLogicalKey(toLogicalKey("value", path10));
1593
2391
  },
1594
- secret(path8) {
1595
- return readValue(graph, toLogicalKey("secret", path8));
2392
+ secret(path10) {
2393
+ return readLogicalKey(toLogicalKey("secret", path10));
1596
2394
  },
1597
- meta(path8) {
1598
- return readValue(graph, toLogicalKey("meta", path8));
2395
+ meta(path10) {
2396
+ return readLogicalKey(toLogicalKey("meta", path10));
1599
2397
  },
1600
2398
  inspect(key) {
1601
2399
  return inspectValue(graph, key);
@@ -1753,21 +2551,26 @@ async function createCnos(options = {}) {
1753
2551
  });
1754
2552
  const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
1755
2553
  const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
2554
+ const secretCache = options.secretResolution === "lazy" ? void 0 : await batchResolveSecrets(promotedGraph, loadedManifest.manifest, options.processEnv);
1756
2555
  return createRuntime(
1757
2556
  loadedManifest.manifest,
1758
2557
  appendMetaEntries({
1759
2558
  ...promotedGraph,
1760
2559
  profileSource: activeProfile.source
1761
2560
  }, options.cnosVersion),
1762
- plugins
2561
+ plugins,
2562
+ secretCache
1763
2563
  );
1764
2564
  }
1765
2565
 
1766
2566
  export {
1767
2567
  CnosManifestError,
1768
2568
  CnosSecurityError,
2569
+ CnosAuthenticationError,
1769
2570
  inspectValue,
1770
2571
  createProvenanceInspector,
2572
+ readKeychain,
2573
+ writeKeychain,
1771
2574
  resolveManifestRoot,
1772
2575
  resolveWorkspaceScopedPath,
1773
2576
  resolveConfigDocumentPath,
@@ -1777,24 +2580,38 @@ export {
1777
2580
  parseYaml,
1778
2581
  stringifyYaml,
1779
2582
  loadManifest,
2583
+ getNamespaceDefinition,
1780
2584
  ensureProjectionAllowed,
1781
2585
  applySchemaRules,
1782
- toNamespaceObject,
1783
- readValue,
1784
- readOrValue,
1785
- requireValue,
2586
+ writeVaultSessionKey,
2587
+ clearVaultSessionKey,
2588
+ clearAllVaultSessionKeys,
1786
2589
  isSecretReference,
1787
2590
  resolveSecretStoreRoot,
1788
- resolveSecretVaultFile,
1789
- resolveSecretPassphrase,
1790
2591
  getVaultPassphraseEnvVar,
1791
2592
  isPassphraseEnvRef,
1792
- resolveConfiguredVaultPassphrase,
1793
- resolveVaultDefinition,
1794
- createSecretVault,
2593
+ getVaultSessionKeyEnvVar,
2594
+ resolveSecretPassphrase,
2595
+ deriveVaultKey,
2596
+ resolveSecretVaultFile,
2597
+ detectLegacyVaultFormat,
2598
+ readVaultMetadata,
1795
2599
  listSecretVaults,
2600
+ createSecretVault,
2601
+ resolveConfiguredVaultPassphrase,
2602
+ resolveVaultAccessKey,
1796
2603
  writeLocalSecret,
2604
+ deleteLocalSecret,
1797
2605
  readLocalSecret,
2606
+ listLocalSecrets,
2607
+ resolveVaultDefinition,
2608
+ removeLocalVaultFiles,
2609
+ createSecretVaultProvider,
2610
+ resolveVaultAuth,
2611
+ toNamespaceObject,
2612
+ readValue,
2613
+ readOrValue,
2614
+ requireValue,
1798
2615
  toEnv,
1799
2616
  toPublicEnv,
1800
2617
  createCnos,