Files
writer-work-flow/apps/web/lib/security/dependencyFloors.test.ts
Yaojia Wang f4c2c4e8ec fix(frontend): 升级 Next→15.5.20 + React 19.2.7 修 RCE/补丁 + 版本下界守卫(CR-C1)
- next/eslint-config-next 15.1.3→15.5.20(backport 安全维护线),react/react-dom 19.0.0→19.2.7
- @types/react(-dom) →^19.2.0;pnpm audit --prod 无 next/react/react-dom 高危/严重告警
- 新增 lib/security/dependencyFloors 守卫 + 回归测试锁定安全下界
- 连带修 useDraftStream.test noUncheckedIndexedAccess(重锁失效增量缓存后暴露,对齐 useReviewStream 既有 ! 约定)
2026-07-08 11:04:55 +02:00

71 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { isAtLeast, SECURITY_FLOORS } from "./dependencyFloors";
// 读取本包 package.json 声明版本(相对本测试文件 ../../ → apps/web/package.json
function declaredVersions(): Record<string, string> {
const raw = readFileSync(
new URL("../../package.json", import.meta.url),
"utf-8",
);
const pkg = JSON.parse(raw) as {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
};
return { ...pkg.devDependencies, ...pkg.dependencies };
}
describe("SECURITY_FLOORS 锁定安全下界CR-C1", () => {
const declared = declaredVersions();
it.each(Object.keys(SECURITY_FLOORS))(
"%s 声明版本不得低于安全下界",
(name) => {
const version = declared[name];
if (version === undefined) {
throw new Error(`${name} 未在 package.json 声明`);
}
const floor = SECURITY_FLOORS[name as keyof typeof SECURITY_FLOORS];
expect(
isAtLeast(version, floor),
`${name}@${version} 低于安全下界 ${floor}`,
).toBe(true);
},
);
});
describe("isAtLeast 语义版本比较", () => {
it("相等即满足", () => {
expect(isAtLeast("15.5.20", "15.5.20")).toBe(true);
});
it("patch 更高满足、更低不满足", () => {
expect(isAtLeast("19.2.7", "19.2.0")).toBe(true);
expect(isAtLeast("19.2.0", "19.2.7")).toBe(false);
});
it("minor 边界", () => {
expect(isAtLeast("15.5.0", "15.1.3")).toBe(true);
expect(isAtLeast("15.1.3", "15.5.20")).toBe(false);
});
it("major 边界", () => {
expect(isAtLeast("19.0.0", "18.9.9")).toBe(true);
expect(isAtLeast("18.9.9", "19.0.0")).toBe(false);
});
it("去除前导 ^ / ~ 范围符", () => {
expect(isAtLeast("^19.2.7", "19.2.7")).toBe(true);
expect(isAtLeast("~19.2.7", "19.2.7")).toBe(true);
expect(isAtLeast("19.2.0", "^19.2.7")).toBe(false);
});
it("缺省段按 0 计", () => {
expect(isAtLeast("15", "15.0.0")).toBe(true);
expect(isAtLeast("15.5", "15.5.0")).toBe(true);
expect(isAtLeast("15", "15.5.0")).toBe(false);
});
});