@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.
- 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-CSA4L64V.js → chunk-NFGPS7VJ.js} +10 -10
- 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-MQ4WG3K6.js → chunk-WPB4HB2K.js} +320 -49
- package/dist/{chunk-EIK7OUFP.js → chunk-XGK6DXQL.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-BW8SLnRx.d.cts} +34 -2
- package/dist/{core-Ud1o2MBn.d.ts → core-BW8SLnRx.d.ts} +34 -2
- package/dist/{envNaming-DxxqiGKN.d.cts → envNaming-1rk7BR0e.d.cts} +1 -1
- package/dist/{envNaming-CPwXl4I6.d.ts → envNaming-CjL28IeH.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-CZzpvhGg.d.cts} +1 -1
- package/dist/{toPublicEnv-C9wPSpRo.d.ts → toPublicEnv-CmydGcxg.d.ts} +1 -1
- package/package.json +1 -1
package/dist/runtime/index.cjs
CHANGED
|
@@ -1600,11 +1600,19 @@ function normalizeVaults(vaults) {
|
|
|
1600
1600
|
throw new CnosManifestError(`Vault "${name}" requires a provider`);
|
|
1601
1601
|
}
|
|
1602
1602
|
const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
|
|
1603
|
-
const normalizedMapping =
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1603
|
+
const normalizedMapping = normalizeVaultMapping(definition.mapping);
|
|
1604
|
+
const fallback = (definition.fallback ?? []).map((entry, index) => {
|
|
1605
|
+
const fallbackProvider = entry.provider?.trim();
|
|
1606
|
+
if (!fallbackProvider) {
|
|
1607
|
+
throw new CnosManifestError(`Vault "${name}" fallback ${index + 1} requires a provider`);
|
|
1608
|
+
}
|
|
1609
|
+
const fallbackMapping = normalizeVaultMapping(entry.mapping);
|
|
1610
|
+
return {
|
|
1611
|
+
provider: fallbackProvider,
|
|
1612
|
+
auth: normalizeVaultAuth(name, fallbackProvider, entry.auth),
|
|
1613
|
+
...Object.keys(fallbackMapping).length > 0 ? { mapping: fallbackMapping } : {}
|
|
1614
|
+
};
|
|
1615
|
+
});
|
|
1608
1616
|
return [
|
|
1609
1617
|
name,
|
|
1610
1618
|
{
|
|
@@ -1612,12 +1620,20 @@ function normalizeVaults(vaults) {
|
|
|
1612
1620
|
auth: normalizedAuth,
|
|
1613
1621
|
...Object.keys(normalizedMapping).length > 0 ? {
|
|
1614
1622
|
mapping: normalizedMapping
|
|
1615
|
-
} : {}
|
|
1623
|
+
} : {},
|
|
1624
|
+
...fallback.length > 0 ? { fallback } : {}
|
|
1616
1625
|
}
|
|
1617
1626
|
];
|
|
1618
1627
|
})
|
|
1619
1628
|
);
|
|
1620
1629
|
}
|
|
1630
|
+
function normalizeVaultMapping(mapping) {
|
|
1631
|
+
return Object.fromEntries(
|
|
1632
|
+
Object.entries(mapping ?? {}).filter(
|
|
1633
|
+
(entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
|
|
1634
|
+
).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1621
1637
|
function normalizeAuthSources(value) {
|
|
1622
1638
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1623
1639
|
return void 0;
|
|
@@ -2565,7 +2581,7 @@ function isObject(value) {
|
|
|
2565
2581
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2566
2582
|
}
|
|
2567
2583
|
function isSecretReference(value) {
|
|
2568
|
-
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));
|
|
2584
|
+
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));
|
|
2569
2585
|
}
|
|
2570
2586
|
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
2571
2587
|
return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
@@ -2912,6 +2928,23 @@ var SecretCache = class {
|
|
|
2912
2928
|
get(vaultId, ref) {
|
|
2913
2929
|
return this.cache.get(`${vaultId}:${ref}`);
|
|
2914
2930
|
}
|
|
2931
|
+
delete(vaultId, ref) {
|
|
2932
|
+
this.cache.delete(`${vaultId}:${ref}`);
|
|
2933
|
+
}
|
|
2934
|
+
replace(vaultId, secrets) {
|
|
2935
|
+
this.clear(vaultId);
|
|
2936
|
+
this.load(vaultId, secrets);
|
|
2937
|
+
}
|
|
2938
|
+
entriesForVault(vaultId) {
|
|
2939
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2940
|
+
for (const [key, value] of this.cache) {
|
|
2941
|
+
const prefix = `${vaultId}:`;
|
|
2942
|
+
if (key.startsWith(prefix)) {
|
|
2943
|
+
entries.set(key.slice(prefix.length), value);
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
return entries;
|
|
2947
|
+
}
|
|
2915
2948
|
clear(vaultId) {
|
|
2916
2949
|
if (!vaultId) {
|
|
2917
2950
|
this.cache.clear();
|
|
@@ -3077,7 +3110,7 @@ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
|
|
|
3077
3110
|
};
|
|
3078
3111
|
|
|
3079
3112
|
// ../core/src/secrets/providers/registry.ts
|
|
3080
|
-
function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
3113
|
+
function createSecretVaultProvider(vaultId, definition, processEnv, factories = []) {
|
|
3081
3114
|
if (definition.provider === "local") {
|
|
3082
3115
|
return new LocalSecretVaultProvider(vaultId, definition, processEnv);
|
|
3083
3116
|
}
|
|
@@ -3087,9 +3120,30 @@ function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
|
3087
3120
|
if (definition.provider === "github-secrets") {
|
|
3088
3121
|
return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
|
|
3089
3122
|
}
|
|
3123
|
+
const factory = factories.find((candidate) => candidate.provider === definition.provider);
|
|
3124
|
+
if (factory) {
|
|
3125
|
+
return factory.create(vaultId, definition, processEnv);
|
|
3126
|
+
}
|
|
3090
3127
|
throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
|
|
3091
3128
|
}
|
|
3092
3129
|
|
|
3130
|
+
// ../core/src/secrets/providerCompatibility.ts
|
|
3131
|
+
function assertSecretRefVaultProviderCompatible(manifest, ref, logicalKey = "secret ref") {
|
|
3132
|
+
if (!ref.vault || !ref.provider) {
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
const definition = manifest.vaults[ref.vault];
|
|
3136
|
+
if (!definition || definition.provider === ref.provider) {
|
|
3137
|
+
return;
|
|
3138
|
+
}
|
|
3139
|
+
throw new CnosManifestError(
|
|
3140
|
+
`Secret ref "${logicalKey}" declares provider "${ref.provider}" but vault "${ref.vault}" uses provider "${definition.provider}". Remove the ref provider or use a matching vault.`
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
// ../core/src/secrets/resolveAuth.ts
|
|
3145
|
+
var import_promises12 = require("fs/promises");
|
|
3146
|
+
|
|
3093
3147
|
// ../core/src/secrets/prompt.ts
|
|
3094
3148
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
3095
3149
|
var import_node_stream = require("stream");
|
|
@@ -3130,6 +3184,23 @@ function toAuthError(vaultId, sources) {
|
|
|
3130
3184
|
`Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
|
|
3131
3185
|
);
|
|
3132
3186
|
}
|
|
3187
|
+
async function resolveTokenFromSource(source, processEnv) {
|
|
3188
|
+
if (source.startsWith("env:")) {
|
|
3189
|
+
return processEnv[source.slice(4)] || void 0;
|
|
3190
|
+
}
|
|
3191
|
+
if (source.startsWith("file:")) {
|
|
3192
|
+
try {
|
|
3193
|
+
const value = await (0, import_promises12.readFile)(expandHomePath(source.slice("file:".length)), "utf8");
|
|
3194
|
+
return value.trim() || void 0;
|
|
3195
|
+
} catch {
|
|
3196
|
+
return void 0;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
if (source.startsWith("keychain:")) {
|
|
3200
|
+
return readKeychain(source.slice("keychain:".length));
|
|
3201
|
+
}
|
|
3202
|
+
return void 0;
|
|
3203
|
+
}
|
|
3133
3204
|
async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
3134
3205
|
const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
|
|
3135
3206
|
if (sessionKey) {
|
|
@@ -3145,6 +3216,32 @@ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
|
3145
3216
|
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3146
3217
|
};
|
|
3147
3218
|
}
|
|
3219
|
+
if (definition.auth?.method === "iam") {
|
|
3220
|
+
return {
|
|
3221
|
+
method: "iam",
|
|
3222
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3223
|
+
};
|
|
3224
|
+
}
|
|
3225
|
+
if (definition.auth?.method === "environment") {
|
|
3226
|
+
return {
|
|
3227
|
+
method: "environment",
|
|
3228
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
const tokenSources = definition.auth?.token?.from ?? [];
|
|
3232
|
+
for (const source of tokenSources) {
|
|
3233
|
+
const token = await resolveTokenFromSource(source, processEnv);
|
|
3234
|
+
if (token) {
|
|
3235
|
+
return {
|
|
3236
|
+
token,
|
|
3237
|
+
method: "token",
|
|
3238
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
if (definition.auth?.method === "token") {
|
|
3243
|
+
throw toAuthError(vaultId, [getVaultSessionKeyEnvVar(vaultId), ...tokenSources]);
|
|
3244
|
+
}
|
|
3148
3245
|
const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
|
|
3149
3246
|
for (const source of sources) {
|
|
3150
3247
|
if (source.startsWith("env:")) {
|
|
@@ -3196,22 +3293,76 @@ function collectSecretDescriptors(graph) {
|
|
|
3196
3293
|
ref: entry.value
|
|
3197
3294
|
}));
|
|
3198
3295
|
}
|
|
3199
|
-
|
|
3296
|
+
function secretGroupKey(manifest, descriptor) {
|
|
3297
|
+
assertSecretRefVaultProviderCompatible(manifest, descriptor.ref, descriptor.logicalKey);
|
|
3298
|
+
const vaultId = descriptor.ref.vault ?? "default";
|
|
3299
|
+
const provider = descriptor.ref.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3300
|
+
return `${vaultId}\0${provider}`;
|
|
3301
|
+
}
|
|
3302
|
+
function vaultDefinitionForRef(manifest, ref) {
|
|
3303
|
+
assertSecretRefVaultProviderCompatible(manifest, ref);
|
|
3304
|
+
const vaultId = ref.vault ?? "default";
|
|
3305
|
+
const base = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
|
|
3306
|
+
if (!ref.provider || ref.provider === base.provider) {
|
|
3307
|
+
return base;
|
|
3308
|
+
}
|
|
3309
|
+
return {
|
|
3310
|
+
...base,
|
|
3311
|
+
provider: ref.provider
|
|
3312
|
+
};
|
|
3313
|
+
}
|
|
3314
|
+
async function resolveFromDefinition(vaultId, definition, refs, processEnv, factories) {
|
|
3315
|
+
const runtimeDefinition = {
|
|
3316
|
+
provider: definition.provider,
|
|
3317
|
+
...definition.auth ? { auth: definition.auth } : {},
|
|
3318
|
+
...definition.mapping ? { mapping: definition.mapping } : {}
|
|
3319
|
+
};
|
|
3320
|
+
const provider = createSecretVaultProvider(vaultId, runtimeDefinition, processEnv, factories);
|
|
3321
|
+
const auth = await resolveVaultAuth(vaultId, runtimeDefinition, processEnv);
|
|
3322
|
+
await provider.authenticate(auth);
|
|
3323
|
+
return provider.batchGet(refs.map((entry) => entry.ref.ref));
|
|
3324
|
+
}
|
|
3325
|
+
async function batchResolveSecrets(graph, manifest, processEnv = process.env, factories = []) {
|
|
3200
3326
|
const cache = new SecretCache();
|
|
3201
3327
|
const descriptors = collectSecretDescriptors(graph);
|
|
3202
3328
|
const grouped = descriptors.reduce((accumulator, descriptor) => {
|
|
3203
|
-
const
|
|
3204
|
-
const bucket = accumulator.get(
|
|
3329
|
+
const key = secretGroupKey(manifest, descriptor);
|
|
3330
|
+
const bucket = accumulator.get(key) ?? [];
|
|
3205
3331
|
bucket.push(descriptor);
|
|
3206
|
-
accumulator.set(
|
|
3332
|
+
accumulator.set(key, bucket);
|
|
3207
3333
|
return accumulator;
|
|
3208
3334
|
}, /* @__PURE__ */ new Map());
|
|
3209
|
-
for (const
|
|
3210
|
-
const
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
const
|
|
3335
|
+
for (const refs of grouped.values()) {
|
|
3336
|
+
const first = refs[0];
|
|
3337
|
+
if (!first) {
|
|
3338
|
+
continue;
|
|
3339
|
+
}
|
|
3340
|
+
const vaultId = first.ref.vault ?? "default";
|
|
3341
|
+
const definition = vaultDefinitionForRef(manifest, first.ref);
|
|
3342
|
+
const definitions = [definition, ...definition.fallback ?? []];
|
|
3343
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
3344
|
+
let remaining = refs;
|
|
3345
|
+
let lastError;
|
|
3346
|
+
for (const candidate of definitions) {
|
|
3347
|
+
try {
|
|
3348
|
+
const candidateValues = await resolveFromDefinition(vaultId, candidate, remaining, processEnv, factories);
|
|
3349
|
+
for (const descriptor of remaining) {
|
|
3350
|
+
const value = candidateValues.get(descriptor.ref.ref);
|
|
3351
|
+
if (value !== void 0) {
|
|
3352
|
+
resolved.set(descriptor.ref.ref, value);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
remaining = remaining.filter((descriptor) => !resolved.has(descriptor.ref.ref));
|
|
3356
|
+
if (remaining.length === 0) {
|
|
3357
|
+
break;
|
|
3358
|
+
}
|
|
3359
|
+
} catch (error) {
|
|
3360
|
+
lastError = error;
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
if (resolved.size === 0 && lastError) {
|
|
3364
|
+
throw lastError;
|
|
3365
|
+
}
|
|
3215
3366
|
cache.load(vaultId, resolved);
|
|
3216
3367
|
await appendAuditEvent(
|
|
3217
3368
|
{
|
|
@@ -3232,7 +3383,11 @@ function resolveSecretEntryValue(key, value, cache) {
|
|
|
3232
3383
|
return value;
|
|
3233
3384
|
}
|
|
3234
3385
|
const vaultId = value.vault ?? "default";
|
|
3235
|
-
|
|
3386
|
+
const resolved = cache.get(vaultId, value.ref);
|
|
3387
|
+
if (resolved !== void 0 || cache.isVaultAuthenticated(vaultId)) {
|
|
3388
|
+
return resolved;
|
|
3389
|
+
}
|
|
3390
|
+
return value;
|
|
3236
3391
|
}
|
|
3237
3392
|
|
|
3238
3393
|
// ../core/src/runtime/projection.ts
|
|
@@ -3335,19 +3490,117 @@ function configHash(values) {
|
|
|
3335
3490
|
function shouldProjectResolvedValue(sourceId) {
|
|
3336
3491
|
return sourceId !== "process-env";
|
|
3337
3492
|
}
|
|
3493
|
+
var SAFE_PROJECTED_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
3494
|
+
"address",
|
|
3495
|
+
"audience",
|
|
3496
|
+
"clientid",
|
|
3497
|
+
"endpoint",
|
|
3498
|
+
"mount",
|
|
3499
|
+
"namespace",
|
|
3500
|
+
"path",
|
|
3501
|
+
"projectid",
|
|
3502
|
+
"region",
|
|
3503
|
+
"scope",
|
|
3504
|
+
"scopes",
|
|
3505
|
+
"serviceaccountemail",
|
|
3506
|
+
"tenant",
|
|
3507
|
+
"tenantid",
|
|
3508
|
+
"url",
|
|
3509
|
+
"version",
|
|
3510
|
+
"vaulturl"
|
|
3511
|
+
]);
|
|
3512
|
+
function isSafeProjectedConfigKey(key) {
|
|
3513
|
+
return SAFE_PROJECTED_CONFIG_KEYS.has(key.replace(/[^A-Za-z0-9]/g, "").toLowerCase());
|
|
3514
|
+
}
|
|
3515
|
+
function sanitizeProjectedConfigValue(value) {
|
|
3516
|
+
if (Array.isArray(value)) {
|
|
3517
|
+
return value.map((item) => sanitizeProjectedConfigValue(item));
|
|
3518
|
+
}
|
|
3519
|
+
if (!value || typeof value !== "object") {
|
|
3520
|
+
return value;
|
|
3521
|
+
}
|
|
3522
|
+
return stableSortObject(
|
|
3523
|
+
Object.fromEntries(
|
|
3524
|
+
Object.entries(value).map(([key, item]) => [key, sanitizeProjectedConfigValue(item)]).filter(([key, item]) => {
|
|
3525
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
3526
|
+
return Object.keys(item).length > 0;
|
|
3527
|
+
}
|
|
3528
|
+
return isSafeProjectedConfigKey(key);
|
|
3529
|
+
})
|
|
3530
|
+
)
|
|
3531
|
+
);
|
|
3532
|
+
}
|
|
3533
|
+
function sanitizeProjectedConfig(config) {
|
|
3534
|
+
const sanitized = sanitizeProjectedConfigValue(config);
|
|
3535
|
+
if (!sanitized || typeof sanitized !== "object" || Array.isArray(sanitized)) {
|
|
3536
|
+
return void 0;
|
|
3537
|
+
}
|
|
3538
|
+
return Object.keys(sanitized).length > 0 ? sanitized : void 0;
|
|
3539
|
+
}
|
|
3540
|
+
function projectVaultAuth(definition) {
|
|
3541
|
+
const auth = definition.auth;
|
|
3542
|
+
if (!auth) {
|
|
3543
|
+
return void 0;
|
|
3544
|
+
}
|
|
3545
|
+
const config = auth.config ? sanitizeProjectedConfig(auth.config) : void 0;
|
|
3546
|
+
const projected = {
|
|
3547
|
+
...auth.method ? { method: auth.method } : {},
|
|
3548
|
+
...auth.passphrase?.from ? {
|
|
3549
|
+
passphrase: {
|
|
3550
|
+
from: [...auth.passphrase.from]
|
|
3551
|
+
}
|
|
3552
|
+
} : {},
|
|
3553
|
+
...auth.token?.from ? {
|
|
3554
|
+
token: {
|
|
3555
|
+
from: [...auth.token.from]
|
|
3556
|
+
}
|
|
3557
|
+
} : {},
|
|
3558
|
+
...config ? { config } : {}
|
|
3559
|
+
};
|
|
3560
|
+
return Object.keys(projected).length > 0 ? projected : void 0;
|
|
3561
|
+
}
|
|
3562
|
+
function projectVaultDefinition(definition) {
|
|
3563
|
+
const auth = projectVaultAuth(definition);
|
|
3564
|
+
const mapping = definition.mapping ? stableSortObject(definition.mapping) : void 0;
|
|
3565
|
+
const fallback = definition.fallback?.map((entry) => projectVaultDefinition({
|
|
3566
|
+
provider: entry.provider,
|
|
3567
|
+
...entry.auth ? { auth: entry.auth } : {},
|
|
3568
|
+
...entry.mapping ? { mapping: entry.mapping } : {}
|
|
3569
|
+
}));
|
|
3570
|
+
return {
|
|
3571
|
+
provider: definition.provider,
|
|
3572
|
+
...auth ? { auth } : {},
|
|
3573
|
+
...mapping && Object.keys(mapping).length > 0 ? { mapping } : {},
|
|
3574
|
+
...fallback && fallback.length > 0 ? { fallback } : {}
|
|
3575
|
+
};
|
|
3576
|
+
}
|
|
3577
|
+
function projectReferencedVaults(manifest, vaultIds) {
|
|
3578
|
+
const projected = {};
|
|
3579
|
+
for (const vaultId of Array.from(vaultIds).sort((left, right) => left.localeCompare(right))) {
|
|
3580
|
+
const definition = manifest.vaults[vaultId];
|
|
3581
|
+
if (definition) {
|
|
3582
|
+
projected[vaultId] = projectVaultDefinition(definition);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
return Object.keys(projected).length > 0 ? projected : void 0;
|
|
3586
|
+
}
|
|
3338
3587
|
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
|
|
3339
3588
|
const values = {};
|
|
3340
3589
|
const derived = {};
|
|
3341
3590
|
const secretRefs = {};
|
|
3591
|
+
const referencedVaultIds = /* @__PURE__ */ new Set();
|
|
3342
3592
|
const namespaces = /* @__PURE__ */ new Set();
|
|
3343
3593
|
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
3344
3594
|
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));
|
|
3345
3595
|
for (const [key, entry] of graph.entries) {
|
|
3346
3596
|
if (entry.namespace === "secret" && isSecretReference(entry.value)) {
|
|
3597
|
+
assertSecretRefVaultProviderCompatible(manifest, entry.value, key);
|
|
3347
3598
|
const vaultId = entry.value.vault ?? "default";
|
|
3599
|
+
const provider = entry.value.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3348
3600
|
const envVar = resolveProjectedEnvVar(manifest, vaultId, entry.value.ref);
|
|
3601
|
+
referencedVaultIds.add(vaultId);
|
|
3349
3602
|
secretRefs[key.slice("secret.".length)] = {
|
|
3350
|
-
provider
|
|
3603
|
+
provider,
|
|
3351
3604
|
vault: vaultId,
|
|
3352
3605
|
ref: entry.value.ref,
|
|
3353
3606
|
...envVar ? {
|
|
@@ -3393,6 +3646,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3393
3646
|
namespaces.add(entry.namespace);
|
|
3394
3647
|
}
|
|
3395
3648
|
}
|
|
3649
|
+
const vaults = projectReferencedVaults(manifest, referencedVaultIds);
|
|
3396
3650
|
return {
|
|
3397
3651
|
version: 1,
|
|
3398
3652
|
workspace: graph.workspace.workspaceId,
|
|
@@ -3402,6 +3656,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3402
3656
|
values: stableSortObject(values),
|
|
3403
3657
|
derived: stableSortObject(derived),
|
|
3404
3658
|
secretRefs: stableSortObject(secretRefs),
|
|
3659
|
+
...vaults ? { vaults } : {},
|
|
3405
3660
|
publicKeys,
|
|
3406
3661
|
runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
|
|
3407
3662
|
meta: {
|
|
@@ -3516,9 +3771,10 @@ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
|
|
|
3516
3771
|
}
|
|
3517
3772
|
|
|
3518
3773
|
// ../core/src/orchestrator/runtime.ts
|
|
3519
|
-
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
|
|
3774
|
+
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev", secretVaultProviders = []) {
|
|
3520
3775
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
|
|
3521
3776
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
3777
|
+
let activeSecretCache = secretCache;
|
|
3522
3778
|
function resolveProjectedSourceKey(key) {
|
|
3523
3779
|
if (!key.startsWith("public.")) {
|
|
3524
3780
|
return key;
|
|
@@ -3535,30 +3791,38 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3535
3791
|
if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
|
|
3536
3792
|
return;
|
|
3537
3793
|
}
|
|
3538
|
-
if (!
|
|
3794
|
+
if (!activeSecretCache) {
|
|
3539
3795
|
return;
|
|
3540
3796
|
}
|
|
3541
3797
|
const vaultId = entry.value.vault ?? "default";
|
|
3542
|
-
const
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3798
|
+
const refreshed = await batchResolveSecrets(
|
|
3799
|
+
{
|
|
3800
|
+
...graph,
|
|
3801
|
+
entries: /* @__PURE__ */ new Map([[key, entry]])
|
|
3802
|
+
},
|
|
3803
|
+
manifest,
|
|
3804
|
+
processEnv,
|
|
3805
|
+
secretVaultProviders
|
|
3806
|
+
);
|
|
3807
|
+
const resolved = refreshed.get(vaultId, entry.value.ref);
|
|
3808
|
+
const existing = activeSecretCache.entriesForVault(vaultId);
|
|
3809
|
+
existing.delete(entry.value.ref);
|
|
3810
|
+
if (resolved !== void 0) {
|
|
3811
|
+
existing.set(entry.value.ref, resolved);
|
|
3552
3812
|
}
|
|
3813
|
+
activeSecretCache.replace(vaultId, existing);
|
|
3553
3814
|
}
|
|
3554
3815
|
async function refreshAllSecrets() {
|
|
3555
|
-
if (!
|
|
3816
|
+
if (!activeSecretCache) {
|
|
3556
3817
|
return;
|
|
3557
3818
|
}
|
|
3558
|
-
const
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3819
|
+
const refreshed = await batchResolveSecrets(
|
|
3820
|
+
graph,
|
|
3821
|
+
manifest,
|
|
3822
|
+
processEnv,
|
|
3823
|
+
secretVaultProviders
|
|
3824
|
+
);
|
|
3825
|
+
activeSecretCache = refreshed;
|
|
3562
3826
|
}
|
|
3563
3827
|
function readLogicalKey2(key) {
|
|
3564
3828
|
const resolved = derivedSupport.read(key, (ref) => {
|
|
@@ -3566,10 +3830,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3566
3830
|
if (!entry2) {
|
|
3567
3831
|
return void 0;
|
|
3568
3832
|
}
|
|
3569
|
-
if (!
|
|
3833
|
+
if (!activeSecretCache) {
|
|
3570
3834
|
return entry2.value;
|
|
3571
3835
|
}
|
|
3572
|
-
return resolveSecretEntryValue(ref, entry2.value,
|
|
3836
|
+
return resolveSecretEntryValue(ref, entry2.value, activeSecretCache);
|
|
3573
3837
|
});
|
|
3574
3838
|
if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
|
|
3575
3839
|
return resolved;
|
|
@@ -3578,10 +3842,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3578
3842
|
if (!entry) {
|
|
3579
3843
|
return void 0;
|
|
3580
3844
|
}
|
|
3581
|
-
if (!
|
|
3845
|
+
if (!activeSecretCache) {
|
|
3582
3846
|
return entry.value;
|
|
3583
3847
|
}
|
|
3584
|
-
return resolveSecretEntryValue(key, entry.value,
|
|
3848
|
+
return resolveSecretEntryValue(key, entry.value, activeSecretCache);
|
|
3585
3849
|
}
|
|
3586
3850
|
return {
|
|
3587
3851
|
manifest,
|
|
@@ -3618,10 +3882,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3618
3882
|
if (!entry) {
|
|
3619
3883
|
return void 0;
|
|
3620
3884
|
}
|
|
3621
|
-
if (!
|
|
3885
|
+
if (!activeSecretCache) {
|
|
3622
3886
|
return entry.value;
|
|
3623
3887
|
}
|
|
3624
|
-
return resolveSecretEntryValue(candidate, entry.value,
|
|
3888
|
+
return resolveSecretEntryValue(candidate, entry.value, activeSecretCache);
|
|
3625
3889
|
})
|
|
3626
3890
|
});
|
|
3627
3891
|
},
|
|
@@ -3812,7 +4076,12 @@ async function createCnos(options = {}) {
|
|
|
3812
4076
|
});
|
|
3813
4077
|
const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
|
|
3814
4078
|
const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
|
|
3815
|
-
const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
|
|
4079
|
+
const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
|
|
4080
|
+
promotedGraph,
|
|
4081
|
+
loadedManifest.manifest,
|
|
4082
|
+
options.processEnv,
|
|
4083
|
+
options.secretVaultProviders
|
|
4084
|
+
);
|
|
3816
4085
|
return createRuntime(
|
|
3817
4086
|
loadedManifest.manifest,
|
|
3818
4087
|
appendMetaEntries({
|
|
@@ -3822,12 +4091,13 @@ async function createCnos(options = {}) {
|
|
|
3822
4091
|
plugins,
|
|
3823
4092
|
secretCache,
|
|
3824
4093
|
options.processEnv,
|
|
3825
|
-
options.cnosVersion
|
|
4094
|
+
options.cnosVersion,
|
|
4095
|
+
options.secretVaultProviders
|
|
3826
4096
|
);
|
|
3827
4097
|
}
|
|
3828
4098
|
|
|
3829
4099
|
// ../core/src/runtime/dump.ts
|
|
3830
|
-
var
|
|
4100
|
+
var import_promises13 = require("fs/promises");
|
|
3831
4101
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
3832
4102
|
|
|
3833
4103
|
// ../core/src/utils/envNaming.ts
|
|
@@ -3865,7 +4135,7 @@ function envVarToLogicalKey(envVar, config = {}) {
|
|
|
3865
4135
|
// package.json
|
|
3866
4136
|
var package_default = {
|
|
3867
4137
|
name: "@kitsy/cnos",
|
|
3868
|
-
version: "1.
|
|
4138
|
+
version: "1.11.0",
|
|
3869
4139
|
description: "Batteries-included CNOS runtime package wired with the official plugins.",
|
|
3870
4140
|
type: "module",
|
|
3871
4141
|
main: "./dist/index.cjs",
|
|
@@ -4064,7 +4334,7 @@ function createCliArgsPlugin() {
|
|
|
4064
4334
|
}
|
|
4065
4335
|
|
|
4066
4336
|
// ../../plugins/dotenv/src/index.ts
|
|
4067
|
-
var
|
|
4337
|
+
var import_promises14 = require("fs/promises");
|
|
4068
4338
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
4069
4339
|
var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
|
|
4070
4340
|
function parseDoubleQuoted(value) {
|
|
@@ -4151,7 +4421,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
|
|
|
4151
4421
|
}
|
|
4152
4422
|
async function readIfPresent(filePath) {
|
|
4153
4423
|
try {
|
|
4154
|
-
return await (0,
|
|
4424
|
+
return await (0, import_promises14.readFile)(filePath, "utf8");
|
|
4155
4425
|
} catch {
|
|
4156
4426
|
return void 0;
|
|
4157
4427
|
}
|
|
@@ -4217,16 +4487,16 @@ function createPublicEnvExportPlugin() {
|
|
|
4217
4487
|
}
|
|
4218
4488
|
|
|
4219
4489
|
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
4220
|
-
var
|
|
4490
|
+
var import_promises16 = require("fs/promises");
|
|
4221
4491
|
|
|
4222
4492
|
// ../../plugins/filesystem/src/helpers.ts
|
|
4223
|
-
var
|
|
4493
|
+
var import_promises15 = require("fs/promises");
|
|
4224
4494
|
var import_node_path15 = __toESM(require("path"), 1);
|
|
4225
4495
|
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
|
|
4226
4496
|
var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
|
|
4227
4497
|
async function existsDirectory(targetPath) {
|
|
4228
4498
|
try {
|
|
4229
|
-
const stat2 = await (0,
|
|
4499
|
+
const stat2 = await (0, import_promises15.readdir)(targetPath);
|
|
4230
4500
|
void stat2;
|
|
4231
4501
|
return true;
|
|
4232
4502
|
} catch {
|
|
@@ -4234,7 +4504,7 @@ async function existsDirectory(targetPath) {
|
|
|
4234
4504
|
}
|
|
4235
4505
|
}
|
|
4236
4506
|
async function collectYamlFiles(root) {
|
|
4237
|
-
const entries = await (0,
|
|
4507
|
+
const entries = await (0, import_promises15.readdir)(root, { withFileTypes: true });
|
|
4238
4508
|
const results = [];
|
|
4239
4509
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
4240
4510
|
const absolutePath = import_node_path15.default.join(root, entry.name);
|
|
@@ -4336,7 +4606,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4336
4606
|
);
|
|
4337
4607
|
const entries = [];
|
|
4338
4608
|
for (const file of files) {
|
|
4339
|
-
const document = await (0,
|
|
4609
|
+
const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
|
|
4340
4610
|
const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
|
|
4341
4611
|
for (const entry of fileEntries) {
|
|
4342
4612
|
const metadata = toSecretReferenceMetadata(entry.value);
|
|
@@ -4352,7 +4622,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4352
4622
|
}
|
|
4353
4623
|
|
|
4354
4624
|
// ../../plugins/filesystem/src/filesystemValuesReader.ts
|
|
4355
|
-
var
|
|
4625
|
+
var import_promises17 = require("fs/promises");
|
|
4356
4626
|
function filesystemValuesReader(filePath, document, workspaceId = "default") {
|
|
4357
4627
|
return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
|
|
4358
4628
|
}
|
|
@@ -4373,7 +4643,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4373
4643
|
).map(([namespace]) => namespace);
|
|
4374
4644
|
const entries = [];
|
|
4375
4645
|
for (const file of files) {
|
|
4376
|
-
const document = await (0,
|
|
4646
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4377
4647
|
entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
|
|
4378
4648
|
}
|
|
4379
4649
|
for (const namespace of customNamespaces) {
|
|
@@ -4388,7 +4658,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4388
4658
|
layers
|
|
4389
4659
|
);
|
|
4390
4660
|
for (const file of namespaceFiles) {
|
|
4391
|
-
const document = await (0,
|
|
4661
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4392
4662
|
entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
|
|
4393
4663
|
}
|
|
4394
4664
|
}
|
|
@@ -4644,6 +4914,19 @@ function graphRequiresSecretHydration(graph) {
|
|
|
4644
4914
|
|
|
4645
4915
|
// src/runtime/index.ts
|
|
4646
4916
|
var NOT_READY_MESSAGE = "CNOS not initialized. Call await cnos.ready() or use cnos run.";
|
|
4917
|
+
var bootstrappedProjection;
|
|
4918
|
+
var singletonRuntimeProviders = /* @__PURE__ */ new Map();
|
|
4919
|
+
var singletonSecretVaultProviders = /* @__PURE__ */ new Map();
|
|
4920
|
+
function registerSingletonSecretVaultProvider(factory) {
|
|
4921
|
+
singletonSecretVaultProviders.set(factory.provider, factory);
|
|
4922
|
+
}
|
|
4923
|
+
function mergeSecretVaultProviders(factories = []) {
|
|
4924
|
+
const merged = new Map(singletonSecretVaultProviders);
|
|
4925
|
+
for (const factory of factories) {
|
|
4926
|
+
merged.set(factory.provider, factory);
|
|
4927
|
+
}
|
|
4928
|
+
return Array.from(merged.values());
|
|
4929
|
+
}
|
|
4647
4930
|
function getRuntimeOrThrow() {
|
|
4648
4931
|
const runtime = getSingletonRuntime();
|
|
4649
4932
|
if (!runtime) {
|
|
@@ -4707,6 +4990,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4707
4990
|
if (getSingletonRuntime()) {
|
|
4708
4991
|
return;
|
|
4709
4992
|
}
|
|
4993
|
+
bootstrappedProjection = void 0;
|
|
4710
4994
|
const bootstrappedManifest = {
|
|
4711
4995
|
version: 1,
|
|
4712
4996
|
project: {
|
|
@@ -4777,6 +5061,9 @@ function attachBootstrappedGraph(graph) {
|
|
|
4777
5061
|
schema: {}
|
|
4778
5062
|
};
|
|
4779
5063
|
const runtimeProviders = createDefaultRuntimeProviders(bootstrappedManifest, process.env);
|
|
5064
|
+
for (const [namespace, provider] of singletonRuntimeProviders) {
|
|
5065
|
+
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
5066
|
+
}
|
|
4780
5067
|
const derivedSupport = createDerivedRuntimeSupport(graph, bootstrappedManifest, runtimeProviders);
|
|
4781
5068
|
const resolveProjectedSourceKey = (key) => {
|
|
4782
5069
|
if (!key.startsWith("public.")) {
|
|
@@ -4845,6 +5132,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4845
5132
|
},
|
|
4846
5133
|
registerRuntimeProvider(namespace, provider) {
|
|
4847
5134
|
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
5135
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
4848
5136
|
},
|
|
4849
5137
|
async refreshSecrets() {
|
|
4850
5138
|
return;
|
|
@@ -4856,7 +5144,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4856
5144
|
setSingletonRuntime(runtime);
|
|
4857
5145
|
setBootstrappedSecretHydrationRequired(graphRequiresSecretHydration(graph));
|
|
4858
5146
|
}
|
|
4859
|
-
function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
5147
|
+
function toBootstrappedManifest(graph, runtimeNamespaces = [], vaults = {}) {
|
|
4860
5148
|
return {
|
|
4861
5149
|
version: 1,
|
|
4862
5150
|
project: {
|
|
@@ -4917,7 +5205,7 @@ function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
|
4917
5205
|
])
|
|
4918
5206
|
)
|
|
4919
5207
|
},
|
|
4920
|
-
vaults
|
|
5208
|
+
vaults,
|
|
4921
5209
|
writePolicy: {
|
|
4922
5210
|
define: {
|
|
4923
5211
|
defaultProfile: graph.profile,
|
|
@@ -5052,14 +5340,34 @@ function graphFromProjection(projection) {
|
|
|
5052
5340
|
}
|
|
5053
5341
|
};
|
|
5054
5342
|
}
|
|
5055
|
-
function
|
|
5343
|
+
function vaultDefinitionFromProjection(manifest, projection, key, ref) {
|
|
5344
|
+
assertSecretRefVaultProviderCompatible(manifest, ref, key);
|
|
5345
|
+
const vaultId = ref.vault ?? "default";
|
|
5346
|
+
const projected = projection.vaults?.[vaultId];
|
|
5347
|
+
const mapping = {
|
|
5348
|
+
...projected?.mapping ?? {},
|
|
5349
|
+
...ref.envVar ? { [ref.envVar]: ref.ref } : {}
|
|
5350
|
+
};
|
|
5351
|
+
return {
|
|
5352
|
+
provider: projected?.provider ?? ref.provider ?? "local",
|
|
5353
|
+
...projected?.auth ? { auth: projected.auth } : {},
|
|
5354
|
+
...Object.keys(mapping).length > 0 ? { mapping } : {},
|
|
5355
|
+
...projected?.fallback ? { fallback: projected.fallback } : {}
|
|
5356
|
+
};
|
|
5357
|
+
}
|
|
5358
|
+
function attachBootstrappedProjection(projection, force = false, options = {}) {
|
|
5056
5359
|
if (getSingletonRuntime() && !force) {
|
|
5057
5360
|
return;
|
|
5058
5361
|
}
|
|
5362
|
+
bootstrappedProjection = projection;
|
|
5059
5363
|
const graph = graphFromProjection(projection);
|
|
5060
|
-
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces);
|
|
5364
|
+
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces, projection.vaults ?? {});
|
|
5061
5365
|
const hydratedSecrets = /* @__PURE__ */ new Map();
|
|
5366
|
+
const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
|
|
5062
5367
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, process.env);
|
|
5368
|
+
for (const [namespace, provider] of singletonRuntimeProviders) {
|
|
5369
|
+
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
5370
|
+
}
|
|
5063
5371
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
5064
5372
|
const resolveProjectedSourceKey = (key) => {
|
|
5065
5373
|
if (!key.startsWith("public.")) {
|
|
@@ -5072,32 +5380,95 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
5072
5380
|
const fallback = `value.${key.slice("public.".length)}`;
|
|
5073
5381
|
return graph.entries.has(fallback) ? fallback : key;
|
|
5074
5382
|
};
|
|
5075
|
-
const
|
|
5383
|
+
const projectedDescriptorForKey = (key) => {
|
|
5076
5384
|
const entry = graph.entries.get(key);
|
|
5077
5385
|
if (!entry || entry.namespace !== "secret") {
|
|
5078
|
-
return
|
|
5079
|
-
}
|
|
5080
|
-
if (hydratedSecrets.has(key)) {
|
|
5081
|
-
return hydratedSecrets.get(key);
|
|
5386
|
+
return void 0;
|
|
5082
5387
|
}
|
|
5083
5388
|
const ref = projection.secretRefs[key.slice("secret.".length)];
|
|
5084
5389
|
if (!ref) {
|
|
5085
5390
|
return void 0;
|
|
5086
5391
|
}
|
|
5087
|
-
const definition =
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
} : {}
|
|
5392
|
+
const definition = vaultDefinitionFromProjection(manifest, projection, key, ref);
|
|
5393
|
+
return {
|
|
5394
|
+
key,
|
|
5395
|
+
ref,
|
|
5396
|
+
vaultId: ref.vault ?? "default",
|
|
5397
|
+
definitions: [definition, ...definition.fallback ?? []]
|
|
5094
5398
|
};
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5399
|
+
};
|
|
5400
|
+
const runtimeDefinitionForCandidate = (candidate) => ({
|
|
5401
|
+
provider: candidate.provider,
|
|
5402
|
+
...candidate.auth ? { auth: candidate.auth } : {},
|
|
5403
|
+
...candidate.mapping ? { mapping: candidate.mapping } : {}
|
|
5404
|
+
});
|
|
5405
|
+
const hydrateProjectedSecrets = async (keys) => {
|
|
5406
|
+
const requestedKeys = keys ?? Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
|
|
5407
|
+
let remaining = requestedKeys.filter((key) => !hydratedSecrets.has(key)).map((key) => projectedDescriptorForKey(key)).filter((descriptor) => Boolean(descriptor));
|
|
5408
|
+
const lastErrors = /* @__PURE__ */ new Map();
|
|
5409
|
+
let candidateIndex = 0;
|
|
5410
|
+
while (remaining.length > 0) {
|
|
5411
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
5412
|
+
const exhausted = [];
|
|
5413
|
+
for (const descriptor of remaining) {
|
|
5414
|
+
const candidate = descriptor.definitions[candidateIndex];
|
|
5415
|
+
if (!candidate) {
|
|
5416
|
+
exhausted.push(descriptor);
|
|
5417
|
+
continue;
|
|
5418
|
+
}
|
|
5419
|
+
const groupKey = `${descriptor.vaultId}\0${candidate.provider}`;
|
|
5420
|
+
const group = grouped.get(groupKey) ?? {
|
|
5421
|
+
vaultId: descriptor.vaultId,
|
|
5422
|
+
definition: candidate,
|
|
5423
|
+
descriptors: []
|
|
5424
|
+
};
|
|
5425
|
+
group.descriptors.push(descriptor);
|
|
5426
|
+
grouped.set(groupKey, group);
|
|
5427
|
+
}
|
|
5428
|
+
if (grouped.size === 0) {
|
|
5429
|
+
remaining = exhausted;
|
|
5430
|
+
break;
|
|
5431
|
+
}
|
|
5432
|
+
const unresolved = [...exhausted];
|
|
5433
|
+
for (const group of grouped.values()) {
|
|
5434
|
+
const runtimeDefinition = runtimeDefinitionForCandidate(group.definition);
|
|
5435
|
+
try {
|
|
5436
|
+
const provider = createSecretVaultProvider(
|
|
5437
|
+
group.vaultId,
|
|
5438
|
+
runtimeDefinition,
|
|
5439
|
+
process.env,
|
|
5440
|
+
secretVaultProviders
|
|
5441
|
+
);
|
|
5442
|
+
const auth = await resolveVaultAuth(group.vaultId, runtimeDefinition, process.env);
|
|
5443
|
+
await provider.authenticate(auth);
|
|
5444
|
+
const refs = Array.from(new Set(group.descriptors.map((descriptor) => descriptor.ref.ref))).sort((left, right) => left.localeCompare(right));
|
|
5445
|
+
const values = await provider.batchGet(refs);
|
|
5446
|
+
for (const descriptor of group.descriptors) {
|
|
5447
|
+
const value = values.get(descriptor.ref.ref);
|
|
5448
|
+
if (value !== void 0) {
|
|
5449
|
+
hydratedSecrets.set(descriptor.key, value);
|
|
5450
|
+
lastErrors.delete(descriptor.key);
|
|
5451
|
+
} else {
|
|
5452
|
+
unresolved.push(descriptor);
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
} catch (error) {
|
|
5456
|
+
for (const descriptor of group.descriptors) {
|
|
5457
|
+
lastErrors.set(descriptor.key, error);
|
|
5458
|
+
unresolved.push(descriptor);
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
remaining = unresolved.filter((descriptor) => !hydratedSecrets.has(descriptor.key));
|
|
5463
|
+
candidateIndex += 1;
|
|
5464
|
+
}
|
|
5465
|
+
for (const descriptor of remaining) {
|
|
5466
|
+
const error = lastErrors.get(descriptor.key);
|
|
5467
|
+
if (error) {
|
|
5468
|
+
throw error;
|
|
5469
|
+
}
|
|
5470
|
+
hydratedSecrets.set(descriptor.key, void 0);
|
|
5471
|
+
}
|
|
5101
5472
|
};
|
|
5102
5473
|
const runtime = {
|
|
5103
5474
|
manifest,
|
|
@@ -5167,14 +5538,14 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
5167
5538
|
toNamespace(namespace) {
|
|
5168
5539
|
return toNamespaceObject(graph, namespace, (key) => this.read(key));
|
|
5169
5540
|
},
|
|
5170
|
-
toEnv(
|
|
5171
|
-
return toEnv(graph, manifest,
|
|
5541
|
+
toEnv(options2) {
|
|
5542
|
+
return toEnv(graph, manifest, options2, {
|
|
5172
5543
|
read: (key) => this.read(key),
|
|
5173
5544
|
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
5174
5545
|
});
|
|
5175
5546
|
},
|
|
5176
|
-
toPublicEnv(
|
|
5177
|
-
return toPublicEnv(graph, manifest,
|
|
5547
|
+
toPublicEnv(options2) {
|
|
5548
|
+
return toPublicEnv(graph, manifest, options2, {
|
|
5178
5549
|
read: (key) => derivedSupport.toConcreteValue(
|
|
5179
5550
|
resolveProjectedSourceKey(key),
|
|
5180
5551
|
(ref) => {
|
|
@@ -5197,16 +5568,18 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
5197
5568
|
},
|
|
5198
5569
|
registerRuntimeProvider(namespace, provider) {
|
|
5199
5570
|
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
5571
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
5200
5572
|
},
|
|
5201
5573
|
async refreshSecrets() {
|
|
5202
|
-
|
|
5574
|
+
const keys = Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
|
|
5575
|
+
for (const key of keys) {
|
|
5203
5576
|
hydratedSecrets.delete(key);
|
|
5204
|
-
await resolveSecretValue(key);
|
|
5205
5577
|
}
|
|
5578
|
+
await hydrateProjectedSecrets(keys);
|
|
5206
5579
|
},
|
|
5207
5580
|
async refreshSecret(key) {
|
|
5208
5581
|
hydratedSecrets.delete(key);
|
|
5209
|
-
await
|
|
5582
|
+
await hydrateProjectedSecrets([key]);
|
|
5210
5583
|
}
|
|
5211
5584
|
};
|
|
5212
5585
|
setSingletonRuntime(runtime);
|
|
@@ -5313,14 +5686,23 @@ var cnos = Object.assign(
|
|
|
5313
5686
|
console.log(formatted);
|
|
5314
5687
|
return formatted;
|
|
5315
5688
|
},
|
|
5316
|
-
async loadProjection(source) {
|
|
5689
|
+
async loadProjection(source, options = {}) {
|
|
5317
5690
|
const resolvedSource = import_node_path16.default.resolve(source);
|
|
5318
5691
|
const projection = deserializeServerProjection((0, import_node_fs.readFileSync)(resolvedSource, "utf8"));
|
|
5319
|
-
attachBootstrappedProjection(projection, true);
|
|
5692
|
+
attachBootstrappedProjection(projection, true, options);
|
|
5320
5693
|
setBootstrappedSecretHydrationRequired(Object.keys(projection.secretRefs).length > 0);
|
|
5321
5694
|
},
|
|
5322
5695
|
registerRuntimeProvider(namespace, provider) {
|
|
5323
5696
|
getRuntimeOrThrow().registerRuntimeProvider(namespace, provider);
|
|
5697
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
5698
|
+
},
|
|
5699
|
+
registerSecretVaultProvider(factory) {
|
|
5700
|
+
registerSingletonSecretVaultProvider(factory);
|
|
5701
|
+
},
|
|
5702
|
+
registerSecretVaultProviders(factories) {
|
|
5703
|
+
for (const factory of factories) {
|
|
5704
|
+
registerSingletonSecretVaultProvider(factory);
|
|
5705
|
+
}
|
|
5324
5706
|
},
|
|
5325
5707
|
async refreshSecrets() {
|
|
5326
5708
|
await getRuntimeOrThrow().refreshSecrets();
|
|
@@ -5329,10 +5711,14 @@ var cnos = Object.assign(
|
|
|
5329
5711
|
async refreshSecret(key) {
|
|
5330
5712
|
await getRuntimeOrThrow().refreshSecret(key);
|
|
5331
5713
|
},
|
|
5332
|
-
async ready() {
|
|
5714
|
+
async ready(options = {}) {
|
|
5333
5715
|
const runtime = getSingletonRuntime();
|
|
5716
|
+
const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
|
|
5334
5717
|
if (runtime && getBootstrappedSecretHydrationRequired()) {
|
|
5335
|
-
|
|
5718
|
+
const runtimeToHydrate = bootstrappedProjection && secretVaultProviders.length > 0 ? (attachBootstrappedProjection(bootstrappedProjection, true, {
|
|
5719
|
+
secretVaultProviders
|
|
5720
|
+
}), getRuntimeOrThrow()) : runtime;
|
|
5721
|
+
await runtimeToHydrate.refreshSecrets();
|
|
5336
5722
|
setBootstrappedSecretHydrationRequired(false);
|
|
5337
5723
|
return;
|
|
5338
5724
|
}
|
|
@@ -5344,7 +5730,10 @@ var cnos = Object.assign(
|
|
|
5344
5730
|
await existing;
|
|
5345
5731
|
return;
|
|
5346
5732
|
}
|
|
5347
|
-
const readyPromise = createCnos2(
|
|
5733
|
+
const readyPromise = createCnos2({
|
|
5734
|
+
...options,
|
|
5735
|
+
secretVaultProviders
|
|
5736
|
+
}).then((runtime2) => {
|
|
5348
5737
|
setSingletonRuntime(runtime2);
|
|
5349
5738
|
setBootstrappedSecretHydrationRequired(false);
|
|
5350
5739
|
return runtime2;
|