@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/build/index.cjs
CHANGED
|
@@ -1340,6 +1340,134 @@ function stripNamespace(key) {
|
|
|
1340
1340
|
return key.split(".").slice(1).join(".");
|
|
1341
1341
|
}
|
|
1342
1342
|
|
|
1343
|
+
// ../core/src/spec/normalizeSpecRule.ts
|
|
1344
|
+
var ALLOWED_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "object", "array"]);
|
|
1345
|
+
var SECRET_FORBIDDEN_FIELDS = ["default", "examples", "enum"];
|
|
1346
|
+
function hasOwn(target, key) {
|
|
1347
|
+
return Object.prototype.hasOwnProperty.call(target, key);
|
|
1348
|
+
}
|
|
1349
|
+
function normalizeOptionalString(value, fieldName, logicalKey) {
|
|
1350
|
+
if (value === void 0) {
|
|
1351
|
+
return void 0;
|
|
1352
|
+
}
|
|
1353
|
+
if (typeof value !== "string") {
|
|
1354
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be a string.`);
|
|
1355
|
+
}
|
|
1356
|
+
const nextValue = value.trim();
|
|
1357
|
+
return nextValue.length > 0 ? nextValue : void 0;
|
|
1358
|
+
}
|
|
1359
|
+
function normalizeStringArray(value, fieldName, logicalKey) {
|
|
1360
|
+
if (value === void 0) {
|
|
1361
|
+
return void 0;
|
|
1362
|
+
}
|
|
1363
|
+
if (!Array.isArray(value)) {
|
|
1364
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be an array.`);
|
|
1365
|
+
}
|
|
1366
|
+
const nextValue = value.map((entry) => {
|
|
1367
|
+
if (typeof entry !== "string") {
|
|
1368
|
+
throw new CnosManifestError(
|
|
1369
|
+
`Invalid schema rule for ${logicalKey}: "${fieldName}" entries must be strings.`
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
return entry.trim();
|
|
1373
|
+
}).filter(Boolean);
|
|
1374
|
+
return nextValue.length > 0 ? nextValue : void 0;
|
|
1375
|
+
}
|
|
1376
|
+
function normalizeUnknownArray(value, fieldName, logicalKey) {
|
|
1377
|
+
if (value === void 0) {
|
|
1378
|
+
return void 0;
|
|
1379
|
+
}
|
|
1380
|
+
if (!Array.isArray(value)) {
|
|
1381
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "${fieldName}" must be an array.`);
|
|
1382
|
+
}
|
|
1383
|
+
return value.length > 0 ? value : void 0;
|
|
1384
|
+
}
|
|
1385
|
+
function assertValidPatternRegex(pattern, logicalKey) {
|
|
1386
|
+
try {
|
|
1387
|
+
void new RegExp(pattern);
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1390
|
+
throw new CnosManifestError(
|
|
1391
|
+
`Invalid schema rule for ${logicalKey}: "pattern" must be a valid regex (${reason}).`
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
function assertSecretRuleSafety(logicalKey, rule) {
|
|
1396
|
+
if (!logicalKey.startsWith("secret.")) {
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
const offendingFields = SECRET_FORBIDDEN_FIELDS.filter((field) => hasOwn(rule, field));
|
|
1400
|
+
if (offendingFields.length === 0) {
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
throw new CnosManifestError(
|
|
1404
|
+
`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.`
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
function normalizeSpecRule(logicalKey, rule) {
|
|
1408
|
+
if (!rule || typeof rule !== "object" || Array.isArray(rule)) {
|
|
1409
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: expected an object.`);
|
|
1410
|
+
}
|
|
1411
|
+
const candidate = rule;
|
|
1412
|
+
assertSecretRuleSafety(logicalKey, candidate);
|
|
1413
|
+
const normalized = {};
|
|
1414
|
+
if (candidate.type !== void 0) {
|
|
1415
|
+
if (typeof candidate.type !== "string" || !ALLOWED_TYPES.has(candidate.type)) {
|
|
1416
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: unsupported type "${String(candidate.type)}".`);
|
|
1417
|
+
}
|
|
1418
|
+
normalized.type = candidate.type;
|
|
1419
|
+
}
|
|
1420
|
+
if (candidate.required !== void 0) {
|
|
1421
|
+
if (typeof candidate.required !== "boolean") {
|
|
1422
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "required" must be a boolean.`);
|
|
1423
|
+
}
|
|
1424
|
+
normalized.required = candidate.required;
|
|
1425
|
+
}
|
|
1426
|
+
if (hasOwn(candidate, "default")) {
|
|
1427
|
+
normalized.default = candidate.default;
|
|
1428
|
+
}
|
|
1429
|
+
const normalizedEnum = normalizeUnknownArray(candidate.enum, "enum", logicalKey);
|
|
1430
|
+
if (normalizedEnum !== void 0) {
|
|
1431
|
+
normalized.enum = normalizedEnum;
|
|
1432
|
+
}
|
|
1433
|
+
const normalizedPattern = normalizeOptionalString(candidate.pattern, "pattern", logicalKey);
|
|
1434
|
+
if (normalizedPattern !== void 0) {
|
|
1435
|
+
assertValidPatternRegex(normalizedPattern, logicalKey);
|
|
1436
|
+
normalized.pattern = normalizedPattern;
|
|
1437
|
+
}
|
|
1438
|
+
const normalizedSummary = normalizeOptionalString(candidate.summary, "summary", logicalKey);
|
|
1439
|
+
if (normalizedSummary !== void 0) {
|
|
1440
|
+
normalized.summary = normalizedSummary;
|
|
1441
|
+
}
|
|
1442
|
+
const normalizedDescription = normalizeOptionalString(candidate.description, "description", logicalKey);
|
|
1443
|
+
if (normalizedDescription !== void 0) {
|
|
1444
|
+
normalized.description = normalizedDescription;
|
|
1445
|
+
}
|
|
1446
|
+
const normalizedExamples = normalizeUnknownArray(candidate.examples, "examples", logicalKey);
|
|
1447
|
+
if (normalizedExamples !== void 0) {
|
|
1448
|
+
normalized.examples = normalizedExamples;
|
|
1449
|
+
}
|
|
1450
|
+
const normalizedUsedBy = normalizeStringArray(candidate.usedBy, "usedBy", logicalKey);
|
|
1451
|
+
if (normalizedUsedBy !== void 0) {
|
|
1452
|
+
normalized.usedBy = normalizedUsedBy;
|
|
1453
|
+
}
|
|
1454
|
+
if (candidate.deprecated !== void 0) {
|
|
1455
|
+
if (typeof candidate.deprecated !== "boolean") {
|
|
1456
|
+
throw new CnosManifestError(`Invalid schema rule for ${logicalKey}: "deprecated" must be a boolean.`);
|
|
1457
|
+
}
|
|
1458
|
+
normalized.deprecated = candidate.deprecated;
|
|
1459
|
+
}
|
|
1460
|
+
const normalizedDeprecationMessage = normalizeOptionalString(
|
|
1461
|
+
candidate.deprecationMessage,
|
|
1462
|
+
"deprecationMessage",
|
|
1463
|
+
logicalKey
|
|
1464
|
+
);
|
|
1465
|
+
if (normalizedDeprecationMessage !== void 0) {
|
|
1466
|
+
normalized.deprecationMessage = normalizedDeprecationMessage;
|
|
1467
|
+
}
|
|
1468
|
+
return normalized;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1343
1471
|
// ../core/src/manifest/normalizeManifest.ts
|
|
1344
1472
|
var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
|
|
1345
1473
|
var DEFAULT_LOADERS = [
|
|
@@ -1473,11 +1601,19 @@ function normalizeVaults(vaults) {
|
|
|
1473
1601
|
throw new CnosManifestError(`Vault "${name}" requires a provider`);
|
|
1474
1602
|
}
|
|
1475
1603
|
const normalizedAuth = normalizeVaultAuth(name, provider, definition.auth);
|
|
1476
|
-
const normalizedMapping =
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1604
|
+
const normalizedMapping = normalizeVaultMapping(definition.mapping);
|
|
1605
|
+
const fallback = (definition.fallback ?? []).map((entry, index) => {
|
|
1606
|
+
const fallbackProvider = entry.provider?.trim();
|
|
1607
|
+
if (!fallbackProvider) {
|
|
1608
|
+
throw new CnosManifestError(`Vault "${name}" fallback ${index + 1} requires a provider`);
|
|
1609
|
+
}
|
|
1610
|
+
const fallbackMapping = normalizeVaultMapping(entry.mapping);
|
|
1611
|
+
return {
|
|
1612
|
+
provider: fallbackProvider,
|
|
1613
|
+
auth: normalizeVaultAuth(name, fallbackProvider, entry.auth),
|
|
1614
|
+
...Object.keys(fallbackMapping).length > 0 ? { mapping: fallbackMapping } : {}
|
|
1615
|
+
};
|
|
1616
|
+
});
|
|
1481
1617
|
return [
|
|
1482
1618
|
name,
|
|
1483
1619
|
{
|
|
@@ -1485,12 +1621,20 @@ function normalizeVaults(vaults) {
|
|
|
1485
1621
|
auth: normalizedAuth,
|
|
1486
1622
|
...Object.keys(normalizedMapping).length > 0 ? {
|
|
1487
1623
|
mapping: normalizedMapping
|
|
1488
|
-
} : {}
|
|
1624
|
+
} : {},
|
|
1625
|
+
...fallback.length > 0 ? { fallback } : {}
|
|
1489
1626
|
}
|
|
1490
1627
|
];
|
|
1491
1628
|
})
|
|
1492
1629
|
);
|
|
1493
1630
|
}
|
|
1631
|
+
function normalizeVaultMapping(mapping) {
|
|
1632
|
+
return Object.fromEntries(
|
|
1633
|
+
Object.entries(mapping ?? {}).filter(
|
|
1634
|
+
(entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
|
|
1635
|
+
).map(([envVar, logicalRef]) => [envVar.trim(), logicalRef.trim()]).filter(([envVar, logicalRef]) => envVar.length > 0 && logicalRef.length > 0)
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1494
1638
|
function normalizeAuthSources(value) {
|
|
1495
1639
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1496
1640
|
return void 0;
|
|
@@ -1538,6 +1682,14 @@ function normalizeVaultAuth(vaultName, provider, auth) {
|
|
|
1538
1682
|
...auth?.config ? { config: auth.config } : {}
|
|
1539
1683
|
};
|
|
1540
1684
|
}
|
|
1685
|
+
function normalizeSchema(schema) {
|
|
1686
|
+
return Object.fromEntries(
|
|
1687
|
+
Object.entries(schema ?? {}).map(([logicalKey, rule]) => [
|
|
1688
|
+
logicalKey,
|
|
1689
|
+
normalizeSpecRule(logicalKey, rule)
|
|
1690
|
+
])
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1541
1693
|
function normalizeManifest(manifest) {
|
|
1542
1694
|
const version = manifest.version ?? 1;
|
|
1543
1695
|
if (version !== 1) {
|
|
@@ -1635,7 +1787,7 @@ function normalizeManifest(manifest) {
|
|
|
1635
1787
|
}
|
|
1636
1788
|
}
|
|
1637
1789
|
},
|
|
1638
|
-
schema: manifest.schema
|
|
1790
|
+
schema: normalizeSchema(manifest.schema)
|
|
1639
1791
|
};
|
|
1640
1792
|
}
|
|
1641
1793
|
|
|
@@ -2269,6 +2421,13 @@ function enumMatches(value, allowed) {
|
|
|
2269
2421
|
const serialized = JSON.stringify(value);
|
|
2270
2422
|
return allowed.some((candidate) => JSON.stringify(candidate) === serialized);
|
|
2271
2423
|
}
|
|
2424
|
+
function testPattern(pattern, value) {
|
|
2425
|
+
try {
|
|
2426
|
+
return new RegExp(pattern).test(value);
|
|
2427
|
+
} catch {
|
|
2428
|
+
return false;
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2272
2431
|
function applySchemaRules(graph, schema) {
|
|
2273
2432
|
const nextEntries = new Map(graph.entries);
|
|
2274
2433
|
const issues = [];
|
|
@@ -2335,11 +2494,11 @@ function applySchemaRules(graph, schema) {
|
|
|
2335
2494
|
key,
|
|
2336
2495
|
message: `Config key ${key} must be a string to match pattern ${rule.pattern}`
|
|
2337
2496
|
});
|
|
2338
|
-
} else if (!
|
|
2497
|
+
} else if (!testPattern(rule.pattern, coercedValue)) {
|
|
2339
2498
|
issues.push({
|
|
2340
2499
|
code: "schema.pattern",
|
|
2341
2500
|
key,
|
|
2342
|
-
message: `Config key ${key} does not match pattern ${rule.pattern}
|
|
2501
|
+
message: `Config key ${key} does not match pattern ${rule.pattern} (or the pattern is invalid).`
|
|
2343
2502
|
});
|
|
2344
2503
|
}
|
|
2345
2504
|
}
|
|
@@ -2423,7 +2582,7 @@ function isObject(value) {
|
|
|
2423
2582
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2424
2583
|
}
|
|
2425
2584
|
function isSecretReference(value) {
|
|
2426
|
-
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));
|
|
2585
|
+
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));
|
|
2427
2586
|
}
|
|
2428
2587
|
function resolveSecretStoreRoot(processEnv = process.env) {
|
|
2429
2588
|
return import_node_path11.default.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
|
|
@@ -2739,16 +2898,19 @@ function resolveVaultDefinition(vaults, vault = "default") {
|
|
|
2739
2898
|
// ../core/src/secrets/auditLog.ts
|
|
2740
2899
|
async function appendAuditEvent(event, processEnv = process.env) {
|
|
2741
2900
|
const auditFile = processEnv.CNOS_AUDIT_FILE ?? import_node_path12.default.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2901
|
+
try {
|
|
2902
|
+
await (0, import_promises11.mkdir)(import_node_path12.default.dirname(auditFile), { recursive: true });
|
|
2903
|
+
await (0, import_promises11.appendFile)(
|
|
2904
|
+
auditFile,
|
|
2905
|
+
`${JSON.stringify({
|
|
2906
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2907
|
+
...event
|
|
2908
|
+
})}
|
|
2749
2909
|
`,
|
|
2750
|
-
|
|
2751
|
-
|
|
2910
|
+
"utf8"
|
|
2911
|
+
);
|
|
2912
|
+
} catch {
|
|
2913
|
+
}
|
|
2752
2914
|
}
|
|
2753
2915
|
|
|
2754
2916
|
// ../core/src/secrets/secretCache.ts
|
|
@@ -2767,6 +2929,23 @@ var SecretCache = class {
|
|
|
2767
2929
|
get(vaultId, ref) {
|
|
2768
2930
|
return this.cache.get(`${vaultId}:${ref}`);
|
|
2769
2931
|
}
|
|
2932
|
+
delete(vaultId, ref) {
|
|
2933
|
+
this.cache.delete(`${vaultId}:${ref}`);
|
|
2934
|
+
}
|
|
2935
|
+
replace(vaultId, secrets) {
|
|
2936
|
+
this.clear(vaultId);
|
|
2937
|
+
this.load(vaultId, secrets);
|
|
2938
|
+
}
|
|
2939
|
+
entriesForVault(vaultId) {
|
|
2940
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2941
|
+
for (const [key, value] of this.cache) {
|
|
2942
|
+
const prefix = `${vaultId}:`;
|
|
2943
|
+
if (key.startsWith(prefix)) {
|
|
2944
|
+
entries.set(key.slice(prefix.length), value);
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
return entries;
|
|
2948
|
+
}
|
|
2770
2949
|
clear(vaultId) {
|
|
2771
2950
|
if (!vaultId) {
|
|
2772
2951
|
this.cache.clear();
|
|
@@ -2932,7 +3111,7 @@ var LocalSecretVaultProvider = class _LocalSecretVaultProvider {
|
|
|
2932
3111
|
};
|
|
2933
3112
|
|
|
2934
3113
|
// ../core/src/secrets/providers/registry.ts
|
|
2935
|
-
function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
3114
|
+
function createSecretVaultProvider(vaultId, definition, processEnv, factories = []) {
|
|
2936
3115
|
if (definition.provider === "local") {
|
|
2937
3116
|
return new LocalSecretVaultProvider(vaultId, definition, processEnv);
|
|
2938
3117
|
}
|
|
@@ -2942,9 +3121,30 @@ function createSecretVaultProvider(vaultId, definition, processEnv) {
|
|
|
2942
3121
|
if (definition.provider === "github-secrets") {
|
|
2943
3122
|
return new GithubSecretsVaultProvider(vaultId, definition, processEnv);
|
|
2944
3123
|
}
|
|
3124
|
+
const factory = factories.find((candidate) => candidate.provider === definition.provider);
|
|
3125
|
+
if (factory) {
|
|
3126
|
+
return factory.create(vaultId, definition, processEnv);
|
|
3127
|
+
}
|
|
2945
3128
|
throw new CnosManifestError(`Unsupported vault provider: ${definition.provider}`);
|
|
2946
3129
|
}
|
|
2947
3130
|
|
|
3131
|
+
// ../core/src/secrets/providerCompatibility.ts
|
|
3132
|
+
function assertSecretRefVaultProviderCompatible(manifest, ref, logicalKey = "secret ref") {
|
|
3133
|
+
if (!ref.vault || !ref.provider) {
|
|
3134
|
+
return;
|
|
3135
|
+
}
|
|
3136
|
+
const definition = manifest.vaults[ref.vault];
|
|
3137
|
+
if (!definition || definition.provider === ref.provider) {
|
|
3138
|
+
return;
|
|
3139
|
+
}
|
|
3140
|
+
throw new CnosManifestError(
|
|
3141
|
+
`Secret ref "${logicalKey}" declares provider "${ref.provider}" but vault "${ref.vault}" uses provider "${definition.provider}". Remove the ref provider or use a matching vault.`
|
|
3142
|
+
);
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// ../core/src/secrets/resolveAuth.ts
|
|
3146
|
+
var import_promises12 = require("fs/promises");
|
|
3147
|
+
|
|
2948
3148
|
// ../core/src/secrets/prompt.ts
|
|
2949
3149
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
2950
3150
|
var import_node_stream = require("stream");
|
|
@@ -2985,6 +3185,23 @@ function toAuthError(vaultId, sources) {
|
|
|
2985
3185
|
`Cannot authenticate to vault "${vaultId}". Tried: ${sources.join(", ")}. Set ${getVaultPassphraseEnvVar(vaultId)} or run cnos vault auth ${vaultId}.`
|
|
2986
3186
|
);
|
|
2987
3187
|
}
|
|
3188
|
+
async function resolveTokenFromSource(source, processEnv) {
|
|
3189
|
+
if (source.startsWith("env:")) {
|
|
3190
|
+
return processEnv[source.slice(4)] || void 0;
|
|
3191
|
+
}
|
|
3192
|
+
if (source.startsWith("file:")) {
|
|
3193
|
+
try {
|
|
3194
|
+
const value = await (0, import_promises12.readFile)(expandHomePath(source.slice("file:".length)), "utf8");
|
|
3195
|
+
return value.trim() || void 0;
|
|
3196
|
+
} catch {
|
|
3197
|
+
return void 0;
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
if (source.startsWith("keychain:")) {
|
|
3201
|
+
return readKeychain(source.slice("keychain:".length));
|
|
3202
|
+
}
|
|
3203
|
+
return void 0;
|
|
3204
|
+
}
|
|
2988
3205
|
async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
2989
3206
|
const sessionKey = await resolveVaultSessionKey(vaultId, processEnv);
|
|
2990
3207
|
if (sessionKey) {
|
|
@@ -3000,6 +3217,32 @@ async function resolveVaultAuth(vaultId, definition, processEnv = process.env) {
|
|
|
3000
3217
|
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3001
3218
|
};
|
|
3002
3219
|
}
|
|
3220
|
+
if (definition.auth?.method === "iam") {
|
|
3221
|
+
return {
|
|
3222
|
+
method: "iam",
|
|
3223
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3224
|
+
};
|
|
3225
|
+
}
|
|
3226
|
+
if (definition.auth?.method === "environment") {
|
|
3227
|
+
return {
|
|
3228
|
+
method: "environment",
|
|
3229
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
const tokenSources = definition.auth?.token?.from ?? [];
|
|
3233
|
+
for (const source of tokenSources) {
|
|
3234
|
+
const token = await resolveTokenFromSource(source, processEnv);
|
|
3235
|
+
if (token) {
|
|
3236
|
+
return {
|
|
3237
|
+
token,
|
|
3238
|
+
method: "token",
|
|
3239
|
+
...definition.auth?.config ? { config: definition.auth.config } : {}
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
if (definition.auth?.method === "token") {
|
|
3244
|
+
throw toAuthError(vaultId, [getVaultSessionKeyEnvVar(vaultId), ...tokenSources]);
|
|
3245
|
+
}
|
|
3003
3246
|
const sources = definition.auth?.passphrase?.from ?? [getVaultPassphraseEnvVar(vaultId)];
|
|
3004
3247
|
for (const source of sources) {
|
|
3005
3248
|
if (source.startsWith("env:")) {
|
|
@@ -3051,22 +3294,76 @@ function collectSecretDescriptors(graph) {
|
|
|
3051
3294
|
ref: entry.value
|
|
3052
3295
|
}));
|
|
3053
3296
|
}
|
|
3054
|
-
|
|
3297
|
+
function secretGroupKey(manifest, descriptor) {
|
|
3298
|
+
assertSecretRefVaultProviderCompatible(manifest, descriptor.ref, descriptor.logicalKey);
|
|
3299
|
+
const vaultId = descriptor.ref.vault ?? "default";
|
|
3300
|
+
const provider = descriptor.ref.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3301
|
+
return `${vaultId}\0${provider}`;
|
|
3302
|
+
}
|
|
3303
|
+
function vaultDefinitionForRef(manifest, ref) {
|
|
3304
|
+
assertSecretRefVaultProviderCompatible(manifest, ref);
|
|
3305
|
+
const vaultId = ref.vault ?? "default";
|
|
3306
|
+
const base = manifest.vaults[vaultId] ?? { provider: "local", auth: { passphrase: { from: [] } } };
|
|
3307
|
+
if (!ref.provider || ref.provider === base.provider) {
|
|
3308
|
+
return base;
|
|
3309
|
+
}
|
|
3310
|
+
return {
|
|
3311
|
+
...base,
|
|
3312
|
+
provider: ref.provider
|
|
3313
|
+
};
|
|
3314
|
+
}
|
|
3315
|
+
async function resolveFromDefinition(vaultId, definition, refs, processEnv, factories) {
|
|
3316
|
+
const runtimeDefinition = {
|
|
3317
|
+
provider: definition.provider,
|
|
3318
|
+
...definition.auth ? { auth: definition.auth } : {},
|
|
3319
|
+
...definition.mapping ? { mapping: definition.mapping } : {}
|
|
3320
|
+
};
|
|
3321
|
+
const provider = createSecretVaultProvider(vaultId, runtimeDefinition, processEnv, factories);
|
|
3322
|
+
const auth = await resolveVaultAuth(vaultId, runtimeDefinition, processEnv);
|
|
3323
|
+
await provider.authenticate(auth);
|
|
3324
|
+
return provider.batchGet(refs.map((entry) => entry.ref.ref));
|
|
3325
|
+
}
|
|
3326
|
+
async function batchResolveSecrets(graph, manifest, processEnv = process.env, factories = []) {
|
|
3055
3327
|
const cache = new SecretCache();
|
|
3056
3328
|
const descriptors = collectSecretDescriptors(graph);
|
|
3057
3329
|
const grouped = descriptors.reduce((accumulator, descriptor) => {
|
|
3058
|
-
const
|
|
3059
|
-
const bucket = accumulator.get(
|
|
3330
|
+
const key = secretGroupKey(manifest, descriptor);
|
|
3331
|
+
const bucket = accumulator.get(key) ?? [];
|
|
3060
3332
|
bucket.push(descriptor);
|
|
3061
|
-
accumulator.set(
|
|
3333
|
+
accumulator.set(key, bucket);
|
|
3062
3334
|
return accumulator;
|
|
3063
3335
|
}, /* @__PURE__ */ new Map());
|
|
3064
|
-
for (const
|
|
3065
|
-
const
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
const
|
|
3336
|
+
for (const refs of grouped.values()) {
|
|
3337
|
+
const first = refs[0];
|
|
3338
|
+
if (!first) {
|
|
3339
|
+
continue;
|
|
3340
|
+
}
|
|
3341
|
+
const vaultId = first.ref.vault ?? "default";
|
|
3342
|
+
const definition = vaultDefinitionForRef(manifest, first.ref);
|
|
3343
|
+
const definitions = [definition, ...definition.fallback ?? []];
|
|
3344
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
3345
|
+
let remaining = refs;
|
|
3346
|
+
let lastError;
|
|
3347
|
+
for (const candidate of definitions) {
|
|
3348
|
+
try {
|
|
3349
|
+
const candidateValues = await resolveFromDefinition(vaultId, candidate, remaining, processEnv, factories);
|
|
3350
|
+
for (const descriptor of remaining) {
|
|
3351
|
+
const value = candidateValues.get(descriptor.ref.ref);
|
|
3352
|
+
if (value !== void 0) {
|
|
3353
|
+
resolved.set(descriptor.ref.ref, value);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
remaining = remaining.filter((descriptor) => !resolved.has(descriptor.ref.ref));
|
|
3357
|
+
if (remaining.length === 0) {
|
|
3358
|
+
break;
|
|
3359
|
+
}
|
|
3360
|
+
} catch (error) {
|
|
3361
|
+
lastError = error;
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
if (resolved.size === 0 && lastError) {
|
|
3365
|
+
throw lastError;
|
|
3366
|
+
}
|
|
3070
3367
|
cache.load(vaultId, resolved);
|
|
3071
3368
|
await appendAuditEvent(
|
|
3072
3369
|
{
|
|
@@ -3087,7 +3384,11 @@ function resolveSecretEntryValue(key, value, cache) {
|
|
|
3087
3384
|
return value;
|
|
3088
3385
|
}
|
|
3089
3386
|
const vaultId = value.vault ?? "default";
|
|
3090
|
-
|
|
3387
|
+
const resolved = cache.get(vaultId, value.ref);
|
|
3388
|
+
if (resolved !== void 0 || cache.isVaultAuthenticated(vaultId)) {
|
|
3389
|
+
return resolved;
|
|
3390
|
+
}
|
|
3391
|
+
return value;
|
|
3091
3392
|
}
|
|
3092
3393
|
|
|
3093
3394
|
// ../core/src/runtime/projection.ts
|
|
@@ -3190,19 +3491,117 @@ function configHash(values) {
|
|
|
3190
3491
|
function shouldProjectResolvedValue(sourceId) {
|
|
3191
3492
|
return sourceId !== "process-env";
|
|
3192
3493
|
}
|
|
3494
|
+
var SAFE_PROJECTED_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
3495
|
+
"address",
|
|
3496
|
+
"audience",
|
|
3497
|
+
"clientid",
|
|
3498
|
+
"endpoint",
|
|
3499
|
+
"mount",
|
|
3500
|
+
"namespace",
|
|
3501
|
+
"path",
|
|
3502
|
+
"projectid",
|
|
3503
|
+
"region",
|
|
3504
|
+
"scope",
|
|
3505
|
+
"scopes",
|
|
3506
|
+
"serviceaccountemail",
|
|
3507
|
+
"tenant",
|
|
3508
|
+
"tenantid",
|
|
3509
|
+
"url",
|
|
3510
|
+
"version",
|
|
3511
|
+
"vaulturl"
|
|
3512
|
+
]);
|
|
3513
|
+
function isSafeProjectedConfigKey(key) {
|
|
3514
|
+
return SAFE_PROJECTED_CONFIG_KEYS.has(key.replace(/[^A-Za-z0-9]/g, "").toLowerCase());
|
|
3515
|
+
}
|
|
3516
|
+
function sanitizeProjectedConfigValue(value) {
|
|
3517
|
+
if (Array.isArray(value)) {
|
|
3518
|
+
return value.map((item) => sanitizeProjectedConfigValue(item));
|
|
3519
|
+
}
|
|
3520
|
+
if (!value || typeof value !== "object") {
|
|
3521
|
+
return value;
|
|
3522
|
+
}
|
|
3523
|
+
return stableSortObject(
|
|
3524
|
+
Object.fromEntries(
|
|
3525
|
+
Object.entries(value).map(([key, item]) => [key, sanitizeProjectedConfigValue(item)]).filter(([key, item]) => {
|
|
3526
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
3527
|
+
return Object.keys(item).length > 0;
|
|
3528
|
+
}
|
|
3529
|
+
return isSafeProjectedConfigKey(key);
|
|
3530
|
+
})
|
|
3531
|
+
)
|
|
3532
|
+
);
|
|
3533
|
+
}
|
|
3534
|
+
function sanitizeProjectedConfig(config) {
|
|
3535
|
+
const sanitized = sanitizeProjectedConfigValue(config);
|
|
3536
|
+
if (!sanitized || typeof sanitized !== "object" || Array.isArray(sanitized)) {
|
|
3537
|
+
return void 0;
|
|
3538
|
+
}
|
|
3539
|
+
return Object.keys(sanitized).length > 0 ? sanitized : void 0;
|
|
3540
|
+
}
|
|
3541
|
+
function projectVaultAuth(definition) {
|
|
3542
|
+
const auth = definition.auth;
|
|
3543
|
+
if (!auth) {
|
|
3544
|
+
return void 0;
|
|
3545
|
+
}
|
|
3546
|
+
const config = auth.config ? sanitizeProjectedConfig(auth.config) : void 0;
|
|
3547
|
+
const projected = {
|
|
3548
|
+
...auth.method ? { method: auth.method } : {},
|
|
3549
|
+
...auth.passphrase?.from ? {
|
|
3550
|
+
passphrase: {
|
|
3551
|
+
from: [...auth.passphrase.from]
|
|
3552
|
+
}
|
|
3553
|
+
} : {},
|
|
3554
|
+
...auth.token?.from ? {
|
|
3555
|
+
token: {
|
|
3556
|
+
from: [...auth.token.from]
|
|
3557
|
+
}
|
|
3558
|
+
} : {},
|
|
3559
|
+
...config ? { config } : {}
|
|
3560
|
+
};
|
|
3561
|
+
return Object.keys(projected).length > 0 ? projected : void 0;
|
|
3562
|
+
}
|
|
3563
|
+
function projectVaultDefinition(definition) {
|
|
3564
|
+
const auth = projectVaultAuth(definition);
|
|
3565
|
+
const mapping = definition.mapping ? stableSortObject(definition.mapping) : void 0;
|
|
3566
|
+
const fallback = definition.fallback?.map((entry) => projectVaultDefinition({
|
|
3567
|
+
provider: entry.provider,
|
|
3568
|
+
...entry.auth ? { auth: entry.auth } : {},
|
|
3569
|
+
...entry.mapping ? { mapping: entry.mapping } : {}
|
|
3570
|
+
}));
|
|
3571
|
+
return {
|
|
3572
|
+
provider: definition.provider,
|
|
3573
|
+
...auth ? { auth } : {},
|
|
3574
|
+
...mapping && Object.keys(mapping).length > 0 ? { mapping } : {},
|
|
3575
|
+
...fallback && fallback.length > 0 ? { fallback } : {}
|
|
3576
|
+
};
|
|
3577
|
+
}
|
|
3578
|
+
function projectReferencedVaults(manifest, vaultIds) {
|
|
3579
|
+
const projected = {};
|
|
3580
|
+
for (const vaultId of Array.from(vaultIds).sort((left, right) => left.localeCompare(right))) {
|
|
3581
|
+
const definition = manifest.vaults[vaultId];
|
|
3582
|
+
if (definition) {
|
|
3583
|
+
projected[vaultId] = projectVaultDefinition(definition);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
return Object.keys(projected).length > 0 ? projected : void 0;
|
|
3587
|
+
}
|
|
3193
3588
|
function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
|
|
3194
3589
|
const values = {};
|
|
3195
3590
|
const derived = {};
|
|
3196
3591
|
const secretRefs = {};
|
|
3592
|
+
const referencedVaultIds = /* @__PURE__ */ new Set();
|
|
3197
3593
|
const namespaces = /* @__PURE__ */ new Set();
|
|
3198
3594
|
const runtimeNamespaces = /* @__PURE__ */ new Set();
|
|
3199
3595
|
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));
|
|
3200
3596
|
for (const [key, entry] of graph.entries) {
|
|
3201
3597
|
if (entry.namespace === "secret" && isSecretReference(entry.value)) {
|
|
3598
|
+
assertSecretRefVaultProviderCompatible(manifest, entry.value, key);
|
|
3202
3599
|
const vaultId = entry.value.vault ?? "default";
|
|
3600
|
+
const provider = entry.value.provider ?? manifest.vaults[vaultId]?.provider ?? "local";
|
|
3203
3601
|
const envVar = resolveProjectedEnvVar(manifest, vaultId, entry.value.ref);
|
|
3602
|
+
referencedVaultIds.add(vaultId);
|
|
3204
3603
|
secretRefs[key.slice("secret.".length)] = {
|
|
3205
|
-
provider
|
|
3604
|
+
provider,
|
|
3206
3605
|
vault: vaultId,
|
|
3207
3606
|
ref: entry.value.ref,
|
|
3208
3607
|
...envVar ? {
|
|
@@ -3248,6 +3647,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3248
3647
|
namespaces.add(entry.namespace);
|
|
3249
3648
|
}
|
|
3250
3649
|
}
|
|
3650
|
+
const vaults = projectReferencedVaults(manifest, referencedVaultIds);
|
|
3251
3651
|
return {
|
|
3252
3652
|
version: 1,
|
|
3253
3653
|
workspace: graph.workspace.workspaceId,
|
|
@@ -3257,6 +3657,7 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers
|
|
|
3257
3657
|
values: stableSortObject(values),
|
|
3258
3658
|
derived: stableSortObject(derived),
|
|
3259
3659
|
secretRefs: stableSortObject(secretRefs),
|
|
3660
|
+
...vaults ? { vaults } : {},
|
|
3260
3661
|
publicKeys,
|
|
3261
3662
|
runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
|
|
3262
3663
|
meta: {
|
|
@@ -3371,9 +3772,10 @@ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
|
|
|
3371
3772
|
}
|
|
3372
3773
|
|
|
3373
3774
|
// ../core/src/orchestrator/runtime.ts
|
|
3374
|
-
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
|
|
3775
|
+
function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev", secretVaultProviders = []) {
|
|
3375
3776
|
const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
|
|
3376
3777
|
const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
|
|
3778
|
+
let activeSecretCache = secretCache;
|
|
3377
3779
|
function resolveProjectedSourceKey(key) {
|
|
3378
3780
|
if (!key.startsWith("public.")) {
|
|
3379
3781
|
return key;
|
|
@@ -3390,30 +3792,38 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3390
3792
|
if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
|
|
3391
3793
|
return;
|
|
3392
3794
|
}
|
|
3393
|
-
if (!
|
|
3795
|
+
if (!activeSecretCache) {
|
|
3394
3796
|
return;
|
|
3395
3797
|
}
|
|
3396
3798
|
const vaultId = entry.value.vault ?? "default";
|
|
3397
|
-
const
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3799
|
+
const refreshed = await batchResolveSecrets(
|
|
3800
|
+
{
|
|
3801
|
+
...graph,
|
|
3802
|
+
entries: /* @__PURE__ */ new Map([[key, entry]])
|
|
3803
|
+
},
|
|
3804
|
+
manifest,
|
|
3805
|
+
processEnv,
|
|
3806
|
+
secretVaultProviders
|
|
3807
|
+
);
|
|
3808
|
+
const resolved = refreshed.get(vaultId, entry.value.ref);
|
|
3809
|
+
const existing = activeSecretCache.entriesForVault(vaultId);
|
|
3810
|
+
existing.delete(entry.value.ref);
|
|
3811
|
+
if (resolved !== void 0) {
|
|
3812
|
+
existing.set(entry.value.ref, resolved);
|
|
3407
3813
|
}
|
|
3814
|
+
activeSecretCache.replace(vaultId, existing);
|
|
3408
3815
|
}
|
|
3409
3816
|
async function refreshAllSecrets() {
|
|
3410
|
-
if (!
|
|
3817
|
+
if (!activeSecretCache) {
|
|
3411
3818
|
return;
|
|
3412
3819
|
}
|
|
3413
|
-
const
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3820
|
+
const refreshed = await batchResolveSecrets(
|
|
3821
|
+
graph,
|
|
3822
|
+
manifest,
|
|
3823
|
+
processEnv,
|
|
3824
|
+
secretVaultProviders
|
|
3825
|
+
);
|
|
3826
|
+
activeSecretCache = refreshed;
|
|
3417
3827
|
}
|
|
3418
3828
|
function readLogicalKey(key) {
|
|
3419
3829
|
const resolved = derivedSupport.read(key, (ref) => {
|
|
@@ -3421,10 +3831,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3421
3831
|
if (!entry2) {
|
|
3422
3832
|
return void 0;
|
|
3423
3833
|
}
|
|
3424
|
-
if (!
|
|
3834
|
+
if (!activeSecretCache) {
|
|
3425
3835
|
return entry2.value;
|
|
3426
3836
|
}
|
|
3427
|
-
return resolveSecretEntryValue(ref, entry2.value,
|
|
3837
|
+
return resolveSecretEntryValue(ref, entry2.value, activeSecretCache);
|
|
3428
3838
|
});
|
|
3429
3839
|
if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
|
|
3430
3840
|
return resolved;
|
|
@@ -3433,10 +3843,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3433
3843
|
if (!entry) {
|
|
3434
3844
|
return void 0;
|
|
3435
3845
|
}
|
|
3436
|
-
if (!
|
|
3846
|
+
if (!activeSecretCache) {
|
|
3437
3847
|
return entry.value;
|
|
3438
3848
|
}
|
|
3439
|
-
return resolveSecretEntryValue(key, entry.value,
|
|
3849
|
+
return resolveSecretEntryValue(key, entry.value, activeSecretCache);
|
|
3440
3850
|
}
|
|
3441
3851
|
return {
|
|
3442
3852
|
manifest,
|
|
@@ -3473,10 +3883,10 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
|
|
|
3473
3883
|
if (!entry) {
|
|
3474
3884
|
return void 0;
|
|
3475
3885
|
}
|
|
3476
|
-
if (!
|
|
3886
|
+
if (!activeSecretCache) {
|
|
3477
3887
|
return entry.value;
|
|
3478
3888
|
}
|
|
3479
|
-
return resolveSecretEntryValue(candidate, entry.value,
|
|
3889
|
+
return resolveSecretEntryValue(candidate, entry.value, activeSecretCache);
|
|
3480
3890
|
})
|
|
3481
3891
|
});
|
|
3482
3892
|
},
|
|
@@ -3667,7 +4077,12 @@ async function createCnos(options = {}) {
|
|
|
3667
4077
|
});
|
|
3668
4078
|
const schemaApplied = applySchemaRules(graph, loadedManifest.manifest.schema);
|
|
3669
4079
|
const promotedGraph = promoteToPublic(schemaApplied.graph, loadedManifest.manifest);
|
|
3670
|
-
const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
|
|
4080
|
+
const secretCache = options.secretResolution === "lazy" ? new SecretCache() : await batchResolveSecrets(
|
|
4081
|
+
promotedGraph,
|
|
4082
|
+
loadedManifest.manifest,
|
|
4083
|
+
options.processEnv,
|
|
4084
|
+
options.secretVaultProviders
|
|
4085
|
+
);
|
|
3671
4086
|
return createRuntime(
|
|
3672
4087
|
loadedManifest.manifest,
|
|
3673
4088
|
appendMetaEntries({
|
|
@@ -3677,12 +4092,13 @@ async function createCnos(options = {}) {
|
|
|
3677
4092
|
plugins,
|
|
3678
4093
|
secretCache,
|
|
3679
4094
|
options.processEnv,
|
|
3680
|
-
options.cnosVersion
|
|
4095
|
+
options.cnosVersion,
|
|
4096
|
+
options.secretVaultProviders
|
|
3681
4097
|
);
|
|
3682
4098
|
}
|
|
3683
4099
|
|
|
3684
4100
|
// ../core/src/runtime/dump.ts
|
|
3685
|
-
var
|
|
4101
|
+
var import_promises13 = require("fs/promises");
|
|
3686
4102
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
3687
4103
|
|
|
3688
4104
|
// ../core/src/utils/envNaming.ts
|
|
@@ -3720,7 +4136,7 @@ function envVarToLogicalKey(envVar, config = {}) {
|
|
|
3720
4136
|
// package.json
|
|
3721
4137
|
var package_default = {
|
|
3722
4138
|
name: "@kitsy/cnos",
|
|
3723
|
-
version: "1.
|
|
4139
|
+
version: "1.11.0",
|
|
3724
4140
|
description: "Batteries-included CNOS runtime package wired with the official plugins.",
|
|
3725
4141
|
type: "module",
|
|
3726
4142
|
main: "./dist/index.cjs",
|
|
@@ -3919,15 +4335,36 @@ function createCliArgsPlugin() {
|
|
|
3919
4335
|
}
|
|
3920
4336
|
|
|
3921
4337
|
// ../../plugins/dotenv/src/index.ts
|
|
3922
|
-
var
|
|
4338
|
+
var import_promises14 = require("fs/promises");
|
|
3923
4339
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
3924
4340
|
var DOTENV_PLUGIN_ID = "@kitsy/cnos/plugins/dotenv";
|
|
3925
4341
|
function parseDoubleQuoted(value) {
|
|
3926
4342
|
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
3927
4343
|
}
|
|
4344
|
+
function isEscapedCharacter(value, index) {
|
|
4345
|
+
let slashCount = 0;
|
|
4346
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
4347
|
+
slashCount += 1;
|
|
4348
|
+
}
|
|
4349
|
+
return slashCount % 2 === 1;
|
|
4350
|
+
}
|
|
4351
|
+
function findClosingQuote(value, quote) {
|
|
4352
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
4353
|
+
if (value[index] !== quote) {
|
|
4354
|
+
continue;
|
|
4355
|
+
}
|
|
4356
|
+
if (quote === '"' && isEscapedCharacter(value, index)) {
|
|
4357
|
+
continue;
|
|
4358
|
+
}
|
|
4359
|
+
return index;
|
|
4360
|
+
}
|
|
4361
|
+
return -1;
|
|
4362
|
+
}
|
|
3928
4363
|
function parseDotenv(document) {
|
|
3929
4364
|
const parsed = {};
|
|
3930
|
-
|
|
4365
|
+
const lines = document.split(/\r?\n/);
|
|
4366
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
4367
|
+
const rawLine = lines[lineIndex] ?? "";
|
|
3931
4368
|
const line = rawLine.trim();
|
|
3932
4369
|
if (!line || line.startsWith("#")) {
|
|
3933
4370
|
continue;
|
|
@@ -3942,10 +4379,18 @@ function parseDotenv(document) {
|
|
|
3942
4379
|
if (!envVar) {
|
|
3943
4380
|
continue;
|
|
3944
4381
|
}
|
|
3945
|
-
if (value.startsWith('"')
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
4382
|
+
if (value.startsWith('"') || value.startsWith("'")) {
|
|
4383
|
+
const quote = value.startsWith('"') ? '"' : "'";
|
|
4384
|
+
let quotedContent = value.slice(1);
|
|
4385
|
+
let closingIndex = findClosingQuote(quotedContent, quote);
|
|
4386
|
+
while (closingIndex === -1 && lineIndex < lines.length - 1) {
|
|
4387
|
+
lineIndex += 1;
|
|
4388
|
+
quotedContent = `${quotedContent}
|
|
4389
|
+
${lines[lineIndex] ?? ""}`;
|
|
4390
|
+
closingIndex = findClosingQuote(quotedContent, quote);
|
|
4391
|
+
}
|
|
4392
|
+
const rawQuotedValue = closingIndex === -1 ? quotedContent : quotedContent.slice(0, closingIndex);
|
|
4393
|
+
value = quote === '"' ? parseDoubleQuoted(rawQuotedValue) : rawQuotedValue;
|
|
3949
4394
|
} else {
|
|
3950
4395
|
value = value.replace(/\s+#.*$/, "").trim();
|
|
3951
4396
|
}
|
|
@@ -3977,7 +4422,7 @@ function dotenvEntriesFromObject(values, mapping = {}, originFile, workspaceId =
|
|
|
3977
4422
|
}
|
|
3978
4423
|
async function readIfPresent(filePath) {
|
|
3979
4424
|
try {
|
|
3980
|
-
return await (0,
|
|
4425
|
+
return await (0, import_promises14.readFile)(filePath, "utf8");
|
|
3981
4426
|
} catch {
|
|
3982
4427
|
return void 0;
|
|
3983
4428
|
}
|
|
@@ -4043,16 +4488,16 @@ function createPublicEnvExportPlugin() {
|
|
|
4043
4488
|
}
|
|
4044
4489
|
|
|
4045
4490
|
// ../../plugins/filesystem/src/filesystemSecretsReader.ts
|
|
4046
|
-
var
|
|
4491
|
+
var import_promises16 = require("fs/promises");
|
|
4047
4492
|
|
|
4048
4493
|
// ../../plugins/filesystem/src/helpers.ts
|
|
4049
|
-
var
|
|
4494
|
+
var import_promises15 = require("fs/promises");
|
|
4050
4495
|
var import_node_path15 = __toESM(require("path"), 1);
|
|
4051
4496
|
var YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yml", ".yaml"]);
|
|
4052
4497
|
var FILESYSTEM_PLUGIN_ID = "@kitsy/cnos/plugins/filesystem";
|
|
4053
4498
|
async function existsDirectory(targetPath) {
|
|
4054
4499
|
try {
|
|
4055
|
-
const stat2 = await (0,
|
|
4500
|
+
const stat2 = await (0, import_promises15.readdir)(targetPath);
|
|
4056
4501
|
void stat2;
|
|
4057
4502
|
return true;
|
|
4058
4503
|
} catch {
|
|
@@ -4060,7 +4505,7 @@ async function existsDirectory(targetPath) {
|
|
|
4060
4505
|
}
|
|
4061
4506
|
}
|
|
4062
4507
|
async function collectYamlFiles(root) {
|
|
4063
|
-
const entries = await (0,
|
|
4508
|
+
const entries = await (0, import_promises15.readdir)(root, { withFileTypes: true });
|
|
4064
4509
|
const results = [];
|
|
4065
4510
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
4066
4511
|
const absolutePath = import_node_path15.default.join(root, entry.name);
|
|
@@ -4162,7 +4607,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4162
4607
|
);
|
|
4163
4608
|
const entries = [];
|
|
4164
4609
|
for (const file of files) {
|
|
4165
|
-
const document = await (0,
|
|
4610
|
+
const document = await (0, import_promises16.readFile)(file.absolutePath, "utf8");
|
|
4166
4611
|
const fileEntries = filesystemSecretsReader(file.relativePath, document, file.workspaceId);
|
|
4167
4612
|
for (const entry of fileEntries) {
|
|
4168
4613
|
const metadata = toSecretReferenceMetadata(entry.value);
|
|
@@ -4178,7 +4623,7 @@ function createFilesystemSecretsPlugin() {
|
|
|
4178
4623
|
}
|
|
4179
4624
|
|
|
4180
4625
|
// ../../plugins/filesystem/src/filesystemValuesReader.ts
|
|
4181
|
-
var
|
|
4626
|
+
var import_promises17 = require("fs/promises");
|
|
4182
4627
|
function filesystemValuesReader(filePath, document, workspaceId = "default") {
|
|
4183
4628
|
return yamlObjectToEntries(document, filePath, "value", "filesystem-values", workspaceId);
|
|
4184
4629
|
}
|
|
@@ -4199,7 +4644,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4199
4644
|
).map(([namespace]) => namespace);
|
|
4200
4645
|
const entries = [];
|
|
4201
4646
|
for (const file of files) {
|
|
4202
|
-
const document = await (0,
|
|
4647
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4203
4648
|
entries.push(...filesystemValuesReader(file.relativePath, document, file.workspaceId));
|
|
4204
4649
|
}
|
|
4205
4650
|
for (const namespace of customNamespaces) {
|
|
@@ -4214,7 +4659,7 @@ function createFilesystemValuesPlugin() {
|
|
|
4214
4659
|
layers
|
|
4215
4660
|
);
|
|
4216
4661
|
for (const file of namespaceFiles) {
|
|
4217
|
-
const document = await (0,
|
|
4662
|
+
const document = await (0, import_promises17.readFile)(file.absolutePath, "utf8");
|
|
4218
4663
|
entries.push(...yamlObjectToEntries(document, file.relativePath, namespace, "filesystem-values", file.workspaceId));
|
|
4219
4664
|
}
|
|
4220
4665
|
}
|
|
@@ -4460,15 +4905,13 @@ function validateServerProjectionSecretRefs(runtime) {
|
|
|
4460
4905
|
}
|
|
4461
4906
|
const vaultId = entry.value.vault ?? "default";
|
|
4462
4907
|
const definition = runtime.manifest.vaults[vaultId];
|
|
4463
|
-
if (!definition) {
|
|
4908
|
+
if (!definition && entry.value.vault) {
|
|
4464
4909
|
throw new CnosManifestError(`Unknown vault "${vaultId}" for secret ref "${entry.key}"`);
|
|
4465
4910
|
}
|
|
4466
|
-
if (entry.value.provider
|
|
4467
|
-
throw new CnosManifestError(
|
|
4468
|
-
`Secret ref "${entry.key}" declares provider "${entry.value.provider}" but vault "${vaultId}" uses provider "${definition.provider}"`
|
|
4469
|
-
);
|
|
4911
|
+
if (!definition && !entry.value.provider) {
|
|
4912
|
+
throw new CnosManifestError(`Secret ref "${entry.key}" must declare a provider or reference a configured vault`);
|
|
4470
4913
|
}
|
|
4471
|
-
|
|
4914
|
+
assertSecretRefVaultProviderCompatible(runtime.manifest, entry.value, entry.key);
|
|
4472
4915
|
}
|
|
4473
4916
|
}
|
|
4474
4917
|
// Annotate the CommonJS export names for ESM import in node:
|