Commit 085324df authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch '6709-group-security-dashboard-api-integration-fe-ee' into 'master'

Security Dashboard API hookup

See merge request gitlab-org/gitlab-ee!7793
parents c4399be0 586f688a
<script>
import { mapActions, mapGetters } from 'vuex';
import { mapActions, mapGetters, mapState } from 'vuex';
import { s__ } from '~/locale';
import Tabs from '~/vue_shared/components/tabs/tabs';
import Tab from '~/vue_shared/components/tabs/tab.vue';
import SecurityDashboardTable from './security_dashboard_table.vue';
import VulnerabilityCountList from './vulnerability_count_list.vue';
import SvgBlankState from '~/pipelines/components/blank_state.vue';
import Icon from '~/vue_shared/components/icon.vue';
import popover from '~/vue_shared/directives/popover';
export default {
name: 'SecurityDashboardApp',
directives: {
popover,
},
components: {
Tabs,
Tab,
Icon,
SecurityDashboardTable,
SvgBlankState,
Tab,
Tabs,
VulnerabilityCountList,
},
props: {
dashboardDocumentation: {
type: String,
required: true,
},
emptyStateSvgPath: {
type: String,
required: true,
},
errorStateSvgPath: {
type: String,
required: true,
},
vulnerabilitiesEndpoint: {
type: String,
required: true,
},
vulnerabilitiesCountEndpoint: {
type: String,
required: true,
},
},
computed: {
...mapGetters('vulnerabilities', ['vulnerabilitiesCountByReportType']),
...mapState('vulnerabilities', ['hasError']),
sastCount() {
return this.vulnerabilitiesCountByReportType('sast');
},
popoverOptions() {
return {
trigger: 'click',
placement: 'right',
title: s__(
'Security Reports|At this time, the security dashboard only supports SAST. More analyzers are coming soon.',
),
content: `
<a
title="${s__('Security Reports|Security Dashboard Roadmap')}"
href="${this.dashboardDocumentation}"
target="_blank"
rel="noopener
noreferrer"
>
<span class="vertical-align-middle">${s__(
'Security Reports|Security Dashboard Roadmap',
)}</span>
${gl.utils.spriteIcon('external-link', 's16 vertical-align-middle')}
</a>
`,
html: true,
};
},
},
created() {
this.setVulnerabilitiesEndpoint(this.vulnerabilitiesEndpoint);
this.setVulnerabilitiesCountEndpoint(this.vulnerabilitiesCountEndpoint);
this.fetchVulnerabilitiesCount();
},
methods: {
...mapActions('vulnerabilities', ['fetchVulnerabilitiesCount']),
...mapActions('vulnerabilities', [
'setVulnerabilitiesCountEndpoint',
'setVulnerabilitiesEndpoint',
'fetchVulnerabilitiesCount',
]),
},
};
</script>
<template>
<div>
<svg-blank-state
v-if="hasError"
:svg-path="errorStateSvgPath"
:message="s__(`Security Reports|There was an error fetching the dashboard.
Please try again in a few moments or contact your support team.`)"
/>
<div v-else>
<vulnerability-count-list />
<tabs stop-propagation>
<tab active>
<template slot="title">
{{ __('SAST') }}
<span>{{ __('SAST') }}</span>
<span
v-if="sastCount"
class="badge badge-pill">
class="badge badge-pill"
>
{{ sastCount }}
</span>
<span
v-popover="popoverOptions"
class="text-muted ml-1"
>
<icon
name="question"
class="vertical-align-middle"
/>
</span>
</template>
<security-dashboard-table/>
<security-dashboard-table
:empty-state-svg-path="emptyStateSvgPath"
/>
</tab>
</tabs>
</div>
</div>
</template>
......@@ -2,6 +2,7 @@
import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import SecurityDashboardActionButtons from './security_dashboard_action_buttons.vue';
import VulnerabilityIssueLink from './vulnerability_issue_link.vue';
export default {
name: 'SecurityDashboardTableRow',
......@@ -9,6 +10,7 @@ export default {
SeverityBadge,
SecurityDashboardActionButtons,
SkeletonLoading,
VulnerabilityIssueLink,
},
props: {
vulnerability: {
......@@ -31,7 +33,13 @@ export default {
},
projectNamespace() {
const { project } = this.vulnerability;
return project && project.name_with_namespace ? project.name_with_namespace : null;
return project && project.full_name ? project.full_name : null;
},
isDismissed() {
return this.vulnerability.dismissal_feedback;
},
hasIssue() {
return this.vulnerability.issue_feedback;
},
},
};
......@@ -65,7 +73,13 @@ export default {
:lines="2"
/>
<div v-else>
<span>{{ vulnerability.description }}</span>
<strike v-if="isDismissed">{{ vulnerability.name }}</strike>
<span v-else>{{ vulnerability.name }}</span>
<vulnerability-issue-link
v-if="hasIssue"
:issue="vulnerability.issue_feedback"
:project-name="vulnerability.project.name"
/>
<br />
<span
v-if="projectNamespace"
......@@ -84,7 +98,8 @@ export default {
{{ s__('Reports|Confidence') }}
</div>
<div class="table-mobile-content text-capitalize">
{{ confidence }}
<strike v-if="isDismissed">{{ confidence }}</strike>
<span v-else>{{ confidence }}</span>
</div>
</div>
......
<script>
import Icon from '~/vue_shared/components/icon.vue';
import Tooltip from '~/vue_shared/directives/tooltip';
export default {
name: 'VulnerabilityIssueLink',
components: {
Icon,
},
directives: {
Tooltip,
},
props: {
issue: {
type: Object,
required: true,
},
projectName: {
type: String,
required: true,
},
},
computed: {
linkText() {
return `${this.projectName}#${this.issue.issue_id}`;
},
},
};
</script>
<template>
<div class="d-inline">
<icon
v-tooltip
name="issues"
css-classes="text-success vertical-align-middle"
:title="s__('Security Dashboard|Issue Created')"
/>
<a
:href="issue.issue_url"
>{{ linkText }}</a>
</div>
</template>
......@@ -12,7 +12,15 @@ export default () => {
GroupSecurityDashboardApp,
},
render(createElement) {
return createElement('group-security-dashboard-app');
return createElement('group-security-dashboard-app', {
props: {
dashboardDocumentation: el.dataset.dashboardDocumentation,
errorStateSvgPath: el.dataset.errorStateSvgPath,
emptyStateSvgPath: el.dataset.emptyStateSvgPath,
vulnerabilitiesEndpoint: el.dataset.vulnerabilitiesEndpoint,
vulnerabilitiesCountEndpoint: el.dataset.vulnerabilitiesSummaryEndpoint,
},
});
},
});
};
......@@ -2,6 +2,14 @@ import axios from '~/lib/utils/axios_utils';
import * as types from './mutation_types';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
export const setVulnerabilitiesEndpoint = ({ commit }, endpoint) => {
commit(types.SET_VULNERABILITIES_ENDPOINT, endpoint);
};
export const setVulnerabilitiesCountEndpoint = ({ commit }, endpoint) => {
commit(types.SET_VULNERABILITIES_COUNT_ENDPOINT, endpoint);
};
export const fetchVulnerabilitiesCount = ({ state, dispatch }) => {
dispatch('requestVulnerabilitiesCount');
......
[
{
"id": "wzexrctyu",
"id": 1,
"report_type": "sast",
"name": "Cipher with no integrity",
"description": "Insecure variable usage",
"severity": "medium",
"name": "Insecure variable usage",
"severity": "critical",
"confidence": "high",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"identifiers": [
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
},
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
}
],
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4",
"project": {
"id": 1,
"name": "project1",
"full_path": "/namespace1/project1",
"full_name": "Gitab.org / security-products / binaries"
},
"dismissal_feedback": null,
"issue_feedback": null,
"description": "The cipher does not provide data integrity update 1",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"location": {
"file": "maven/src/main/java/com/gitlab/security_products/tests/App.java",
"start_line": 29,
......@@ -18,71 +41,119 @@
"class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher"
},
"links": [
{
"name": "Cipher does not check for integrity first?",
"url": "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first"
}
]
},
{
"id": 2,
"report_type": "sast",
"name": "Insecure variable usage",
"severity": "critical",
"confidence": "high",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"identifiers": [
{
"external_type": "find_sec_bugs_type",
"external_id": "CIPHER_INTEGRITY",
"name": "Find Security Bugs-CIPHER_INTEGRITY",
"primary": true,
"url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY"
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
},
{
"external_type": "cwe",
"external_id": "353",
"name": "CWE-353",
"primary": false,
"url": "https://cwe.mitre.org/data/definitions/353.html"
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
}
],
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4",
"project": {
"id": 1,
"name": "project1",
"full_path": "/namespace1/project1",
"full_name": "Gitab.org / quality / staging"
},
"dismissal_feedback": null,
"issue_feedback": null,
"description": "The cipher does not provide data integrity update 1",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"location": {
"file": "maven/src/main/java/com/gitlab/security_products/tests/App.java",
"start_line": 29,
"end_line": 29,
"class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher"
},
"links": [
{
"name": "Cipher does not check for integrity first?",
"url": "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first"
}
]
},
{
"id": 3,
"report_type": "sast",
"name": "Insecure variable usage",
"severity": "medium",
"confidence": "",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"identifiers": [
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
},
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
}
],
"project_fingerprint": "a42cbe949d1471a4310e3bd6fc16619ad2691f3f",
"vulnerability_feedback_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common/vulnerability_feedback",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4",
"project": {
"name_with_namespace": "GitLab.org / security-products / binaries",
"web_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common"
"id": 1,
"name": "project1",
"full_path": "/namespace1/project1",
"full_name": "Gitab.org / security-products / licence-management"
},
"dismissal_feedback": {
"id": 19,
"project_id": 6126012,
"id": 1,
"project_id": 1,
"author": {
"id": 30915,
"name": "Philippe Lafoucrière",
"username": "plafoucriere",
"id": 6,
"name": "John Doe7",
"username": "user6",
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/79f933bb7e06a2400302f5b30f28689e?s=80\u0026d=identicon",
"web_url": "https://gitlab.com/plafoucriere",
"avatar_url": "https://www.gravatar.com/avatar/3de3cc5a52553af613b6c457da6c219a?s=80&d=identicon",
"web_url": "http://localhost/user6",
"status_tooltip_html": null,
"path": "/plafoucriere"
"path": "/user6"
},
"issue_id": null,
"pipeline": {
"id": 23035216,
"path": "/gitlab-org/security-products/analyzers/common/pipelines/23035216"
"id": 2,
"path": "/namespace5/project5/pipelines/2"
},
"category": "sast",
"feedback_type": "dismissal",
"branch": "gitlab-ee-5043_enrich_sast_reports",
"project_fingerprint": "1235d9f927a0dee633570a53c0773249e0a734a8"
"branch": "master",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4"
},
"issue_feedback": null
},
{
"id": "jawodjbwkdjbawkdjba",
"report_type": "sast",
"name": "Cipher with no integrity",
"issue_feedback": null,
"description": "The cipher does not provide data integrity update 1",
"severity": "unknown",
"confidence": "",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"location": {
"file": "maven/src/main/java/com/gitlab/security_products/tests/App.java",
"start_line": 29,
......@@ -90,71 +161,71 @@
"class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher"
},
"identifiers": [
{
"external_type": "find_sec_bugs_type",
"external_id": "CIPHER_INTEGRITY",
"name": "Find Security Bugs-CIPHER_INTEGRITY",
"primary": true,
"url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY"
},
{
"external_type": "cwe",
"external_id": "353",
"name": "CWE-353",
"primary": false,
"url": "https://cwe.mitre.org/data/definitions/353.html"
}
],
"links": [
{
"name": "Cipher does not check for integrity first?",
"url": "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first"
}
]
},
{
"id": 4,
"report_type": "sast",
"name": "Insecure variable usage",
"severity": "high",
"confidence": "low",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"identifiers": [
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
},
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
}
],
"project_fingerprint": "a42cbe949d1471a4310e3bd6fc16619ad2691f3f",
"vulnerability_feedback_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common/vulnerability_feedback",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4",
"project": {
"name_with_namespace": "GitLab.org / Security Products / Analyzers / Common",
"web_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common"
"id": 1,
"name": "project1",
"full_path": "/namespace1/project1",
"full_name": "Gitab.org / security-products / codequality"
},
"dismissal_feedback": {
"id": 19,
"project_id": 6126012,
"dismissal_feedback": null,
"issue_feedback": {
"id": 2,
"project_id": 1,
"author": {
"id": 30915,
"name": "Philippe Lafoucrière",
"username": "plafoucriere",
"id": 8,
"name": "John Doe9",
"username": "user8",
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/79f933bb7e06a2400302f5b30f28689e?s=80\u0026d=identicon",
"web_url": "https://gitlab.com/plafoucriere",
"avatar_url": "https://www.gravatar.com/avatar/51798cfc94af924ac2dffb7083baa6f4?s=80&d=identicon",
"web_url": "http://localhost/user8",
"status_tooltip_html": null,
"path": "/plafoucriere"
"path": "/user8"
},
"issue_id": null,
"issue_id": 1,
"pipeline": {
"id": 23035216,
"path": "/gitlab-org/security-products/analyzers/common/pipelines/23035216"
"id": 3,
"path": "/namespace6/project6/pipelines/3"
},
"issue_url": "http://localhost/namespace1/project1/issues/1",
"category": "sast",
"feedback_type": "dismissal",
"branch": "gitlab-ee-5043_enrich_sast_reports",
"project_fingerprint": "1235d9f927a0dee633570a53c0773249e0a734a8"
"feedback_type": "issue",
"branch": "master",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4"
},
"issue_feedback": null
},
{
"id": "wertvbvtc",
"report_type": "sast",
"name": "Cipher with no integrity",
"description": "The cipher does not provide data integrity update 1",
"severity": "low",
"confidence": "high",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"location": {
"file": "maven/src/main/java/com/gitlab/security_products/tests/App.java",
"start_line": 29,
......@@ -162,71 +233,93 @@
"class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher"
},
"identifiers": [
{
"external_type": "find_sec_bugs_type",
"external_id": "CIPHER_INTEGRITY",
"name": "Find Security Bugs-CIPHER_INTEGRITY",
"primary": true,
"url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY"
},
{
"external_type": "cwe",
"external_id": "353",
"name": "CWE-353",
"primary": false,
"url": "https://cwe.mitre.org/data/definitions/353.html"
}
],
"links": [
{
"name": "Cipher does not check for integrity first?",
"url": "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first"
}
]
},
{
"id": 5,
"report_type": "sast",
"name": "Remote command execution due to flaw in the include params attribute of URL and Anchor tags for org.apache.struts/struts2core",
"severity": "low",
"confidence": "",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"identifiers": [
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
},
{
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
}
],
"project_fingerprint": "a42cbe949d1471a4310e3bd6fc16619ad2691f3f",
"vulnerability_feedback_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common/vulnerability_feedback",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4",
"project": {
"name_with_namespace": "GitLab.org / Security Products / Analyzers / Common",
"web_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common"
"id": 1,
"name": "project1",
"full_path": "/namespace1/project1",
"full_name": "Gitab.org / security-products / staging"
},
"dismissal_feedback": {
"id": 19,
"project_id": 6126012,
"id": 1,
"project_id": 1,
"author": {
"id": 30915,
"name": "Philippe Lafoucrière",
"username": "plafoucriere",
"id": 6,
"name": "John Doe7",
"username": "user6",
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/79f933bb7e06a2400302f5b30f28689e?s=80\u0026d=identicon",
"web_url": "https://gitlab.com/plafoucriere",
"avatar_url": "https://www.gravatar.com/avatar/3de3cc5a52553af613b6c457da6c219a?s=80&d=identicon",
"web_url": "http://localhost/user6",
"status_tooltip_html": null,
"path": "/plafoucriere"
"path": "/user6"
},
"issue_id": null,
"pipeline": {
"id": 23035216,
"path": "/gitlab-org/security-products/analyzers/common/pipelines/23035216"
"id": 2,
"path": "/namespace5/project5/pipelines/2"
},
"category": "sast",
"feedback_type": "dismissal",
"branch": "gitlab-ee-5043_enrich_sast_reports",
"project_fingerprint": "1235d9f927a0dee633570a53c0773249e0a734a8"
"branch": "master",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4"
},
"issue_feedback": {
"id": 2,
"project_id": 1,
"author": {
"id": 8,
"name": "John Doe9",
"username": "user8",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/51798cfc94af924ac2dffb7083baa6f4?s=80&d=identicon",
"web_url": "http://localhost/user8",
"status_tooltip_html": null,
"path": "/user8"
},
"issue_feedback": null
"issue_id": 1,
"pipeline": {
"id": 3,
"path": "/namespace6/project6/pipelines/3"
},
"issue_url": "http://localhost/namespace1/project1/issues/1",
"category": "sast",
"feedback_type": "issue",
"branch": "master",
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4"
},
{
"id": "iouygdfei",
"report_type": "sast",
"name": "Cipher with no integrity",
"description": "The cipher does not provide data integrity update 1",
"severity": "critical",
"confidence": "ignore",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"location": {
"file": "maven/src/main/java/com/gitlab/security_products/tests/App.java",
"start_line": 29,
......@@ -234,57 +327,60 @@
"class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher"
},
"links": [
{
"name": "Cipher does not check for integrity first?",
"url": "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first"
}
]
},
{
"id": 6,
"report_type": "sast",
"name": "Doorkeeper Gem does not revoke token for public clients",
"severity": "unknown",
"confidence": "",
"scanner": {
"external_id": "find_sec_bugs",
"name": "Find Security Bugs"
},
"identifiers": [
{
"external_type": "find_sec_bugs_type",
"external_id": "CIPHER_INTEGRITY",
"name": "Find Security Bugs-CIPHER_INTEGRITY",
"primary": true,
"url": "https://find-sec-bugs.github.io/bugs.htm#CIPHER_INTEGRITY"
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
},
{
"external_type": "cwe",
"external_id": "353",
"name": "CWE-353",
"primary": false,
"url": "https://cwe.mitre.org/data/definitions/353.html"
"external_type": "CVE",
"external_id": "CVE-2018-1234",
"name": "CVE-2018-1234",
"url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234"
}
],
"project_fingerprint": "4e5b6966dd100170b4b1ad599c7058cce91b57b4",
"project": {
"id": 1,
"name": "project1",
"full_path": "/namespace1/project1",
"full_name": "Gitab.org / security-products / binaries"
},
"dismissal_feedback": null,
"issue_feedback": null,
"description": "The cipher does not provide data integrity update 1",
"solution": "GCM mode introduces an HMAC into the resulting encrypted data, providing integrity of the result.",
"location": {
"file": "maven/src/main/java/com/gitlab/security_products/tests/App.java",
"start_line": 29,
"end_line": 29,
"class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher"
},
"links": [
{
"name": "Cipher does not check for integrity first?",
"url": "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first"
}
],
"project_fingerprint": "a42cbe949d1471a4310e3bd6fc16619ad2691f3f",
"vulnerability_feedback_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common/vulnerability_feedback",
"project": {
"name_with_namespace": "GitLab.org / Security Products / Analyzers / Common",
"web_url": "https://gitlab.com/gitlab-org/security-products/analyzers/common"
},
"dismissal_feedback": {
"id": 19,
"project_id": 6126012,
"author": {
"id": 30915,
"name": "Philippe Lafoucrière",
"username": "plafoucriere",
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/79f933bb7e06a2400302f5b30f28689e?s=80\u0026d=identicon",
"web_url": "https://gitlab.com/plafoucriere",
"status_tooltip_html": null,
"path": "/plafoucriere"
},
"issue_id": null,
"pipeline": {
"id": 23035216,
"path": "/gitlab-org/security-products/analyzers/common/pipelines/23035216"
},
"category": "sast",
"feedback_type": "dismissal",
"branch": "gitlab-ee-5043_enrich_sast_reports",
"project_fingerprint": "1235d9f927a0dee633570a53c0773249e0a734a8"
},
"issue_feedback": null
]
}
]
\ No newline at end of file
export const SET_VULNERABILITIES_ENDPOINT = 'SET_VULNERABILITIES_ENDPOINT';
export const REQUEST_VULNERABILITIES = 'REQUEST_VULNERABILITIES';
export const RECEIVE_VULNERABILITIES_SUCCESS = 'RECEIVE_VULNERABILITIES_SUCCESS';
export const RECEIVE_VULNERABILITIES_ERROR = 'RECEIVE_VULNERABILITIES_ERROR';
export const SET_VULNERABILITIES_COUNT_ENDPOINT = 'SET_VULNERABILITIES_COUNT_ENDPOINT';
export const REQUEST_VULNERABILITIES_COUNT = 'REQUEST_VULNERABILITIES_COUNT';
export const RECEIVE_VULNERABILITIES_COUNT_SUCCESS = 'RECEIVE_VULNERABILITIES_COUNT_SUCCESS';
export const RECEIVE_VULNERABILITIES_COUNT_ERROR = 'RECEIVE_VULNERABILITIES_COUNT_ERROR';
import * as types from './mutation_types';
export default {
[types.SET_VULNERABILITIES_ENDPOINT](state, payload) {
state.vulnerabilitiesEndpoint = payload;
},
[types.REQUEST_VULNERABILITIES](state) {
state.isLoadingVulnerabilities = true;
state.hasError = false;
},
[types.RECEIVE_VULNERABILITIES_SUCCESS](state, payload) {
state.isLoadingVulnerabilities = false;
state.errorLoadingVulnerabilities = false;
state.pageInfo = payload.pageInfo;
state.vulnerabilities = payload.vulnerabilities;
},
[types.RECEIVE_VULNERABILITIES_ERROR](state) {
state.isLoadingVulnerabilities = false;
state.errorLoadingVulnerabilities = true;
state.hasError = true;
},
[types.SET_VULNERABILITIES_COUNT_ENDPOINT](state, payload) {
state.vulnerabilitiesCountEndpoint = payload;
},
[types.REQUEST_VULNERABILITIES_COUNT](state) {
state.isLoadingVulnerabilitiesCount = true;
state.hasError = false;
},
[types.RECEIVE_VULNERABILITIES_COUNT_SUCCESS](state, payload) {
state.isLoadingVulnerabilitiesCount = false;
state.errorLoadingVulnerabilities = false;
state.vulnerabilitiesCount = payload;
},
[types.RECEIVE_VULNERABILITIES_COUNT_ERROR](state) {
state.isLoadingVulnerabilitiesCount = false;
state.errorLoadingVulnerabilities = true;
state.hasError = true;
},
};
export default () => ({
isLoadingVulnerabilities: false,
isLoadingVulnerabilitiesCount: false,
hasError: false,
isLoadingVulnerabilities: true,
isLoadingVulnerabilitiesCount: true,
pageInfo: {},
vulnerabilities: [],
vulnerabilitiesCount: {},
errorLoadingVulnerabilities: false,
vulnerabilitiesCountEndpoint: null,
vulnerabilitiesEndpoint: null,
});
- breadcrumb_title _("Security Dashboard")
- page_title _("Security Dashboard")
#js-group-security-dashboard
#js-group-security-dashboard{ data: { vulnerabilities_endpoint: group_security_vulnerabilities_path(@group),
vulnerabilities_summary_endpoint: summary_group_security_vulnerabilities_path(@group),
dashboard_documentation: help_page_path('user/group/security_dashboard'),
empty_state_svg_path: image_path('illustrations/security-dashboard-empty-state.svg'),
error_state_svg_path: image_path('illustrations/security-dashboard-api-error-empty-state.svg') } }
---
title: Connects the Group Security Dashboard API and Frontend
merge_request: 7793
author:
type: other
......@@ -36,9 +36,9 @@ describe('Security Dashboard Table Row', () => {
beforeEach(() => {
const vulnerability = {
severity: 'high',
description: 'Test vulnerability',
name: 'Test vulnerability',
confidence: 'medium',
project: { name_with_namespace: 'project name' },
project: { full_name: 'project name' },
};
props = { vulnerability };
......@@ -55,15 +55,15 @@ describe('Security Dashboard Table Row', () => {
);
});
it('should render the description', () => {
it('should render the name', () => {
expect(vm.$el.querySelectorAll('.table-mobile-content')[1].textContent).toContain(
props.vulnerability.description,
props.vulnerability.name,
);
});
it('should render the project namespace', () => {
expect(vm.$el.querySelectorAll('.table-mobile-content')[1].textContent).toContain(
props.vulnerability.project.name_with_namespace,
props.vulnerability.project.full_name,
);
});
......
import Vue from 'vue';
import component from 'ee/security_dashboard/components/vulnerability_issue_link.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Vulnerability Issue Link component', () => {
const Component = Vue.extend(component);
let vm;
let props;
beforeEach(() => {
const issue = {
issue_id: 1,
issue_url: 'https://gitlab.com',
};
const projectName = 'Project Name';
props = { issue, projectName };
vm = mountComponent(Component, props);
});
afterEach(() => {
vm.$destroy();
});
it('should render the severity label', () => {
expect(vm.$el.textContent).toContain(`${props.projectName}#${props.issue.issue_id}`);
});
it('should link to the issue', () => {
const link = vm.$el.querySelector('a');
expect(link.href).toMatch(props.issue.issue_url);
});
});
......@@ -234,4 +234,46 @@ describe('vulnerabilities actions', () => {
);
});
});
describe('setVulnerabilitiesEndpoint', () => {
it('should commit the correct mutuation', done => {
const state = initialState;
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesCountEndpoint', () => {
it('should commit the correct mutuation', done => {
const state = initialState;
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesCountEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_COUNT_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
});
......@@ -3,14 +3,35 @@ import * as types from 'ee/security_dashboard/store/modules/vulnerabilities/muta
import mutations from 'ee/security_dashboard/store/modules/vulnerabilities/mutations';
describe('vulnerabilities module mutations', () => {
describe('REQUEST_VULNERABILITIES', () => {
it('should set `isLoadingVulnerabilities` to `true`', () => {
describe('SET_VULNERABILITIES_ENDPOINT', () => {
it('should set `vulnerabilitiesEndpoint` to `fakepath.json`', () => {
const state = initialState;
const endpoint = 'fakepath.json';
mutations[types.SET_VULNERABILITIES_ENDPOINT](state, endpoint);
expect(state.vulnerabilitiesEndpoint).toEqual(endpoint);
});
});
describe('REQUEST_VULNERABILITIES', () => {
let state;
beforeEach(() => {
state = {
...initialState,
hasError: true,
};
mutations[types.REQUEST_VULNERABILITIES](state);
});
it('should set `isLoadingVulnerabilities` to `true`', () => {
expect(state.isLoadingVulnerabilities).toBeTruthy();
});
it('should set `hasError` to `false`', () => {
expect(state.hasError).toBeFalsy();
});
});
describe('RECEIVE_VULNERABILITIES_SUCCESS', () => {
......@@ -30,10 +51,6 @@ describe('vulnerabilities module mutations', () => {
expect(state.isLoadingVulnerabilities).toBeFalsy();
});
it('should set `errorLoadingData` to `false`', () => {
expect(state.errorLoadingData).toBeFalsy();
});
it('should set `pageInfo`', () => {
expect(state.pageInfo).toBe(payload.pageInfo);
});
......@@ -53,14 +70,35 @@ describe('vulnerabilities module mutations', () => {
});
});
describe('REQUEST_VULNERABILITIES_COUNT', () => {
it('should set `isLoadingVulnerabilitiesCount` to `true`', () => {
describe('SET_VULNERABILITIES_COUNT_ENDPOINT', () => {
it('should set `vulnerabilitiesCountEndpoint` to `fakepath.json`', () => {
const state = initialState;
const endpoint = 'fakepath.json';
mutations[types.SET_VULNERABILITIES_COUNT_ENDPOINT](state, endpoint);
expect(state.vulnerabilitiesCountEndpoint).toEqual(endpoint);
});
});
describe('REQUEST_VULNERABILITIES_COUNT', () => {
let state;
beforeEach(() => {
state = {
...initialState,
hasError: true,
};
mutations[types.REQUEST_VULNERABILITIES_COUNT](state);
});
it('should set `isLoadingVulnerabilitiesCount` to `true`', () => {
expect(state.isLoadingVulnerabilitiesCount).toBeTruthy();
});
it('should set `hasError` to `false`', () => {
expect(state.hasError).toBeFalsy();
});
});
describe('RECEIVE_VULNERABILITIES_COUNT_SUCCESS', () => {
......@@ -77,10 +115,6 @@ describe('vulnerabilities module mutations', () => {
expect(state.isLoadingVulnerabilitiesCount).toBeFalsy();
});
it('should set `errorLoadingData` to `false`', () => {
expect(state.errorLoadingData).toBeFalsy();
});
it('should set `vulnerabilitiesCount`', () => {
expect(state.vulnerabilitiesCount).toBe(payload);
});
......
......@@ -6916,6 +6916,18 @@ msgstr ""
msgid "Security Dashboard"
msgstr ""
msgid "Security Dashboard|Issue Created"
msgstr ""
msgid "Security Reports|At this time, the security dashboard only supports SAST. More analyzers are coming soon."
msgstr ""
msgid "Security Reports|Security Dashboard Roadmap"
msgstr ""
msgid "Security Reports|There was an error fetching the dashboard. Please try again in a few moments or contact your support team."
msgstr ""
msgid "SecurityDashboard| The security dashboard displays the latest security report. Use it to find and fix vulnerabilities."
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