Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
88880b76
Commit
88880b76
authored
Nov 26, 2021
by
Savas Vedova
Committed by
Olena Horal-Koretska
Nov 26, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow user unlinking a project
parent
fc23ee11
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
185 additions
and
28 deletions
+185
-28
ee/app/assets/javascripts/threat_monitoring/components/policies/scan_new_policy_modal.vue
..._monitoring/components/policies/scan_new_policy_modal.vue
+106
-22
ee/app/assets/javascripts/threat_monitoring/graphql/mutations/link_security_policy_project.mutation.graphql
...l/mutations/link_security_policy_project.mutation.graphql
+5
-0
ee/app/assets/javascripts/threat_monitoring/graphql/mutations/unlink_security_policy_project.mutation.graphql
...mutations/unlink_security_policy_project.mutation.graphql
+5
-0
ee/spec/frontend/threat_monitoring/components/policies/scan_new_policy_modal_spec.js
...itoring/components/policies/scan_new_policy_modal_spec.js
+49
-5
ee/spec/frontend/threat_monitoring/mocks/mock_apollo.js
ee/spec/frontend/threat_monitoring/mocks/mock_apollo.js
+8
-1
locale/gitlab.pot
locale/gitlab.pot
+12
-0
No files found.
ee/app/assets/javascripts/threat_monitoring/components/policies/scan_new_policy_modal.vue
View file @
88880b76
<
script
>
import
{
GlButton
,
GlDropdown
,
GlSprintf
,
GlAlert
,
GlModal
}
from
'
@gitlab/ui
'
;
import
{
s__
,
__
}
from
'
~/locale
'
;
import
assignSecurityPolicyProject
from
'
../../graphql/mutations/assign_security_policy_project.mutation.graphql
'
;
import
linkSecurityPolicyProject
from
'
../../graphql/mutations/link_security_policy_project.mutation.graphql
'
;
import
unlinkSecurityPolicyProject
from
'
../../graphql/mutations/unlink_security_policy_project.mutation.graphql
'
;
import
InstanceProjectSelector
from
'
../instance_project_selector.vue
'
;
export
default
{
...
...
@@ -12,9 +13,19 @@ export default {
header
:
s__
(
'
SecurityOrchestration|Select security project
'
),
},
save
:
{
ok
:
s__
(
'
SecurityOrchestration|Security policy project was linked successfully
'
),
error
:
s__
(
'
SecurityOrchestration|An error occurred assigning your security policy project
'
),
okLink
:
s__
(
'
SecurityOrchestration|Security policy project was linked successfully
'
),
okUnlink
:
s__
(
'
SecurityOrchestration|Security policy project was unlinked successfully
'
),
errorLink
:
s__
(
'
SecurityOrchestration|An error occurred assigning your security policy project
'
,
),
errorUnlink
:
s__
(
'
SecurityOrchestration|An error occurred unassigning your security policy project
'
,
),
},
unlinkButtonLabel
:
s__
(
'
SecurityOrchestration|Unlink project
'
),
unlinkWarning
:
s__
(
'
SecurityOrchestration|Unlinking a security project removes all policies stored in the linked security project. Save to confirm this action.
'
,
),
disabledWarning
:
s__
(
'
SecurityOrchestration|Only owners can update Security Policy Project
'
),
description
:
s__
(
'
SecurityOrchestration|Select a project to store your security policies in. %{linkStart}More information.%{linkEnd}
'
,
...
...
@@ -45,9 +56,13 @@ export default {
return
{
selectedProject
:
{
...
this
.
assignedPolicyProject
},
hasSelectedNewProject
:
false
,
shouldShowUnlinkWarning
:
false
,
};
},
computed
:
{
selectedProjects
()
{
return
[
this
.
selectedProject
];
},
selectedProjectId
()
{
return
this
.
selectedProject
?.
id
||
''
;
},
...
...
@@ -55,16 +70,18 @@ export default {
return
this
.
selectedProject
?.
name
||
''
;
},
isModalOkButtonDisabled
()
{
if
(
this
.
shouldShowUnlinkWarning
)
{
return
false
;
}
return
this
.
disableSecurityPolicyProject
||
!
this
.
hasSelectedNewProject
;
},
},
methods
:
{
async
saveChanges
()
{
this
.
$emit
(
'
updating-project
'
);
async
linkProject
()
{
try
{
const
{
data
}
=
await
this
.
$apollo
.
mutate
({
mutation
:
assign
SecurityPolicyProject
,
mutation
:
link
SecurityPolicyProject
,
variables
:
{
input
:
{
projectPath
:
this
.
projectPath
,
...
...
@@ -77,19 +94,69 @@ export default {
throw
new
Error
(
data
.
securityPolicyProjectAssign
.
errors
);
}
this
.
$emit
(
'
project-updated
'
,
{
text
:
this
.
$options
.
i18n
.
save
.
ok
,
variant
:
'
success
'
});
this
.
$emit
(
'
project-updated
'
,
{
text
:
this
.
$options
.
i18n
.
save
.
okLink
,
variant
:
'
success
'
,
});
}
catch
{
this
.
$emit
(
'
project-updated
'
,
{
text
:
this
.
$options
.
i18n
.
save
.
errorLink
,
variant
:
'
danger
'
,
});
}
},
async
unlinkProject
()
{
try
{
const
{
data
}
=
await
this
.
$apollo
.
mutate
({
mutation
:
unlinkSecurityPolicyProject
,
variables
:
{
input
:
{
projectPath
:
this
.
projectPath
,
},
},
});
if
(
data
?.
securityPolicyProjectUnassign
?.
errors
?.
length
)
{
throw
new
Error
(
data
.
securityPolicyProjectUnassign
.
errors
);
}
this
.
shouldShowUnlinkWarning
=
false
;
this
.
selectedProject
=
{};
this
.
$emit
(
'
project-updated
'
,
{
text
:
this
.
$options
.
i18n
.
save
.
okUnlink
,
variant
:
'
success
'
,
});
}
catch
{
this
.
$emit
(
'
project-updated
'
,
{
text
:
this
.
$options
.
i18n
.
save
.
error
,
variant
:
'
danger
'
});
}
finally
{
this
.
hasSelectedNewProject
=
false
;
this
.
$emit
(
'
project-updated
'
,
{
text
:
this
.
$options
.
i18n
.
save
.
errorUnlink
,
variant
:
'
danger
'
,
});
}
},
async
saveChanges
()
{
this
.
$emit
(
'
updating-project
'
);
if
(
this
.
shouldShowUnlinkWarning
)
{
await
this
.
unlinkProject
();
}
else
{
await
this
.
linkProject
();
}
this
.
hasSelectedNewProject
=
false
;
},
setSelectedProject
(
data
)
{
this
.
shouldShowUnlinkWarning
=
false
;
this
.
hasSelectedNewProject
=
true
;
this
.
selectedProject
=
data
;
this
.
$refs
.
dropdown
.
hide
();
},
confirmDeletion
()
{
this
.
shouldShowUnlinkWarning
=
!
this
.
shouldShowUnlinkWarning
;
},
closeModal
()
{
this
.
shouldShowUnlinkWarning
=
false
;
this
.
$emit
(
'
close
'
);
},
},
...
...
@@ -120,20 +187,37 @@ export default {
>
{{
$options
.
i18n
.
disabledWarning
}}
</gl-alert>
<gl-dropdown
ref=
"dropdown"
class=
"gl-w-full gl-pb-5"
menu-class=
"gl-w-full! gl-max-w-full!"
:disabled=
"disableSecurityPolicyProject"
:text=
"selectedProjectName"
<gl-alert
v-if=
"shouldShowUnlinkWarning"
class=
"gl-mb-4"
variant=
"warning"
:dismissible=
"false"
>
<instance-project-selector
{{
$options
.
i18n
.
unlinkWarning
}}
</gl-alert>
<div
class=
"gl-display-flex gl-mb-3"
>
<gl-dropdown
ref=
"dropdown"
class=
"gl-w-full"
:max-list-height=
"$options.PROJECT_SELECTOR_HEIGHT"
:selected-projects=
"[selectedProject]"
@
projectClicked=
"setSelectedProject"
menu-class=
"gl-w-full! gl-max-w-full!"
:disabled=
"disableSecurityPolicyProject"
:text=
"selectedProjectName"
>
<instance-project-selector
class=
"gl-w-full"
:max-list-height=
"$options.PROJECT_SELECTOR_HEIGHT"
:selected-projects=
"selectedProjects"
@
projectClicked=
"setSelectedProject"
/>
</gl-dropdown>
<gl-button
v-if=
"selectedProjectId"
icon=
"remove"
class=
"gl-ml-3"
:aria-label=
"$options.i18n.unlinkButtonLabel"
@
click=
"confirmDeletion"
/>
</
gl-dropdown
>
</
div
>
<div
class=
"gl-pb-5"
>
<gl-sprintf
:message=
"$options.i18n.description"
>
<template
#link
="
{ content }">
...
...
ee/app/assets/javascripts/threat_monitoring/graphql/mutations/
assign
_security_policy_project.mutation.graphql
→
ee/app/assets/javascripts/threat_monitoring/graphql/mutations/
link
_security_policy_project.mutation.graphql
View file @
88880b76
mutation
assign
SecurityPolicyProject
(
$input
:
SecurityPolicyProjectAssignInput
!)
{
mutation
link
SecurityPolicyProject
(
$input
:
SecurityPolicyProjectAssignInput
!)
{
securityPolicyProjectAssign
(
input
:
$input
)
{
errors
}
...
...
ee/app/assets/javascripts/threat_monitoring/graphql/mutations/unlink_security_policy_project.mutation.graphql
0 → 100644
View file @
88880b76
mutation
securityPolicyProjectUnassign
(
$input
:
SecurityPolicyProjectUnassignInput
!)
{
securityPolicyProjectUnassign
(
input
:
$input
)
{
errors
}
}
ee/spec/frontend/threat_monitoring/components/policies/scan_new_policy_modal_spec.js
View file @
88880b76
...
...
@@ -3,11 +3,16 @@ import { createLocalVue } from '@vue/test-utils';
import
VueApollo
from
'
vue-apollo
'
;
import
InstanceProjectSelector
from
'
ee/threat_monitoring/components/instance_project_selector.vue
'
;
import
ScanNewPolicyModal
from
'
ee/threat_monitoring/components/policies/scan_new_policy_modal.vue
'
;
import
assignSecurityPolicyProject
from
'
ee/threat_monitoring/graphql/mutations/assign_security_policy_project.mutation.graphql
'
;
import
linkSecurityPolicyProject
from
'
ee/threat_monitoring/graphql/mutations/link_security_policy_project.mutation.graphql
'
;
import
unlinkSecurityPolicyProject
from
'
ee/threat_monitoring/graphql/mutations/unlink_security_policy_project.mutation.graphql
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
mountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
mockAssignSecurityPolicyProjectResponses
}
from
'
../../mocks/mock_apollo
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
mockLinkSecurityPolicyProjectResponses
,
mockUnlinkSecurityPolicyProjectResponses
,
}
from
'
../../mocks/mock_apollo
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
...
...
@@ -18,6 +23,7 @@ describe('ScanNewPolicyModal Component', () => {
const
findDropdown
=
()
=>
wrapper
.
findComponent
(
GlDropdown
);
const
findInstanceProjectSelector
=
()
=>
wrapper
.
findComponent
(
InstanceProjectSelector
);
const
findUnlinkButton
=
()
=>
wrapper
.
findByLabelText
(
'
Unlink project
'
);
const
findAlert
=
()
=>
wrapper
.
findComponent
(
GlAlert
);
const
findModal
=
()
=>
wrapper
.
findComponent
(
GlModal
);
...
...
@@ -34,12 +40,13 @@ describe('ScanNewPolicyModal Component', () => {
};
const
createWrapper
=
({
mutationResult
=
mockAssignSecurityPolicyProjectResponses
.
success
,
mutationQuery
=
linkSecurityPolicyProject
,
mutationResult
=
mockLinkSecurityPolicyProjectResponses
.
success
,
provide
=
{},
}
=
{})
=>
{
wrapper
=
mountExtended
(
ScanNewPolicyModal
,
{
localVue
,
apolloProvider
:
createMockApollo
([[
assignSecurityPolicyProject
,
mutationResult
]]),
apolloProvider
:
createMockApollo
([[
mutationQuery
,
mutationResult
]]),
stubs
:
{
GlModal
:
stubComponent
(
GlModal
,
{
template
:
...
...
@@ -100,6 +107,43 @@ describe('ScanNewPolicyModal Component', () => {
expect
(
wrapper
.
emitted
(
'
close
'
)).
toEqual
([[]]);
});
describe
(
'
unlinking project
'
,
()
=>
{
it
.
each
`
mutationResult | expectedVariant | expectedText
${
'
success
'
}
|
${
'
success
'
}
|
${
'
okUnlink
'
}
${
'
failure
'
}
|
${
'
danger
'
}
|
${
'
errorUnlink
'
}
`
(
'
unlinks a project and handles $mutationResult case
'
,
async
({
mutationResult
,
expectedVariant
,
expectedText
})
=>
{
createWrapper
({
mutationQuery
:
unlinkSecurityPolicyProject
,
mutationResult
:
mockUnlinkSecurityPolicyProjectResponses
[
mutationResult
],
provide
:
{
assignedPolicyProject
:
{
id
:
'
gid://gitlab/Project/0
'
,
name
:
'
Test 0
'
}
},
});
// Initial state
expect
(
findModal
().
attributes
(
'
ok-disabled
'
)).
toBe
(
'
true
'
);
expect
(
wrapper
.
findByText
(
wrapper
.
vm
.
$options
.
i18n
.
unlinkWarning
).
exists
()).
toBe
(
false
);
// When we click on the delete button, the component should display a warning
findUnlinkButton
().
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
findByText
(
wrapper
.
vm
.
$options
.
i18n
.
unlinkWarning
).
exists
()).
toBe
(
true
);
expect
(
findModal
().
attributes
(
'
ok-disabled
'
)).
toBeUndefined
();
// Clicking the OK button should submit a GraphQL query
findModal
().
vm
.
$emit
(
'
ok
'
);
await
waitForPromises
();
expect
(
projectUpdatedListener
).
toHaveBeenCalledWith
({
text
:
wrapper
.
vm
.
$options
.
i18n
.
save
[
expectedText
],
variant
:
expectedVariant
,
});
},
);
});
describe
(
'
project selection
'
,
()
=>
{
it
(
'
enables the "Save" button only if a new project is selected
'
,
async
()
=>
{
createWrapper
({
...
...
@@ -129,7 +173,7 @@ describe('ScanNewPolicyModal Component', () => {
it
(
'
emits an event with an error message
'
,
async
()
=>
{
await
createWrapperAndSelectProject
({
mutationResult
:
mock
Assign
SecurityPolicyProjectResponses
.
failure
,
mutationResult
:
mock
Link
SecurityPolicyProjectResponses
.
failure
,
});
expect
(
projectUpdatedListener
).
toHaveBeenCalledWith
({
...
...
ee/spec/frontend/threat_monitoring/mocks/mock_apollo.js
View file @
88880b76
...
...
@@ -52,9 +52,16 @@ export const scanExecutionPolicies = (nodes) =>
},
});
export
const
mock
Assign
SecurityPolicyProjectResponses
=
{
export
const
mock
Link
SecurityPolicyProjectResponses
=
{
success
:
jest
.
fn
().
mockResolvedValue
({
data
:
{
securityPolicyProjectAssign
:
{
errors
:
[]
}
}
}),
failure
:
jest
.
fn
()
.
mockResolvedValue
({
data
:
{
securityPolicyProjectAssign
:
{
errors
:
[
'
mutation failed
'
]
}
}
}),
};
export
const
mockUnlinkSecurityPolicyProjectResponses
=
{
success
:
jest
.
fn
().
mockResolvedValue
({
data
:
{
securityPolicyProjectUnassign
:
{
errors
:
[]
}
}
}),
failure
:
jest
.
fn
().
mockResolvedValue
({
data
:
{
securityPolicyProjectUnassign
:
{
errors
:
[
'
mutation failed
'
]
}
},
}),
};
locale/gitlab.pot
View file @
88880b76
...
...
@@ -30872,6 +30872,9 @@ msgstr ""
msgid "SecurityOrchestration|An error occurred assigning your security policy project"
msgstr ""
msgid "SecurityOrchestration|An error occurred unassigning your security policy project"
msgstr ""
msgid "SecurityOrchestration|Description"
msgstr ""
...
...
@@ -30950,6 +30953,9 @@ msgstr ""
msgid "SecurityOrchestration|Security policy project was linked successfully"
msgstr ""
msgid "SecurityOrchestration|Security policy project was unlinked successfully"
msgstr ""
msgid "SecurityOrchestration|Select a project to store your security policies in. %{linkStart}More information.%{linkEnd}"
msgstr ""
...
...
@@ -30971,6 +30977,12 @@ msgstr ""
msgid "SecurityOrchestration|To widen your search, change filters above or select a different security policy project."
msgstr ""
msgid "SecurityOrchestration|Unlink project"
msgstr ""
msgid "SecurityOrchestration|Unlinking a security project removes all policies stored in the linked security project. Save to confirm this action."
msgstr ""
msgid "SecurityOrchestration|Update scan execution policies"
msgstr ""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment