Skip to content

Commit 7a490c6

Browse files
committed
runtime validation
1 parent 10d1e75 commit 7a490c6

5 files changed

Lines changed: 712 additions & 23 deletions

File tree

web-report/package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
8-
"generate": "json2ts ../src/main/resources/wfc/schemas/report.yaml src/types/GeneratedTypes.tsx",
8+
"generate": "json2ts ../src/main/resources/wfc/schemas/report.yaml src/types/GeneratedTypes.tsx && ts-to-zod src/types/GeneratedTypes.tsx src/types/GeneratedTypesZod.ts",
99
"build": "tsc -b && vite build",
10-
"installAndBuild": "yarn install && yarn generate && vitest --no-watch && tsc -b && vite build",
10+
"installAndBuild": "yarn install && yarn generate && vitest --no-watch && tsc -b && vite build && yarn copyRunFiles",
11+
"copyRunFiles": "cpx webreport.bat ../target/classes/webreport && cpx webreport.command ../target/classes/webreport && cpx webreport.py ../target/classes/webreport",
1112
"lint": "eslint .",
1213
"preview": "vite preview",
1314
"debug": "vite build && cpx \"src-e2e/static/*\" ../target/classes/webreport && vite preview",
@@ -31,7 +32,8 @@
3132
"recharts": "^2.15.1",
3233
"tailwind-merge": "^3.0.2",
3334
"tailwindcss": "^4.0.14",
34-
"tailwindcss-animate": "^1.0.7"
35+
"tailwindcss-animate": "^1.0.7",
36+
"zod": "^3.25.67"
3537
},
3638
"devDependencies": {
3739
"@eslint/js": "^9.21.0",
@@ -51,6 +53,7 @@
5153
"eslint-plugin-react-refresh": "^0.4.19",
5254
"globals": "^15.15.0",
5355
"happy-dom": "^17.4.7",
56+
"ts-to-zod": "^3.15.0",
5457
"typescript": "^5.8.3",
5558
"typescript-eslint": "^8.24.1",
5659
"vite": "^6.2.0",

web-report/src-e2e/App.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {resolve} from "path";
44
import {readFileSync} from "fs";
55
import {vi} from "vitest";
66
import App from "../src/App";
7-
import {fetchFileContent, getFaultCounts} from "@/lib/utils";
7+
import {fetchFileContent, getFaultCounts} from "../src/lib/utils";
88

99
// Read the report.json file
1010
const reportJsonPath = resolve(__dirname, './static/report.json');

web-report/src/AppProvider.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {createContext, useContext, useState, ReactNode, useEffect} from 'react';
22
import {WebFuzzingCommonsReport} from "@/types/GeneratedTypes.tsx";
33
import {ITestFiles} from "@/types/General.tsx";
44
import {fetchFileContent, ITransformedReport, transformWebFuzzingReport} from "@/lib/utils.tsx";
5+
import {webFuzzingCommonsReportSchema} from "@/types/GeneratedTypesZod.ts";
56

67
type AppContextType = {
78
data: WebFuzzingCommonsReport | null;
@@ -31,10 +32,17 @@ export const AppProvider = ({ children }: AppProviderProps) => {
3132
const fetchData = async () => {
3233
try {
3334
const jsonData = await fetchFileContent('./report.json') as WebFuzzingCommonsReport;
35+
36+
// Validate the JSON data against the schema
37+
const report = webFuzzingCommonsReportSchema.safeParse(jsonData);
38+
if (!report.success) {
39+
setError("Invalid report format. Please ensure the report is generated correctly.");
40+
return;
41+
}
3442
setData(jsonData);
3543
} catch (error: Error | unknown) {
3644
if (error instanceof Error) {
37-
setError("Could not load the report file. Please check if the file exists and is accessible in /public folder.");
45+
setError("Could not load the report file. Please check if the file exists and is accessible in main folder.");
3846
} else {
3947
console.error(error);
4048
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Generated by ts-to-zod
2+
import { z } from "zod";
3+
4+
export const operationIdSchema = z.string();
5+
6+
export const testCaseIdSchema = z.string();
7+
8+
export const httpStatusSchema = z.number();
9+
10+
export const testFilePathSchema = z.string();
11+
12+
export const testCaseSchema = z.record(z.unknown()).and(
13+
z.object({
14+
id: testCaseIdSchema.optional(),
15+
filePath: testFilePathSchema.optional(),
16+
name: z.string().optional(),
17+
startLine: z.number().optional(),
18+
endLine: z.number().optional(),
19+
}),
20+
);
21+
22+
export const faultCategoryIdSchema = z.record(z.unknown()).and(
23+
z.object({
24+
code: z.number(),
25+
context: z.string().optional(),
26+
}),
27+
);
28+
29+
export const coveredEndpointSchema = z.record(z.unknown()).and(
30+
z.object({
31+
endpointId: operationIdSchema,
32+
testCaseId: testCaseIdSchema,
33+
httpStatus: z.tuple([httpStatusSchema]).rest(httpStatusSchema),
34+
}),
35+
);
36+
37+
export const coverageCriterionSchema = z.record(z.unknown()).and(
38+
z.object({
39+
name: z.string(),
40+
covered: z.number(),
41+
total: z.number().optional(),
42+
}),
43+
);
44+
45+
export const rESTReportSchema = z.record(z.unknown()).and(
46+
z.object({
47+
totalHttpCalls: z.number(),
48+
endpointIds: z.array(operationIdSchema),
49+
coveredHttpStatus: z.array(coveredEndpointSchema),
50+
}),
51+
);
52+
53+
export const coverageSchema = z.record(z.unknown()).and(
54+
z.object({
55+
toolName: z.string(),
56+
criteria: z.array(coverageCriterionSchema),
57+
}),
58+
);
59+
60+
export const foundFaultSchema = z.record(z.unknown()).and(
61+
z.object({
62+
operationId: operationIdSchema.optional(),
63+
testCaseId: testCaseIdSchema,
64+
faultCategories: z
65+
.tuple([faultCategoryIdSchema])
66+
.rest(faultCategoryIdSchema),
67+
}),
68+
);
69+
70+
export const faultsSchema = z.record(z.unknown()).and(
71+
z.object({
72+
totalNumber: z.number(),
73+
foundFaults: z.array(foundFaultSchema),
74+
}),
75+
);
76+
77+
export const webFuzzingCommonsReportSchema = z.record(z.unknown()).and(
78+
z.object({
79+
schemaVersion: z.string(),
80+
toolName: z.string(),
81+
toolVersion: z.string(),
82+
creationTime: z.string(),
83+
faults: faultsSchema,
84+
problemDetails: z.record(z.unknown()).and(
85+
z.object({
86+
rest: rESTReportSchema.optional(),
87+
}),
88+
),
89+
totalTests: z.number(),
90+
testFilePaths: z.array(testFilePathSchema),
91+
testCases: z.array(testCaseSchema),
92+
extra: z.array(coverageSchema).optional(),
93+
}),
94+
);

0 commit comments

Comments
 (0)