@kitsy/cnos 1.10.0 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/index.cjs +331 -63
- package/dist/build/index.d.cts +1 -1
- package/dist/build/index.d.ts +1 -1
- package/dist/build/index.js +13 -15
- package/dist/{chunk-A5U7EZCJ.js → chunk-2DMCB3PK.js} +1 -1
- package/dist/{chunk-RTHKUGJV.js → chunk-5JGNRADB.js} +1 -1
- package/dist/{chunk-3EZGPQCE.js → chunk-DPC2BV3S.js} +1 -1
- package/dist/{chunk-FHXLOWAB.js → chunk-KJ57PF47.js} +1 -1
- package/dist/{chunk-ESBHCFC6.js → chunk-NU25VFA2.js} +1 -1
- package/dist/{chunk-UGLATJJD.js → chunk-RNTTPI5S.js} +1 -1
- package/dist/{chunk-UKNL2Y4N.js → chunk-T3E57MSQ.js} +1 -1
- package/dist/{chunk-CSA4L64V.js → chunk-V3USPV5U.js} +8 -8
- package/dist/{chunk-MQ4WG3K6.js → chunk-WPB4HB2K.js} +320 -49
- package/dist/{chunk-EIK7OUFP.js → chunk-X4PBPUKL.js} +157 -37
- package/dist/configure/index.cjs +329 -59
- package/dist/configure/index.d.cts +3 -3
- package/dist/configure/index.d.ts +3 -3
- package/dist/configure/index.js +8 -8
- package/dist/{core-Ud1o2MBn.d.cts → core-CGJObpyy.d.cts} +40 -2
- package/dist/{core-Ud1o2MBn.d.ts → core-CGJObpyy.d.ts} +40 -2
- package/dist/{envNaming-DxxqiGKN.d.cts → envNaming-DIaBgT6E.d.cts} +1 -1
- package/dist/{envNaming-CPwXl4I6.d.ts → envNaming-_WD9sLZI.d.ts} +1 -1
- package/dist/index.cjs +480 -91
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -10
- package/dist/internal.cjs +89 -23
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +2 -2
- package/dist/plugin/basic-schema.cjs +4 -1
- package/dist/plugin/basic-schema.d.cts +1 -1
- package/dist/plugin/basic-schema.d.ts +1 -1
- package/dist/plugin/basic-schema.js +2 -2
- package/dist/plugin/cli-args.cjs +4 -1
- package/dist/plugin/cli-args.d.cts +1 -1
- package/dist/plugin/cli-args.d.ts +1 -1
- package/dist/plugin/cli-args.js +2 -2
- package/dist/plugin/dotenv.cjs +6 -3
- package/dist/plugin/dotenv.d.cts +2 -2
- package/dist/plugin/dotenv.d.ts +2 -2
- package/dist/plugin/dotenv.js +2 -2
- package/dist/plugin/env-export.cjs +5 -2
- package/dist/plugin/env-export.d.cts +2 -2
- package/dist/plugin/env-export.d.ts +2 -2
- package/dist/plugin/env-export.js +2 -2
- package/dist/plugin/filesystem.cjs +13 -10
- package/dist/plugin/filesystem.d.cts +1 -1
- package/dist/plugin/filesystem.d.ts +1 -1
- package/dist/plugin/filesystem.js +2 -2
- package/dist/plugin/process-env.cjs +4 -1
- package/dist/plugin/process-env.d.cts +2 -2
- package/dist/plugin/process-env.d.ts +2 -2
- package/dist/plugin/process-env.js +2 -2
- package/dist/runtime/index.cjs +480 -91
- package/dist/runtime/index.d.cts +13 -6
- package/dist/runtime/index.d.ts +13 -6
- package/dist/runtime/index.js +10 -10
- package/dist/{toPublicEnv-fUZMRUOz.d.cts → toPublicEnv-C3A8aLjo.d.cts} +1 -1
- package/dist/{toPublicEnv-C9wPSpRo.d.ts → toPublicEnv-DLNNcEso.d.ts} +1 -1
- 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 =
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
3680
|
-
const bucket = accumulator.get(
|
|
3805
|
+
const key = secretGroupKey(manifest, descriptor);
|
|
3806
|
+
const bucket = accumulator.get(key) ?? [];
|
|
3681
3807
|
bucket.push(descriptor);
|
|
3682
|
-
accumulator.set(
|
|
3808
|
+
accumulator.set(key, bucket);
|
|
3683
3809
|
return accumulator;
|
|
3684
3810
|
}, /* @__PURE__ */ new Map());
|
|
3685
|
-
for (const
|
|
3686
|
-
const
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
const
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
4090
|
+
if (!activeSecretCache) {
|
|
3835
4091
|
return;
|
|
3836
4092
|
}
|
|
3837
4093
|
const vaultId = entry.value.vault ?? "default";
|
|
3838
|
-
const
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
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 (!
|
|
4112
|
+
if (!activeSecretCache) {
|
|
3852
4113
|
return;
|
|
3853
4114
|
}
|
|
3854
|
-
const
|
|
3855
|
-
|
|
3856
|
-
|
|
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 (!
|
|
4129
|
+
if (!activeSecretCache) {
|
|
3866
4130
|
return entry2.value;
|
|
3867
4131
|
}
|
|
3868
|
-
return resolveSecretEntryValue(ref, entry2.value,
|
|
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 (!
|
|
4141
|
+
if (!activeSecretCache) {
|
|
3878
4142
|
return entry.value;
|
|
3879
4143
|
}
|
|
3880
|
-
return resolveSecretEntryValue(key, entry.value,
|
|
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 (!
|
|
4181
|
+
if (!activeSecretCache) {
|
|
3918
4182
|
return entry.value;
|
|
3919
4183
|
}
|
|
3920
|
-
return resolveSecretEntryValue(candidate, entry.value,
|
|
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(
|
|
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,
|