/** * 密钥安全管理模块测试 * 验证:密钥必须来自环境变量,缺失时拒绝启动,绝不使用硬编码fallback */ import { describe, it, expect, beforeEach, afterEach } from "vitest"; describe("secrets - 密钥安全管理", () => { const originalEnv = { ...process.env }; afterEach(() => { // 恢复环境变量 process.env = { ...originalEnv }; }); it("所有必要密钥已配置时,validateSecrets应通过", async () => { process.env.NAC_MYSQL_URL = "mysql://user:pass@host:3306/db"; process.env.NAC_MONGO_URL = "mongodb://user:pass@host:27017/db"; process.env.NAC_JWT_SECRET = "test-jwt-secret-at-least-32-chars-long"; const { validateSecrets } = await import("./secrets"); expect(() => validateSecrets()).not.toThrow(); }); it("NAC_MYSQL_URL缺失时,validateSecrets应抛出错误", async () => { delete process.env.NAC_MYSQL_URL; process.env.NAC_MONGO_URL = "mongodb://user:pass@host:27017/db"; process.env.NAC_JWT_SECRET = "test-jwt-secret-at-least-32-chars-long"; // 动态重新导入以绕过模块缓存 const mod = await import("./secrets?t=" + Date.now()); expect(() => mod.validateSecrets()).toThrow(/NAC_MYSQL_URL/); }); it("NAC_MONGO_URL缺失时,validateSecrets应抛出错误", async () => { process.env.NAC_MYSQL_URL = "mysql://user:pass@host:3306/db"; delete process.env.NAC_MONGO_URL; process.env.NAC_JWT_SECRET = "test-jwt-secret-at-least-32-chars-long"; const mod = await import("./secrets?t=" + Date.now()); expect(() => mod.validateSecrets()).toThrow(/NAC_MONGO_URL/); }); it("NAC_JWT_SECRET缺失时,validateSecrets应抛出错误", async () => { process.env.NAC_MYSQL_URL = "mysql://user:pass@host:3306/db"; process.env.NAC_MONGO_URL = "mongodb://user:pass@host:27017/db"; delete process.env.NAC_JWT_SECRET; const mod = await import("./secrets?t=" + Date.now()); expect(() => mod.validateSecrets()).toThrow(/NAC_JWT_SECRET/); }); it("getNacMysqlUrl在密钥未配置时应抛出错误,而非返回硬编码值", async () => { delete process.env.NAC_MYSQL_URL; const mod = await import("./secrets?t=" + Date.now()); expect(() => mod.getNacMysqlUrl()).toThrow(/NAC_MYSQL_URL/); }); it("getNacJwtSecret在密钥未配置时应抛出错误,而非返回硬编码值", async () => { delete process.env.NAC_JWT_SECRET; const mod = await import("./secrets?t=" + Date.now()); expect(() => mod.getNacJwtSecret()).toThrow(/NAC_JWT_SECRET/); }); it("密钥值不应出现在错误消息中(防止密钥泄露)", async () => { const secretValue = "super-secret-password-12345"; process.env.NAC_MYSQL_URL = `mysql://user:${secretValue}@host:3306/db`; delete process.env.NAC_MONGO_URL; process.env.NAC_JWT_SECRET = "test-secret"; const mod = await import("./secrets?t=" + Date.now()); try { mod.validateSecrets(); } catch (e) { const errorMsg = (e as Error).message; // 错误消息中不应包含任何密钥值 expect(errorMsg).not.toContain(secretValue); } }); });