mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-28 04:38:59 +00:00
fix(security): relabel unchanged bucket for cross-image comparisons (#662)
When comparing scans from two different image refs, same-CVE+package matches are not necessarily the same finding. Relabel the pill and row status from 'Unchanged' to 'Shared' in that case to convey that the caveat in the warning banner applies.
This commit is contained in:
@@ -241,9 +241,14 @@ export function ScanComparisonSheet({
|
||||
size="sm"
|
||||
className="h-7 text-xs px-2.5"
|
||||
onClick={() => { setFilter('unchanged'); setPage(0); }}
|
||||
title={
|
||||
crossImage
|
||||
? 'Same CVE and package name appear in both images. Because the images differ, this does not necessarily mean the finding is literally unchanged.'
|
||||
: 'Findings present in both scans'
|
||||
}
|
||||
>
|
||||
<Equal className="w-3 h-3 mr-1" strokeWidth={1.5} />
|
||||
Unchanged ({data.unchanged.length})
|
||||
{crossImage ? 'Shared' : 'Unchanged'} ({data.unchanged.length})
|
||||
</Button>
|
||||
{needsPagination && (
|
||||
<div className="flex items-center gap-1 ml-auto">
|
||||
@@ -349,7 +354,7 @@ export function ScanComparisonSheet({
|
||||
{filter === 'unchanged' && (
|
||||
<span className="inline-flex items-center gap-1 text-muted-foreground">
|
||||
<Equal className="w-3 h-3" strokeWidth={1.5} />
|
||||
Unchanged
|
||||
{crossImage ? 'Shared' : 'Unchanged'}
|
||||
</span>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
@@ -171,6 +171,41 @@ describe('ScanComparisonSheet', () => {
|
||||
expect(screen.queryByText(/findings per scan/i)).toBeNull();
|
||||
});
|
||||
|
||||
it('relabels the unchanged bucket as "Shared" for cross-image comparisons', async () => {
|
||||
mockedFetch.mockResolvedValueOnce(
|
||||
jsonResponse(200, result({
|
||||
scanB: { id: 2, image_ref: 'alpine:3.19', scanned_at: 1_700_000_010_000 },
|
||||
unchanged: [vuln({ vulnerability_id: 'CVE-U', pkg_name: 'pu' })],
|
||||
})),
|
||||
);
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<ScanComparisonSheet baselineScanId={1} currentScanId={2} onClose={() => {}} />);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByRole('button', { name: /Shared \(1\)/ })).toBeInTheDocument(),
|
||||
);
|
||||
expect(screen.queryByRole('button', { name: /Unchanged/ })).toBeNull();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /Shared \(1\)/ }));
|
||||
expect(screen.getByText('Shared')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps the "Unchanged" label when both scans use the same image', async () => {
|
||||
mockedFetch.mockResolvedValueOnce(
|
||||
jsonResponse(200, result({
|
||||
unchanged: [vuln({ vulnerability_id: 'CVE-U', pkg_name: 'pu' })],
|
||||
})),
|
||||
);
|
||||
|
||||
render(<ScanComparisonSheet baselineScanId={1} currentScanId={2} onClose={() => {}} />);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByRole('button', { name: /Unchanged \(1\)/ })).toBeInTheDocument(),
|
||||
);
|
||||
expect(screen.queryByRole('button', { name: /Shared/ })).toBeNull();
|
||||
});
|
||||
|
||||
it('reloads when the scan ids change', async () => {
|
||||
mockedFetch.mockResolvedValue(jsonResponse(200, result()));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user