vaultkeeper 0.5.1 → 0.5.3
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/index.cjs +59 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +59 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -647,7 +647,13 @@ declare class VaultKeeper {
|
|
|
647
647
|
* Runs doctor checks (unless skipped), loads config, and sets up the key manager.
|
|
648
648
|
*/
|
|
649
649
|
static init(options?: VaultKeeperOptions): Promise<VaultKeeper>;
|
|
650
|
-
/**
|
|
650
|
+
/**
|
|
651
|
+
* Run doctor checks without full initialization.
|
|
652
|
+
*
|
|
653
|
+
* Uses conservative platform defaults — all platform-native dependency
|
|
654
|
+
* checks are treated as required regardless of any backend configuration.
|
|
655
|
+
* For config-aware scoping, call `runDoctor({ backends })` directly.
|
|
656
|
+
*/
|
|
651
657
|
static doctor(): Promise<PreflightResult>;
|
|
652
658
|
/**
|
|
653
659
|
* Retrieve a secret from the backend and return a JWE token that encapsulates it.
|
|
@@ -813,6 +819,18 @@ type Platform = 'darwin' | 'win32' | 'linux';
|
|
|
813
819
|
interface RunDoctorOptions {
|
|
814
820
|
/** Override the platform detection (useful for testing). */
|
|
815
821
|
platform?: Platform;
|
|
822
|
+
/**
|
|
823
|
+
* When provided, doctor checks are scoped to the given backends.
|
|
824
|
+
* Platform-native dependency checks (e.g. `secret-tool`, `security`,
|
|
825
|
+
* `powershell`) are demoted from required to optional when the
|
|
826
|
+
* corresponding backend is not enabled. Plugin tool checks (`op`,
|
|
827
|
+
* `ykman`) are promoted from optional to required when their backend
|
|
828
|
+
* (`1password`, `yubikey`) is explicitly enabled.
|
|
829
|
+
*
|
|
830
|
+
* When omitted, all platform-default checks are treated as required
|
|
831
|
+
* (backward-compatible behavior).
|
|
832
|
+
*/
|
|
833
|
+
backends?: BackendConfig[];
|
|
816
834
|
}
|
|
817
835
|
/**
|
|
818
836
|
* Run all platform-appropriate preflight checks and aggregate the results.
|
package/dist/index.d.ts
CHANGED
|
@@ -647,7 +647,13 @@ declare class VaultKeeper {
|
|
|
647
647
|
* Runs doctor checks (unless skipped), loads config, and sets up the key manager.
|
|
648
648
|
*/
|
|
649
649
|
static init(options?: VaultKeeperOptions): Promise<VaultKeeper>;
|
|
650
|
-
/**
|
|
650
|
+
/**
|
|
651
|
+
* Run doctor checks without full initialization.
|
|
652
|
+
*
|
|
653
|
+
* Uses conservative platform defaults — all platform-native dependency
|
|
654
|
+
* checks are treated as required regardless of any backend configuration.
|
|
655
|
+
* For config-aware scoping, call `runDoctor({ backends })` directly.
|
|
656
|
+
*/
|
|
651
657
|
static doctor(): Promise<PreflightResult>;
|
|
652
658
|
/**
|
|
653
659
|
* Retrieve a secret from the backend and return a JWE token that encapsulates it.
|
|
@@ -813,6 +819,18 @@ type Platform = 'darwin' | 'win32' | 'linux';
|
|
|
813
819
|
interface RunDoctorOptions {
|
|
814
820
|
/** Override the platform detection (useful for testing). */
|
|
815
821
|
platform?: Platform;
|
|
822
|
+
/**
|
|
823
|
+
* When provided, doctor checks are scoped to the given backends.
|
|
824
|
+
* Platform-native dependency checks (e.g. `secret-tool`, `security`,
|
|
825
|
+
* `powershell`) are demoted from required to optional when the
|
|
826
|
+
* corresponding backend is not enabled. Plugin tool checks (`op`,
|
|
827
|
+
* `ykman`) are promoted from optional to required when their backend
|
|
828
|
+
* (`1password`, `yubikey`) is explicitly enabled.
|
|
829
|
+
*
|
|
830
|
+
* When omitted, all platform-default checks are treated as required
|
|
831
|
+
* (backward-compatible behavior).
|
|
832
|
+
*/
|
|
833
|
+
backends?: BackendConfig[];
|
|
816
834
|
}
|
|
817
835
|
/**
|
|
818
836
|
* Run all platform-appropriate preflight checks and aggregate the results.
|
package/dist/index.js
CHANGED
|
@@ -1592,7 +1592,13 @@ function validateConfig(config) {
|
|
|
1592
1592
|
if (typeof config.defaults.ttlMinutes !== "number" || config.defaults.ttlMinutes <= 0) {
|
|
1593
1593
|
throw new Error("Config defaults.ttlMinutes must be a positive number");
|
|
1594
1594
|
}
|
|
1595
|
-
|
|
1595
|
+
let tier = config.defaults.trustTier;
|
|
1596
|
+
if (typeof tier === "string") {
|
|
1597
|
+
const parsed = Number(tier);
|
|
1598
|
+
if (!Number.isNaN(parsed)) {
|
|
1599
|
+
tier = parsed;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1596
1602
|
if (tier !== 1 && tier !== 2 && tier !== 3) {
|
|
1597
1603
|
throw new Error("Config defaults.trustTier must be 1, 2, or 3");
|
|
1598
1604
|
}
|
|
@@ -1994,7 +2000,6 @@ var SecretAccessorTarget = class {
|
|
|
1994
2000
|
};
|
|
1995
2001
|
function createSecretAccessor(secretValue) {
|
|
1996
2002
|
let consumed = false;
|
|
1997
|
-
const revokeHolder = { fn: void 0 };
|
|
1998
2003
|
function readImpl(callback) {
|
|
1999
2004
|
if (consumed) {
|
|
2000
2005
|
throw new Error("SecretAccessor has already been consumed \u2014 call getSecret() again to obtain a new accessor");
|
|
@@ -2005,7 +2010,6 @@ function createSecretAccessor(secretValue) {
|
|
|
2005
2010
|
callback(buf);
|
|
2006
2011
|
} finally {
|
|
2007
2012
|
buf.fill(0);
|
|
2008
|
-
revokeHolder.fn?.();
|
|
2009
2013
|
}
|
|
2010
2014
|
}
|
|
2011
2015
|
function inspectImpl() {
|
|
@@ -2063,9 +2067,7 @@ function createSecretAccessor(secretValue) {
|
|
|
2063
2067
|
return ["read", INSPECT_CUSTOM];
|
|
2064
2068
|
}
|
|
2065
2069
|
};
|
|
2066
|
-
|
|
2067
|
-
revokeHolder.fn = revoke;
|
|
2068
|
-
return proxy;
|
|
2070
|
+
return new Proxy(target, handler);
|
|
2069
2071
|
}
|
|
2070
2072
|
|
|
2071
2073
|
// src/access/sign-util.ts
|
|
@@ -2259,7 +2261,8 @@ async function runDoctor(options) {
|
|
|
2259
2261
|
nextSteps: ["Unsupported platform. vaultkeeper supports macOS, Linux, and Windows."]
|
|
2260
2262
|
};
|
|
2261
2263
|
}
|
|
2262
|
-
const
|
|
2264
|
+
const enabledTypes = enabledBackendTypes(options?.backends);
|
|
2265
|
+
const entries = buildCheckList(platform, enabledTypes);
|
|
2263
2266
|
const resolved = await Promise.all(
|
|
2264
2267
|
entries.map(async ({ check, required }) => {
|
|
2265
2268
|
const result = await check();
|
|
@@ -2293,24 +2296,48 @@ async function runDoctor(options) {
|
|
|
2293
2296
|
const checks = resolved.map(({ result }) => result);
|
|
2294
2297
|
return { checks, ready, warnings, nextSteps };
|
|
2295
2298
|
}
|
|
2296
|
-
function
|
|
2299
|
+
function enabledBackendTypes(backends) {
|
|
2300
|
+
if (backends === void 0) return null;
|
|
2301
|
+
const types = /* @__PURE__ */ new Set();
|
|
2302
|
+
for (const b of backends) {
|
|
2303
|
+
if (b.enabled) types.add(b.type);
|
|
2304
|
+
}
|
|
2305
|
+
return types;
|
|
2306
|
+
}
|
|
2307
|
+
function buildCheckList(platform, enabledTypes) {
|
|
2297
2308
|
const entries = [{ check: checkOpenssl, required: true }];
|
|
2298
2309
|
if (platform === "darwin") {
|
|
2299
|
-
entries.push({
|
|
2310
|
+
entries.push({
|
|
2311
|
+
check: checkSecurity,
|
|
2312
|
+
required: enabledTypes === null || enabledTypes.has("keychain")
|
|
2313
|
+
});
|
|
2300
2314
|
entries.push({ check: checkBash, required: false });
|
|
2301
2315
|
} else if (platform === "win32") {
|
|
2302
|
-
entries.push({
|
|
2316
|
+
entries.push({
|
|
2317
|
+
check: checkPowershell,
|
|
2318
|
+
required: enabledTypes === null || enabledTypes.has("dpapi")
|
|
2319
|
+
});
|
|
2303
2320
|
} else {
|
|
2304
2321
|
entries.push({ check: checkBash, required: true });
|
|
2305
|
-
entries.push({
|
|
2322
|
+
entries.push({
|
|
2323
|
+
check: checkSecretTool,
|
|
2324
|
+
required: enabledTypes === null || enabledTypes.has("secret-tool")
|
|
2325
|
+
});
|
|
2306
2326
|
}
|
|
2307
|
-
entries.push({
|
|
2308
|
-
|
|
2327
|
+
entries.push({
|
|
2328
|
+
check: checkOp,
|
|
2329
|
+
required: enabledTypes?.has("1password") ?? false
|
|
2330
|
+
});
|
|
2331
|
+
entries.push({
|
|
2332
|
+
check: checkYkman,
|
|
2333
|
+
required: enabledTypes?.has("yubikey") ?? false
|
|
2334
|
+
});
|
|
2309
2335
|
return entries;
|
|
2310
2336
|
}
|
|
2311
2337
|
|
|
2312
2338
|
// src/vault.ts
|
|
2313
2339
|
var usageCounts = /* @__PURE__ */ new Map();
|
|
2340
|
+
var USAGE_MAP_MAX_SIZE = 1e4;
|
|
2314
2341
|
var VaultKeeper = class _VaultKeeper {
|
|
2315
2342
|
#config;
|
|
2316
2343
|
#keyManager;
|
|
@@ -2326,23 +2353,29 @@ var VaultKeeper = class _VaultKeeper {
|
|
|
2326
2353
|
* Runs doctor checks (unless skipped), loads config, and sets up the key manager.
|
|
2327
2354
|
*/
|
|
2328
2355
|
static async init(options) {
|
|
2356
|
+
const configDir = options?.configDir ?? getDefaultConfigDir();
|
|
2357
|
+
const config = options?.config ?? await loadConfig(configDir);
|
|
2329
2358
|
if (options?.skipDoctor !== true) {
|
|
2330
|
-
const doctorResult = await runDoctor();
|
|
2359
|
+
const doctorResult = await runDoctor({ backends: config.backends });
|
|
2331
2360
|
if (!doctorResult.ready) {
|
|
2332
2361
|
throw new VaultError(
|
|
2333
2362
|
`System not ready: ${doctorResult.nextSteps.join("; ")}`
|
|
2334
2363
|
);
|
|
2335
2364
|
}
|
|
2336
2365
|
}
|
|
2337
|
-
const configDir = options?.configDir ?? getDefaultConfigDir();
|
|
2338
|
-
const config = options?.config ?? await loadConfig(configDir);
|
|
2339
2366
|
const keyManager = new KeyManager();
|
|
2340
2367
|
await keyManager.init();
|
|
2341
2368
|
const vault = new _VaultKeeper(config, keyManager, configDir);
|
|
2342
2369
|
vault.#backend = vault.#resolveBackend();
|
|
2343
2370
|
return vault;
|
|
2344
2371
|
}
|
|
2345
|
-
/**
|
|
2372
|
+
/**
|
|
2373
|
+
* Run doctor checks without full initialization.
|
|
2374
|
+
*
|
|
2375
|
+
* Uses conservative platform defaults — all platform-native dependency
|
|
2376
|
+
* checks are treated as required regardless of any backend configuration.
|
|
2377
|
+
* For config-aware scoping, call `runDoctor({ backends })` directly.
|
|
2378
|
+
*/
|
|
2346
2379
|
static async doctor() {
|
|
2347
2380
|
return runDoctor();
|
|
2348
2381
|
}
|
|
@@ -2406,12 +2439,16 @@ var VaultKeeper = class _VaultKeeper {
|
|
|
2406
2439
|
const jti = claims.jti;
|
|
2407
2440
|
const currentCount = usageCounts.get(jti) ?? 0;
|
|
2408
2441
|
validateClaims(claims, currentCount);
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
usageCounts.delete(jti);
|
|
2412
|
-
blockToken(jti);
|
|
2413
|
-
} else {
|
|
2442
|
+
if (claims.use !== null) {
|
|
2443
|
+
const newCount = currentCount + 1;
|
|
2414
2444
|
usageCounts.set(jti, newCount);
|
|
2445
|
+
if (usageCounts.size > USAGE_MAP_MAX_SIZE) {
|
|
2446
|
+
const oldest = usageCounts.keys().next().value;
|
|
2447
|
+
if (oldest !== void 0) {
|
|
2448
|
+
usageCounts.delete(oldest);
|
|
2449
|
+
blockToken(oldest);
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2415
2452
|
}
|
|
2416
2453
|
const token = createCapabilityToken(claims);
|
|
2417
2454
|
const response = { keyStatus };
|