Commit b7b473f3 authored by Alexander Turinske's avatar Alexander Turinske

Create agent-specific vulnerability list

- use vulnerability-list component
- pass up additional data
- update tests
parent 1b49113d
......@@ -51,16 +51,7 @@ export default {
TokenTable,
ActivityEvents,
},
props: {
agentName: {
required: true,
type: String,
},
projectPath: {
required: true,
type: String,
},
},
inject: ['agentName', 'projectPath'],
data() {
return {
cursor: {
......@@ -131,12 +122,12 @@ export default {
</p>
<gl-tabs sync-active-tab-with-query-params lazy>
<slot name="ee-security-tab"></slot>
<gl-tab :title="$options.i18n.activity" query-param-value="activity">
<activity-events :agent-name="agentName" :project-path="projectPath" />
</gl-tab>
<slot name="ee-security-tab"></slot>
<gl-tab query-param-value="tokens">
<template #title>
<span data-testid="cluster-agent-token-count">
......
{"__schema":{"types":[{"kind":"UNION","name":"VulnerabilityLocation","possibleTypes":[{"name":"VulnerabilityLocationContainerScanning"},{"name":"VulnerabilityLocationDast"},{"name":"VulnerabilityLocationDependencyScanning"},{"name":"VulnerabilityLocationSast"},{"name":"VulnerabilityLocationSecretDetection"}]}]}}
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import introspectionQueryResultData from './fragmentTypes.json';
Vue.use(VueApollo);
// We create a fragment matcher so that we can create a fragment from an interface
// Without this, Apollo throws a heuristic fragment matcher warning
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,
});
const defaultClient = createDefaultClient(
{},
{
cacheConfig: {
fragmentMatcher,
},
},
);
export default new VueApollo({
defaultClient,
});
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import AgentShowPage from 'ee_else_ce/clusters/agents/components/show.vue';
Vue.use(VueApollo);
import apolloProvider from './graphql/provider';
export default () => {
const el = document.querySelector('#js-cluster-agent-details');
......@@ -12,20 +9,26 @@ export default () => {
return null;
}
const defaultClient = createDefaultClient();
const { agentName, projectPath, activityEmptyStateImage } = el.dataset;
const {
activityEmptyStateImage,
agentName,
dashboardDocumentation,
emptyStateSvgPath,
projectPath,
} = el.dataset;
return new Vue({
el,
apolloProvider: new VueApollo({ defaultClient }),
provide: { agentName, projectPath, activityEmptyStateImage },
apolloProvider,
provide: {
activityEmptyStateImage,
agentName,
dashboardDocumentation,
emptyStateSvgPath,
projectPath,
},
render(createElement) {
return createElement(AgentShowPage, {
props: {
agentName,
projectPath,
},
});
return createElement(AgentShowPage);
},
});
};
......@@ -3,9 +3,11 @@
module Projects::ClusterAgentsHelper
def js_cluster_agent_details_data(agent_name, project)
{
activity_empty_state_image: image_path('illustrations/empty-state/empty-state-agents.svg'),
agent_name: agent_name,
project_path: project.full_path,
activity_empty_state_image: image_path('illustrations/empty-state/empty-state-agents.svg')
dashboard_documentation: help_page_path('user/application_security/security_dashboard/index'),
empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'),
project_path: project.full_path
}
end
end
......@@ -3,23 +3,18 @@ import { GlTab } from '@gitlab/ui';
import { s__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AgentShowPage from '~/clusters/agents/components/show.vue';
import AgentVulnerabilityReport from 'ee/security_dashboard/components/agent/agent_vulnerability_report.vue';
export default {
i18n: {
securityTabTitle: s__('ClusterAgents|Security'),
},
components: { AgentShowPage, GlTab },
mixins: [glFeatureFlagMixin()],
props: {
agentName: {
required: true,
type: String,
},
projectPath: {
required: true,
type: String,
},
components: {
AgentShowPage,
GlTab,
AgentVulnerabilityReport,
},
mixins: [glFeatureFlagMixin()],
computed: {
showSecurityTab() {
return (
......@@ -33,8 +28,9 @@ export default {
<template>
<agent-show-page v-bind="$props">
<template v-if="showSecurityTab" #ee-security-tab>
<!-- Placeholder for https://gitlab.com/gitlab-org/gitlab/-/issues/343912-->
<gl-tab :title="$options.i18n.securityTabTitle"><div></div></gl-tab>
<gl-tab :title="$options.i18n.securityTabTitle">
<agent-vulnerability-report />
</gl-tab>
</template>
</agent-show-page>
</template>
<script>
import VulnerabilityListGraphql from '../shared/vulnerability_report/vulnerability_list_graphql.vue';
import VulnerabilityFilters from '../shared/vulnerability_report/vulnerability_filters.vue';
import {
FIELD_PRESETS,
FILTER_PRESETS,
REPORT_TAB,
REPORT_TYPE_PRESETS,
} from '../shared/vulnerability_report/constants';
import projectVulnerabilitiesQuery from '../../graphql/queries/project_vulnerabilities.query.graphql';
import { DASHBOARD_TYPES } from '../../store/constants';
export default {
components: {
VulnerabilityFilters,
VulnerabilityListGraphql,
},
provide() {
return {
dashboardType: DASHBOARD_TYPES.PROJECT,
canAdminVulnerability: true,
fullPath: this.projectPath,
canViewFalsePositive: false,
hasJiraVulnerabilitiesIntegrationEnabled: false,
};
},
inject: ['projectPath'],
data() {
return {
graphqlFilters: undefined,
};
},
computed: {
fieldsToShow() {
return FIELD_PRESETS[REPORT_TAB.OPERATIONAL];
},
filtersToShow() {
return FILTER_PRESETS[REPORT_TAB.OPERATIONAL];
},
},
methods: {
updateGraphqlFilters(graphqlFilters) {
this.graphqlFilters = graphqlFilters;
this.graphqlFilters.reportType = REPORT_TYPE_PRESETS.OPERATIONAL;
},
},
REPORT_TAB,
projectVulnerabilitiesQuery,
};
</script>
<template>
<div>
<vulnerability-filters
:filters="filtersToShow"
class="security-dashboard-filters gl-mt-7"
@filters-changed="updateGraphqlFilters"
/>
<vulnerability-list-graphql
:query="$options.projectVulnerabilitiesQuery"
:fields="fieldsToShow"
:filters="graphqlFilters"
/>
</div>
</template>
......@@ -3,24 +3,19 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ClusterAgentShow from 'ee/clusters/agents/components/show.vue';
import CEClusterAgentShowPage from '~/clusters/agents/components/show.vue';
describe('ClusterAgentShow', () => {
let wrapper;
const agentName = 'best-agent';
const projectPath = 'path/to/project';
const createWrapper = ({ glFeatures = {} } = {}) => {
wrapper = extendedWrapper(
shallowMount(ClusterAgentShow, {
propsData: { agentName, projectPath },
provide: { glFeatures },
}),
);
};
const findTab = () => wrapper.findComponent(GlTab);
const findCEClusterAgentShowPage = () => wrapper.findComponent(CEClusterAgentShowPage);
afterEach(() => {
wrapper.destroy();
......@@ -36,7 +31,6 @@ describe('ClusterAgentShow', () => {
`('$title', async ({ glFeatures, tabStatus }) => {
createWrapper({ glFeatures });
await nextTick();
expect(findCEClusterAgentShowPage().props()).toStrictEqual({ agentName, projectPath });
expect(findTab().exists()).toBe(tabStatus);
});
});
......
import { shallowMount } from '@vue/test-utils';
import VulnerabilityListGraphql from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue';
import VulnerabilityFilters from 'ee/security_dashboard/components/shared/vulnerability_report/vulnerability_filters.vue';
import AgentVulnerabilityReport from 'ee/security_dashboard/components/agent/agent_vulnerability_report.vue';
describe('Agent vulnerability report component', () => {
let wrapper;
const provide = { agentName: 'primary-agent', projectPath: '/path/to/project/' };
const createWrapper = () => {
wrapper = shallowMount(AgentVulnerabilityReport, { provide });
};
const findVulnerabilityFilters = () => wrapper.findComponent(VulnerabilityFilters);
const findVulnerabilityList = () => wrapper.findComponent(VulnerabilityListGraphql);
afterEach(() => {
wrapper.destroy();
});
it('renders', () => {
createWrapper();
expect(findVulnerabilityFilters().exists()).toBe(true);
expect(findVulnerabilityList().exists()).toBe(true);
});
});
......@@ -17,5 +17,11 @@ RSpec.describe Projects::ClusterAgentsHelper do
it 'returns project path' do
expect(subject[:project_path]).to eq(project.full_path)
end
it 'returns string contants' do
expect(subject[:activity_empty_state_image]).to be_kind_of(String)
expect(subject[:dashboard_documentation]).to be_kind_of(String)
expect(subject[:empty_state_svg_path]).to be_kind_of(String)
end
end
end
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