@kitsy/cnos 1.10.0 → 1.11.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 (61) hide show
  1. package/dist/build/index.cjs +331 -63
  2. package/dist/build/index.d.cts +1 -1
  3. package/dist/build/index.d.ts +1 -1
  4. package/dist/build/index.js +13 -15
  5. package/dist/{chunk-A5U7EZCJ.js → chunk-2DMCB3PK.js} +1 -1
  6. package/dist/{chunk-RTHKUGJV.js → chunk-5JGNRADB.js} +1 -1
  7. package/dist/{chunk-3EZGPQCE.js → chunk-DPC2BV3S.js} +1 -1
  8. package/dist/{chunk-FHXLOWAB.js → chunk-KJ57PF47.js} +1 -1
  9. package/dist/{chunk-CSA4L64V.js → chunk-NFGPS7VJ.js} +10 -10
  10. package/dist/{chunk-ESBHCFC6.js → chunk-NU25VFA2.js} +1 -1
  11. package/dist/{chunk-UGLATJJD.js → chunk-RNTTPI5S.js} +1 -1
  12. package/dist/{chunk-UKNL2Y4N.js → chunk-T3E57MSQ.js} +1 -1
  13. package/dist/{chunk-MQ4WG3K6.js → chunk-WPB4HB2K.js} +320 -49
  14. package/dist/{chunk-EIK7OUFP.js → chunk-XGK6DXQL.js} +157 -37
  15. package/dist/configure/index.cjs +329 -59
  16. package/dist/configure/index.d.cts +3 -3
  17. package/dist/configure/index.d.ts +3 -3
  18. package/dist/configure/index.js +8 -8
  19. package/dist/{core-Ud1o2MBn.d.cts → core-BW8SLnRx.d.cts} +34 -2
  20. package/dist/{core-Ud1o2MBn.d.ts → core-BW8SLnRx.d.ts} +34 -2
  21. package/dist/{envNaming-DxxqiGKN.d.cts → envNaming-1rk7BR0e.d.cts} +1 -1
  22. package/dist/{envNaming-CPwXl4I6.d.ts → envNaming-CjL28IeH.d.ts} +1 -1
  23. package/dist/index.cjs +480 -91
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +10 -10
  27. package/dist/internal.cjs +89 -23
  28. package/dist/internal.d.cts +3 -3
  29. package/dist/internal.d.ts +3 -3
  30. package/dist/internal.js +2 -2
  31. package/dist/plugin/basic-schema.cjs +4 -1
  32. package/dist/plugin/basic-schema.d.cts +1 -1
  33. package/dist/plugin/basic-schema.d.ts +1 -1
  34. package/dist/plugin/basic-schema.js +2 -2
  35. package/dist/plugin/cli-args.cjs +4 -1
  36. package/dist/plugin/cli-args.d.cts +1 -1
  37. package/dist/plugin/cli-args.d.ts +1 -1
  38. package/dist/plugin/cli-args.js +2 -2
  39. package/dist/plugin/dotenv.cjs +6 -3
  40. package/dist/plugin/dotenv.d.cts +2 -2
  41. package/dist/plugin/dotenv.d.ts +2 -2
  42. package/dist/plugin/dotenv.js +2 -2
  43. package/dist/plugin/env-export.cjs +5 -2
  44. package/dist/plugin/env-export.d.cts +2 -2
  45. package/dist/plugin/env-export.d.ts +2 -2
  46. package/dist/plugin/env-export.js +2 -2
  47. package/dist/plugin/filesystem.cjs +13 -10
  48. package/dist/plugin/filesystem.d.cts +1 -1
  49. package/dist/plugin/filesystem.d.ts +1 -1
  50. package/dist/plugin/filesystem.js +2 -2
  51. package/dist/plugin/process-env.cjs +4 -1
  52. package/dist/plugin/process-env.d.cts +2 -2
  53. package/dist/plugin/process-env.d.ts +2 -2
  54. package/dist/plugin/process-env.js +2 -2
  55. package/dist/runtime/index.cjs +480 -91
  56. package/dist/runtime/index.d.cts +13 -6
  57. package/dist/runtime/index.d.ts +13 -6
  58. package/dist/runtime/index.js +10 -10
  59. package/dist/{toPublicEnv-fUZMRUOz.d.cts → toPublicEnv-CZzpvhGg.d.cts} +1 -1
  60. package/dist/{toPublicEnv-C9wPSpRo.d.ts → toPublicEnv-CmydGcxg.d.ts} +1 -1
  61. package/package.json +1 -1
@@ -1616,11 +1616,19 @@ function normalizeVaults(vaults) {
1616
1616
  throw new CnosManifestError(`Vault "${name}" requires a provider`);
1617
1617
  }
1618
1618
  const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
1619
- const normalizedMapping = Object.fromEntries(
1620
- Object.entries(definition.mapping ?? {}).filter(
1621
- (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
1622
- ).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
1623
- );
1619
+ const normalizedMapping = normalizeVaultMapping(definition.mapping);
1620
+ const fallback = (definition.fallback ?? []).map((entry, index) => {
1621
+ const fallbackProvider = entry.provider?.trim();
1622
+ if (!fallbackProvider) {
1623
+ throw new CnosManifestError(`Vault "${name}" fallback ${index + 1} requires a provider`);
1624
+ }
1625
+ const fallbackMapping = normalizeVaultMapping(entry.mapping);
1626
+ return {
1627
+ provider: fallbackProvider,
1628
+ auth: normalizeVaultAuth(name, fallbackProvider, entry.auth),
1629
+ ...Object.keys(fallbackMapping).length > 0 ? { mapping: fallbackMapping } : {}
1630
+ };
1631
+ });
1624
1632
  return [
1625
1633
  name,
1626
1634
  {
@@ -1628,12 +1636,20 @@ function normalizeVaults(vaults) {
1628
1636
  auth: normalizedAuth,
1629
1637
  ...Object.keys(normalizedMapping).length > 0 ? {
1630
1638
  mapping: normalizedMapping
1631
- } : {}
1639
+ } : {},
1640
+ ...fallback.length > 0 ? { fallback } : {}
1632
1641
  }
1633
1642
  ];
1634
1643
  })
1635
1644
  );
1636
1645
  }
1646
+ function normalizeVaultMapping(mapping) {
1647
+ return Object.fromEntries(
1648
+ Object.entries(mapping ?? {}).filter(
1649
+ (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
1650
+ ).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
1651
+ );
1652
+ }
1637
1653
  function normalizeAuthSources(value) {
1638
1654
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1639
1655
  return void 0;
@@ -1939,7 +1955,7 @@ function isObject(value) {
1939
1955
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1940
1956
  }
1941
1957
  function isSecretReference(value) {
1942
- 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));
1958
+ return isObject(value) && (value.provider === void 0 || 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));
1943
1959
  }
1944
1960
  function resolveSecretStoreRoot(processEnv = process.env) {
1945
1961
  return path8.resolve(expandHomePath2(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
@@ -2443,7 +2459,7 @@ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
2443
2459
  };
2444
2460
 
2445
2461
  // ../core/src/secrets/providers/registry.ts
2446
- function createSecretVaultProvider(vaultId, definition, processEnv) {
2462
+ function createSecretVaultProvider(vaultId, definition, processEnv, factories = []) {
2447
2463
  if (definition.provider === "local") {
2448
2464
  return new LocalSecretVaultProvider(vaultId, definition, processEnv);
2449
2465
  }
@@ -2453,9 +2469,30 @@ function createSecretVaultProvider(vaultId, definition, processEnv) {
2453
2469
  if (definition.provider === "github-secrets") {
2454
2470
  return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
2455
2471
  }
2472
+ const factory = factories.find((candidate) => candidate.provider === definition.provider);
2473
+ if (factory) {
2474
+ return factory.create(vaultId, definition, processEnv);
2475
+ }
2456
2476
  throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
2457
2477
  }
2458
2478
 
2479
+ // ../core/src/secrets/providerCompatibility.ts
2480
+ function assertSecretRefVaultProviderCompatible(manifest, ref, logicalKey = "secret ref") {
2481
+ if (!ref.vault || !ref.provider) {
2482
+ return;
2483
+ }
2484
+ const definition = manifest.vaults[ref.vault];
2485
+ if (!definition || definition.provider === ref.provider) {
2486
+ return;
2487
+ }
2488
+ throw new CnosManifestError(
2489
+ `Secret ref "${logicalKey}" declares provider "${ref.provider}" but vault "${ref.vault}" uses provider "${definition.provider}". Remove the ref provider or use a matching vault.`
2490
+ );
2491
+ }
2492
+
2493
+ // ../core/src/secrets/resolveAuth.ts
2494
+ import { readFile as readFile6 } from "fs/promises";
2495
+
2459
2496
  // ../core/src/secrets/prompt.ts
2460
2497
  import readline from "readline";
2461
2498
  import { Writable } from "stream";
@@ -2496,6 +2533,23 @@ function toAuthError(vaultId, sources) {
2496
2533
  `Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
2497
2534
  );
2498
2535
  }
2536
+ async function resolveTokenFromSource(source, processEnv) {
2537
+ if (source.startsWith("env:")) {
2538
+ return processEnv[source.slice(4)] || void 0;
2539
+ }
2540
+ if (source.startsWith("file:")) {
2541
+ try {
2542
+ const value = await readFile6(expandHomePath2(source.slice("file:".length)), "utf8");
2543
+ return value.trim() || void 0;
2544
+ } catch {
2545
+ return void 0;
2546
+ }
2547
+ }
2548
+ if (source.startsWith("keychain:")) {
2549
+ return readKeychain(source.slice("keychain:".length));
2550
+ }
2551
+ return void 0;
2552
+ }
2499
2553
  async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
2500
2554
  const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
2501
2555
  if (sessionKey) {
@@ -2511,6 +2565,32 @@ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
2511
2565
  ...definition.auth?.config ? { config: definition.auth.config } : {}
2512
2566
  };
2513
2567
  }
2568
+ if (definition.auth?.method === "iam") {
2569
+ return {
2570
+ method: "iam",
2571
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
2572
+ };
2573
+ }
2574
+ if (definition.auth?.method === "environment") {
2575
+ return {
2576
+ method: "environment",
2577
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
2578
+ };
2579
+ }
2580
+ const tokenSources = definition.auth?.token?.from ?? [];
2581
+ for (const source of tokenSources) {
2582
+ const token = await resolveTokenFromSource(source, processEnv);
2583
+ if (token) {
2584
+ return {
2585
+ token,
2586
+ method: "token",
2587
+ ...definition.auth?.config ? { config: definition.auth.config } : {}
2588
+ };
2589
+ }
2590
+ }
2591
+ if (definition.auth?.method === "token") {
2592
+ throw toAuthError(vaultId, [getVaultSessionKeyEnvVar(vaultId), ...tokenSources]);
2593
+ }
2514
2594
  const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
2515
2595
  for (const source of sources) {
2516
2596
  if (source.startsWith("env:")) {
@@ -2964,12 +3044,12 @@ function createProvenanceInspector() {
2964
3044
  }
2965
3045
 
2966
3046
  // ../core/src/manifest/loadWorkspaceFile.ts
2967
- import { readFile as readFile6 } from "fs/promises";
3047
+ import { readFile as readFile7 } from "fs/promises";
2968
3048
  import path11 from "path";
2969
3049
  async function loadWorkspaceFile(repoRoot) {
2970
3050
  const workspaceFilePath = path11.join(repoRoot, ".cnos-workspace.yml");
2971
3051
  try {
2972
- const source = await readFile6(workspaceFilePath, "utf8");
3052
+ const source = await readFile7(workspaceFilePath, "utf8");
2973
3053
  const parsed = parseYaml(source);
2974
3054
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2975
3055
  throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
@@ -2992,7 +3072,7 @@ async function loadWorkspaceFile(repoRoot) {
2992
3072
  }
2993
3073
 
2994
3074
  // ../core/src/profiles/expandProfileChain.ts
2995
- import { access as access4, readFile as readFile7 } from "fs/promises";
3075
+ import { access as access4, readFile as readFile8 } from "fs/promises";
2996
3076
  import path12 from "path";
2997
3077
  async function fileExists(targetPath) {
2998
3078
  try {
@@ -3034,7 +3114,7 @@ async function loadProfileDefinition(profileName, options) {
3034
3114
  if (!await fileExists(profilePath)) {
3035
3115
  continue;
3036
3116
  }
3037
- const document = await readFile7(profilePath, "utf8");
3117
+ const document = await readFile8(profilePath, "utf8");
3038
3118
  const parsed = parseYaml(document);
3039
3119
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3040
3120
  throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
@@ -3650,6 +3730,23 @@ var SecretCache = class {
3650
3730
  get(vaultId, ref) {
3651
3731
  return this.cache.get(`${vaultId}:${ref}`);
3652
3732
  }
3733
+ delete(vaultId, ref) {
3734
+ this.cache.delete(`${vaultId}:${ref}`);
3735
+ }
3736
+ replace(vaultId, secrets) {
3737
+ this.clear(vaultId);
3738
+ this.load(vaultId, secrets);
3739
+ }
3740
+ entriesForVault(vaultId) {
3741
+ const entries = /* @__PURE__ */ new Map();
3742
+ for (const [key, value] of this.cache) {
3743
+ const prefix = `${vaultId}:`;
3744
+ if (key.startsWith(prefix)) {
3745
+ entries.set(key.slice(prefix.length), value);
3746
+ }
3747
+ }
3748
+ return entries;
3749
+ }
3653
3750
  clear(vaultId) {
3654
3751
  if (!vaultId) {
3655
3752
  this.cache.clear();
@@ -3672,22 +3769,76 @@ function collectSecretDescriptors(graph) {
3672
3769
  ref: entry.value
3673
3770
  }));
3674
3771
  }
3675
- async function batchResolveSecrets(graph, manifest, processEnv = process.env) {
3772
+ function secretGroupKey(manifest, descriptor) {
3773
+ assertSecretRefVaultProviderCompatible(manifest, descriptor.ref, descriptor.logicalKey);
3774
+ const vaultId = descriptor.ref.vault ?? "default";
3775
+ const provider = descriptor.ref.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
3776
+ return `${vaultId}\0${provider}`;
3777
+ }
3778
+ function vaultDefinitionForRef(manifest, ref) {
3779
+ assertSecretRefVaultProviderCompatible(manifest, ref);
3780
+ const vaultId = ref.vault ?? "default";
3781
+ const base = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
3782
+ if (!ref.provider || ref.provider === base.provider) {
3783
+ return base;
3784
+ }
3785
+ return {
3786
+ ...base,
3787
+ provider: ref.provider
3788
+ };
3789
+ }
3790
+ async function resolveFromDefinition(vaultId, definition, refs, processEnv, factories) {
3791
+ const runtimeDefinition = {
3792
+ provider: definition.provider,
3793
+ ...definition.auth ? { auth: definition.auth } : {},
3794
+ ...definition.mapping ? { mapping: definition.mapping } : {}
3795
+ };
3796
+ const provider = createSecretVaultProvider(vaultId, runtimeDefinition, processEnv, factories);
3797
+ const auth = await resolveVaultAuth(vaultId, runtimeDefinition, processEnv);
3798
+ await provider.authenticate(auth);
3799
+ return provider.batchGet(refs.map((entry) => entry.ref.ref));
3800
+ }
3801
+ async function batchResolveSecrets(graph, manifest, processEnv = process.env, factories = []) {
3676
3802
  const cache = new SecretCache();
3677
3803
  const descriptors = collectSecretDescriptors(graph);
3678
3804
  const grouped = descriptors.reduce((accumulator, descriptor) => {
3679
- const vaultId = descriptor.ref.vault ?? "default";
3680
- const bucket = accumulator.get(vaultId) ?? [];
3805
+ const key = secretGroupKey(manifest, descriptor);
3806
+ const bucket = accumulator.get(key) ?? [];
3681
3807
  bucket.push(descriptor);
3682
- accumulator.set(vaultId, bucket);
3808
+ accumulator.set(key, bucket);
3683
3809
  return accumulator;
3684
3810
  }, /* @__PURE__ */ new Map());
3685
- for (const [vaultId, refs] of grouped) {
3686
- const definition = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
3687
- const provider = createSecretVaultProvider(vaultId, definition, processEnv);
3688
- const auth = await resolveVaultAuth(vaultId, definition, processEnv);
3689
- await provider.authenticate(auth);
3690
- const resolved = await provider.batchGet(refs.map((entry) => entry.ref.ref));
3811
+ for (const refs of grouped.values()) {
3812
+ const first = refs[0];
3813
+ if (!first) {
3814
+ continue;
3815
+ }
3816
+ const vaultId = first.ref.vault ?? "default";
3817
+ const definition = vaultDefinitionForRef(manifest, first.ref);
3818
+ const definitions = [definition, ...definition.fallback ?? []];
3819
+ const resolved = /* @__PURE__ */ new Map();
3820
+ let remaining = refs;
3821
+ let lastError;
3822
+ for (const candidate of definitions) {
3823
+ try {
3824
+ const candidateValues = await resolveFromDefinition(vaultId, candidate, remaining, processEnv, factories);
3825
+ for (const descriptor of remaining) {
3826
+ const value = candidateValues.get(descriptor.ref.ref);
3827
+ if (value !== void 0) {
3828
+ resolved.set(descriptor.ref.ref, value);
3829
+ }
3830
+ }
3831
+ remaining = remaining.filter((descriptor) => !resolved.has(descriptor.ref.ref));
3832
+ if (remaining.length === 0) {
3833
+ break;
3834
+ }
3835
+ } catch (error) {
3836
+ lastError = error;
3837
+ }
3838
+ }
3839
+ if (resolved.size === 0 && lastError) {
3840
+ throw lastError;
3841
+ }
3691
3842
  cache.load(vaultId, resolved);
3692
3843
  await appendAuditEvent(
3693
3844
  {
@@ -3708,7 +3859,11 @@ function resolveSecretEntryValue(key, value, cache) {
3708
3859
  return value;
3709
3860
  }
3710
3861
  const vaultId = value.vault ?? "default";
3711
- return cache.get(vaultId, value.ref) ?? value;
3862
+ const resolved = cache.get(vaultId, value.ref);
3863
+ if (resolved !== void 0 || cache.isVaultAuthenticated(vaultId)) {
3864
+ return resolved;
3865
+ }
3866
+ return value;
3712
3867
  }
3713
3868
 
3714
3869
  // ../core/src/runtime/toServerProjection.ts
@@ -3733,19 +3888,117 @@ function configHash(values) {
3733
3888
  function shouldProjectResolvedValue(sourceId) {
3734
3889
  return sourceId !== "process-env";
3735
3890
  }
3891
+ var SAFE_PROJECTED_CONFIG_KEYS = /* @__PURE__ */ new Set([
3892
+ "address",
3893
+ "audience",
3894
+ "clientid",
3895
+ "endpoint",
3896
+ "mount",
3897
+ "namespace",
3898
+ "path",
3899
+ "projectid",
3900
+ "region",
3901
+ "scope",
3902
+ "scopes",
3903
+ "serviceaccountemail",
3904
+ "tenant",
3905
+ "tenantid",
3906
+ "url",
3907
+ "version",
3908
+ "vaulturl"
3909
+ ]);
3910
+ function isSafeProjectedConfigKey(key) {
3911
+ return SAFE_PROJECTED_CONFIG_KEYS.has(key.replace(/[^A-Za-z0-9]/g, "").toLowerCase());
3912
+ }
3913
+ function sanitizeProjectedConfigValue(value) {
3914
+ if (Array.isArray(value)) {
3915
+ return value.map((item) => sanitizeProjectedConfigValue(item));
3916
+ }
3917
+ if (!value || typeof value !== "object") {
3918
+ return value;
3919
+ }
3920
+ return stableSortObject(
3921
+ Object.fromEntries(
3922
+ Object.entries(value).map(([key, item]) => [key, sanitizeProjectedConfigValue(item)]).filter(([key, item]) => {
3923
+ if (item && typeof item === "object" && !Array.isArray(item)) {
3924
+ return Object.keys(item).length > 0;
3925
+ }
3926
+ return isSafeProjectedConfigKey(key);
3927
+ })
3928
+ )
3929
+ );
3930
+ }
3931
+ function sanitizeProjectedConfig(config) {
3932
+ const sanitized = sanitizeProjectedConfigValue(config);
3933
+ if (!sanitized || typeof sanitized !== "object" || Array.isArray(sanitized)) {
3934
+ return void 0;
3935
+ }
3936
+ return Object.keys(sanitized).length > 0 ? sanitized : void 0;
3937
+ }
3938
+ function projectVaultAuth(definition) {
3939
+ const auth = definition.auth;
3940
+ if (!auth) {
3941
+ return void 0;
3942
+ }
3943
+ const config = auth.config ? sanitizeProjectedConfig(auth.config) : void 0;
3944
+ const projected = {
3945
+ ...auth.method ? { method: auth.method } : {},
3946
+ ...auth.passphrase?.from ? {
3947
+ passphrase: {
3948
+ from: [...auth.passphrase.from]
3949
+ }
3950
+ } : {},
3951
+ ...auth.token?.from ? {
3952
+ token: {
3953
+ from: [...auth.token.from]
3954
+ }
3955
+ } : {},
3956
+ ...config ? { config } : {}
3957
+ };
3958
+ return Object.keys(projected).length > 0 ? projected : void 0;
3959
+ }
3960
+ function projectVaultDefinition(definition) {
3961
+ const auth = projectVaultAuth(definition);
3962
+ const mapping = definition.mapping ? stableSortObject(definition.mapping) : void 0;
3963
+ const fallback = definition.fallback?.map((entry) => projectVaultDefinition({
3964
+ provider: entry.provider,
3965
+ ...entry.auth ? { auth: entry.auth } : {},
3966
+ ...entry.mapping ? { mapping: entry.mapping } : {}
3967
+ }));
3968
+ return {
3969
+ provider: definition.provider,
3970
+ ...auth ? { auth } : {},
3971
+ ...mapping && Object.keys(mapping).length > 0 ? { mapping } : {},
3972
+ ...fallback && fallback.length > 0 ? { fallback } : {}
3973
+ };
3974
+ }
3975
+ function projectReferencedVaults(manifest, vaultIds) {
3976
+ const projected = {};
3977
+ for (const vaultId of Array.from(vaultIds).sort((left, right) => left.localeCompare(right))) {
3978
+ const definition = manifest.vaults[vaultId];
3979
+ if (definition) {
3980
+ projected[vaultId] = projectVaultDefinition(definition);
3981
+ }
3982
+ }
3983
+ return Object.keys(projected).length > 0 ? projected : void 0;
3984
+ }
3736
3985
  function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
3737
3986
  const values = {};
3738
3987
  const derived = {};
3739
3988
  const secretRefs = {};
3989
+ const referencedVaultIds = /* @__PURE__ */ new Set();
3740
3990
  const namespaces = /* @__PURE__ */ new Set();
3741
3991
  const runtimeNamespaces = /* @__PURE__ */ new Set();
3742
3992
  const publicKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").map((entry) => entry.key.slice("public.".length)).sort((left, right) => left.localeCompare(right));
3743
3993
  for (const [key, entry] of graph.entries) {
3744
3994
  if (entry.namespace === "secret" && isSecretReference(entry.value)) {
3995
+ assertSecretRefVaultProviderCompatible(manifest, entry.value, key);
3745
3996
  const vaultId = entry.value.vault ?? "default";
3997
+ const provider = entry.value.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
3746
3998
  const envVar = resolveProjectedEnvVar(manifest, vaultId, entry.value.ref);
3999
+ referencedVaultIds.add(vaultId);
3747
4000
  secretRefs[key.slice("secret.".length)] = {
3748
- provider: entry.value.provider,
4001
+ provider,
3749
4002
  vault: vaultId,
3750
4003
  ref: entry.value.ref,
3751
4004
  ...envVar ? {
@@ -3791,6 +4044,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
3791
4044
  namespaces.add(entry.namespace);
3792
4045
  }
3793
4046
  }
4047
+ const vaults = projectReferencedVaults(manifest, referencedVaultIds);
3794
4048
  return {
3795
4049
  version: 1,
3796
4050
  workspace: graph.workspace.workspaceId,
@@ -3800,6 +4054,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
3800
4054
  values: stableSortObject(values),
3801
4055
  derived: stableSortObject(derived),
3802
4056
  secretRefs: stableSortObject(secretRefs),
4057
+ ...vaults ? { vaults } : {},
3803
4058
  publicKeys,
3804
4059
  runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
3805
4060
  meta: {
@@ -3812,9 +4067,10 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
3812
4067
  }
3813
4068
 
3814
4069
  // ../core/src/orchestrator/runtime.ts
3815
- function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
4070
+ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev", secretVaultProviders = []) {
3816
4071
  const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
3817
4072
  const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
4073
+ let activeSecretCache = secretCache;
3818
4074
  function resolveProjectedSourceKey(key) {
3819
4075
  if (!key.startsWith("public.")) {
3820
4076
  return key;
@@ -3831,30 +4087,38 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3831
4087
  if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
3832
4088
  return;
3833
4089
  }
3834
- if (!secretCache) {
4090
+ if (!activeSecretCache) {
3835
4091
  return;
3836
4092
  }
3837
4093
  const vaultId = entry.value.vault ?? "default";
3838
- const definition = manifest.vaults[vaultId] ?? {
3839
- provider: entry.value.provider,
3840
- auth: { passphrase: { from: [] } }
3841
- };
3842
- const provider = createSecretVaultProvider(vaultId, definition, processEnv);
3843
- const auth = await resolveVaultAuth(vaultId, definition, processEnv);
3844
- await provider.authenticate(auth);
3845
- const value = await provider.get(entry.value.ref);
3846
- if (value !== void 0) {
3847
- secretCache.load(vaultId, /* @__PURE__ */ new Map([[entry.value.ref, value]]));
4094
+ const refreshed = await batchResolveSecrets(
4095
+ {
4096
+ ...graph,
4097
+ entries: /* @__PURE__ */ new Map([[key, entry]])
4098
+ },
4099
+ manifest,
4100
+ processEnv,
4101
+ secretVaultProviders
4102
+ );
4103
+ const resolved = refreshed.get(vaultId, entry.value.ref);
4104
+ const existing = activeSecretCache.entriesForVault(vaultId);
4105
+ existing.delete(entry.value.ref);
4106
+ if (resolved !== void 0) {
4107
+ existing.set(entry.value.ref, resolved);
3848
4108
  }
4109
+ activeSecretCache.replace(vaultId, existing);
3849
4110
  }
3850
4111
  async function refreshAllSecrets() {
3851
- if (!secretCache) {
4112
+ if (!activeSecretCache) {
3852
4113
  return;
3853
4114
  }
3854
- const secretKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "secret" && isSecretReference(entry.value)).map((entry) => entry.key);
3855
- for (const key of secretKeys) {
3856
- await refreshSecretEntry(key);
3857
- }
4115
+ const refreshed = await batchResolveSecrets(
4116
+ graph,
4117
+ manifest,
4118
+ processEnv,
4119
+ secretVaultProviders
4120
+ );
4121
+ activeSecretCache = refreshed;
3858
4122
  }
3859
4123
  function readLogicalKey(key) {
3860
4124
  const resolved = derivedSupport.read(key, (ref) => {
@@ -3862,10 +4126,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3862
4126
  if (!entry2) {
3863
4127
  return void 0;
3864
4128
  }
3865
- if (!secretCache) {
4129
+ if (!activeSecretCache) {
3866
4130
  return entry2.value;
3867
4131
  }
3868
- return resolveSecretEntryValue(ref, entry2.value, secretCache);
4132
+ return resolveSecretEntryValue(ref, entry2.value, activeSecretCache);
3869
4133
  });
3870
4134
  if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
3871
4135
  return resolved;
@@ -3874,10 +4138,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3874
4138
  if (!entry) {
3875
4139
  return void 0;
3876
4140
  }
3877
- if (!secretCache) {
4141
+ if (!activeSecretCache) {
3878
4142
  return entry.value;
3879
4143
  }
3880
- return resolveSecretEntryValue(key, entry.value, secretCache);
4144
+ return resolveSecretEntryValue(key, entry.value, activeSecretCache);
3881
4145
  }
3882
4146
  return {
3883
4147
  manifest,
@@ -3914,10 +4178,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
3914
4178
  if (!entry) {
3915
4179
  return void 0;
3916
4180
  }
3917
- if (!secretCache) {
4181
+ if (!activeSecretCache) {
3918
4182
  return entry.value;
3919
4183
  }
3920
- return resolveSecretEntryValue(candidate, entry.value, secretCache);
4184
+ return resolveSecretEntryValue(candidate, entry.value, activeSecretCache);
3921
4185
  })
3922
4186
  });
3923
4187
  },
@@ -4108,7 +4372,12 @@ async function createCnos(options = {}) {
4108
4372
  });
4109
4373
  const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
4110
4374
  const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
4111
- const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(promotedGraph, loadedManifest.manifest, options.processEnv);
4375
+ const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
4376
+ promotedGraph,
4377
+ loadedManifest.manifest,
4378
+ options.processEnv,
4379
+ options.secretVaultProviders
4380
+ );
4112
4381
  return createRuntime(
4113
4382
  loadedManifest.manifest,
4114
4383
  appendMetaEntries({
@@ -4118,7 +4387,8 @@ async function createCnos(options = {}) {
4118
4387
  plugins,
4119
4388
  secretCache,
4120
4389
  options.processEnv,
4121
- options.cnosVersion
4390
+ options.cnosVersion,
4391
+ options.secretVaultProviders
4122
4392
  );
4123
4393
  }
4124
4394
 
@@ -4181,6 +4451,7 @@ export {
4181
4451
  resolveVaultDefinition,
4182
4452
  removeLocalVaultFiles,
4183
4453
  createSecretVaultProvider,
4454
+ assertSecretRefVaultProviderCompatible,
4184
4455
  resolveVaultAuth,
4185
4456
  toNamespaceObject,
4186
4457
  readValue,