test(config): cover secret bundle inode races
This commit is contained in:
@@ -2,7 +2,7 @@ import { afterEach, expect, test } from "vitest";
|
||||
import { chmodSync, mkdtempSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { loadSecretBundle, secretValue } from "../src/config/secret-bundle.js";
|
||||
import { loadSecretBundle, loadSecretBundleWithFs, secretValue } from "../src/config/secret-bundle.js";
|
||||
|
||||
const dirs: string[] = [];
|
||||
afterEach(() => { for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true }); });
|
||||
@@ -48,6 +48,22 @@ test("checks inode identity before parsing", () => {
|
||||
expect(loadSecretBundle(file).get("THT_MODEL_API_KEY")).toBe("replaced");
|
||||
});
|
||||
|
||||
test("rejects inode replacement between lstat and open without reading", () => {
|
||||
let reads = 0;
|
||||
const stat = (ino: number) => ({
|
||||
dev: 7, ino, uid: process.getuid?.() ?? 0, mode: 0o100600, nlink: 1, size: 24,
|
||||
isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false,
|
||||
});
|
||||
expect(() => loadSecretBundleWithFs("/safe/bundle", {
|
||||
lstat: () => stat(1) as any,
|
||||
open: () => 9,
|
||||
fstat: () => stat(2) as any,
|
||||
read: () => { reads += 1; return "THT_MODEL_API_KEY=secret\n"; },
|
||||
close: () => undefined,
|
||||
})).toThrow("secret bundle is unavailable");
|
||||
expect(reads).toBe(0);
|
||||
});
|
||||
|
||||
test("secretValue prefers bundle and supports the legacy file fallback", () => {
|
||||
const file = bundle("THT_MODEL_API_KEY=from-bundle\n");
|
||||
const legacy = bundle("from-legacy");
|
||||
|
||||
Reference in New Issue
Block a user