foreman_cve_scanner 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +22 -4
- data/app/controllers/api/v2/cve_scans_controller.rb +23 -1
- data/app/models/concerns/foreman_cve_scanner/host_extensions.rb +122 -1
- data/app/models/host_status/cve_status.rb +4 -0
- data/app/services/foreman_cve_scanner/cve_report_scanner.rb +9 -7
- data/app/services/foreman_cve_scanner/katello_fix_availability.rb +208 -0
- data/app/services/foreman_cve_scanner/latest_scan_summaries.rb +51 -0
- data/app/services/foreman_cve_scanner/scan_importer.rb +2 -16
- data/app/services/foreman_cve_scanner/scan_post_processor.rb +29 -0
- data/app/views/api/v2/cve_scans/main.json.rabl +3 -1
- data/app/views/foreman_cve_scanner/job_templates/install_cve_scanners.erb +94 -57
- data/config/routes.rb +1 -0
- data/lib/foreman_cve_scanner/engine.rb +28 -19
- data/lib/foreman_cve_scanner/version.rb +1 -1
- data/test/controllers/api/v2/cve_scans_controller_test.rb +96 -0
- data/test/models/foreman_cve_scanner/host_extensions_test.rb +91 -0
- data/test/models/host_status/cve_status_test.rb +8 -0
- data/test/services/foreman_cve_scanner/cve_report_scanner_test.rb +86 -2
- data/test/services/foreman_cve_scanner/katello_fix_availability_test.rb +164 -0
- data/test/services/foreman_cve_scanner/latest_scan_summaries_test.rb +95 -0
- data/test/services/foreman_cve_scanner/scan_comparison_test.rb +28 -0
- data/test/services/foreman_cve_scanner/scan_importer_test.rb +55 -0
- data/test/services/foreman_cve_scanner/scan_post_processor_test.rb +59 -0
- data/webpack/components/CveCompareModal.js +9 -28
- data/webpack/components/CveDetailsCard.js +54 -65
- data/webpack/components/CveFindingsModal.js +15 -234
- data/webpack/components/CveFindingsView.js +307 -0
- data/webpack/components/CveKatelloFixLink.js +59 -0
- data/webpack/components/CveLink.js +28 -0
- data/webpack/components/CveScansReports.js +25 -62
- data/webpack/components/CveScansTab.js +42 -9
- data/webpack/components/CveSummaryCell.js +31 -19
- data/webpack/components/CveTrendChart.js +1 -16
- data/webpack/components/__tests__/CveDetailsCard.test.js +83 -14
- data/webpack/components/__tests__/CveFindingsModal.test.js +5 -2
- data/webpack/components/__tests__/CveFindingsView.test.js +153 -0
- data/webpack/components/__tests__/CveScansTab.test.js +141 -147
- data/webpack/components/__tests__/CveSummaryCell.test.js +68 -0
- data/webpack/components/__tests__/CveTrendChart.test.js +1 -3
- data/webpack/components/__tests__/cve_helpers.test.js +84 -0
- data/webpack/components/cve_helpers.js +114 -0
- data/webpack/components/cve_scans.scss +49 -0
- data/webpack/components/cve_summary_store.js +91 -0
- data/webpack/components/useSortBy.js +34 -0
- metadata +21 -1
|
@@ -209,6 +209,50 @@ button.cve-summary {
|
|
|
209
209
|
cursor: pointer;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
.cve-katello-fix {
|
|
213
|
+
border: 1px solid var(--pf-v5-global--BorderColor--100);
|
|
214
|
+
border-radius: 2px;
|
|
215
|
+
display: inline-flex;
|
|
216
|
+
font-size: 0.85rem;
|
|
217
|
+
font-weight: 600;
|
|
218
|
+
line-height: 1.3;
|
|
219
|
+
padding: 0.1rem 0.35rem;
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.cve-katello-fix[href] {
|
|
224
|
+
text-decoration: none;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.cve-katello-fix[href]:hover,
|
|
228
|
+
.cve-katello-fix[href]:focus {
|
|
229
|
+
text-decoration: underline;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.cve-katello-fix--installable {
|
|
233
|
+
background: #edf8ef;
|
|
234
|
+
border-color: var(--pf-v5-global--success-color--100);
|
|
235
|
+
color: var(--pf-v5-global--success-color--200);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.cve-katello-fix--applicable {
|
|
239
|
+
background: #fff7db;
|
|
240
|
+
border-color: var(--pf-v5-global--warning-color--100);
|
|
241
|
+
color: #795600;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.cve-katello-fix--unavailable,
|
|
245
|
+
.cve-katello-fix--unknown {
|
|
246
|
+
background: var(--pf-v5-global--BackgroundColor--200);
|
|
247
|
+
color: var(--pf-v5-global--Color--200);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.cve-katello-summary {
|
|
251
|
+
display: inline-flex;
|
|
252
|
+
flex-wrap: wrap;
|
|
253
|
+
gap: 0.35rem;
|
|
254
|
+
}
|
|
255
|
+
|
|
212
256
|
.cve-filter-button.is-active {
|
|
213
257
|
box-shadow: 0 0 0 2px var(--pf-v5-global--primary-color--100) inset;
|
|
214
258
|
}
|
|
@@ -520,6 +564,11 @@ button.cve-summary {
|
|
|
520
564
|
min-height: 26rem;
|
|
521
565
|
}
|
|
522
566
|
|
|
567
|
+
.cve-findings-meta {
|
|
568
|
+
margin-bottom: 0.75rem;
|
|
569
|
+
text-align: right;
|
|
570
|
+
}
|
|
571
|
+
|
|
523
572
|
.cve-modal-filters {
|
|
524
573
|
flex: 0 0 auto;
|
|
525
574
|
align-items: flex-end;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* eslint-disable import/no-unresolved */
|
|
2
|
+
import { foremanUrl } from 'foremanReact/common/helpers';
|
|
3
|
+
|
|
4
|
+
const listeners = new Map();
|
|
5
|
+
const cache = new Map();
|
|
6
|
+
const pendingHostIds = new Set();
|
|
7
|
+
let flushScheduled = false;
|
|
8
|
+
|
|
9
|
+
const notify = (hostId, value) => {
|
|
10
|
+
const hostListeners = listeners.get(hostId) || new Set();
|
|
11
|
+
hostListeners.forEach(listener => listener(value));
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const storeValue = (hostId, value) => {
|
|
15
|
+
cache.set(hostId, value);
|
|
16
|
+
notify(hostId, value);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const flushPending = async () => {
|
|
20
|
+
flushScheduled = false;
|
|
21
|
+
const hostIds = [...pendingHostIds];
|
|
22
|
+
pendingHostIds.clear();
|
|
23
|
+
if (!hostIds.length) return;
|
|
24
|
+
|
|
25
|
+
const params = new URLSearchParams();
|
|
26
|
+
hostIds.forEach(hostId => params.append('host_ids[]', hostId));
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(
|
|
30
|
+
foremanUrl(`/api/v2/cve_scans/latest_by_hosts?${params.toString()}`),
|
|
31
|
+
{ credentials: 'same-origin' }
|
|
32
|
+
);
|
|
33
|
+
if (!response.ok) throw new Error('Failed to load CVE summaries');
|
|
34
|
+
|
|
35
|
+
const payload = await response.json();
|
|
36
|
+
const results = Array.isArray(payload?.results) ? payload.results : [];
|
|
37
|
+
const byHostId = new Map(results.map(result => [result.host_id, result]));
|
|
38
|
+
|
|
39
|
+
hostIds.forEach(hostId => {
|
|
40
|
+
storeValue(hostId, byHostId.get(hostId) || null);
|
|
41
|
+
});
|
|
42
|
+
} catch (_error) {
|
|
43
|
+
hostIds.forEach(hostId => {
|
|
44
|
+
storeValue(hostId, null);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const scheduleFlush = () => {
|
|
50
|
+
if (flushScheduled) return;
|
|
51
|
+
|
|
52
|
+
flushScheduled = true;
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
flushPending();
|
|
55
|
+
}, 0);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const enqueueHostId = hostId => {
|
|
59
|
+
if (cache.has(hostId) || pendingHostIds.has(hostId)) return;
|
|
60
|
+
|
|
61
|
+
pendingHostIds.add(hostId);
|
|
62
|
+
scheduleFlush();
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const subscribeToCveSummary = (hostId, listener) => {
|
|
66
|
+
if (!listeners.has(hostId)) listeners.set(hostId, new Set());
|
|
67
|
+
listeners.get(hostId).add(listener);
|
|
68
|
+
|
|
69
|
+
if (cache.has(hostId)) {
|
|
70
|
+
listener(cache.get(hostId));
|
|
71
|
+
} else {
|
|
72
|
+
enqueueHostId(hostId);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
const hostListeners = listeners.get(hostId);
|
|
77
|
+
if (!hostListeners) return;
|
|
78
|
+
|
|
79
|
+
hostListeners.delete(listener);
|
|
80
|
+
if (!hostListeners.size) listeners.delete(hostId);
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const getCachedCveSummary = hostId => cache.get(hostId);
|
|
85
|
+
|
|
86
|
+
export const resetCveSummaryStore = () => {
|
|
87
|
+
listeners.clear();
|
|
88
|
+
cache.clear();
|
|
89
|
+
pendingHostIds.clear();
|
|
90
|
+
flushScheduled = false;
|
|
91
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable import/no-unresolved */
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
import { SortByDirection } from '@patternfly/react-table';
|
|
4
|
+
|
|
5
|
+
const useSortBy = (initialColumn, sorters, items) => {
|
|
6
|
+
const [sortBy, setSortBy] = useState({
|
|
7
|
+
direction: SortByDirection.desc,
|
|
8
|
+
column: initialColumn,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const onSort = column => {
|
|
12
|
+
setSortBy(prev => ({
|
|
13
|
+
column,
|
|
14
|
+
direction:
|
|
15
|
+
prev.column === column && prev.direction === SortByDirection.asc
|
|
16
|
+
? SortByDirection.desc
|
|
17
|
+
: SortByDirection.asc,
|
|
18
|
+
}));
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const sortedItems = useMemo(() => {
|
|
22
|
+
const list = [...items];
|
|
23
|
+
const sorter = sorters[sortBy.column] || sorters[initialColumn];
|
|
24
|
+
list.sort((a, b) => {
|
|
25
|
+
const result = sorter(a, b);
|
|
26
|
+
return sortBy.direction === SortByDirection.asc ? result : -result;
|
|
27
|
+
});
|
|
28
|
+
return list;
|
|
29
|
+
}, [initialColumn, items, sortBy, sorters]);
|
|
30
|
+
|
|
31
|
+
return { sortBy, onSort, sortedItems, setSortBy };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default useSortBy;
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_cve_scanner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bernhard Suttner
|
|
@@ -74,9 +74,12 @@ files:
|
|
|
74
74
|
- app/models/host_status/cve_status.rb
|
|
75
75
|
- app/services/concerns/foreman_cve_scanner/profiles_uploader.rb
|
|
76
76
|
- app/services/foreman_cve_scanner/cve_report_scanner.rb
|
|
77
|
+
- app/services/foreman_cve_scanner/katello_fix_availability.rb
|
|
78
|
+
- app/services/foreman_cve_scanner/latest_scan_summaries.rb
|
|
77
79
|
- app/services/foreman_cve_scanner/scan_cleanup.rb
|
|
78
80
|
- app/services/foreman_cve_scanner/scan_comparison.rb
|
|
79
81
|
- app/services/foreman_cve_scanner/scan_importer.rb
|
|
82
|
+
- app/services/foreman_cve_scanner/scan_post_processor.rb
|
|
80
83
|
- app/views/api/v2/cve_scans/base.json.rabl
|
|
81
84
|
- app/views/api/v2/cve_scans/index.json.rabl
|
|
82
85
|
- app/views/api/v2/cve_scans/latest.json.rabl
|
|
@@ -103,15 +106,22 @@ files:
|
|
|
103
106
|
- test/lib/foreman_cve_scanner/profiles_uploader_test.rb
|
|
104
107
|
- test/lib/foreman_cve_scanner/template_helpers_test.rb
|
|
105
108
|
- test/models/foreman_cve_scanner/cve_scan_test.rb
|
|
109
|
+
- test/models/foreman_cve_scanner/host_extensions_test.rb
|
|
106
110
|
- test/models/host_status/cve_status_test.rb
|
|
107
111
|
- test/services/foreman_cve_scanner/cve_report_scanner_test.rb
|
|
112
|
+
- test/services/foreman_cve_scanner/katello_fix_availability_test.rb
|
|
113
|
+
- test/services/foreman_cve_scanner/latest_scan_summaries_test.rb
|
|
108
114
|
- test/services/foreman_cve_scanner/scan_cleanup_test.rb
|
|
109
115
|
- test/services/foreman_cve_scanner/scan_comparison_test.rb
|
|
110
116
|
- test/services/foreman_cve_scanner/scan_importer_test.rb
|
|
117
|
+
- test/services/foreman_cve_scanner/scan_post_processor_test.rb
|
|
111
118
|
- test/test_plugin_helper.rb
|
|
112
119
|
- webpack/components/CveCompareModal.js
|
|
113
120
|
- webpack/components/CveDetailsCard.js
|
|
114
121
|
- webpack/components/CveFindingsModal.js
|
|
122
|
+
- webpack/components/CveFindingsView.js
|
|
123
|
+
- webpack/components/CveKatelloFixLink.js
|
|
124
|
+
- webpack/components/CveLink.js
|
|
115
125
|
- webpack/components/CveScansReports.js
|
|
116
126
|
- webpack/components/CveScansTab.js
|
|
117
127
|
- webpack/components/CveSummaryCell.js
|
|
@@ -120,12 +130,16 @@ files:
|
|
|
120
130
|
- webpack/components/__tests__/CveCompareModal.test.js
|
|
121
131
|
- webpack/components/__tests__/CveDetailsCard.test.js
|
|
122
132
|
- webpack/components/__tests__/CveFindingsModal.test.js
|
|
133
|
+
- webpack/components/__tests__/CveFindingsView.test.js
|
|
123
134
|
- webpack/components/__tests__/CveScansTab.test.js
|
|
135
|
+
- webpack/components/__tests__/CveSummaryCell.test.js
|
|
124
136
|
- webpack/components/__tests__/CveTrendChart.test.js
|
|
125
137
|
- webpack/components/__tests__/cve_helpers.test.js
|
|
126
138
|
- webpack/components/cve_helpers.js
|
|
127
139
|
- webpack/components/cve_scans.scss
|
|
140
|
+
- webpack/components/cve_summary_store.js
|
|
128
141
|
- webpack/components/useModalScan.js
|
|
142
|
+
- webpack/components/useSortBy.js
|
|
129
143
|
- webpack/fills.js
|
|
130
144
|
- webpack/fills_index.js
|
|
131
145
|
- webpack/index.js
|
|
@@ -162,15 +176,21 @@ test_files:
|
|
|
162
176
|
- test/lib/foreman_cve_scanner/profiles_uploader_test.rb
|
|
163
177
|
- test/lib/foreman_cve_scanner/template_helpers_test.rb
|
|
164
178
|
- test/models/foreman_cve_scanner/cve_scan_test.rb
|
|
179
|
+
- test/models/foreman_cve_scanner/host_extensions_test.rb
|
|
165
180
|
- test/models/host_status/cve_status_test.rb
|
|
166
181
|
- test/services/foreman_cve_scanner/cve_report_scanner_test.rb
|
|
182
|
+
- test/services/foreman_cve_scanner/katello_fix_availability_test.rb
|
|
183
|
+
- test/services/foreman_cve_scanner/latest_scan_summaries_test.rb
|
|
167
184
|
- test/services/foreman_cve_scanner/scan_cleanup_test.rb
|
|
168
185
|
- test/services/foreman_cve_scanner/scan_comparison_test.rb
|
|
169
186
|
- test/services/foreman_cve_scanner/scan_importer_test.rb
|
|
187
|
+
- test/services/foreman_cve_scanner/scan_post_processor_test.rb
|
|
170
188
|
- test/test_plugin_helper.rb
|
|
171
189
|
- webpack/components/__tests__/CveCompareModal.test.js
|
|
172
190
|
- webpack/components/__tests__/CveDetailsCard.test.js
|
|
173
191
|
- webpack/components/__tests__/CveFindingsModal.test.js
|
|
192
|
+
- webpack/components/__tests__/CveFindingsView.test.js
|
|
174
193
|
- webpack/components/__tests__/CveScansTab.test.js
|
|
194
|
+
- webpack/components/__tests__/CveSummaryCell.test.js
|
|
175
195
|
- webpack/components/__tests__/CveTrendChart.test.js
|
|
176
196
|
- webpack/components/__tests__/cve_helpers.test.js
|