@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/index.cjs
CHANGED
|
@@ -1342,6 +1342,134 @@ function stripNamespace(key) {
|
|
|
1342
1342
|
return key.split(".").slice(1).join(".");
|
|
1343
1343
|
}
|
|
1344
1344
|
|
|
1345
|
+
// ../core/src/spec/normalizeSpecRule.ts
|
|
1346
|
+
var ALLOWED_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "object", "array"]);
|
|
1347
|
+
var SECRET_FORBIDDEN_FIELDS = ["default", "examples", "enum"];
|
|
1348
|
+
function hasOwn(target, key) {
|
|
1349
|
+
return Object.prototype.hasOwnProperty.call(target, key);
|
|
1350
|
+
}
|
|
1351
|
+
function normalizeOptionalString(value, fieldName, logicalKey) {
|
|
1352
|
+
if (value === void 0) {
|
|
1353
|
+
return void 0;
|
|
1354
|
+
}
|
|
1355
|
+
if (typeof value !== "string") {
|
|
1356
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be a string.`);
|
|
1357
|
+
}
|
|
1358
|
+
const nextValue = value.trim();
|
|
1359
|
+
return nextValue.length > 0 ? nextValue : void 0;
|
|
1360
|
+
}
|
|
1361
|
+
function normalizeStringArray(value, fieldName, logicalKey) {
|
|
1362
|
+
if (value === void 0) {
|
|
1363
|
+
return void 0;
|
|
1364
|
+
}
|
|
1365
|
+
if (!Array.isArray(value)) {
|
|
1366
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be an array.`);
|
|
1367
|
+
}
|
|
1368
|
+
const nextValue = value.map((entry) => {
|
|
1369
|
+
if (typeof entry !== "string") {
|
|
1370
|
+
throw new CnosManifestError(
|
|
1371
|
+
`Invalid schema rule for ${logicalKey}: "${fieldName}" entries must be strings.`
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
return entry.trim();
|
|
1375
|
+
}).filter(Boolean);
|
|
1376
|
+
return nextValue.length > 0 ? nextValue : void 0;
|
|
1377
|
+
}
|
|
1378
|
+
function normalizeUnknownArray(value, fieldName, logicalKey) {
|
|
1379
|
+
if (value === void 0) {
|
|
1380
|
+
return void 0;
|
|
1381
|
+
}
|
|
1382
|
+
if (!Array.isArray(value)) {
|
|
1383
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be an array.`);
|
|
1384
|
+
}
|
|
1385
|
+
return value.length > 0 ? value : void 0;
|
|
1386
|
+
}
|
|
1387
|
+
function assertValidPatternRegex(pattern, logicalKey) {
|
|
1388
|
+
try {
|
|
1389
|
+
void new RegExp(pattern);
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1392
|
+
throw new CnosManifestError(
|
|
1393
|
+
`Invalid schema rule for ${logicalKey}: "pattern" must be a valid regex (${reason}).`
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
function assertSecretRuleSafety(logicalKey, rule) {
|
|
1398
|
+
if (!logicalKey.startsWith("secret.")) {
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
const offendingFields = SECRET_FORBIDDEN_FIELDS.filter((field) => hasOwn(rule, field));
|
|
1402
|
+
if (offendingFields.length === 0) {
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
throw new CnosManifestError(
|
|
1406
|
+
`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.`
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
function normalizeSpecRule(logicalKey, rule) {
|
|
1410
|
+
if (!rule || typeof rule !== "object" || Array.isArray(rule)) {
|
|
1411
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: expected an object.`);
|
|
1412
|
+
}
|
|
1413
|
+
const candidate = rule;
|
|
1414
|
+
assertSecretRuleSafety(logicalKey, candidate);
|
|
1415
|
+
const normalized = {};
|
|
1416
|
+
if (candidate.type !== void 0) {
|
|
1417
|
+
if (typeof candidate.type !== "string" || !ALLOWED_TYPES.has(candidate.type)) {
|
|
1418
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: unsupported type "${String(candidate.type)}".`);
|
|
1419
|
+
}
|
|
1420
|
+
normalized.type = candidate.type;
|
|
1421
|
+
}
|
|
1422
|
+
if (candidate.required !== void 0) {
|
|
1423
|
+
if (typeof candidate.required !== "boolean") {
|
|
1424
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "required" must be a boolean.`);
|
|
1425
|
+
}
|
|
1426
|
+
normalized.required = candidate.required;
|
|
1427
|
+
}
|
|
1428
|
+
if (hasOwn(candidate, "default")) {
|
|
1429
|
+
normalized.default = candidate.default;
|
|
1430
|
+
}
|
|
1431
|
+
const normalizedEnum = normalizeUnknownArray(candidate.enum, "enum", logicalKey);
|
|
1432
|
+
if (normalizedEnum !== void 0) {
|
|
1433
|
+
normalized.enum = normalizedEnum;
|
|
1434
|
+
}
|
|
1435
|
+
const normalizedPattern = normalizeOptionalString(candidate.pattern, "pattern", logicalKey);
|
|
1436
|
+
if (normalizedPattern !== void 0) {
|
|
1437
|
+
assertValidPatternRegex(normalizedPattern, logicalKey);
|
|
1438
|
+
normalized.pattern = normalizedPattern;
|
|
1439
|
+
}
|
|
1440
|
+
const normalizedSummary = normalizeOptionalString(candidate.summary, "summary", logicalKey);
|
|
1441
|
+
if (normalizedSummary !== void 0) {
|
|
1442
|
+
normalized.summary = normalizedSummary;
|
|
1443
|
+
}
|
|
1444
|
+
const normalizedDescription = normalizeOptionalString(candidate.description, "description", logicalKey);
|
|
1445
|
+
if (normalizedDescription !== void 0) {
|
|
1446
|
+
normalized.description = normalizedDescription;
|
|
1447
|
+
}
|
|
1448
|
+
const normalizedExamples = normalizeUnknownArray(candidate.examples, "examples", logicalKey);
|
|
1449
|
+
if (normalizedExamples !== void 0) {
|
|
1450
|
+
normalized.examples = normalizedExamples;
|
|
1451
|
+
}
|
|
1452
|
+
const normalizedUsedBy = normalizeStringArray(candidate.usedBy, "usedBy", logicalKey);
|
|
1453
|
+
if (normalizedUsedBy !== void 0) {
|
|
1454
|
+
normalized.usedBy = normalizedUsedBy;
|
|
1455
|
+
}
|
|
1456
|
+
if (candidate.deprecated !== void 0) {
|
|
1457
|
+
if (typeof candidate.deprecated !== "boolean") {
|
|
1458
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "deprecated" must be a boolean.`);
|
|
1459
|
+
}
|
|
1460
|
+
normalized.deprecated = candidate.deprecated;
|
|
1461
|
+
}
|
|
1462
|
+
const normalizedDeprecationMessage = normalizeOptionalString(
|
|
1463
|
+
candidate.deprecationMessage,
|
|
1464
|
+
"deprecationMessage",
|
|
1465
|
+
logicalKey
|
|
1466
|
+
);
|
|
1467
|
+
if (normalizedDeprecationMessage !== void 0) {
|
|
1468
|
+
normalized.deprecationMessage = normalizedDeprecationMessage;
|
|
1469
|
+
}
|
|
1470
|
+
return normalized;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1345
1473
|
// ../core/src/manifest/normalizeManifest.ts
|
|
1346
1474
|
var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
1347
1475
|
var DEFAULT_LOADERS = [
|
|
@@ -1475,11 +1603,19 @@ function normalizeVaults(vaults) {
|
|
|
1475
1603
|
throw new CnosManifestError(`Vault "${name}" requires a provider`);
|
|
1476
1604
|
}
|
|
1477
1605
|
const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
|
|
1478
|
-
const normalizedMapping =
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1606
|
+
const normalizedMapping = normalizeVaultMapping(definition.mapping);
|
|
1607
|
+
const fallback = (definition.fallback ?? []).map((entry, index) => {
|
|
1608
|
+
const fallbackProvider = entry.provider?.trim();
|
|
1609
|
+
if (!fallbackProvider) {
|
|
1610
|
+
throw new CnosManifestError(`Vault "${name}" fallback ${index + 1} requires a provider`);
|
|
1611
|
+
}
|
|
1612
|
+
const fallbackMapping = normalizeVaultMapping(entry.mapping);
|
|
1613
|
+
return {
|
|
1614
|
+
provider: fallbackProvider,
|
|
1615
|
+
auth: normalizeVaultAuth(name, fallbackProvider, entry.auth),
|
|
1616
|
+
...Object.keys(fallbackMapping).length > 0 ? { mapping: fallbackMapping } : {}
|
|
1617
|
+
};
|
|
1618
|
+
});
|
|
1483
1619
|
return [
|
|
1484
1620
|
name,
|
|
1485
1621
|
{
|
|
@@ -1487,12 +1623,20 @@ function normalizeVaults(vaults) {
|
|
|
1487
1623
|
auth: normalizedAuth,
|
|
1488
1624
|
...Object.keys(normalizedMapping).length > 0 ? {
|
|
1489
1625
|
mapping: normalizedMapping
|
|
1490
|
-
} : {}
|
|
1626
|
+
} : {},
|
|
1627
|
+
...fallback.length > 0 ? { fallback } : {}
|
|
1491
1628
|
}
|
|
1492
1629
|
];
|
|
1493
1630
|
})
|
|
1494
1631
|
);
|
|
1495
1632
|
}
|
|
1633
|
+
function normalizeVaultMapping(mapping) {
|
|
1634
|
+
return Object.fromEntries(
|
|
1635
|
+
Object.entries(mapping ?? {}).filter(
|
|
1636
|
+
(entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
|
|
1637
|
+
).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1496
1640
|
function normalizeAuthSources(value) {
|
|
1497
1641
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1498
1642
|
return void 0;
|
|
@@ -1540,6 +1684,14 @@ function normalizeVaultAuth(vaultName, provider, auth) {
|
|
|
1540
1684
|
...auth?.config ? { config: auth.config } : {}
|
|
1541
1685
|
};
|
|
1542
1686
|
}
|
|
1687
|
+
function normalizeSchema(schema) {
|
|
1688
|
+
return Object.fromEntries(
|
|
1689
|
+
Object.entries(schema ?? {}).map(([logicalKey, rule]) => [
|
|
1690
|
+
logicalKey,
|
|
1691
|
+
normalizeSpecRule(logicalKey, rule)
|
|
1692
|
+
])
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1543
1695
|
function normalizeManifest(manifest) {
|
|
1544
1696
|
const version = manifest.version ?? 1;
|
|
1545
1697
|
if (version !== 1) {
|
|
@@ -1637,7 +1789,7 @@ function normalizeManifest(manifest) {
|
|
|
1637
1789
|
}
|
|
1638
1790
|
}
|
|
1639
1791
|
},
|
|
1640
|
-
schema: manifest.schema
|
|
1792
|
+
schema: normalizeSchema(manifest.schema)
|
|
1641
1793
|
};
|
|
1642
1794
|
}
|
|
1643
1795
|
|
|
@@ -2271,6 +2423,13 @@ function enumMatches(value, allowed) {
|
|
|
2271
2423
|
const serialized = JSON.stringify(value);
|
|
2272
2424
|
return allowed.some((candidate) => JSON.stringify(candidate) === serialized);
|
|
2273
2425
|
}
|
|
2426
|
+
function testPattern(pattern, value) {
|
|
2427
|
+
try {
|
|
2428
|
+
return new RegExp(pattern).test(value);
|
|
2429
|
+
} catch {
|
|
2430
|
+
return false;
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2274
2433
|
function applySchemaRules(graph, schema) {
|
|
2275
2434
|
const nextEntries = new Map(graph.entries);
|
|
2276
2435
|
const issues = [];
|
|
@@ -2337,11 +2496,11 @@ function applySchemaRules(graph, schema) {
|
|
|
2337
2496
|
key,
|
|
2338
2497
|
message: `Config key ${key} must be a string to match pattern ${rule.pattern}`
|
|
2339
2498
|
});
|
|
2340
|
-
} else if (!
|
|
2499
|
+
} else if (!testPattern(rule.pattern, coercedValue)) {
|
|
2341
2500
|
issues.push({
|
|
2342
2501
|
code: "schema.pattern",
|
|
2343
2502
|
key,
|
|
2344
|
-
message: `Config key ${key} does not match pattern ${rule.pattern}
|
|
2503
|
+
message: `Config key ${key} does not match pattern ${rule.pattern} (or the pattern is invalid).`
|
|
2345
2504
|
});
|
|
2346
2505
|
}
|
|
2347
2506
|
}
|
|
@@ -2425,7 +2584,7 @@ function isObject(value) {
|
|
|
2425
2584
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2426
2585
|
}
|
|
2427
2586
|
function isSecretReference(value) {
|
|
2428
|
-
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));
|
|
2587
|
+
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));
|
|
2429
2588
|
}
|
|
2430
2589
|
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
2431
2590
|
return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
@@ -2741,16 +2900,19 @@ function resolveVaultDefinition(vaults, vault = "default") {
|
|
|
2741
2900
|
// ../core/src/secrets/auditLog.ts
|
|
2742
2901
|
async function appendAuditEvent(event, processEnv = process.env) {
|
|
2743
2902
|
const auditFile = processEnv.CNOS_AUDIT_FILE ?? import_node_path12.default.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2903
|
+
try {
|
|
2904
|
+
await (0, import_promises11.mkdir)(import_node_path12.default.dirname(auditFile), { recursive: true });
|
|
2905
|
+
await (0, import_promises11.appendFile)(
|
|
2906
|
+
auditFile,
|
|
2907
|
+
`${JSON.stringify({
|
|
2908
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2909
|
+
...event
|
|
2910
|
+
})}
|
|
2751
2911
|
`,
|
|
2752
|
-
|
|
2753
|
-
|
|
2912
|
+
"utf8"
|
|
2913
|
+
);
|
|
2914
|
+
} catch {
|
|
2915
|
+
}
|
|
2754
2916
|
}
|
|
2755
2917
|
|
|
2756
2918
|
// ../core/src/secrets/secretCache.ts
|
|
@@ -2769,6 +2931,23 @@ var SecretCache = class {
|
|
|
2769
2931
|
get(vaultId, ref) {
|
|
2770
2932
|
return this.cache.get(`${vaultId}:${ref}`);
|
|
2771
2933
|
}
|
|
2934
|
+
delete(vaultId, ref) {
|
|
2935
|
+
this.cache.delete(`${vaultId}:${ref}`);
|
|
2936
|
+
}
|
|
2937
|
+
replace(vaultId, secrets) {
|
|
2938
|
+
this.clear(vaultId);
|
|
2939
|
+
this.load(vaultId, secrets);
|
|
2940
|
+
}
|
|
2941
|
+
entriesForVault(vaultId) {
|
|
2942
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2943
|
+
for (const [key, value] of this.cache) {
|
|
2944
|
+
const prefix = `${vaultId}:`;
|
|
2945
|
+
if (key.startsWith(prefix)) {
|
|
2946
|
+
entries.set(key.slice(prefix.length), value);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
return entries;
|
|
2950
|
+
}
|
|
2772
2951
|
clear(vaultId) {
|
|
2773
2952
|
if (!vaultId) {
|
|
2774
2953
|
this.cache.clear();
|
|
@@ -2934,7 +3113,7 @@ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
|
|
|
2934
3113
|
};
|
|
2935
3114
|
|
|
2936
3115
|
// ../core/src/secrets/providers/registry.ts
|
|
2937
|
-
function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
3116
|
+
function createSecretVaultProvider(vaultId, definition, processEnv, factories = []) {
|
|
2938
3117
|
if (definition.provider === "local") {
|
|
2939
3118
|
return new LocalSecretVaultProvider(vaultId, definition, processEnv);
|
|
2940
3119
|
}
|
|
@@ -2944,9 +3123,30 @@ function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
|
2944
3123
|
if (definition.provider === "github-secrets") {
|
|
2945
3124
|
return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
|
|
2946
3125
|
}
|
|
3126
|
+
const factory = factories.find((candidate) => candidate.provider === definition.provider);
|
|
3127
|
+
if (factory) {
|
|
3128
|
+
return factory.create(vaultId, definition, processEnv);
|
|
3129
|
+
}
|
|
2947
3130
|
throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
|
|
2948
3131
|
}
|
|
2949
3132
|
|
|
3133
|
+
// ../core/src/secrets/providerCompatibility.ts
|
|
3134
|
+
function assertSecretRefVaultProviderCompatible(manifest, ref, logicalKey = "secret ref") {
|
|
3135
|
+
if (!ref.vault || !ref.provider) {
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
3138
|
+
const definition = manifest.vaults[ref.vault];
|
|
3139
|
+
if (!definition || definition.provider === ref.provider) {
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
throw new CnosManifestError(
|
|
3143
|
+
`Secret ref "${logicalKey}" declares provider "${ref.provider}" but vault "${ref.vault}" uses provider "${definition.provider}". Remove the ref provider or use a matching vault.`
|
|
3144
|
+
);
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
// ../core/src/secrets/resolveAuth.ts
|
|
3148
|
+
var import_promises12 = require("fs/promises");
|
|
3149
|
+
|
|
2950
3150
|
// ../core/src/secrets/prompt.ts
|
|
2951
3151
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
2952
3152
|
var import_node_stream = require("stream");
|
|
@@ -2987,6 +3187,23 @@ function toAuthError(vaultId, sources) {
|
|
|
2987
3187
|
`Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
|
|
2988
3188
|
);
|
|
2989
3189
|
}
|
|
3190
|
+
async function resolveTokenFromSource(source, processEnv) {
|
|
3191
|
+
if (source.startsWith("env:")) {
|
|
3192
|
+
return processEnv[source.slice(4)] || void 0;
|
|
3193
|
+
}
|
|
3194
|
+
if (source.startsWith("file:")) {
|
|
3195
|
+
try {
|
|
3196
|
+
const value = await (0, import_promises12.readFile)(expandHomePath(source.slice("file:".length)), "utf8");
|
|
3197
|
+
return value.trim() || void 0;
|
|
3198
|
+
} catch {
|
|
3199
|
+
return void 0;
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
if (source.startsWith("keychain:")) {
|
|
3203
|
+
return readKeychain(source.slice("keychain:".length));
|
|
3204
|
+
}
|
|
3205
|
+
return void 0;
|
|
3206
|
+
}
|
|
2990
3207
|
async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
2991
3208
|
const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
|
|
2992
3209
|
if (sessionKey) {
|
|
@@ -3002,6 +3219,32 @@ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
|
3002
3219
|
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3003
3220
|
};
|
|
3004
3221
|
}
|
|
3222
|
+
if (definition.auth?.method === "iam") {
|
|
3223
|
+
return {
|
|
3224
|
+
method: "iam",
|
|
3225
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3226
|
+
};
|
|
3227
|
+
}
|
|
3228
|
+
if (definition.auth?.method === "environment") {
|
|
3229
|
+
return {
|
|
3230
|
+
method: "environment",
|
|
3231
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3232
|
+
};
|
|
3233
|
+
}
|
|
3234
|
+
const tokenSources = definition.auth?.token?.from ?? [];
|
|
3235
|
+
for (const source of tokenSources) {
|
|
3236
|
+
const token = await resolveTokenFromSource(source, processEnv);
|
|
3237
|
+
if (token) {
|
|
3238
|
+
return {
|
|
3239
|
+
token,
|
|
3240
|
+
method: "token",
|
|
3241
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3242
|
+
};
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
if (definition.auth?.method === "token") {
|
|
3246
|
+
throw toAuthError(vaultId, [getVaultSessionKeyEnvVar(vaultId), ...tokenSources]);
|
|
3247
|
+
}
|
|
3005
3248
|
const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
|
|
3006
3249
|
for (const source of sources) {
|
|
3007
3250
|
if (source.startsWith("env:")) {
|
|
@@ -3053,22 +3296,76 @@ function collectSecretDescriptors(graph) {
|
|
|
3053
3296
|
ref: entry.value
|
|
3054
3297
|
}));
|
|
3055
3298
|
}
|
|
3056
|
-
|
|
3299
|
+
function secretGroupKey(manifest, descriptor) {
|
|
3300
|
+
assertSecretRefVaultProviderCompatible(manifest, descriptor.ref, descriptor.logicalKey);
|
|
3301
|
+
const vaultId = descriptor.ref.vault ?? "default";
|
|
3302
|
+
const provider = descriptor.ref.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3303
|
+
return `${vaultId}\0${provider}`;
|
|
3304
|
+
}
|
|
3305
|
+
function vaultDefinitionForRef(manifest, ref) {
|
|
3306
|
+
assertSecretRefVaultProviderCompatible(manifest, ref);
|
|
3307
|
+
const vaultId = ref.vault ?? "default";
|
|
3308
|
+
const base = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
|
|
3309
|
+
if (!ref.provider || ref.provider === base.provider) {
|
|
3310
|
+
return base;
|
|
3311
|
+
}
|
|
3312
|
+
return {
|
|
3313
|
+
...base,
|
|
3314
|
+
provider: ref.provider
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
async function resolveFromDefinition(vaultId, definition, refs, processEnv, factories) {
|
|
3318
|
+
const runtimeDefinition = {
|
|
3319
|
+
provider: definition.provider,
|
|
3320
|
+
...definition.auth ? { auth: definition.auth } : {},
|
|
3321
|
+
...definition.mapping ? { mapping: definition.mapping } : {}
|
|
3322
|
+
};
|
|
3323
|
+
const provider = createSecretVaultProvider(vaultId, runtimeDefinition, processEnv, factories);
|
|
3324
|
+
const auth = await resolveVaultAuth(vaultId, runtimeDefinition, processEnv);
|
|
3325
|
+
await provider.authenticate(auth);
|
|
3326
|
+
return provider.batchGet(refs.map((entry) => entry.ref.ref));
|
|
3327
|
+
}
|
|
3328
|
+
async function batchResolveSecrets(graph, manifest, processEnv = process.env, factories = []) {
|
|
3057
3329
|
const cache = new SecretCache();
|
|
3058
3330
|
const descriptors = collectSecretDescriptors(graph);
|
|
3059
3331
|
const grouped = descriptors.reduce((accumulator, descriptor) => {
|
|
3060
|
-
const
|
|
3061
|
-
const bucket = accumulator.get(
|
|
3332
|
+
const key = secretGroupKey(manifest, descriptor);
|
|
3333
|
+
const bucket = accumulator.get(key) ?? [];
|
|
3062
3334
|
bucket.push(descriptor);
|
|
3063
|
-
accumulator.set(
|
|
3335
|
+
accumulator.set(key, bucket);
|
|
3064
3336
|
return accumulator;
|
|
3065
3337
|
}, /* @__PURE__ */ new Map());
|
|
3066
|
-
for (const
|
|
3067
|
-
const
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
const
|
|
3338
|
+
for (const refs of grouped.values()) {
|
|
3339
|
+
const first = refs[0];
|
|
3340
|
+
if (!first) {
|
|
3341
|
+
continue;
|
|
3342
|
+
}
|
|
3343
|
+
const vaultId = first.ref.vault ?? "default";
|
|
3344
|
+
const definition = vaultDefinitionForRef(manifest, first.ref);
|
|
3345
|
+
const definitions = [definition, ...definition.fallback ?? []];
|
|
3346
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
3347
|
+
let remaining = refs;
|
|
3348
|
+
let lastError;
|
|
3349
|
+
for (const candidate of definitions) {
|
|
3350
|
+
try {
|
|
3351
|
+
const candidateValues = await resolveFromDefinition(vaultId, candidate, remaining, processEnv, factories);
|
|
3352
|
+
for (const descriptor of remaining) {
|
|
3353
|
+
const value = candidateValues.get(descriptor.ref.ref);
|
|
3354
|
+
if (value !== void 0) {
|
|
3355
|
+
resolved.set(descriptor.ref.ref, value);
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
remaining = remaining.filter((descriptor) => !resolved.has(descriptor.ref.ref));
|
|
3359
|
+
if (remaining.length === 0) {
|
|
3360
|
+
break;
|
|
3361
|
+
}
|
|
3362
|
+
} catch (error) {
|
|
3363
|
+
lastError = error;
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
if (resolved.size === 0 && lastError) {
|
|
3367
|
+
throw lastError;
|
|
3368
|
+
}
|
|
3072
3369
|
cache.load(vaultId, resolved);
|
|
3073
3370
|
await appendAuditEvent(
|
|
3074
3371
|
{
|
|
@@ -3089,7 +3386,11 @@ function resolveSecretEntryValue(key, value, cache) {
|
|
|
3089
3386
|
return value;
|
|
3090
3387
|
}
|
|
3091
3388
|
const vaultId = value.vault ?? "default";
|
|
3092
|
-
|
|
3389
|
+
const resolved = cache.get(vaultId, value.ref);
|
|
3390
|
+
if (resolved !== void 0 || cache.isVaultAuthenticated(vaultId)) {
|
|
3391
|
+
return resolved;
|
|
3392
|
+
}
|
|
3393
|
+
return value;
|
|
3093
3394
|
}
|
|
3094
3395
|
|
|
3095
3396
|
// ../core/src/runtime/projection.ts
|
|
@@ -3192,19 +3493,117 @@ function configHash(values) {
|
|
|
3192
3493
|
function shouldProjectResolvedValue(sourceId) {
|
|
3193
3494
|
return sourceId !== "process-env";
|
|
3194
3495
|
}
|
|
3496
|
+
var SAFE_PROJECTED_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
3497
|
+
"address",
|
|
3498
|
+
"audience",
|
|
3499
|
+
"clientid",
|
|
3500
|
+
"endpoint",
|
|
3501
|
+
"mount",
|
|
3502
|
+
"namespace",
|
|
3503
|
+
"path",
|
|
3504
|
+
"projectid",
|
|
3505
|
+
"region",
|
|
3506
|
+
"scope",
|
|
3507
|
+
"scopes",
|
|
3508
|
+
"serviceaccountemail",
|
|
3509
|
+
"tenant",
|
|
3510
|
+
"tenantid",
|
|
3511
|
+
"url",
|
|
3512
|
+
"version",
|
|
3513
|
+
"vaulturl"
|
|
3514
|
+
]);
|
|
3515
|
+
function isSafeProjectedConfigKey(key) {
|
|
3516
|
+
return SAFE_PROJECTED_CONFIG_KEYS.has(key.replace(/[^A-Za-z0-9]/g, "").toLowerCase());
|
|
3517
|
+
}
|
|
3518
|
+
function sanitizeProjectedConfigValue(value) {
|
|
3519
|
+
if (Array.isArray(value)) {
|
|
3520
|
+
return value.map((item) => sanitizeProjectedConfigValue(item));
|
|
3521
|
+
}
|
|
3522
|
+
if (!value || typeof value !== "object") {
|
|
3523
|
+
return value;
|
|
3524
|
+
}
|
|
3525
|
+
return stableSortObject(
|
|
3526
|
+
Object.fromEntries(
|
|
3527
|
+
Object.entries(value).map(([key, item]) => [key, sanitizeProjectedConfigValue(item)]).filter(([key, item]) => {
|
|
3528
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
3529
|
+
return Object.keys(item).length > 0;
|
|
3530
|
+
}
|
|
3531
|
+
return isSafeProjectedConfigKey(key);
|
|
3532
|
+
})
|
|
3533
|
+
)
|
|
3534
|
+
);
|
|
3535
|
+
}
|
|
3536
|
+
function sanitizeProjectedConfig(config) {
|
|
3537
|
+
const sanitized = sanitizeProjectedConfigValue(config);
|
|
3538
|
+
if (!sanitized || typeof sanitized !== "object" || Array.isArray(sanitized)) {
|
|
3539
|
+
return void 0;
|
|
3540
|
+
}
|
|
3541
|
+
return Object.keys(sanitized).length > 0 ? sanitized : void 0;
|
|
3542
|
+
}
|
|
3543
|
+
function projectVaultAuth(definition) {
|
|
3544
|
+
const auth = definition.auth;
|
|
3545
|
+
if (!auth) {
|
|
3546
|
+
return void 0;
|
|
3547
|
+
}
|
|
3548
|
+
const config = auth.config ? sanitizeProjectedConfig(auth.config) : void 0;
|
|
3549
|
+
const projected = {
|
|
3550
|
+
...auth.method ? { method: auth.method } : {},
|
|
3551
|
+
...auth.passphrase?.from ? {
|
|
3552
|
+
passphrase: {
|
|
3553
|
+
from: [...auth.passphrase.from]
|
|
3554
|
+
}
|
|
3555
|
+
} : {},
|
|
3556
|
+
...auth.token?.from ? {
|
|
3557
|
+
token: {
|
|
3558
|
+
from: [...auth.token.from]
|
|
3559
|
+
}
|
|
3560
|
+
} : {},
|
|
3561
|
+
...config ? { config } : {}
|
|
3562
|
+
};
|
|
3563
|
+
return Object.keys(projected).length > 0 ? projected : void 0;
|
|
3564
|
+
}
|
|
3565
|
+
function projectVaultDefinition(definition) {
|
|
3566
|
+
const auth = projectVaultAuth(definition);
|
|
3567
|
+
const mapping = definition.mapping ? stableSortObject(definition.mapping) : void 0;
|
|
3568
|
+
const fallback = definition.fallback?.map((entry) => projectVaultDefinition({
|
|
3569
|
+
provider: entry.provider,
|
|
3570
|
+
...entry.auth ? { auth: entry.auth } : {},
|
|
3571
|
+
...entry.mapping ? { mapping: entry.mapping } : {}
|
|
3572
|
+
}));
|
|
3573
|
+
return {
|
|
3574
|
+
provider: definition.provider,
|
|
3575
|
+
...auth ? { auth } : {},
|
|
3576
|
+
...mapping && Object.keys(mapping).length > 0 ? { mapping } : {},
|
|
3577
|
+
...fallback && fallback.length > 0 ? { fallback } : {}
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
function projectReferencedVaults(manifest, vaultIds) {
|
|
3581
|
+
const projected = {};
|
|
3582
|
+
for (const vaultId of Array.from(vaultIds).sort((left, right) => left.localeCompare(right))) {
|
|
3583
|
+
const definition = manifest.vaults[vaultId];
|
|
3584
|
+
if (definition) {
|
|
3585
|
+
projected[vaultId] = projectVaultDefinition(definition);
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
return Object.keys(projected).length > 0 ? projected : void 0;
|
|
3589
|
+
}
|
|
3195
3590
|
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
|
|
3196
3591
|
const values = {};
|
|
3197
3592
|
const derived = {};
|
|
3198
3593
|
const secretRefs = {};
|
|
3594
|
+
const referencedVaultIds = /* @__PURE__ */ new Set();
|
|
3199
3595
|
const namespaces = /* @__PURE__ */ new Set();
|
|
3200
3596
|
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
3201
3597
|
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));
|
|
3202
3598
|
for (const [key, entry] of graph.entries) {
|
|
3203
3599
|
if (entry.namespace === "secret" && isSecretReference(entry.value)) {
|
|
3600
|
+
assertSecretRefVaultProviderCompatible(manifest, entry.value, key);
|
|
3204
3601
|
const vaultId = entry.value.vault ?? "default";
|
|
3602
|
+
const provider = entry.value.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3205
3603
|
const envVar = resolveProjectedEnvVar(manifest, vaultId, entry.value.ref);
|
|
3604
|
+
referencedVaultIds.add(vaultId);
|
|
3206
3605
|
secretRefs[key.slice("secret.".length)] = {
|
|
3207
|
-
provider
|
|
3606
|
+
provider,
|
|
3208
3607
|
vault: vaultId,
|
|
3209
3608
|
ref: entry.value.ref,
|
|
3210
3609
|
...envVar ? {
|
|
@@ -3250,6 +3649,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3250
3649
|
namespaces.add(entry.namespace);
|
|
3251
3650
|
}
|
|
3252
3651
|
}
|
|
3652
|
+
const vaults = projectReferencedVaults(manifest, referencedVaultIds);
|
|
3253
3653
|
return {
|
|
3254
3654
|
version: 1,
|
|
3255
3655
|
workspace: graph.workspace.workspaceId,
|
|
@@ -3259,6 +3659,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3259
3659
|
values: stableSortObject(values),
|
|
3260
3660
|
derived: stableSortObject(derived),
|
|
3261
3661
|
secretRefs: stableSortObject(secretRefs),
|
|
3662
|
+
...vaults ? { vaults } : {},
|
|
3262
3663
|
publicKeys,
|
|
3263
3664
|
runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
|
|
3264
3665
|
meta: {
|
|
@@ -3373,9 +3774,10 @@ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
|
|
|
3373
3774
|
}
|
|
3374
3775
|
|
|
3375
3776
|
// ../core/src/orchestrator/runtime.ts
|
|
3376
|
-
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
|
|
3777
|
+
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev", secretVaultProviders = []) {
|
|
3377
3778
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
|
|
3378
3779
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
3780
|
+
let activeSecretCache = secretCache;
|
|
3379
3781
|
function resolveProjectedSourceKey(key) {
|
|
3380
3782
|
if (!key.startsWith("public.")) {
|
|
3381
3783
|
return key;
|
|
@@ -3392,30 +3794,38 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3392
3794
|
if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
|
|
3393
3795
|
return;
|
|
3394
3796
|
}
|
|
3395
|
-
if (!
|
|
3797
|
+
if (!activeSecretCache) {
|
|
3396
3798
|
return;
|
|
3397
3799
|
}
|
|
3398
3800
|
const vaultId = entry.value.vault ?? "default";
|
|
3399
|
-
const
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3801
|
+
const refreshed = await batchResolveSecrets(
|
|
3802
|
+
{
|
|
3803
|
+
...graph,
|
|
3804
|
+
entries: /* @__PURE__ */ new Map([[key, entry]])
|
|
3805
|
+
},
|
|
3806
|
+
manifest,
|
|
3807
|
+
processEnv,
|
|
3808
|
+
secretVaultProviders
|
|
3809
|
+
);
|
|
3810
|
+
const resolved = refreshed.get(vaultId, entry.value.ref);
|
|
3811
|
+
const existing = activeSecretCache.entriesForVault(vaultId);
|
|
3812
|
+
existing.delete(entry.value.ref);
|
|
3813
|
+
if (resolved !== void 0) {
|
|
3814
|
+
existing.set(entry.value.ref, resolved);
|
|
3409
3815
|
}
|
|
3816
|
+
activeSecretCache.replace(vaultId, existing);
|
|
3410
3817
|
}
|
|
3411
3818
|
async function refreshAllSecrets() {
|
|
3412
|
-
if (!
|
|
3819
|
+
if (!activeSecretCache) {
|
|
3413
3820
|
return;
|
|
3414
3821
|
}
|
|
3415
|
-
const
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3822
|
+
const refreshed = await batchResolveSecrets(
|
|
3823
|
+
graph,
|
|
3824
|
+
manifest,
|
|
3825
|
+
processEnv,
|
|
3826
|
+
secretVaultProviders
|
|
3827
|
+
);
|
|
3828
|
+
activeSecretCache = refreshed;
|
|
3419
3829
|
}
|
|
3420
3830
|
function readLogicalKey2(key) {
|
|
3421
3831
|
const resolved = derivedSupport.read(key, (ref) => {
|
|
@@ -3423,10 +3833,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3423
3833
|
if (!entry2) {
|
|
3424
3834
|
return void 0;
|
|
3425
3835
|
}
|
|
3426
|
-
if (!
|
|
3836
|
+
if (!activeSecretCache) {
|
|
3427
3837
|
return entry2.value;
|
|
3428
3838
|
}
|
|
3429
|
-
return resolveSecretEntryValue(ref, entry2.value,
|
|
3839
|
+
return resolveSecretEntryValue(ref, entry2.value, activeSecretCache);
|
|
3430
3840
|
});
|
|
3431
3841
|
if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
|
|
3432
3842
|
return resolved;
|
|
@@ -3435,10 +3845,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3435
3845
|
if (!entry) {
|
|
3436
3846
|
return void 0;
|
|
3437
3847
|
}
|
|
3438
|
-
if (!
|
|
3848
|
+
if (!activeSecretCache) {
|
|
3439
3849
|
return entry.value;
|
|
3440
3850
|
}
|
|
3441
|
-
return resolveSecretEntryValue(key, entry.value,
|
|
3851
|
+
return resolveSecretEntryValue(key, entry.value, activeSecretCache);
|
|
3442
3852
|
}
|
|
3443
3853
|
return {
|
|
3444
3854
|
manifest,
|
|
@@ -3475,10 +3885,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3475
3885
|
if (!entry) {
|
|
3476
3886
|
return void 0;
|
|
3477
3887
|
}
|
|
3478
|
-
if (!
|
|
3888
|
+
if (!activeSecretCache) {
|
|
3479
3889
|
return entry.value;
|
|
3480
3890
|
}
|
|
3481
|
-
return resolveSecretEntryValue(candidate, entry.value,
|
|
3891
|
+
return resolveSecretEntryValue(candidate, entry.value, activeSecretCache);
|
|
3482
3892
|
})
|
|
3483
3893
|
});
|
|
3484
3894
|
},
|
|
@@ -3669,7 +4079,12 @@ async function createCnos(options = {}) {
|
|
|
3669
4079
|
});
|
|
3670
4080
|
const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
|
|
3671
4081
|
const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
|
|
3672
|
-
const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
|
|
4082
|
+
const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
|
|
4083
|
+
promotedGraph,
|
|
4084
|
+
loadedManifest.manifest,
|
|
4085
|
+
options.processEnv,
|
|
4086
|
+
options.secretVaultProviders
|
|
4087
|
+
);
|
|
3673
4088
|
return createRuntime(
|
|
3674
4089
|
loadedManifest.manifest,
|
|
3675
4090
|
appendMetaEntries({
|
|
@@ -3679,12 +4094,13 @@ async function createCnos(options = {}) {
|
|
|
3679
4094
|
plugins,
|
|
3680
4095
|
secretCache,
|
|
3681
4096
|
options.processEnv,
|
|
3682
|
-
options.cnosVersion
|
|
4097
|
+
options.cnosVersion,
|
|
4098
|
+
options.secretVaultProviders
|
|
3683
4099
|
);
|
|
3684
4100
|
}
|
|
3685
4101
|
|
|
3686
4102
|
// ../core/src/runtime/dump.ts
|
|
3687
|
-
var
|
|
4103
|
+
var import_promises13 = require("fs/promises");
|
|
3688
4104
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
3689
4105
|
|
|
3690
4106
|
// ../core/src/utils/envNaming.ts
|
|
@@ -3722,7 +4138,7 @@ function envVarToLogicalKey(envVar, config = {}) {
|
|
|
3722
4138
|
// package.json
|
|
3723
4139
|
var package_default = {
|
|
3724
4140
|
name: "@kitsy/cnos",
|
|
3725
|
-
version: "1.
|
|
4141
|
+
version: "1.11.0",
|
|
3726
4142
|
description: "Batteries-included CNOS runtime package wired with the official plugins.",
|
|
3727
4143
|
type: "module",
|
|
3728
4144
|
main: "./dist/index.cjs",
|
|
@@ -3921,15 +4337,36 @@ function createCliArgsPlugin() {
|
|
|
3921
4337
|
}
|
|
3922
4338
|
|
|
3923
4339
|
// ../../plugins/dotenv/src/index.ts
|
|
3924
|
-
var
|
|
4340
|
+
var import_promises14 = require("fs/promises");
|
|
3925
4341
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
3926
4342
|
var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
|
|
3927
4343
|
function parseDoubleQuoted(value) {
|
|
3928
4344
|
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
3929
4345
|
}
|
|
4346
|
+
function isEscapedCharacter(value, index) {
|
|
4347
|
+
let slashCount = 0;
|
|
4348
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
4349
|
+
slashCount += 1;
|
|
4350
|
+
}
|
|
4351
|
+
return slashCount % 2 === 1;
|
|
4352
|
+
}
|
|
4353
|
+
function findClosingQuote(value, quote) {
|
|
4354
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
4355
|
+
if (value[index] !== quote) {
|
|
4356
|
+
continue;
|
|
4357
|
+
}
|
|
4358
|
+
if (quote === '"' && isEscapedCharacter(value, index)) {
|
|
4359
|
+
continue;
|
|
4360
|
+
}
|
|
4361
|
+
return index;
|
|
4362
|
+
}
|
|
4363
|
+
return -1;
|
|
4364
|
+
}
|
|
3930
4365
|
function parseDotenv(document) {
|
|
3931
4366
|
const parsed = {};
|
|
3932
|
-
|
|
4367
|
+
const lines = document.split(/\r?\n/);
|
|
4368
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4369
|
+
const rawLine = lines[lineIndex] ?? "";
|
|
3933
4370
|
const line = rawLine.trim();
|
|
3934
4371
|
if (!line || line.startsWith("#")) {
|
|
3935
4372
|
continue;
|
|
@@ -3944,10 +4381,18 @@ function parseDotenv(document) {
|
|
|
3944
4381
|
if (!envVar) {
|
|
3945
4382
|
continue;
|
|
3946
4383
|
}
|
|
3947
|
-
if (value.startsWith('"')
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
4384
|
+
if (value.startsWith('"') || value.startsWith("'")) {
|
|
4385
|
+
const quote = value.startsWith('"') ? '"' : "'";
|
|
4386
|
+
let quotedContent = value.slice(1);
|
|
4387
|
+
let closingIndex = findClosingQuote(quotedContent, quote);
|
|
4388
|
+
while (closingIndex === -1 && lineIndex < lines.length - 1) {
|
|
4389
|
+
lineIndex += 1;
|
|
4390
|
+
quotedContent = `${quotedContent}
|
|
4391
|
+
${lines[lineIndex] ?? ""}`;
|
|
4392
|
+
closingIndex = findClosingQuote(quotedContent, quote);
|
|
4393
|
+
}
|
|
4394
|
+
const rawQuotedValue = closingIndex === -1 ? quotedContent : quotedContent.slice(0, closingIndex);
|
|
4395
|
+
value = quote === '"' ? parseDoubleQuoted(rawQuotedValue) : rawQuotedValue;
|
|
3951
4396
|
} else {
|
|
3952
4397
|
value = value.replace(/\s+#.*$/, "").trim();
|
|
3953
4398
|
}
|
|
@@ -3979,7 +4424,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
|
|
|
3979
4424
|
}
|
|
3980
4425
|
async function readIfPresent(filePath) {
|
|
3981
4426
|
try {
|
|
3982
|
-
return await (0,
|
|
4427
|
+
return await (0, import_promises14.readFile)(filePath, "utf8");
|
|
3983
4428
|
} catch {
|
|
3984
4429
|
return void 0;
|
|
3985
4430
|
}
|
|
@@ -4045,16 +4490,16 @@ function createPublicEnvExportPlugin() {
|
|
|
4045
4490
|
}
|
|
4046
4491
|
|
|
4047
4492
|
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
4048
|
-
var
|
|
4493
|
+
var import_promises16 = require("fs/promises");
|
|
4049
4494
|
|
|
4050
4495
|
// ../../plugins/filesystem/src/helpers.ts
|
|
4051
|
-
var
|
|
4496
|
+
var import_promises15 = require("fs/promises");
|
|
4052
4497
|
var import_node_path15 = __toESM(require("path"), 1);
|
|
4053
4498
|
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
|
|
4054
4499
|
var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
|
|
4055
4500
|
async function existsDirectory(targetPath) {
|
|
4056
4501
|
try {
|
|
4057
|
-
const stat2 = await (0,
|
|
4502
|
+
const stat2 = await (0, import_promises15.readdir)(targetPath);
|
|
4058
4503
|
void stat2;
|
|
4059
4504
|
return true;
|
|
4060
4505
|
} catch {
|
|
@@ -4062,7 +4507,7 @@ async function existsDirectory(targetPath) {
|
|
|
4062
4507
|
}
|
|
4063
4508
|
}
|
|
4064
4509
|
async function collectYamlFiles(root) {
|
|
4065
|
-
const entries = await (0,
|
|
4510
|
+
const entries = await (0, import_promises15.readdir)(root, { withFileTypes: true });
|
|
4066
4511
|
const results = [];
|
|
4067
4512
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
4068
4513
|
const absolutePath = import_node_path15.default.join(root, entry.name);
|
|
@@ -4164,7 +4609,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4164
4609
|
);
|
|
4165
4610
|
const entries = [];
|
|
4166
4611
|
for (const file of files) {
|
|
4167
|
-
const document = await (0,
|
|
4612
|
+
const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
|
|
4168
4613
|
const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
|
|
4169
4614
|
for (const entry of fileEntries) {
|
|
4170
4615
|
const metadata = toSecretReferenceMetadata(entry.value);
|
|
@@ -4180,7 +4625,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4180
4625
|
}
|
|
4181
4626
|
|
|
4182
4627
|
// ../../plugins/filesystem/src/filesystemValuesReader.ts
|
|
4183
|
-
var
|
|
4628
|
+
var import_promises17 = require("fs/promises");
|
|
4184
4629
|
function filesystemValuesReader(filePath, document, workspaceId = "default") {
|
|
4185
4630
|
return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
|
|
4186
4631
|
}
|
|
@@ -4201,7 +4646,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4201
4646
|
).map(([namespace]) => namespace);
|
|
4202
4647
|
const entries = [];
|
|
4203
4648
|
for (const file of files) {
|
|
4204
|
-
const document = await (0,
|
|
4649
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4205
4650
|
entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
|
|
4206
4651
|
}
|
|
4207
4652
|
for (const namespace of customNamespaces) {
|
|
@@ -4216,7 +4661,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4216
4661
|
layers
|
|
4217
4662
|
);
|
|
4218
4663
|
for (const file of namespaceFiles) {
|
|
4219
|
-
const document = await (0,
|
|
4664
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4220
4665
|
entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
|
|
4221
4666
|
}
|
|
4222
4667
|
}
|
|
@@ -4472,6 +4917,19 @@ function graphRequiresSecretHydration(graph) {
|
|
|
4472
4917
|
|
|
4473
4918
|
// src/runtime/index.ts
|
|
4474
4919
|
var NOT_READY_MESSAGE = "CNOS not initialized. Call await cnos.ready() or use cnos run.";
|
|
4920
|
+
var bootstrappedProjection;
|
|
4921
|
+
var singletonRuntimeProviders = /* @__PURE__ */ new Map();
|
|
4922
|
+
var singletonSecretVaultProviders = /* @__PURE__ */ new Map();
|
|
4923
|
+
function registerSingletonSecretVaultProvider(factory) {
|
|
4924
|
+
singletonSecretVaultProviders.set(factory.provider, factory);
|
|
4925
|
+
}
|
|
4926
|
+
function mergeSecretVaultProviders(factories = []) {
|
|
4927
|
+
const merged = new Map(singletonSecretVaultProviders);
|
|
4928
|
+
for (const factory of factories) {
|
|
4929
|
+
merged.set(factory.provider, factory);
|
|
4930
|
+
}
|
|
4931
|
+
return Array.from(merged.values());
|
|
4932
|
+
}
|
|
4475
4933
|
function getRuntimeOrThrow() {
|
|
4476
4934
|
const runtime = getSingletonRuntime();
|
|
4477
4935
|
if (!runtime) {
|
|
@@ -4535,6 +4993,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4535
4993
|
if (getSingletonRuntime()) {
|
|
4536
4994
|
return;
|
|
4537
4995
|
}
|
|
4996
|
+
bootstrappedProjection = void 0;
|
|
4538
4997
|
const bootstrappedManifest = {
|
|
4539
4998
|
version: 1,
|
|
4540
4999
|
project: {
|
|
@@ -4605,6 +5064,9 @@ function attachBootstrappedGraph(graph) {
|
|
|
4605
5064
|
schema: {}
|
|
4606
5065
|
};
|
|
4607
5066
|
const runtimeProviders = createDefaultRuntimeProviders(bootstrappedManifest, process.env);
|
|
5067
|
+
for (const [namespace, provider] of singletonRuntimeProviders) {
|
|
5068
|
+
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
5069
|
+
}
|
|
4608
5070
|
const derivedSupport = createDerivedRuntimeSupport(graph, bootstrappedManifest, runtimeProviders);
|
|
4609
5071
|
const resolveProjectedSourceKey = (key) => {
|
|
4610
5072
|
if (!key.startsWith("public.")) {
|
|
@@ -4673,6 +5135,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4673
5135
|
},
|
|
4674
5136
|
registerRuntimeProvider(namespace, provider) {
|
|
4675
5137
|
registerRuntimeProvider(bootstrappedManifest, runtimeProviders, namespace, provider);
|
|
5138
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
4676
5139
|
},
|
|
4677
5140
|
async refreshSecrets() {
|
|
4678
5141
|
return;
|
|
@@ -4684,7 +5147,7 @@ function attachBootstrappedGraph(graph) {
|
|
|
4684
5147
|
setSingletonRuntime(runtime);
|
|
4685
5148
|
setBootstrappedSecretHydrationRequired(graphRequiresSecretHydration(graph));
|
|
4686
5149
|
}
|
|
4687
|
-
function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
5150
|
+
function toBootstrappedManifest(graph, runtimeNamespaces = [], vaults = {}) {
|
|
4688
5151
|
return {
|
|
4689
5152
|
version: 1,
|
|
4690
5153
|
project: {
|
|
@@ -4745,7 +5208,7 @@ function toBootstrappedManifest(graph, runtimeNamespaces = []) {
|
|
|
4745
5208
|
])
|
|
4746
5209
|
)
|
|
4747
5210
|
},
|
|
4748
|
-
vaults
|
|
5211
|
+
vaults,
|
|
4749
5212
|
writePolicy: {
|
|
4750
5213
|
define: {
|
|
4751
5214
|
defaultProfile: graph.profile,
|
|
@@ -4880,14 +5343,34 @@ function graphFromProjection(projection) {
|
|
|
4880
5343
|
}
|
|
4881
5344
|
};
|
|
4882
5345
|
}
|
|
4883
|
-
function
|
|
5346
|
+
function vaultDefinitionFromProjection(manifest, projection, key, ref) {
|
|
5347
|
+
assertSecretRefVaultProviderCompatible(manifest, ref, key);
|
|
5348
|
+
const vaultId = ref.vault ?? "default";
|
|
5349
|
+
const projected = projection.vaults?.[vaultId];
|
|
5350
|
+
const mapping = {
|
|
5351
|
+
...projected?.mapping ?? {},
|
|
5352
|
+
...ref.envVar ? { [ref.envVar]: ref.ref } : {}
|
|
5353
|
+
};
|
|
5354
|
+
return {
|
|
5355
|
+
provider: projected?.provider ?? ref.provider ?? "local",
|
|
5356
|
+
...projected?.auth ? { auth: projected.auth } : {},
|
|
5357
|
+
...Object.keys(mapping).length > 0 ? { mapping } : {},
|
|
5358
|
+
...projected?.fallback ? { fallback: projected.fallback } : {}
|
|
5359
|
+
};
|
|
5360
|
+
}
|
|
5361
|
+
function attachBootstrappedProjection(projection, force = false, options = {}) {
|
|
4884
5362
|
if (getSingletonRuntime() && !force) {
|
|
4885
5363
|
return;
|
|
4886
5364
|
}
|
|
5365
|
+
bootstrappedProjection = projection;
|
|
4887
5366
|
const graph = graphFromProjection(projection);
|
|
4888
|
-
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces);
|
|
5367
|
+
const manifest = toBootstrappedManifest(graph, projection.runtimeNamespaces, projection.vaults ?? {});
|
|
4889
5368
|
const hydratedSecrets = /* @__PURE__ */ new Map();
|
|
5369
|
+
const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
|
|
4890
5370
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, process.env);
|
|
5371
|
+
for (const [namespace, provider] of singletonRuntimeProviders) {
|
|
5372
|
+
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
5373
|
+
}
|
|
4891
5374
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
4892
5375
|
const resolveProjectedSourceKey = (key) => {
|
|
4893
5376
|
if (!key.startsWith("public.")) {
|
|
@@ -4900,32 +5383,95 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
4900
5383
|
const fallback = `value.${key.slice("public.".length)}`;
|
|
4901
5384
|
return graph.entries.has(fallback) ? fallback : key;
|
|
4902
5385
|
};
|
|
4903
|
-
const
|
|
5386
|
+
const projectedDescriptorForKey = (key) => {
|
|
4904
5387
|
const entry = graph.entries.get(key);
|
|
4905
5388
|
if (!entry || entry.namespace !== "secret") {
|
|
4906
|
-
return
|
|
4907
|
-
}
|
|
4908
|
-
if (hydratedSecrets.has(key)) {
|
|
4909
|
-
return hydratedSecrets.get(key);
|
|
5389
|
+
return void 0;
|
|
4910
5390
|
}
|
|
4911
5391
|
const ref = projection.secretRefs[key.slice("secret.".length)];
|
|
4912
5392
|
if (!ref) {
|
|
4913
5393
|
return void 0;
|
|
4914
5394
|
}
|
|
4915
|
-
const definition =
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
} : {}
|
|
5395
|
+
const definition = vaultDefinitionFromProjection(manifest, projection, key, ref);
|
|
5396
|
+
return {
|
|
5397
|
+
key,
|
|
5398
|
+
ref,
|
|
5399
|
+
vaultId: ref.vault ?? "default",
|
|
5400
|
+
definitions: [definition, ...definition.fallback ?? []]
|
|
4922
5401
|
};
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
5402
|
+
};
|
|
5403
|
+
const runtimeDefinitionForCandidate = (candidate) => ({
|
|
5404
|
+
provider: candidate.provider,
|
|
5405
|
+
...candidate.auth ? { auth: candidate.auth } : {},
|
|
5406
|
+
...candidate.mapping ? { mapping: candidate.mapping } : {}
|
|
5407
|
+
});
|
|
5408
|
+
const hydrateProjectedSecrets = async (keys) => {
|
|
5409
|
+
const requestedKeys = keys ?? Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
|
|
5410
|
+
let remaining = requestedKeys.filter((key) => !hydratedSecrets.has(key)).map((key) => projectedDescriptorForKey(key)).filter((descriptor) => Boolean(descriptor));
|
|
5411
|
+
const lastErrors = /* @__PURE__ */ new Map();
|
|
5412
|
+
let candidateIndex = 0;
|
|
5413
|
+
while (remaining.length > 0) {
|
|
5414
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
5415
|
+
const exhausted = [];
|
|
5416
|
+
for (const descriptor of remaining) {
|
|
5417
|
+
const candidate = descriptor.definitions[candidateIndex];
|
|
5418
|
+
if (!candidate) {
|
|
5419
|
+
exhausted.push(descriptor);
|
|
5420
|
+
continue;
|
|
5421
|
+
}
|
|
5422
|
+
const groupKey = `${descriptor.vaultId}\0${candidate.provider}`;
|
|
5423
|
+
const group = grouped.get(groupKey) ?? {
|
|
5424
|
+
vaultId: descriptor.vaultId,
|
|
5425
|
+
definition: candidate,
|
|
5426
|
+
descriptors: []
|
|
5427
|
+
};
|
|
5428
|
+
group.descriptors.push(descriptor);
|
|
5429
|
+
grouped.set(groupKey, group);
|
|
5430
|
+
}
|
|
5431
|
+
if (grouped.size === 0) {
|
|
5432
|
+
remaining = exhausted;
|
|
5433
|
+
break;
|
|
5434
|
+
}
|
|
5435
|
+
const unresolved = [...exhausted];
|
|
5436
|
+
for (const group of grouped.values()) {
|
|
5437
|
+
const runtimeDefinition = runtimeDefinitionForCandidate(group.definition);
|
|
5438
|
+
try {
|
|
5439
|
+
const provider = createSecretVaultProvider(
|
|
5440
|
+
group.vaultId,
|
|
5441
|
+
runtimeDefinition,
|
|
5442
|
+
process.env,
|
|
5443
|
+
secretVaultProviders
|
|
5444
|
+
);
|
|
5445
|
+
const auth = await resolveVaultAuth(group.vaultId, runtimeDefinition, process.env);
|
|
5446
|
+
await provider.authenticate(auth);
|
|
5447
|
+
const refs = Array.from(new Set(group.descriptors.map((descriptor) => descriptor.ref.ref))).sort((left, right) => left.localeCompare(right));
|
|
5448
|
+
const values = await provider.batchGet(refs);
|
|
5449
|
+
for (const descriptor of group.descriptors) {
|
|
5450
|
+
const value = values.get(descriptor.ref.ref);
|
|
5451
|
+
if (value !== void 0) {
|
|
5452
|
+
hydratedSecrets.set(descriptor.key, value);
|
|
5453
|
+
lastErrors.delete(descriptor.key);
|
|
5454
|
+
} else {
|
|
5455
|
+
unresolved.push(descriptor);
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
} catch (error) {
|
|
5459
|
+
for (const descriptor of group.descriptors) {
|
|
5460
|
+
lastErrors.set(descriptor.key, error);
|
|
5461
|
+
unresolved.push(descriptor);
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
remaining = unresolved.filter((descriptor) => !hydratedSecrets.has(descriptor.key));
|
|
5466
|
+
candidateIndex += 1;
|
|
5467
|
+
}
|
|
5468
|
+
for (const descriptor of remaining) {
|
|
5469
|
+
const error = lastErrors.get(descriptor.key);
|
|
5470
|
+
if (error) {
|
|
5471
|
+
throw error;
|
|
5472
|
+
}
|
|
5473
|
+
hydratedSecrets.set(descriptor.key, void 0);
|
|
5474
|
+
}
|
|
4929
5475
|
};
|
|
4930
5476
|
const runtime = {
|
|
4931
5477
|
manifest,
|
|
@@ -4995,14 +5541,14 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
4995
5541
|
toNamespace(namespace) {
|
|
4996
5542
|
return toNamespaceObject(graph, namespace, (key) => this.read(key));
|
|
4997
5543
|
},
|
|
4998
|
-
toEnv(
|
|
4999
|
-
return toEnv(graph, manifest,
|
|
5544
|
+
toEnv(options2) {
|
|
5545
|
+
return toEnv(graph, manifest, options2, {
|
|
5000
5546
|
read: (key) => this.read(key),
|
|
5001
5547
|
isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
|
|
5002
5548
|
});
|
|
5003
5549
|
},
|
|
5004
|
-
toPublicEnv(
|
|
5005
|
-
return toPublicEnv(graph, manifest,
|
|
5550
|
+
toPublicEnv(options2) {
|
|
5551
|
+
return toPublicEnv(graph, manifest, options2, {
|
|
5006
5552
|
read: (key) => derivedSupport.toConcreteValue(
|
|
5007
5553
|
resolveProjectedSourceKey(key),
|
|
5008
5554
|
(ref) => {
|
|
@@ -5025,16 +5571,18 @@ function attachBootstrappedProjection(projection, force = false) {
|
|
|
5025
5571
|
},
|
|
5026
5572
|
registerRuntimeProvider(namespace, provider) {
|
|
5027
5573
|
registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
|
|
5574
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
5028
5575
|
},
|
|
5029
5576
|
async refreshSecrets() {
|
|
5030
|
-
|
|
5577
|
+
const keys = Object.keys(projection.secretRefs).map((segment) => `secret.${segment}`);
|
|
5578
|
+
for (const key of keys) {
|
|
5031
5579
|
hydratedSecrets.delete(key);
|
|
5032
|
-
await resolveSecretValue(key);
|
|
5033
5580
|
}
|
|
5581
|
+
await hydrateProjectedSecrets(keys);
|
|
5034
5582
|
},
|
|
5035
5583
|
async refreshSecret(key) {
|
|
5036
5584
|
hydratedSecrets.delete(key);
|
|
5037
|
-
await
|
|
5585
|
+
await hydrateProjectedSecrets([key]);
|
|
5038
5586
|
}
|
|
5039
5587
|
};
|
|
5040
5588
|
setSingletonRuntime(runtime);
|
|
@@ -5141,14 +5689,23 @@ var cnos = Object.assign(
|
|
|
5141
5689
|
console.log(formatted);
|
|
5142
5690
|
return formatted;
|
|
5143
5691
|
},
|
|
5144
|
-
async loadProjection(source) {
|
|
5692
|
+
async loadProjection(source, options = {}) {
|
|
5145
5693
|
const resolvedSource = import_node_path16.default.resolve(source);
|
|
5146
5694
|
const projection = deserializeServerProjection((0, import_node_fs.readFileSync)(resolvedSource, "utf8"));
|
|
5147
|
-
attachBootstrappedProjection(projection, true);
|
|
5695
|
+
attachBootstrappedProjection(projection, true, options);
|
|
5148
5696
|
setBootstrappedSecretHydrationRequired(Object.keys(projection.secretRefs).length > 0);
|
|
5149
5697
|
},
|
|
5150
5698
|
registerRuntimeProvider(namespace, provider) {
|
|
5151
5699
|
getRuntimeOrThrow().registerRuntimeProvider(namespace, provider);
|
|
5700
|
+
singletonRuntimeProviders.set(namespace, provider);
|
|
5701
|
+
},
|
|
5702
|
+
registerSecretVaultProvider(factory) {
|
|
5703
|
+
registerSingletonSecretVaultProvider(factory);
|
|
5704
|
+
},
|
|
5705
|
+
registerSecretVaultProviders(factories) {
|
|
5706
|
+
for (const factory of factories) {
|
|
5707
|
+
registerSingletonSecretVaultProvider(factory);
|
|
5708
|
+
}
|
|
5152
5709
|
},
|
|
5153
5710
|
async refreshSecrets() {
|
|
5154
5711
|
await getRuntimeOrThrow().refreshSecrets();
|
|
@@ -5157,10 +5714,14 @@ var cnos = Object.assign(
|
|
|
5157
5714
|
async refreshSecret(key) {
|
|
5158
5715
|
await getRuntimeOrThrow().refreshSecret(key);
|
|
5159
5716
|
},
|
|
5160
|
-
async ready() {
|
|
5717
|
+
async ready(options = {}) {
|
|
5161
5718
|
const runtime = getSingletonRuntime();
|
|
5719
|
+
const secretVaultProviders = mergeSecretVaultProviders(options.secretVaultProviders);
|
|
5162
5720
|
if (runtime && getBootstrappedSecretHydrationRequired()) {
|
|
5163
|
-
|
|
5721
|
+
const runtimeToHydrate = bootstrappedProjection && secretVaultProviders.length > 0 ? (attachBootstrappedProjection(bootstrappedProjection, true, {
|
|
5722
|
+
secretVaultProviders
|
|
5723
|
+
}), getRuntimeOrThrow()) : runtime;
|
|
5724
|
+
await runtimeToHydrate.refreshSecrets();
|
|
5164
5725
|
setBootstrappedSecretHydrationRequired(false);
|
|
5165
5726
|
return;
|
|
5166
5727
|
}
|
|
@@ -5172,7 +5733,10 @@ var cnos = Object.assign(
|
|
|
5172
5733
|
await existing;
|
|
5173
5734
|
return;
|
|
5174
5735
|
}
|
|
5175
|
-
const readyPromise = createCnos2(
|
|
5736
|
+
const readyPromise = createCnos2({
|
|
5737
|
+
...options,
|
|
5738
|
+
secretVaultProviders
|
|
5739
|
+
}).then((runtime2) => {
|
|
5176
5740
|
setSingletonRuntime(runtime2);
|
|
5177
5741
|
setBootstrappedSecretHydrationRequired(false);
|
|
5178
5742
|
return runtime2;
|