42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import {
|
|
createSourceRange,
|
|
diagnose,
|
|
diagnosticSummary,
|
|
sliceSource,
|
|
supportsSyntaxFeature,
|
|
} from "../src/index.ts";
|
|
|
|
describe("syntax contract and security diagnostics", () => {
|
|
test("validates source ranges and summarizes diagnostic codes", () => {
|
|
const range = createSourceRange(2, 6);
|
|
expect(sliceSource("0123456789", range)).toBe("2345");
|
|
expect(() => createSourceRange(-1, 2)).toThrow(RangeError);
|
|
expect(() => createSourceRange(4, 3)).toThrow(RangeError);
|
|
expect(supportsSyntaxFeature("runtime-markers")).toBe(true);
|
|
expect(supportsSyntaxFeature("dynamic-eval")).toBe(false);
|
|
|
|
const summary = diagnosticSummary([
|
|
{ code: "A", severity: "error", message: "a" },
|
|
{ code: "A", severity: "warning", message: "b" },
|
|
{ code: "B", severity: "info", message: "c" },
|
|
]);
|
|
expect(summary).toEqual({ errors: 1, warnings: 1, info: 1, codes: { A: 2, B: 1 } });
|
|
});
|
|
|
|
test("rejects browser secret reads, executable sinks, and sensitive persistence", () => {
|
|
const diagnostics = diagnose(`page store Unsafe {
|
|
client state { apiToken: string = process.env.API_TOKEN }
|
|
persist { storage = "local" include = ["apiToken"] version = 1 }
|
|
functions {
|
|
client function render(raw: string): void { document.write(raw); setTimeout("run()", 1) }
|
|
}
|
|
}`);
|
|
const codes = diagnostics.map((diagnostic) => diagnostic.code);
|
|
expect(codes).toContain("WRN-SEC-SERVER-SECRET-SOURCE");
|
|
expect(codes).toContain("WRN-SEC-DOM-SINK");
|
|
expect(codes).toContain("WRN-SEC-STRING-TIMER");
|
|
expect(codes).toContain("WRN-PERSIST-SENSITIVE");
|
|
});
|
|
});
|