Skip to content

Commit 2a88ebf

Browse files
updated report to show repo level results
1 parent b7bd9fe commit 2a88ebf

File tree

3 files changed

+316
-123
lines changed

3 files changed

+316
-123
lines changed

src/components/SecurityReport.js

Lines changed: 79 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -4,138 +4,79 @@ import {
44
Page,
55
Text,
66
View,
7-
StyleSheet,
87
Image,
98
Svg,
109
Path,
1110
} from '@react-pdf/renderer';
12-
13-
const styles = StyleSheet.create({
14-
page: {
15-
padding: 30,
16-
fontSize: 12,
17-
},
18-
headerContainer: {
19-
flexDirection: 'row',
20-
alignItems: 'center',
21-
marginBottom: 40,
22-
},
23-
logoContainer: {
24-
width: 40,
25-
height: 40,
26-
marginRight: 10,
27-
},
28-
headerText: {
29-
fontSize: 24,
30-
fontWeight: 'bold',
31-
},
32-
infoTable: {
33-
marginBottom: 20,
34-
},
35-
infoRow: {
36-
flexDirection: 'row',
37-
marginBottom: 8,
38-
},
39-
infoLabel: {
40-
width: 150,
41-
fontWeight: 'bold',
42-
},
43-
infoValue: {
44-
flex: 1,
45-
},
46-
section: {
47-
marginTop: 15,
48-
marginBottom: 10,
49-
},
50-
sectionTitle: {
51-
fontSize: 18,
52-
marginBottom: 10,
53-
},
54-
table: {
55-
width: 'auto',
56-
borderStyle: 'solid',
57-
borderWidth: 1,
58-
borderRightWidth: 0,
59-
borderBottomWidth: 0,
60-
marginBottom: 10,
61-
},
62-
tableRow: {
63-
margin: 'auto',
64-
flexDirection: 'row',
65-
},
66-
tableHeader: {
67-
backgroundColor: '#f6f6f6',
68-
},
69-
tableCell: {
70-
width: '33%',
71-
borderStyle: 'solid',
72-
borderWidth: 1,
73-
borderLeftWidth: 0,
74-
borderTopWidth: 0,
75-
padding: 5,
76-
},
77-
tableCellHeader: {
78-
width: '33%',
79-
borderStyle: 'solid',
80-
borderWidth: 1,
81-
borderLeftWidth: 0,
82-
borderTopWidth: 0,
83-
padding: 5,
84-
backgroundColor: '#f6f6f6',
85-
fontWeight: 'bold',
86-
},
87-
tableCellHalf: {
88-
width: '50%',
89-
borderStyle: 'solid',
90-
borderWidth: 1,
91-
borderLeftWidth: 0,
92-
borderTopWidth: 0,
93-
padding: 5,
94-
},
95-
tableCellHeaderHalf: {
96-
width: '50%',
97-
borderStyle: 'solid',
98-
borderWidth: 1,
99-
borderLeftWidth: 0,
100-
borderTopWidth: 0,
101-
padding: 5,
102-
backgroundColor: '#f6f6f6',
103-
fontWeight: 'bold',
104-
},
105-
chartContainer: {
106-
marginTop: 10,
107-
marginBottom: 10,
108-
width: '100%',
109-
height: 200,
110-
},
111-
chart: {
112-
width: '100%',
113-
height: '100%',
114-
objectFit: 'contain',
115-
},
116-
alertItem: {
117-
marginBottom: 10,
118-
padding: 5,
119-
borderStyle: 'solid',
120-
borderWidth: 1,
121-
borderColor: '#ccc',
122-
},
123-
});
11+
import { styles } from '../styles/reportStyles';
12412

12513
const formatDate = () => {
12614
const now = new Date();
12715
return now.toISOString().replace('T', ' ').slice(0, -5) + 'Z';
12816
};
12917

