Commit a7b48a1e authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '210327-add-line-number' into 'master'

Add line number to SAST and Secret Detection

Closes #210327

See merge request gitlab-org/gitlab!35536
parents e3d3fc24 5412e7bf
<script>
import { s__, __ } from '~/locale';
import { s__, __, sprintf } from '~/locale';
import { GlEmptyState, GlFormCheckbox, GlLink, GlSkeletonLoading, GlTable } from '@gitlab/ui';
import RemediatedBadge from './remediated_badge.vue';
import getPrimaryIdentifier from 'ee/vue_shared/security_reports/store/utils/get_primary_identifier';
......@@ -148,6 +148,19 @@ export default {
},
},
methods: {
createLocationString(location) {
const { image, file, startLine } = location;
if (image) {
return image;
}
if (file && startLine) {
return `${file} ${sprintf(__('(line: %{startLine})'), { startLine })}`;
}
return file;
},
deselectAllVulnerabilities() {
this.selectedVulnerabilities = {};
},
......@@ -263,7 +276,7 @@ export default {
{{ item.project.nameWithNamespace }}
</div>
<div v-if="shouldShowVulnerabilityPath(item)" class="monospace">
{{ item.location.image || item.location.file }}
{{ createLocationString(item.location) }}
</div>
</div>
<remediated-badge v-if="item.resolved_on_default_branch" class="ml-2" />
......
......@@ -28,9 +28,11 @@ fragment Vulnerability on Vulnerability {
}
... on VulnerabilityLocationSast {
file
startLine
}
... on VulnerabilityLocationSecretDetection {
file
startLine
}
}
project {
......
---
title: Add line number to SAST and Secret Detection
merge_request: 35536
author:
type: changed
......@@ -37,6 +37,7 @@ export const generateVulnerabilities = () => [
reportType: 'DEPENDENCY_SCANNING',
location: {
file: 'src/main/java/com/gitlab/security_products/tests/App.java',
startLine: '1337',
},
project: {
nameWithNamespace: 'Administrator / Vulnerability reports',
......@@ -49,7 +50,7 @@ export const generateVulnerabilities = () => [
state: 'opened',
reportType: 'CUSTOM_SCANNER_WITHOUT_TRANSLATION',
location: {
file: 'yarn.lock',
file: 'src/main/java/com/gitlab/security_products/tests/App.java',
},
project: {
nameWithNamespace: 'Mixed Vulnerabilities / Dependency List Test 01',
......@@ -64,7 +65,17 @@ export const generateVulnerabilities = () => [
file: 'yarn.lock',
},
project: {
nameWithNamespace: 'Mixed Vulnerabilities / Dependency List Test 01',
nameWithNamespace: 'Mixed Vulnerabilities / Rails App',
},
},
{
id: 'id_4',
title: 'Vulnerability 4',
severity: 'critical',
state: 'dismissed',
location: {},
project: {
nameWithNamespace: 'Administrator / Security reports',
},
},
];
......
......@@ -35,6 +35,7 @@ describe('Vulnerability list component', () => {
const findRowVulnerabilityCommentIcon = row => findRow(row).find(VulnerabilityCommentIcon);
const findDataCell = label => wrapper.find(`[data-testid="${label}"]`);
const findDataCells = label => wrapper.findAll(`[data-testid="${label}"]`);
const findCellText = label => findDataCell(label).text();
afterEach(() => {
wrapper.destroy();
......@@ -116,19 +117,35 @@ describe('Vulnerability list component', () => {
});
});
it('should display the vulnerability locations', () => {
expect(findDataCell(`location-${newVulnerabilities[0].id}`).text()).toContain(
'Administrator / Security reports',
);
expect(findDataCell(`location-${newVulnerabilities[0].id}`).text()).toContain(
'registry.gitlab.com/groulot/container-scanning-test/master:5f21de6956aee99ddb68ae49498662d9872f50ff',
);
expect(findDataCell(`location-${newVulnerabilities[1].id}`).text()).toContain(
'Administrator / Vulnerability reports',
);
expect(findDataCell(`location-${newVulnerabilities[1].id}`).text()).toContain(
'src/main/java/com/gitlab/security_products/tests/App.java',
);
it('should display the vulnerability locations for images', () => {
const { id, project, location } = newVulnerabilities[0];
const cellText = findCellText(`location-${id}`);
expect(cellText).toContain(project.nameWithNamespace);
expect(cellText).toContain(location.image);
expect(cellText).not.toContain('(line: ');
});
it('should display the vulnerability locations for code', () => {
const { id, project, location } = newVulnerabilities[1];
const cellText = findCellText(`location-${id}`);
expect(cellText).toContain(project.nameWithNamespace);
expect(cellText).toContain(location.file);
expect(cellText).toContain(`(line: ${location.startLine})`);
});
it('should display the vulnerability locations for code with no line data', () => {
const { id, project, location } = newVulnerabilities[2];
const cellText = findCellText(`location-${id}`);
expect(cellText).toContain(project.nameWithNamespace);
expect(cellText).toContain(location.file);
expect(cellText).not.toContain('(line: ');
});
it('should not display the vulnerability locations for vulnerabilities without a location', () => {
const { id, project } = newVulnerabilities[4];
const cellText = findCellText(`location-${id}`);
expect(cellText).toEqual(project.nameWithNamespace);
expect(cellText).not.toContain('(line: ');
});
it('should not display the vulnerability identifier', () => {
......@@ -140,30 +157,6 @@ describe('Vulnerability list component', () => {
const cell = findDataCell('vulnerability-report-type');
expect(cell.exists()).toBe(false);
});
it('should not display the vulnerability locations', () => {
const vulnerabilityWithoutLocation = [
{
id: 'id_0',
title: 'Vulnerability 1',
severity: 'critical',
state: 'dismissed',
location: {},
project: {
nameWithNamespace: 'Administrator / Security reports',
},
},
];
wrapper = createWrapper({
props: { vulnerabilities: vulnerabilityWithoutLocation, shouldShowProjectNamespace: true },
});
expect(findDataCell(`location-${vulnerabilityWithoutLocation[0].id}`).text()).toContain(
'Administrator / Security reports',
);
expect(
findDataCell(`location-${vulnerabilityWithoutLocation[0].id}`).findAll('div').length,
).toBe(2);
});
});
describe('when displayed on a project level dashboard', () => {
......@@ -179,19 +172,25 @@ describe('Vulnerability list component', () => {
});
});
it('should not display the vulnerability locations', () => {
expect(findDataCell(`location-${newVulnerabilities[0].id}`).text()).not.toContain(
'Administrator / Security reports',
);
expect(findDataCell(`location-${newVulnerabilities[0].id}`).text()).toContain(
'registry.gitlab.com/groulot/container-scanning-test/master:5f21de6956aee99ddb68ae49498662d9872f50ff',
);
expect(findDataCell(`location-${newVulnerabilities[1].id}`).text()).not.toContain(
'Administrator / Vulnerability reports',
);
expect(findDataCell(`location-${newVulnerabilities[1].id}`).text()).toContain(
'src/main/java/com/gitlab/security_products/tests/App.java',
);
it('should not display the vulnerability group/project locations for images', () => {
const { id, project, location } = newVulnerabilities[0];
const cellText = findCellText(`location-${id}`);
expect(cellText).not.toContain(project.nameWithNamespace);
expect(cellText).toEqual(location.image);
});
it('should display the vulnerability locations for code', () => {
const { id, project, location } = newVulnerabilities[1];
const cellText = findCellText(`location-${id}`);
expect(cellText).not.toContain(project.nameWithNamespace);
expect(cellText).toEqual(`${location.file} (line: ${location.startLine})`);
});
it('should not display the vulnerability group/project locations for code with no line data', () => {
const { id, project, location } = newVulnerabilities[2];
const cellText = findCellText(`location-${id}`);
expect(cellText).not.toContain(project.nameWithNamespace);
expect(cellText).toEqual(location.file);
});
it('should correctly render the identifier', () => {
......
......@@ -752,6 +752,9 @@ msgstr ""
msgid "(external source)"
msgstr ""
msgid "(line: %{startLine})"
msgstr ""
msgid "(removed)"
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment