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
569988c1
Commit
569988c1
authored
Mar 11, 2022
by
Samantha Ming
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adjust security training to use temp resolvers
Also removing the test temporaily until the BE is resolved
parent
a4d1bb67
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
36 additions
and
356 deletions
+36
-356
app/assets/javascripts/security_configuration/graphql/security_training_vulnerability.query.graphql
...ion/graphql/security_training_vulnerability.query.graphql
+1
-1
ee/app/assets/javascripts/security_dashboard/graphql/provider.js
...assets/javascripts/security_dashboard/graphql/provider.js
+4
-1
ee/app/assets/javascripts/security_dashboard/graphql/temp_resolver.js
...s/javascripts/security_dashboard/graphql/temp_resolver.js
+31
-0
ee/spec/frontend/vulnerabilities/vulnerability_training_spec.js
...c/frontend/vulnerabilities/vulnerability_training_spec.js
+0
-354
No files found.
app/assets/javascripts/security_configuration/graphql/security_training_vulnerability.query.graphql
View file @
569988c1
query
getSecurityTrainingVulnerability
(
$id
:
ID
!)
{
vulnerability
(
id
:
$id
)
{
vulnerability
(
id
:
$id
)
@client
{
id
identifiers
{
externalType
...
...
ee/app/assets/javascripts/security_dashboard/graphql/provider.js
View file @
569988c1
import
Vue
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
createDefaultClient
from
'
~/lib/graphql
'
;
import
tempResolver
from
'
./temp_resolver
'
;
Vue
.
use
(
VueApollo
);
const
defaultClient
=
createDefaultClient
();
const
defaultClient
=
createDefaultClient
({
...
tempResolver
,
});
export
default
new
VueApollo
({
defaultClient
,
...
...
ee/app/assets/javascripts/security_dashboard/graphql/temp_resolver.js
0 → 100644
View file @
569988c1
// Note: this is behind a feature flag and only a placeholder
// until the actual GraphQL fields have been added
// https://gitlab.com/gitlab-org/gitlab/-/issues/349910
export
default
{
Query
:
{
vulnerability
()
{
/* eslint-disable @gitlab/require-i18n-strings */
return
{
__typename
:
'
Vulnerability
'
,
id
:
'
id: "gid://gitlab/Vulnerability/295"
'
,
identifiers
:
[{
externalType
:
'
cwe
'
,
__typename
:
'
VulnerabilityIdentifier
'
}],
securityTrainingUrls
:
[
{
__typename
:
'
SecurityTrainingUrls
'
,
id
:
101
,
name
:
'
Kontra
'
,
url
:
null
,
status
:
'
COMPLETED
'
,
},
{
__typename
:
'
SecurityTrainingUrls
'
,
id
:
102
,
name
:
'
Secure Code Warrior
'
,
url
:
'
https://www.securecodewarrior.com/
'
,
status
:
'
COMPLETED
'
,
},
],
};
},
},
};
ee/spec/frontend/vulnerabilities/vulnerability_training_spec.js
deleted
100644 → 0
View file @
a4d1bb67
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
*
as
Sentry
from
'
@sentry/browser
'
;
import
{
GlLink
,
GlIcon
,
GlSkeletonLoader
}
from
'
@gitlab/ui
'
;
import
{
mockTracking
,
unmockTracking
}
from
'
helpers/tracking_helper
'
;
import
VulnerabilityTraining
,
{
i18n
,
}
from
'
ee/vulnerabilities/components/vulnerability_training.vue
'
;
import
securityTrainingProvidersQuery
from
'
~/security_configuration/graphql/security_training_providers.query.graphql
'
;
import
securityTrainingVulnerabilityQuery
from
'
~/security_configuration/graphql/security_training_vulnerability.query.graphql
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
SUPPORTED_IDENTIFIER_TYPES
,
SECURITY_TRAINING_URL_STATUS_PENDING
,
}
from
'
ee/vulnerabilities/constants
'
;
import
{
TRACK_CLICK_TRAINING_LINK_ACTION
,
TRACK_TRAINING_LOADED_ACTION
,
}
from
'
~/security_configuration/constants
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
testProviderName
,
testTrainingUrls
,
getSecurityTrainingProvidersData
,
tempProviderLogos
,
}
from
'
jest/security_configuration/mock_data
'
;
import
{
getSecurityTrainingVulnerabilityData
,
defaultProps
}
from
'
./mock_data
'
;
Vue
.
use
(
VueApollo
);
const
createIdentifiersData
=
(
externalType
=
'
not supported identifier
'
)
=>
getSecurityTrainingVulnerabilityData
({
identifiers
:
[{
externalType
}],
});
const
createTrainingData
=
(
first
=
{},
second
=
{},
urls
)
=>
getSecurityTrainingVulnerabilityData
({
urls
,
urlOverrides
:
{
first
,
second
,
},
});
const
projectFullPath
=
'
namespace/project
'
;
const
TEST_TRAINING_PROVIDERS_ALL_DISABLED
=
getSecurityTrainingProvidersData
();
const
TEST_TRAINING_PROVIDERS_FIRST_ENABLED
=
getSecurityTrainingProvidersData
({
providerOverrides
:
{
first
:
{
isEnabled
:
true
}
},
});
const
TEST_TRAINING_PROVIDERS_DEFAULT
=
TEST_TRAINING_PROVIDERS_FIRST_ENABLED
;
const
TEST_TRAINING_VULNERABILITY_DEFAULT
=
getSecurityTrainingVulnerabilityData
();
const
TEST_TRAINING_VULNERABILITY_NO_URLS
=
createTrainingData
(
null
,
null
,
[]);
describe
(
'
VulnerabilityTraining component
'
,
()
=>
{
let
wrapper
;
let
apolloProvider
;
const
createApolloProvider
=
({
providersQueryHandler
,
vulnerabilityQueryHandler
}
=
{})
=>
{
apolloProvider
=
createMockApollo
([
[
securityTrainingProvidersQuery
,
providersQueryHandler
||
jest
.
fn
().
mockResolvedValue
(
TEST_TRAINING_PROVIDERS_DEFAULT
.
response
),
],
[
securityTrainingVulnerabilityQuery
,
vulnerabilityQueryHandler
||
jest
.
fn
().
mockResolvedValue
(
TEST_TRAINING_VULNERABILITY_DEFAULT
.
response
),
],
]);
};
const
createComponent
=
(
props
=
{},
{
slots
=
{},
secureVulnerabilityTraining
=
true
}
=
{})
=>
{
wrapper
=
shallowMountExtended
(
VulnerabilityTraining
,
{
propsData
:
{
...
defaultProps
,
...
props
,
},
slots
,
apolloProvider
,
provide
:
{
projectFullPath
,
glFeatures
:
{
secureVulnerabilityTraining
,
},
},
});
};
beforeEach
(
async
()
=>
{
createApolloProvider
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
apolloProvider
=
null
;
});
const
waitForQueryToBeLoaded
=
()
=>
waitForPromises
();
const
findDescription
=
()
=>
wrapper
.
findByTestId
(
'
description
'
);
const
findUnavailableMessage
=
()
=>
wrapper
.
findByTestId
(
'
unavailable-message
'
);
const
findTrainingItemName
=
(
name
)
=>
wrapper
.
findByText
(
name
);
const
findTrainingItemLinks
=
()
=>
wrapper
.
findAllComponents
(
GlLink
);
const
findTrainingItemLinkIcons
=
()
=>
wrapper
.
findAllComponents
(
GlIcon
);
const
findTrainingLogos
=
()
=>
wrapper
.
findAll
(
'
img
'
);
describe
(
'
with the query being successful
'
,
()
=>
{
describe
(
'
basic structure
'
,
()
=>
{
it
(
'
displays the description
'
,
async
()
=>
{
createApolloProvider
();
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findDescription
().
text
()).
toBe
(
i18n
.
trainingDescription
);
});
it
(
'
does not render component when there are no enabled securityTrainingProviders
'
,
async
()
=>
{
createApolloProvider
({
providersQueryHandler
:
jest
.
fn
()
.
mockResolvedValue
(
TEST_TRAINING_PROVIDERS_ALL_DISABLED
.
response
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
wrapper
.
html
()).
toBeFalsy
();
});
it
(
'
watches showVulnerabilityTraining and emits change
'
,
async
()
=>
{
createApolloProvider
();
createComponent
();
await
waitForQueryToBeLoaded
();
await
nextTick
();
// Note: the event emits twice - the second time is when the query is loaded
expect
(
wrapper
.
emitted
(
'
show-vulnerability-training
'
)).
toEqual
([[
false
],
[
true
]]);
});
});
describe
(
'
with title slot
'
,
()
=>
{
it
(
'
renders slot content
'
,
async
()
=>
{
const
mockSlotText
=
'
some title
'
;
createComponent
({},
{
slots
:
{
header
:
mockSlotText
}
});
await
waitForQueryToBeLoaded
();
expect
(
wrapper
.
text
()).
toContain
(
mockSlotText
);
});
});
describe
(
'
training availability message
'
,
()
=>
{
it
(
'
displays message when there are no supported identifier
'
,
async
()
=>
{
createApolloProvider
({
vulnerabilityQueryHandler
:
jest
.
fn
().
mockResolvedValue
(
createIdentifiersData
().
response
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findUnavailableMessage
().
text
()).
toBe
(
i18n
.
trainingUnavailable
);
});
it
(
'
displays message when there are no security training urls
'
,
async
()
=>
{
createApolloProvider
({
vulnerabilityQueryHandler
:
jest
.
fn
()
.
mockResolvedValue
(
TEST_TRAINING_VULNERABILITY_NO_URLS
.
response
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findUnavailableMessage
().
exists
()).
toBe
(
true
);
});
it
.
each
`
identifier | exists
${
SUPPORTED_IDENTIFIER_TYPES
.
cwe
.
toUpperCase
()}
|
${
false
}
${
SUPPORTED_IDENTIFIER_TYPES
.
cwe
.
toLowerCase
()}
|
${
false
}
`
(
'
sets it to "$exists" for "$identifier"
'
,
async
({
identifier
,
exists
})
=>
{
createApolloProvider
({
vulnerabilityQueryHandler
:
jest
.
fn
()
.
mockResolvedValue
(
createIdentifiersData
(
identifier
).
response
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findUnavailableMessage
().
exists
()).
toBe
(
exists
);
});
});
describe
(
'
GlSkeletonLoader
'
,
()
=>
{
it
(
'
displays when there are supported identifiers and some urls are in pending status
'
,
async
()
=>
{
createApolloProvider
({
vulnerabilityQueryHandler
:
jest
.
fn
().
mockResolvedValue
(
createTrainingData
({
status
:
SECURITY_TRAINING_URL_STATUS_PENDING
,
}).
response
,
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
wrapper
.
findComponent
(
GlSkeletonLoader
).
exists
()).
toBe
(
true
);
});
});
describe
(
'
polling
'
,
()
=>
{
beforeEach
(()
=>
{
createApolloProvider
();
createComponent
();
});
it
(
'
sets polling at 5000 ms
'
,
()
=>
{
expect
(
wrapper
.
vm
.
$apollo
.
queries
.
vulnerability
.
options
.
pollInterval
).
toBe
(
5000
);
});
it
(
'
stops polling when every training url status is completed
'
,
async
()
=>
{
jest
.
spyOn
(
wrapper
.
vm
.
$apollo
.
queries
.
vulnerability
,
'
stopPolling
'
)
.
mockImplementation
(
jest
.
fn
());
await
waitForQueryToBeLoaded
();
await
nextTick
();
expect
(
wrapper
.
vm
.
$apollo
.
queries
.
vulnerability
.
stopPolling
).
toHaveBeenCalled
();
});
});
describe
(
'
training logo
'
,
()
=>
{
beforeEach
(
async
()
=>
{
createApolloProvider
();
createComponent
();
wrapper
.
vm
.
$options
.
TEMP_PROVIDER_LOGOS
=
tempProviderLogos
;
await
waitForQueryToBeLoaded
();
});
const
providerIndexArray
=
[
0
,
1
];
it
.
each
(
providerIndexArray
)(
'
displays the correct width for training item %s
'
,
(
index
)
=>
{
expect
(
findTrainingLogos
().
at
(
index
).
attributes
(
'
width
'
)).
toBe
(
'
12
'
);
});
it
.
each
(
providerIndexArray
)(
'
has a11y decorative attribute for provider %s
'
,
(
index
)
=>
{
expect
(
findTrainingLogos
().
at
(
index
).
attributes
(
'
role
'
)).
toBe
(
'
presentation
'
);
});
it
.
each
(
providerIndexArray
)(
'
displays the correct svg path for training item %s
'
,
(
index
)
=>
{
expect
(
findTrainingLogos
().
at
(
index
).
attributes
(
'
src
'
)).
toBe
(
tempProviderLogos
[
testProviderName
[
index
]].
svg
,
);
});
});
describe
(
'
training item
'
,
()
=>
{
it
(
'
displays correct number of training items
'
,
async
()
=>
{
createApolloProvider
();
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findTrainingItemLinks
()).
toHaveLength
(
testTrainingUrls
.
length
);
});
it
.
each
([
0
,
1
])(
'
displays training item %s
'
,
async
(
index
)
=>
{
createApolloProvider
();
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findTrainingItemName
(
testProviderName
[
index
]).
exists
()).
toBe
(
true
);
expect
(
findTrainingItemLinks
().
at
(
index
).
attributes
(
'
href
'
)).
toBe
(
testTrainingUrls
[
index
]);
expect
(
findTrainingItemLinkIcons
().
at
(
index
).
attributes
(
'
name
'
)).
toBe
(
'
external-link
'
);
});
it
(
'
does not display training item if there are no securityTrainingUrls
'
,
async
()
=>
{
createApolloProvider
({
vulnerabilityQueryHandler
:
jest
.
fn
()
.
mockResolvedValue
(
TEST_TRAINING_VULNERABILITY_NO_URLS
.
response
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
findTrainingItemLinks
().
exists
()).
toBe
(
false
);
expect
(
findTrainingItemLinkIcons
().
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
with the query resulting in an error
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
Sentry
,
'
captureException
'
);
createApolloProvider
({
providersQueryHandler
:
jest
.
fn
().
mockResolvedValue
(
new
Error
())
});
createComponent
();
});
it
(
'
reports the error to sentry
'
,
async
()
=>
{
expect
(
Sentry
.
captureException
).
not
.
toHaveBeenCalled
();
await
waitForQueryToBeLoaded
();
expect
(
Sentry
.
captureException
).
toHaveBeenCalled
();
});
});
describe
(
'
metrics
'
,
()
=>
{
let
trackingSpy
;
beforeEach
(()
=>
{
trackingSpy
=
mockTracking
(
undefined
,
wrapper
.
element
,
jest
.
spyOn
);
});
afterEach
(()
=>
{
unmockTracking
();
});
const
expectedTrackingOptions
=
(
index
)
=>
({
label
:
`vendor_
${
testProviderName
[
index
]}
`
,
property
:
projectFullPath
,
});
it
(
'
tracks when the training link is loading
'
,
async
()
=>
{
createApolloProvider
({
vulnerabilityQueryHandler
:
jest
.
fn
().
mockResolvedValue
(
createTrainingData
({
status
:
SECURITY_TRAINING_URL_STATUS_PENDING
,
}).
response
,
),
});
createComponent
();
await
waitForQueryToBeLoaded
();
expect
(
trackingSpy
).
toHaveBeenCalledWith
(
undefined
,
TRACK_TRAINING_LOADED_ACTION
,
{
property
:
projectFullPath
,
});
});
it
.
each
([
0
,
1
])(
'
tracks when training link %s gets clicked
'
,
async
(
index
)
=>
{
createApolloProvider
();
createComponent
();
await
waitForQueryToBeLoaded
();
await
findTrainingItemLinks
().
at
(
index
).
vm
.
$emit
(
'
click
'
);
expect
(
trackingSpy
).
toHaveBeenCalledWith
(
undefined
,
TRACK_CLICK_TRAINING_LINK_ACTION
,
expectedTrackingOptions
(
index
),
);
});
});
describe
(
'
when secureVulnerabilityTraining feature flag is disabled
'
,
()
=>
{
it
(
'
does not render the VulnerabilityTraining component
'
,
()
=>
{
createComponent
({},
{
secureVulnerabilityTraining
:
false
});
expect
(
wrapper
.
html
()).
toBeFalsy
();
});
});
});
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