@kitsy/cnos 1.9.2 → 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 +523 -80
- 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-6QQPHDUI.js → chunk-2DMCB3PK.js} +1 -1
- package/dist/{chunk-LURQ4LAK.js → chunk-5JGNRADB.js} +1 -1
- package/dist/{chunk-2JBA2LXU.js → chunk-DPC2BV3S.js} +35 -6
- package/dist/{chunk-7JZO6XN3.js → chunk-KJ57PF47.js} +1 -1
- package/dist/{chunk-CPGRRZLP.js → chunk-NFGPS7VJ.js} +8 -8
- package/dist/{chunk-A2WG3ZKW.js → chunk-NU25VFA2.js} +1 -1
- package/dist/{chunk-L7JVECPE.js → chunk-RNTTPI5S.js} +1 -1
- package/dist/{chunk-NVFACB64.js → chunk-T3E57MSQ.js} +1 -1
- package/dist/{chunk-7KVM5PUW.js → chunk-WPB4HB2K.js} +478 -61
- package/dist/{chunk-QK7BMU47.js → chunk-XGK6DXQL.js} +157 -37
- package/dist/configure/index.cjs +521 -76
- 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-zDTUSVx9.d.cts → core-BW8SLnRx.d.cts} +46 -7
- package/dist/{core-zDTUSVx9.d.ts → core-BW8SLnRx.d.ts} +46 -7
- package/dist/{envNaming-EFzezmB3.d.cts → envNaming-1rk7BR0e.d.cts} +1 -1
- package/dist/{envNaming-BkorOKW_.d.ts → envNaming-CjL28IeH.d.ts} +1 -1
- package/dist/index.cjs +672 -108
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -10
- package/dist/internal.cjs +378 -54
- package/dist/internal.d.cts +32 -4
- package/dist/internal.d.ts +32 -4
- package/dist/internal.js +141 -23
- package/dist/plugin/basic-schema.cjs +13 -3
- 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 +40 -8
- 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 +672 -108
- 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-Ds1DRwCX.d.cts → toPublicEnv-CZzpvhGg.d.cts} +1 -1
- package/dist/{toPublicEnv-CT265rzS.d.ts → toPublicEnv-CmydGcxg.d.ts} +1 -1
- package/package.json +1 -1
package/dist/runtime/index.cjs
CHANGED
|
@@ -1339,6 +1339,134 @@ function stripNamespace(key) {
|
|
|
1339
1339
|
return key.split(".").slice(1).join(".");
|
|
1340
1340
|
}
|
|
1341
1341
|
|
|
1342
|
+
// ../core/src/spec/normalizeSpecRule.ts
|
|
1343
|
+
var ALLOWED_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "object", "array"]);
|
|
1344
|
+
var SECRET_FORBIDDEN_FIELDS = ["default", "examples", "enum"];
|
|
1345
|
+
function hasOwn(target, key) {
|
|
1346
|
+
return Object.prototype.hasOwnProperty.call(target, key);
|
|
1347
|
+
}
|
|
1348
|
+
function normalizeOptionalString(value, fieldName, logicalKey) {
|
|
1349
|
+
if (value === void 0) {
|
|
1350
|
+
return void 0;
|
|
1351
|
+
}
|
|
1352
|
+
if (typeof value !== "string") {
|
|
1353
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be a string.`);
|
|
1354
|
+
}
|
|
1355
|
+
const nextValue = value.trim();
|
|
1356
|
+
return nextValue.length > 0 ? nextValue : void 0;
|
|
1357
|
+
}
|
|
1358
|
+
function normalizeStringArray(value, fieldName, logicalKey) {
|
|
1359
|
+
if (value === void 0) {
|
|
1360
|
+
return void 0;
|
|
1361
|
+
}
|
|
1362
|
+
if (!Array.isArray(value)) {
|
|
1363
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be an array.`);
|
|
1364
|
+
}
|
|
1365
|
+
const nextValue = value.map((entry) => {
|
|
1366
|
+
if (typeof entry !== "string") {
|
|
1367
|
+
throw new CnosManifestError(
|
|
1368
|
+
`Invalid schema rule for ${logicalKey}: "${fieldName}" entries must be strings.`
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
return entry.trim();
|
|
1372
|
+
}).filter(Boolean);
|
|
1373
|
+
return nextValue.length > 0 ? nextValue : void 0;
|
|
1374
|
+
}
|
|
1375
|
+
function normalizeUnknownArray(value, fieldName, logicalKey) {
|
|
1376
|
+
if (value === void 0) {
|
|
1377
|
+
return void 0;
|
|
1378
|
+
}
|
|
1379
|
+
if (!Array.isArray(value)) {
|
|
1380
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be an array.`);
|
|
1381
|
+
}
|
|
1382
|
+
return value.length > 0 ? value : void 0;
|
|
1383
|
+
}
|
|
1384
|
+
function assertValidPatternRegex(pattern, logicalKey) {
|
|
1385
|
+
try {
|
|
1386
|
+
void new RegExp(pattern);
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1389
|
+
throw new CnosManifestError(
|
|
1390
|
+
`Invalid schema rule for ${logicalKey}: "pattern" must be a valid regex (${reason}).`
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
function assertSecretRuleSafety(logicalKey, rule) {
|
|
1395
|
+
if (!logicalKey.startsWith("secret.")) {
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
const offendingFields = SECRET_FORBIDDEN_FIELDS.filter((field) => hasOwn(rule, field));
|
|
1399
|
+
if (offendingFields.length === 0) {
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
throw new CnosManifestError(
|
|
1403
|
+
`Invalid schema rule for ${logicalKey}: secret specs cannot include ${offendingFields.join(", ")}. Store secret values in the vault, not schema metadata. Remove ${offendingFields.map((field) => `schema.${logicalKey}.${field}`).join(", ")} to continue.`
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
function normalizeSpecRule(logicalKey, rule) {
|
|
1407
|
+
if (!rule || typeof rule !== "object" || Array.isArray(rule)) {
|
|
1408
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: expected an object.`);
|
|
1409
|
+
}
|
|
1410
|
+
const candidate = rule;
|
|
1411
|
+
assertSecretRuleSafety(logicalKey, candidate);
|
|
1412
|
+
const normalized = {};
|
|
1413
|
+
if (candidate.type !== void 0) {
|
|
1414
|
+
if (typeof candidate.type !== "string" || !ALLOWED_TYPES.has(candidate.type)) {
|
|
1415
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: unsupported type "${String(candidate.type)}".`);
|
|
1416
|
+
}
|
|
1417
|
+
normalized.type = candidate.type;
|
|
1418
|
+
}
|
|
1419
|
+
if (candidate.required !== void 0) {
|
|
1420
|
+
if (typeof candidate.required !== "boolean") {
|
|
1421
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "required" must be a boolean.`);
|
|
1422
|
+
}
|
|
1423
|
+
normalized.required = candidate.required;
|
|
1424
|
+
}
|
|
1425
|
+
if (hasOwn(candidate, "default")) {
|
|
1426
|
+
normalized.default = candidate.default;
|
|
1427
|
+
}
|
|
1428
|
+
const normalizedEnum = normalizeUnknownArray(candidate.enum, "enum", logicalKey);
|
|
1429
|
+
if (normalizedEnum !== void 0) {
|
|
1430
|
+
normalized.enum = normalizedEnum;
|
|
1431
|
+
}
|
|
1432
|
+
const normalizedPattern = normalizeOptionalString(candidate.pattern, "pattern", logicalKey);
|
|
1433
|
+
if (normalizedPattern !== void 0) {
|
|
1434
|
+
assertValidPatternRegex(normalizedPattern, logicalKey);
|
|
1435
|
+
normalized.pattern = normalizedPattern;
|
|
1436
|
+
}
|
|
1437
|
+
const normalizedSummary = normalizeOptionalString(candidate.summary, "summary", logicalKey);
|
|
1438
|
+
if (normalizedSummary !== void 0) {
|
|
1439
|
+
normalized.summary = normalizedSummary;
|
|
1440
|
+
}
|
|
1441
|
+
const normalizedDescription = normalizeOptionalString(candidate.description, "description", logicalKey);
|
|
1442
|
+
if (normalizedDescription !== void 0) {
|
|
1443
|
+
normalized.description = normalizedDescription;
|
|
1444
|
+
}
|
|
1445
|
+
const normalizedExamples = normalizeUnknownArray(candidate.examples, "examples", logicalKey);
|
|
1446
|
+
if (normalizedExamples !== void 0) {
|
|
1447
|
+
normalized.examples = normalizedExamples;
|
|
1448
|
+
}
|
|
1449
|
+
const normalizedUsedBy = normalizeStringArray(candidate.usedBy, "usedBy", logicalKey);
|
|
1450
|
+
if (normalizedUsedBy !== void 0) {
|
|
1451
|
+
normalized.usedBy = normalizedUsedBy;
|
|
1452
|
+
}
|
|
1453
|
+
if (candidate.deprecated !== void 0) {
|
|
1454
|
+
if (typeof candidate.deprecated !== "boolean") {
|
|
1455
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "deprecated" must be a boolean.`);
|
|
1456
|
+
}
|
|
1457
|
+
normalized.deprecated = candidate.deprecated;
|
|
1458
|
+
}
|
|
1459
|
+
const normalizedDeprecationMessage = normalizeOptionalString(
|
|
1460
|
+
candidate.deprecationMessage,
|
|
1461
|
+
"deprecationMessage",
|
|
1462
|
+
logicalKey
|
|
1463
|
+
);
|
|
1464
|
+
if (normalizedDeprecationMessage !== void 0) {
|
|
1465
|
+
normalized.deprecationMessage = normalizedDeprecationMessage;
|
|
1466
|
+
}
|
|
1467
|
+
return normalized;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1342
1470
|
// ../core/src/manifest/normalizeManifest.ts
|
|
1343
1471
|
var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
1344
1472
|
var DEFAULT_LOADERS = [
|
|
@@ -1472,11 +1600,19 @@ function normalizeVaults(vaults) {
|
|
|
1472
1600
|
throw new CnosManifestError(`Vault "${name}" requires a provider`);
|
|
1473
1601
|
}
|
|
1474
1602
|
const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
|
|
1475
|
-
const normalizedMapping =
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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
|
+
});
|
|
1480
1616
|
return [
|
|
1481
1617
|
name,
|
|
1482
1618
|
{
|
|
@@ -1484,12 +1620,20 @@ function normalizeVaults(vaults) {
|
|
|
1484
1620
|
auth: normalizedAuth,
|
|
1485
1621
|
...Object.keys(normalizedMapping).length > 0 ? {
|
|
1486
1622
|
mapping: normalizedMapping
|
|
1487
|
-
} : {}
|
|
1623
|
+
} : {},
|
|
1624
|
+
...fallback.length > 0 ? { fallback } : {}
|
|
1488
1625
|
}
|
|
1489
1626
|
];
|
|
1490
1627
|
})
|
|
1491
1628
|
);
|
|
1492
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
|
+
}
|
|
1493
1637
|
function normalizeAuthSources(value) {
|
|
1494
1638
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1495
1639
|
return void 0;
|
|
@@ -1537,6 +1681,14 @@ function normalizeVaultAuth(vaultName, provider, auth) {
|
|
|
1537
1681
|
...auth?.config ? { config: auth.config } : {}
|
|
1538
1682
|
};
|
|
1539
1683
|
}
|
|
1684
|
+
function normalizeSchema(schema) {
|
|
1685
|
+
return Object.fromEntries(
|
|
1686
|
+
Object.entries(schema ?? {}).map(([logicalKey, rule]) => [
|
|
1687
|
+
logicalKey,
|
|
1688
|
+
normalizeSpecRule(logicalKey, rule)
|
|
1689
|
+
])
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1540
1692
|
function normalizeManifest(manifest) {
|
|
1541
1693
|
const version = manifest.version ?? 1;
|
|
1542
1694
|
if (version !== 1) {
|
|
@@ -1634,7 +1786,7 @@ function normalizeManifest(manifest) {
|
|
|
1634
1786
|
}
|
|
1635
1787
|
}
|
|
1636
1788
|
},
|
|
1637
|
-
schema: manifest.schema
|
|
1789
|
+
schema: normalizeSchema(manifest.schema)
|
|
1638
1790
|
};
|
|
1639
1791
|
}
|
|
1640
1792
|
|
|
@@ -2268,6 +2420,13 @@ function enumMatches(value, allowed) {
|
|
|
2268
2420
|
const serialized = JSON.stringify(value);
|
|
2269
2421
|
return allowed.some((candidate) => JSON.stringify(candidate) === serialized);
|
|
2270
2422
|
}
|
|
2423
|
+
function testPattern(pattern, value) {
|
|
2424
|
+
try {
|
|
2425
|
+
return new RegExp(pattern).test(value);
|
|
2426
|
+
} catch {
|
|
2427
|
+
return false;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2271
2430
|
function applySchemaRules(graph, schema) {
|
|
2272
2431
|
const nextEntries = new Map(graph.entries);
|
|
2273
2432
|
const issues = [];
|
|
@@ -2334,11 +2493,11 @@ function applySchemaRules(graph, schema) {
|
|
|
2334
2493
|
key,
|
|
2335
2494
|
message: `Config key ${key} must be a string to match pattern ${rule.pattern}`
|
|
2336
2495
|
});
|
|
2337
|
-
} else if (!
|
|
2496
|
+
} else if (!testPattern(rule.pattern, coercedValue)) {
|
|
2338
2497
|
issues.push({
|
|
2339
2498
|
code: "schema.pattern",
|
|
2340
2499
|
key,
|
|
2341
|
-
message: `Config key ${key} does not match pattern ${rule.pattern}
|
|
2500
|
+
message: `Config key ${key} does not match pattern ${rule.pattern} (or the pattern is invalid).`
|
|
2342
2501
|
});
|
|
2343
2502
|
}
|
|
2344
2503
|
}
|
|
@@ -2422,7 +2581,7 @@ function isObject(value) {
|
|
|
2422
2581
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2423
2582
|
}
|
|
2424
2583
|
function isSecretReference(value) {
|
|
2425
|
-
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));
|
|
2426
2585
|
}
|
|
2427
2586
|
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
2428
2587
|
return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
@@ -2738,16 +2897,19 @@ function resolveVaultDefinition(vaults, vault = "default") {
|
|
|
2738
2897
|
// ../core/src/secrets/auditLog.ts
|
|
2739
2898
|
async function appendAuditEvent(event, processEnv = process.env) {
|
|
2740
2899
|
const auditFile = processEnv.CNOS_AUDIT_FILE ?? import_node_path12.default.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2900
|
+
try {
|
|
2901
|
+
await (0, import_promises11.mkdir)(import_node_path12.default.dirname(auditFile), { recursive: true });
|
|
2902
|
+
await (0, import_promises11.appendFile)(
|
|
2903
|
+
auditFile,
|
|
2904
|
+
`${JSON.stringify({
|
|
2905
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2906
|
+
...event
|
|
2907
|
+
})}
|
|
2748
2908
|
`,
|
|
2749
|
-
|
|
2750
|
-
|
|
2909
|
+
"utf8"
|
|
2910
|
+
);
|
|
2911
|
+
} catch {
|
|
2912
|
+
}
|
|
2751
2913
|
}
|
|
2752
2914
|
|
|
2753
2915
|
// ../core/src/secrets/secretCache.ts
|
|
@@ -2766,6 +2928,23 @@ var SecretCache = class {
|
|
|
2766
2928
|
get(vaultId, ref) {
|
|
2767
2929
|
return this.cache.get(`${vaultId}:${ref}`);
|
|
2768
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
|
+
}
|
|
2769
2948
|
clear(vaultId) {
|
|
2770
2949
|
if (!vaultId) {
|
|
2771
2950
|
this.cache.clear();
|
|
@@ -2931,7 +3110,7 @@ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
|
|
|
2931
3110
|
};
|
|
2932
3111
|
|
|
2933
3112
|
// ../core/src/secrets/providers/registry.ts
|
|
2934
|
-
function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
3113
|
+
function createSecretVaultProvider(vaultId, definition, processEnv, factories = []) {
|
|
2935
3114
|
if (definition.provider === "local") {
|
|
2936
3115
|
return new LocalSecretVaultProvider(vaultId, definition, processEnv);
|
|
2937
3116
|
}
|
|
@@ -2941,9 +3120,30 @@ function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
|
2941
3120
|
if (definition.provider === "github-secrets") {
|
|
2942
3121
|
return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
|
|
2943
3122
|
}
|
|
3123
|
+
const factory = factories.find((candidate) => candidate.provider === definition.provider);
|
|
3124
|
+
if (factory) {
|
|
3125
|
+
return factory.create(vaultId, definition, processEnv);
|
|
3126
|
+
}
|
|
2944
3127
|
throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
|
|
2945
3128
|
}
|
|
2946
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
|
+
|
|
2947
3147
|
// ../core/src/secrets/prompt.ts
|
|
2948
3148
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
2949
3149
|
var import_node_stream = require("stream");
|
|
@@ -2984,6 +3184,23 @@ function toAuthError(vaultId, sources) {
|
|
|
2984
3184
|
`Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
|
|
2985
3185
|
);
|
|
2986
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
|
+
}
|
|
2987
3204
|
async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
2988
3205
|
const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
|
|
2989
3206
|
if (sessionKey) {
|
|
@@ -2999,6 +3216,32 @@ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
|
2999
3216
|
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3000
3217
|
};
|
|
3001
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
|
+
}
|
|
3002
3245
|
const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
|
|
3003
3246
|
for (const source of sources) {
|
|
3004
3247
|
if (source.startsWith("env:")) {
|
|
@@ -3050,22 +3293,76 @@ function collectSecretDescriptors(graph) {
|
|
|
3050
3293
|
ref: entry.value
|
|
3051
3294
|
}));
|
|
3052
3295
|
}
|
|
3053
|
-
|
|
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 = []) {
|
|
3054
3326
|
const cache = new SecretCache();
|
|
3055
3327
|
const descriptors = collectSecretDescriptors(graph);
|
|
3056
3328
|
const grouped = descriptors.reduce((accumulator, descriptor) => {
|
|
3057
|
-
const
|
|
3058
|
-
const bucket = accumulator.get(
|
|
3329
|
+
const key = secretGroupKey(manifest, descriptor);
|
|
3330
|
+
const bucket = accumulator.get(key) ?? [];
|
|
3059
3331
|
bucket.push(descriptor);
|
|
3060
|
-
accumulator.set(
|
|
3332
|
+
accumulator.set(key, bucket);
|
|
3061
3333
|
return accumulator;
|
|
3062
3334
|
}, /* @__PURE__ */ new Map());
|
|
3063
|
-
for (const
|
|
3064
|
-
const
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
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
|
+
}
|
|
3069
3366
|
cache.load(vaultId, resolved);
|
|
3070
3367
|
await appendAuditEvent(
|
|
3071
3368
|
{
|
|
@@ -3086,7 +3383,11 @@ function resolveSecretEntryValue(key, value, cache) {
|
|
|
3086
3383
|
return value;
|
|
3087
3384
|
}
|
|
3088
3385
|
const vaultId = value.vault ?? "default";
|
|
3089
|
-
|
|
3386
|
+
const resolved = cache.get(vaultId, value.ref);
|
|
3387
|
+
if (resolved !== void 0 || cache.isVaultAuthenticated(vaultId)) {
|
|
3388
|
+
return resolved;
|
|
3389
|
+
}
|
|
3390
|
+
return value;
|
|
3090
3391
|
}
|
|
3091
3392
|
|
|
3092
3393
|
// ../core/src/runtime/projection.ts
|
|
@@ -3189,19 +3490,117 @@ function configHash(values) {
|
|
|
3189
3490
|
function shouldProjectResolvedValue(sourceId) {
|
|
3190
3491
|
return sourceId !== "process-env";
|
|
3191
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
|
+
}
|
|
3192
3587
|
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
|
|
3193
3588
|
const values = {};
|
|
3194
3589
|
const derived = {};
|
|
3195
3590
|
const secretRefs = {};
|
|
3591
|
+
const referencedVaultIds = /* @__PURE__ */ new Set();
|
|
3196
3592
|
const namespaces = /* @__PURE__ */ new Set();
|
|
3197
3593
|
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
3198
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));
|
|
3199
3595
|
for (const [key, entry] of graph.entries) {
|
|
3200
3596
|
if (entry.namespace === "secret" && isSecretReference(entry.value)) {
|
|
3597
|
+
assertSecretRefVaultProviderCompatible(manifest, entry.value, key);
|
|
3201
3598
|
const vaultId = entry.value.vault ?? "default";
|
|
3599
|
+
const provider = entry.value.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3202
3600
|
const envVar = resolveProjectedEnvVar(manifest, vaultId, entry.value.ref);
|
|
3601
|
+
referencedVaultIds.add(vaultId);
|
|
3203
3602
|
secretRefs[key.slice("secret.".length)] = {
|
|
3204
|
-
provider
|
|
3603
|
+
provider,
|
|
3205
3604
|
vault: vaultId,
|
|
3206
3605
|
ref: entry.value.ref,
|
|
3207
3606
|
...envVar ? {
|
|
@@ -3247,6 +3646,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3247
3646
|
namespaces.add(entry.namespace);
|
|
3248
3647
|
}
|
|
3249
3648
|
}
|
|
3649
|
+
const vaults = projectReferencedVaults(manifest, referencedVaultIds);
|
|
3250
3650
|
return {
|
|
3251
3651
|
version: 1,
|
|
3252
3652
|
workspace: graph.workspace.workspaceId,
|
|
@@ -3256,6 +3656,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3256
3656
|
values: stableSortObject(values),
|
|
3257
3657
|
derived: stableSortObject(derived),
|
|
3258
3658
|
secretRefs: stableSortObject(secretRefs),
|
|
3659
|
+
...vaults ? { vaults } : {},
|
|
3259
3660
|
publicKeys,
|
|
3260
3661
|
runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
|
|
3261
3662
|
meta: {
|
|
@@ -3370,9 +3771,10 @@ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
|
|
|
3370
3771
|
}
|
|
3371
3772
|
|
|
3372
3773
|
// ../core/src/orchestrator/runtime.ts
|
|
3373
|
-
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 = []) {
|
|
3374
3775
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
|
|
3375
3776
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
3777
|
+
let activeSecretCache = secretCache;
|
|
3376
3778
|
function resolveProjectedSourceKey(key) {
|
|
3377
3779
|
if (!key.startsWith("public.")) {
|
|
3378
3780
|
return key;
|
|
@@ -3389,30 +3791,38 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3389
3791
|
if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
|
|
3390
3792
|
return;
|
|
3391
3793
|
}
|
|
3392
|
-
if (!
|
|
3794
|
+
if (!activeSecretCache) {
|
|
3393
3795
|
return;
|
|
3394
3796
|
}
|
|
3395
3797
|
const vaultId = entry.value.vault ?? "default";
|
|
3396
|
-
const
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
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);
|
|
3406
3812
|
}
|
|
3813
|
+
activeSecretCache.replace(vaultId, existing);
|
|
3407
3814
|
}
|
|
3408
3815
|
async function refreshAllSecrets() {
|
|
3409
|
-
if (!
|
|
3816
|
+
if (!activeSecretCache) {
|
|
3410
3817
|
return;
|
|
3411
3818
|
}
|
|
3412
|
-
const
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3819
|
+
const refreshed = await batchResolveSecrets(
|
|
3820
|
+
graph,
|
|
3821
|
+
manifest,
|
|
3822
|
+
processEnv,
|
|
3823
|
+
secretVaultProviders
|
|
3824
|
+
);
|
|
3825
|
+
activeSecretCache = refreshed;
|
|
3416
3826
|
}
|
|
3417
3827
|
function readLogicalKey2(key) {
|
|
3418
3828
|
const resolved = derivedSupport.read(key, (ref) => {
|
|
@@ -3420,10 +3830,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3420
3830
|
if (!entry2) {
|
|
3421
3831
|
return void 0;
|
|
3422
3832
|
}
|
|
3423
|
-
if (!
|
|
3833
|
+
if (!activeSecretCache) {
|
|
3424
3834
|
return entry2.value;
|
|
3425
3835
|
}
|
|
3426
|
-
return resolveSecretEntryValue(ref, entry2.value,
|
|
3836
|
+
return resolveSecretEntryValue(ref, entry2.value, activeSecretCache);
|
|
3427
3837
|
});
|
|
3428
3838
|
if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
|
|
3429
3839
|
return resolved;
|
|
@@ -3432,10 +3842,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3432
3842
|
if (!entry) {
|
|
3433
3843
|
return void 0;
|
|
3434
3844
|
}
|
|
3435
|
-
if (!
|
|
3845
|
+
if (!activeSecretCache) {
|
|
3436
3846
|
return entry.value;
|
|
3437
3847
|
}
|
|
3438
|
-
return resolveSecretEntryValue(key, entry.value,
|
|
3848
|
+
return resolveSecretEntryValue(key, entry.value, activeSecretCache);
|
|
3439
3849
|
}
|
|
3440
3850
|
return {
|
|
3441
3851
|
manifest,
|
|
@@ -3472,10 +3882,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3472
3882
|
if (!entry) {
|
|
3473
3883
|
return void 0;
|
|
3474
3884
|
}
|
|
3475
|
-
if (!
|
|
3885
|
+
if (!activeSecretCache) {
|
|
3476
3886
|
return entry.value;
|
|
3477
3887
|
}
|
|
3478
|
-
return resolveSecretEntryValue(candidate, entry.value,
|
|
3888
|
+
return resolveSecretEntryValue(candidate, entry.value, activeSecretCache);
|
|
3479
3889
|
})
|
|
3480
3890
|
});
|
|
3481
3891
|
},
|
|
@@ -3666,7 +4076,12 @@ async function createCnos(options = {}) {
|
|
|
3666
4076
|
});
|
|
3667
4077
|
const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
|
|
3668
4078
|
const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
|
|
3669
|
-
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
|
+
);
|
|
3670
4085
|
return createRuntime(
|
|
3671
4086
|
loadedManifest.manifest,
|
|
3672
4087
|
appendMetaEntries({
|
|
@@ -3676,12 +4091,13 @@ async function createCnos(options = {}) {
|
|
|
3676
4091
|
plugins,
|
|
3677
4092
|
secretCache,
|
|
3678
4093
|
options.processEnv,
|
|
3679
|
-
options.cnosVersion
|
|
4094
|
+
options.cnosVersion,
|
|
4095
|
+
options.secretVaultProviders
|
|
3680
4096
|
);
|
|
3681
4097
|
}
|
|
3682
4098
|
|
|
3683
4099
|
// ../core/src/runtime/dump.ts
|
|
3684
|
-
var
|
|
4100
|
+
var import_promises13 = require("fs/promises");
|
|
3685
4101
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
3686
4102
|
|
|
3687
4103
|
// ../core/src/utils/envNaming.ts
|
|
@@ -3719,7 +4135,7 @@ function envVarToLogicalKey(envVar, config = {}) {
|
|
|
3719
4135
|
// package.json
|
|
3720
4136
|
var package_default = {
|
|
3721
4137
|
name: "@kitsy/cnos",
|
|
3722
|
-
version: "1.
|
|
4138
|
+
version: "1.11.0",
|
|
3723
4139
|
description: "Batteries-included CNOS runtime package wired with the official plugins.",
|
|
3724
4140
|
type: "module",
|
|
3725
4141
|
main: "./dist/index.cjs",
|
|
@@ -3918,15 +4334,36 @@ function createCliArgsPlugin() {
|
|
|
3918
4334
|
}
|
|
3919
4335
|
|
|
3920
4336
|
// ../../plugins/dotenv/src/index.ts
|
|
3921
|
-
var
|
|
4337
|
+
var import_promises14 = require("fs/promises");
|
|
3922
4338
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
3923
4339
|
var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
|
|
3924
4340
|
function parseDoubleQuoted(value) {
|
|
3925
4341
|
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
3926
4342
|
}
|
|
4343
|
+
function isEscapedCharacter(value, index) {
|
|
4344
|
+
let slashCount = 0;
|
|
4345
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
4346
|
+
slashCount += 1;
|
|
4347
|
+
}
|
|
4348
|
+
return slashCount % 2 === 1;
|
|
4349
|
+
}
|
|
4350
|
+
function findClosingQuote(value, quote) {
|
|
4351
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
4352
|
+
if (value[index] !== quote) {
|
|
4353
|
+
continue;
|
|
4354
|
+
}
|
|
4355
|
+
if (quote === '"' && isEscapedCharacter(value, index)) {
|
|
4356
|
+
continue;
|
|
4357
|
+
}
|
|
4358
|
+
return index;
|
|
4359
|
+
}
|
|
4360
|
+
return -1;
|
|
4361
|
+
}
|
|
3927
4362
|
function parseDotenv(document) {
|
|
3928
4363
|
const parsed = {};
|
|
3929
|
-
|
|
4364
|
+
const lines = document.split(/\r?\n/);
|
|
4365
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4366
|
+
const rawLine = lines[lineIndex] ?? "";
|
|
3930
4367
|
const line = rawLine.trim();
|
|
3931
4368
|
if (!line || line.startsWith("#")) {
|
|
3932
4369
|
continue;
|
|
@@ -3941,10 +4378,18 @@ function parseDotenv(document) {
|
|
|
3941
4378
|
if (!envVar) {
|
|
3942
4379
|
continue;
|
|
3943
4380
|
}
|
|
3944
|
-
if (value.startsWith('"')
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
4381
|
+
if (value.startsWith('"') || value.startsWith("'")) {
|
|
4382
|
+
const quote = value.startsWith('"') ? '"' : "'";
|
|
4383
|
+
let quotedContent = value.slice(1);
|
|
4384
|
+
let closingIndex = findClosingQuote(quotedContent, quote);
|
|
4385
|
+
while (closingIndex === -1 && lineIndex < lines.length - 1) {
|
|
4386
|
+
lineIndex += 1;
|
|
4387
|
+
quotedContent = `${quotedContent}
|
|
4388
|
+
${lines[lineIndex] ?? ""}`;
|
|
4389
|
+
closingIndex = findClosingQuote(quotedContent, quote);
|
|
4390
|
+
}
|
|
4391
|
+
const rawQuotedValue = closingIndex === -1 ? quotedContent : quotedContent.slice(0, closingIndex);
|
|
4392
|
+
value = quote === '"' ? parseDoubleQuoted(rawQuotedValue) : rawQuotedValue;
|
|
3948
4393
|
} else {
|
|
3949
4394
|
value = value.replace(/\s+#.*$/, "").trim();
|
|
3950
4395
|
}
|
|
@@ -3976,7 +4421,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
|
|
|
3976
4421
|
}
|
|
3977
4422
|
async function readIfPresent(filePath) {
|
|
3978
4423
|
try {
|
|
3979
|
-
return await (0,
|
|
4424
|
+
return await (0, import_promises14.readFile)(filePath, "utf8");
|
|
3980
4425
|
} catch {
|
|
3981
4426
|
return void 0;
|
|
3982
4427
|
}
|
|
@@ -4042,16 +4487,16 @@ function createPublicEnvExportPlugin() {
|
|
|
4042
4487
|
}
|
|
4043
4488
|
|
|
4044
4489
|
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
4045
|
-
var
|
|
4490
|
+
var import_promises16 = require("fs/promises");
|
|
4046
4491
|
|
|
4047
4492
|
// ../../plugins/filesystem/src/helpers.ts
|
|
4048
|
-
var
|
|
4493
|
+
var import_promises15 = require("fs/promises");
|
|
4049
4494
|
var import_node_path15 = __toESM(require("path"), 1);
|
|
4050
4495
|
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
|
|
4051
4496
|
var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
|
|
4052
4497
|
async function existsDirectory(targetPath) {
|
|
4053
4498
|
try {
|
|
4054
|
-
const stat2 = await (0,
|
|
4499
|
+
const stat2 = await (0, import_promises15.readdir)(targetPath);
|
|
4055
4500
|
void stat2;
|
|
4056
4501
|
return true;
|
|
4057
4502
|
} catch {
|
|
@@ -4059,7 +4504,7 @@ async function existsDirectory(targetPath) {
|
|
|
4059
4504
|
}
|
|
4060
4505
|
}
|
|
4061
4506
|
async function collectYamlFiles(root) {
|
|
4062
|
-
const entries = await (0,
|
|
4507
|
+
const entries = await (0, import_promises15.readdir)(root, { withFileTypes: true });
|
|
4063
4508
|
const results = [];
|
|
4064
4509
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
4065
4510
|
const absolutePath = import_node_path15.default.join(root, entry.name);
|
|
@@ -4161,7 +4606,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4161
4606
|
);
|
|
4162
4607
|
const entries = [];
|
|
4163
4608
|
for (const file of files) {
|
|
4164
|
-
const document = await (0,
|
|
4609
|
+
const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
|
|
4165
4610
|
const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
|
|
4166
4611
|
for (const entry of fileEntries) {
|
|
4167
4612
|
const metadata = toSecretReferenceMetadata(entry.value);
|
|
@@ -4177,7 +4622,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4177
4622
|
}
|
|
4178
4623
|
|
|
4179
4624
|
// ../../plugins/filesystem/src/filesystemValuesReader.ts
|
|
4180
|
-
var
|
|
4625
|
+
var import_promises17 = require("fs/promises");
|
|
4181
4626
|
function filesystemValuesReader(filePath, document, workspaceId = "default") {
|
|
4182
4627
|
return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
|
|
4183
4628
|
}
|
|
@@ -4198,7 +4643,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4198
4643
|
).map(([namespace]) => namespace);
|
|
4199
4644
|
const entries = [];
|
|
4200
4645
|
for (const file of files) {
|
|
4201
|
-
const document = await (0,
|
|
4646
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4202
4647
|
entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
|
|
4203
4648
|
}
|
|
4204
4649
|
for (const namespace of customNamespaces) {
|
|
@@ -4213,7 +4658,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4213
4658
|
layers
|
|
4214
4659
|
);
|
|
4215
4660
|
for (const file of namespaceFiles) {
|
|
4216
|
-
const document = await (0,
|
|
4661
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4217
4662
|
entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
|
|
4218
4663
|
}
|
|
4219
4664
|
}
|
|
@@ -4469,6 +4914,19 @@ function graphRequiresSecretHydration(graph) {
|
|
|
4469
4914
|
|
|
4470
4915
|
// src/runtime/index.ts
|
|
4471
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
|
+
}
|
|
4472
4930
|
function getRuntimeOrThrow() {
|
|
4473
4931
|
const runtime = getSingletonRuntime();
|
|
4474
4932
|
if (!runtime) {
|
|
@@ -4532,6 +4990,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4532
4990
|
if (getSingletonRuntime()) {
|
|
4533
4991
|
return;
|
|
4534
4992
|
}
|
|
4993
|
+
bootstrappedProjection = void 0;
|
|
4535
4994
|
const bootstrappedManifest = {
|
|
4536
4995
|
version: 1,
|
|
4537
4996
|
project: {
|
|
@@ -4602,6 +5061,9 @@ function attachBootstrappedGraph(graph) {
|
|
|
4602
5061
|
schema: {}
|
|
4603
5062
|
};
|
|
4604
5063
|
const runtimeProviders = createDefaultRuntimeProviders(bootstrappedManifest, process.env);
|
|
5064
|
+
for (const [namespace, provider] of singletonRuntimeProviders) {
|
|
5065
|
+
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
5066
|
+
}
|
|
4605
5067
|
const derivedSupport = createDerivedRuntimeSupport(graph, bootstrappedManifest, runtimeProviders);
|
|
4606
5068
|
const resolveProjectedSourceKey = (key) => {
|
|
4607
5069
|
if (!key.startsWith("public.")) {
|
|
@@ -4670,6 +5132,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4670
5132
|
},
|
|
4671
5133
|
registerRuntimeProvider(namespace, provider) {
|
|
4672
5134
|
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
5135
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
4673
5136
|
},
|
|
4674
5137
|
async refreshSecrets() {
|
|
4675
5138
|
return;
|
|
@@ -4681,7 +5144,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4681
5144
|
setSingletonRuntime(runtime);
|
|
4682
5145
|
setBootstrappedSecretHydrationRequired(graphRequiresSecretHydration(graph));
|
|
4683
5146
|
}
|
|
4684
|
-
function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
5147
|
+
function toBootstrappedManifest(graph, runtimeNamespaces = [], vaults = {}) {
|
|
4685
5148
|
return {
|
|
4686
5149
|
version: 1,
|
|
4687
5150
|
project: {
|
|
@@ -4742,7 +5205,7 @@ function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
|
4742
5205
|
])
|
|
4743
5206
|
)
|
|
4744
5207
|
},
|
|
4745
|
-
vaults
|
|
5208
|
+
vaults,
|
|
4746
5209
|
writePolicy: {
|
|
4747
5210
|
define: {
|
|
4748
5211
|
defaultProfile: graph.profile,
|
|
@@ -4877,14 +5340,34 @@ function graphFromProjection(projection) {
|
|
|
4877
5340
|
}
|
|
4878
5341
|
};
|
|
4879
5342
|
}
|
|
4880
|
-
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 = {}) {
|
|
4881
5359
|
if (getSingletonRuntime() && !force) {
|
|
4882
5360
|
return;
|
|
4883
5361
|
}
|
|
5362
|
+
bootstrappedProjection = projection;
|
|
4884
5363
|
const graph = graphFromProjection(projection);
|
|
4885
|
-
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces);
|
|
5364
|
+
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces, projection.vaults ?? {});
|
|
4886
5365
|
const hydratedSecrets = /* @__PURE__ */ new Map();
|
|
5366
|
+
const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
|
|
4887
5367
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, process.env);
|
|
5368
|
+
for (const [namespace, provider] of singletonRuntimeProviders) {
|
|
5369
|
+
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
5370
|
+
}
|
|
4888
5371
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
4889
5372
|
const resolveProjectedSourceKey = (key) => {
|
|
4890
5373
|
if (!key.startsWith("public.")) {
|
|
@@ -4897,32 +5380,95 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
4897
5380
|
const fallback = `value.${key.slice("public.".length)}`;
|
|
4898
5381
|
return graph.entries.has(fallback) ? fallback : key;
|
|
4899
5382
|
};
|
|
4900
|
-
const
|
|
5383
|
+
const projectedDescriptorForKey = (key) => {
|
|
4901
5384
|
const entry = graph.entries.get(key);
|
|
4902
5385
|
if (!entry || entry.namespace !== "secret") {
|
|
4903
|
-
return
|
|
4904
|
-
}
|
|
4905
|
-
if (hydratedSecrets.has(key)) {
|
|
4906
|
-
return hydratedSecrets.get(key);
|
|
5386
|
+
return void 0;
|
|
4907
5387
|
}
|
|
4908
5388
|
const ref = projection.secretRefs[key.slice("secret.".length)];
|
|
4909
5389
|
if (!ref) {
|
|
4910
5390
|
return void 0;
|
|
4911
5391
|
}
|
|
4912
|
-
const definition =
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
} : {}
|
|
5392
|
+
const definition = vaultDefinitionFromProjection(manifest, projection, key, ref);
|
|
5393
|
+
return {
|
|
5394
|
+
key,
|
|
5395
|
+
ref,
|
|
5396
|
+
vaultId: ref.vault ?? "default",
|
|
5397
|
+
definitions: [definition, ...definition.fallback ?? []]
|
|
4919
5398
|
};
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
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
|
+
}
|
|
4926
5472
|
};
|
|
4927
5473
|
const runtime = {
|
|
4928
5474
|
manifest,
|
|
@@ -4992,14 +5538,14 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
4992
5538
|
toNamespace(namespace) {
|
|
4993
5539
|
return toNamespaceObject(graph, namespace, (key) => this.read(key));
|
|
4994
5540
|
},
|
|
4995
|
-
toEnv(
|
|
4996
|
-
return toEnv(graph, manifest,
|
|
5541
|
+
toEnv(options2) {
|
|
5542
|
+
return toEnv(graph, manifest, options2, {
|
|
4997
5543
|
read: (key) => this.read(key),
|
|
4998
5544
|
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
4999
5545
|
});
|
|
5000
5546
|
},
|
|
5001
|
-
toPublicEnv(
|
|
5002
|
-
return toPublicEnv(graph, manifest,
|
|
5547
|
+
toPublicEnv(options2) {
|
|
5548
|
+
return toPublicEnv(graph, manifest, options2, {
|
|
5003
5549
|
read: (key) => derivedSupport.toConcreteValue(
|
|
5004
5550
|
resolveProjectedSourceKey(key),
|
|
5005
5551
|
(ref) => {
|
|
@@ -5022,16 +5568,18 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
5022
5568
|
},
|
|
5023
5569
|
registerRuntimeProvider(namespace, provider) {
|
|
5024
5570
|
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
5571
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
5025
5572
|
},
|
|
5026
5573
|
async refreshSecrets() {
|
|
5027
|
-
|
|
5574
|
+
const keys = Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
|
|
5575
|
+
for (const key of keys) {
|
|
5028
5576
|
hydratedSecrets.delete(key);
|
|
5029
|
-
await resolveSecretValue(key);
|
|
5030
5577
|
}
|
|
5578
|
+
await hydrateProjectedSecrets(keys);
|
|
5031
5579
|
},
|
|
5032
5580
|
async refreshSecret(key) {
|
|
5033
5581
|
hydratedSecrets.delete(key);
|
|
5034
|
-
await
|
|
5582
|
+
await hydrateProjectedSecrets([key]);
|
|
5035
5583
|
}
|
|
5036
5584
|
};
|
|
5037
5585
|
setSingletonRuntime(runtime);
|
|
@@ -5138,14 +5686,23 @@ var cnos = Object.assign(
|
|
|
5138
5686
|
console.log(formatted);
|
|
5139
5687
|
return formatted;
|
|
5140
5688
|
},
|
|
5141
|
-
async loadProjection(source) {
|
|
5689
|
+
async loadProjection(source, options = {}) {
|
|
5142
5690
|
const resolvedSource = import_node_path16.default.resolve(source);
|
|
5143
5691
|
const projection = deserializeServerProjection((0, import_node_fs.readFileSync)(resolvedSource, "utf8"));
|
|
5144
|
-
attachBootstrappedProjection(projection, true);
|
|
5692
|
+
attachBootstrappedProjection(projection, true, options);
|
|
5145
5693
|
setBootstrappedSecretHydrationRequired(Object.keys(projection.secretRefs).length > 0);
|
|
5146
5694
|
},
|
|
5147
5695
|
registerRuntimeProvider(namespace, provider) {
|
|
5148
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
|
+
}
|
|
5149
5706
|
},
|
|
5150
5707
|
async refreshSecrets() {
|
|
5151
5708
|
await getRuntimeOrThrow().refreshSecrets();
|
|
@@ -5154,10 +5711,14 @@ var cnos = Object.assign(
|
|
|
5154
5711
|
async refreshSecret(key) {
|
|
5155
5712
|
await getRuntimeOrThrow().refreshSecret(key);
|
|
5156
5713
|
},
|
|
5157
|
-
async ready() {
|
|
5714
|
+
async ready(options = {}) {
|
|
5158
5715
|
const runtime = getSingletonRuntime();
|
|
5716
|
+
const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
|
|
5159
5717
|
if (runtime && getBootstrappedSecretHydrationRequired()) {
|
|
5160
|
-
|
|
5718
|
+
const runtimeToHydrate = bootstrappedProjection && secretVaultProviders.length > 0 ? (attachBootstrappedProjection(bootstrappedProjection, true, {
|
|
5719
|
+
secretVaultProviders
|
|
5720
|
+
}), getRuntimeOrThrow()) : runtime;
|
|
5721
|
+
await runtimeToHydrate.refreshSecrets();
|
|
5161
5722
|
setBootstrappedSecretHydrationRequired(false);
|
|
5162
5723
|
return;
|
|
5163
5724
|
}
|
|
@@ -5169,7 +5730,10 @@ var cnos = Object.assign(
|
|
|
5169
5730
|
await existing;
|
|
5170
5731
|
return;
|
|
5171
5732
|
}
|
|
5172
|
-
const readyPromise = createCnos2(
|
|
5733
|
+
const readyPromise = createCnos2({
|
|
5734
|
+
...options,
|
|
5735
|
+
secretVaultProviders
|
|
5736
|
+
}).then((runtime2) => {
|
|
5173
5737
|
setSingletonRuntime(runtime2);
|
|
5174
5738
|
setBootstrappedSecretHydrationRequired(false);
|
|
5175
5739
|
return runtime2;
|