130-
const TableRow = ({ items, isHeader = false, twoColumns = false }) => (
131-
<View style={styles.tableRow}>
132-
{items.map((item, i) => (
133-
<Text key={i} style={isHeader ?
134-
(twoColumns ? styles.tableCellHeaderHalf : styles.tableCellHeader) :
135-
(twoColumns ? styles.tableCellHalf : styles.tableCell)
136-
}>
137-
{item}
138-
</Text>
18+
const TableRow = ({ items, isHeader = false, twoColumns = false, isRepoTable = false, threeColumns = false }) => {
19+
let cellStyle, headerStyle;
20+
21+
if (isRepoTable) {
22+
if (threeColumns) {
23+
cellStyle = styles.repoTableCellThird;
24+
headerStyle = styles.repoTableCellHeaderThird;
25+
} else {
26+
cellStyle = styles.repoTableCell;
27+
headerStyle = styles.repoTableCellHeader;
28+
}
29+
} else if (twoColumns) {
30+
cellStyle = styles.tableCellHalf;
31+
headerStyle = styles.tableCellHeaderHalf;
32+
} else {
33+
cellStyle = styles.tableCell;
34+
headerStyle = styles.tableCellHeader;
35+
}
36+
37+
return (
38+
<View style={styles.tableRow}>
39+
{items.map((item, i) => (
40+
<Text key={i} style={isHeader ? headerStyle : cellStyle}>
41+
{item}
42+
</Text>
43+
))}
44+
</View>
45+
);
46+
};
47+
48+
const RepoBreakdownTable = ({ data, showSeverity = true }) => (
49+
<View style={styles.repoTable}>
50+
<TableRow
51+
items={showSeverity ?
52+
['Repository', 'Total', 'Critical', 'High', 'Medium', 'Low'] :
53+
['Repository', 'Total', 'Open']
54+
}
55+
isHeader={true}
56+
isRepoTable={true}
57+
threeColumns={!showSeverity}
58+
/>
59+
{Object.entries(data).map(([repoName, stats]) => (
60+
<TableRow
61+
key={repoName}
62+
items={showSeverity ?
63+
[
64+
repoName,
65+
stats.total.toString(),
66+
stats.severity.critical.toString(),
67+
stats.severity.high.toString(),
68+
stats.severity.medium.toString(),
69+
stats.severity.low.toString()
70+
] :
71+
[
72+
repoName,
73+
stats.total.toString(),
74+
stats.open.toString()
75+
]
76+
}
77+
isRepoTable={true}
78+
threeColumns={!showSeverity}
79+
/>
13980
))}
14081
</View>
14182
);
@@ -193,7 +134,7 @@ const SecurityReport = ({ organization, alerts, summary, showAllAlerts, chartIma
193134
</View>
194135
</View>
195136

196-
{/* Code Scanning Section */}
137+
{/* Code Scanning Section - Part 1 */}
197138
<View style={styles.section}>
198139
<Text style={styles.sectionTitle}>Code Scanning Alerts</Text>
199140
{chartImages?.codeScanning && (
@@ -208,6 +149,15 @@ const SecurityReport = ({ organization, alerts, summary, showAllAlerts, chartIma
208149
<TableRow items={['Medium', summary.codeScanning.severity.medium.toString()]} twoColumns={true} />
209150
<TableRow items={['Low', summary.codeScanning.severity.low.toString()]} twoColumns={true} />
210151
</View>
152+
</View>
153+
</Page>
154+
155+
{/* New page for Repository Breakdown */}
156+
<Page size="A4" style={styles.page}>
157+
{/* Code Scanning Section - Part 2 */}
158+
<View style={styles.section}>
159+
<Text style={[styles.sectionTitle, { fontSize: 14, marginTop: 10 }]}>Repository Breakdown</Text>
160+
<RepoBreakdownTable data={summary.codeScanning.byRepository} />
211161

212162
{showAllAlerts && alerts.codeScanning.map((alert, index) => (
213163
<View key={index} style={styles.alertItem}>
@@ -230,6 +180,9 @@ const SecurityReport = ({ organization, alerts, summary, showAllAlerts, chartIma
230180
))}
231181
</View>
232182

183+
<Text style={[styles.sectionTitle, { fontSize: 14, marginTop: 10 }]}>Repository Breakdown</Text>
184+
<RepoBreakdownTable data={summary.secretScanning.byRepository} showSeverity={false} />
185+
233186
{showAllAlerts && alerts.secretScanning.map((alert, index) => (
234187
<View key={index} style={styles.alertItem}>
235188
<Text>Type: {alert.secret_type_display_name}</Text>
@@ -256,6 +209,9 @@ const SecurityReport = ({ organization, alerts, summary, showAllAlerts, chartIma
256209
<TableRow items={['Low', summary.dependabot.severity.low.toString()]} twoColumns={true} />
257210
</View>
258211

212+
<Text style={[styles.sectionTitle, { fontSize: 14, marginTop: 10 }]}>Repository Breakdown</Text>
213+
<RepoBreakdownTable data={summary.dependabot.byRepository} />
214+
259215
{showAllAlerts && alerts.dependabot.map((alert, index) => (
260216
<View key={index} style={styles.alertItem}>
261217
<Text>Package: {alert.dependency.package.name}</Text>

src/services/githubService.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,76 @@ export const fetchSecurityAlerts = async (token, organization) => {
9090
};
9191

9292
export const generateAlertsSummary = (alerts) => {
93+
// Initialize repository tracking
94+
const repoStats = {
95+
codeScanning: {},
96+
secretScanning: {},
97+
dependabot: {}
98+
};
99+
100+
// Process code scanning alerts by repository
101+
alerts.codeScanning.forEach(alert => {
102+
const repoName = alert.repository.name;
103+
if (!repoStats.codeScanning[repoName]) {
104+
repoStats.codeScanning[repoName] = {
105+
total: 0,
106+
open: 0,
107+
severity: {
108+
critical: 0,
109+
high: 0,
110+
medium: 0,
111+
low: 0
112+
}
113+
};
114+
}
115+
116+
repoStats.codeScanning[repoName].total++;
117+
if (alert.state === 'open') repoStats.codeScanning[repoName].open++;
118+
if (alert.rule?.security_severity_level) {
119+
repoStats.codeScanning[repoName].severity[alert.rule.security_severity_level]++;
120+
}
121+
});
122+
123+
// Process secret scanning alerts by repository
124+
alerts.secretScanning.forEach(alert => {
125+
const repoName = alert.repository.name;
126+
if (!repoStats.secretScanning[repoName]) {
127+
repoStats.secretScanning[repoName] = {
128+
total: 0,
129+
open: 0,
130+
types: {}
131+
};
132+
}
133+
134+
repoStats.secretScanning[repoName].total++;
135+
if (alert.state === 'open') repoStats.secretScanning[repoName].open++;
136+
repoStats.secretScanning[repoName].types[alert.secret_type] =
137+
(repoStats.secretScanning[repoName].types[alert.secret_type] || 0) + 1;
138+
});
139+
140+
// Process dependabot alerts by repository
141+
alerts.dependabot.forEach(alert => {
142+
const repoName = alert.repository.name;
143+
if (!repoStats.dependabot[repoName]) {
144+
repoStats.dependabot[repoName] = {
145+
total: 0,
146+
open: 0,
147+
severity: {
148+
critical: 0,
149+
high: 0,
150+
medium: 0,
151+
low: 0
152+
}
153+
};
154+
}
155+
156+
repoStats.dependabot[repoName].total++;
157+
if (alert.state === 'open') repoStats.dependabot[repoName].open++;
158+
if (alert.security_advisory?.severity) {
159+
repoStats.dependabot[repoName].severity[alert.security_advisory.severity]++;
160+
}
161+
});
162+
93163
return {
94164
codeScanning: {
95165
total: alerts.codeScanning.length,
@@ -100,6 +170,7 @@ export const generateAlertsSummary = (alerts) => {
100170
medium: alerts.codeScanning.filter(alert => alert.rule?.security_severity_level === 'medium').length,
101171
low: alerts.codeScanning.filter(alert => alert.rule?.security_severity_level === 'low').length,
102172
},
173+
byRepository: repoStats.codeScanning
103174
},
104175
secretScanning: {
105176
total: alerts.secretScanning.length,
@@ -108,6 +179,7 @@ export const generateAlertsSummary = (alerts) => {
108179
acc[alert.secret_type] = (acc[alert.secret_type] || 0) + 1;
109180
return acc;
110181
}, {}),
182+
byRepository: repoStats.secretScanning
111183
},
112184
dependabot: {
113185
total: alerts.dependabot.length,
@@ -118,6 +190,7 @@ export const generateAlertsSummary = (alerts) => {
118190
medium: alerts.dependabot.filter(alert => alert.security_advisory?.severity === 'medium').length,
119191
low: alerts.dependabot.filter(alert => alert.security_advisory?.severity === 'low').length,
120192
},
193+
byRepository: repoStats.dependabot
121194
},
122195
};
123196
};

0 commit comments

Comments
 (0)