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
c18a76b6
Commit
c18a76b6
authored
Jul 21, 2020
by
Philip Cunningham
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create DAST on-demand scan using DastSiteProfile
Adds GraphQL mutation that creates a new DAST on-demand scan.
parent
17ab3d16
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
483 additions
and
5 deletions
+483
-5
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+41
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+143
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+10
-0
ee/app/graphql/ee/types/mutation_type.rb
ee/app/graphql/ee/types/mutation_type.rb
+1
-0
ee/app/graphql/mutations/dast_on_demand_scans/create.rb
ee/app/graphql/mutations/dast_on_demand_scans/create.rb
+76
-0
ee/app/models/dast_site_profile.rb
ee/app/models/dast_site_profile.rb
+2
-0
ee/spec/factories/dast_site_profiles.rb
ee/spec/factories/dast_site_profiles.rb
+2
-5
ee/spec/graphql/mutations/dast_on_demand_scans/create_spec.rb
...pec/graphql/mutations/dast_on_demand_scans/create_spec.rb
+119
-0
ee/spec/models/dast_site_profile_spec.rb
ee/spec/models/dast_site_profile_spec.rb
+14
-0
ee/spec/requests/api/graphql/mutations/dast_on_demand_scans/create_spec.rb
...api/graphql/mutations/dast_on_demand_scans/create_spec.rb
+75
-0
No files found.
doc/api/graphql/reference/gitlab_schema.graphql
View file @
c18a76b6
...
...
@@ -2152,6 +2152,46 @@ type CreateSnippetPayload {
snippet
:
Snippet
}
"""
Autogenerated input type of DastOnDemandScanCreate
"""
input
DastOnDemandScanCreateInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
ID
of
the
site
profile
to
be
used
for
the
scan
.
"""
dastSiteProfileId
:
ID
!
"""
The
project
the
site
profile
belongs
to
.
"""
fullPath
:
ID
!
}
"""
Autogenerated return type of DastOnDemandScanCreate
"""
type
DastOnDemandScanCreatePayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Errors
encountered
during
execution
of
the
mutation
.
"""
errors
:
[
String
!]!
"""
URL
of
the
pipeline
that
was
created
.
"""
pipelineUrl
:
String
}
enum
DastScanTypeEnum
{
"""
Passive
DAST
scan
.
This
scan
will
not
make
active
attacks
against
the
target
site
.
...
...
@@ -8275,6 +8315,7 @@ type Mutation {
createNote
(
input
:
CreateNoteInput
!):
CreateNotePayload
createRequirement
(
input
:
CreateRequirementInput
!):
CreateRequirementPayload
createSnippet
(
input
:
CreateSnippetInput
!):
CreateSnippetPayload
dastOnDemandScanCreate
(
input
:
DastOnDemandScanCreateInput
!):
DastOnDemandScanCreatePayload
dastScannerProfileCreate
(
input
:
DastScannerProfileCreateInput
!):
DastScannerProfileCreatePayload
dastSiteProfileCreate
(
input
:
DastSiteProfileCreateInput
!):
DastSiteProfileCreatePayload
deleteAnnotation
(
input
:
DeleteAnnotationInput
!):
DeleteAnnotationPayload
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
c18a76b6
...
...
@@ -5768,6 +5768,122 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "DastOnDemandScanCreateInput",
"description": "Autogenerated input type of DastOnDemandScanCreate",
"fields": null,
"inputFields": [
{
"name": "fullPath",
"description": "The project the site profile belongs to.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "dastSiteProfileId",
"description": "ID of the site profile to be used for the scan.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "DastOnDemandScanCreatePayload",
"description": "Autogenerated return type of DastOnDemandScanCreate",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Errors encountered during execution of the mutation.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pipelineUrl",
"description": "URL of the pipeline that was created.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "DastScanTypeEnum",
...
...
@@ -23712,6 +23828,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "dastOnDemandScanCreate",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "DastOnDemandScanCreateInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "DastOnDemandScanCreatePayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "dastScannerProfileCreate",
"description": null,
doc/api/graphql/reference/index.md
View file @
c18a76b6
...
...
@@ -382,6 +382,16 @@ Autogenerated return type of CreateSnippet
|
`errors`
| String! => Array | Errors encountered during execution of the mutation. |
|
`snippet`
| Snippet | The snippet after mutation |
## DastOnDemandScanCreatePayload
Autogenerated return type of DastOnDemandScanCreate
| Name | Type | Description |
| --- | ---- | ---------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Errors encountered during execution of the mutation. |
|
`pipelineUrl`
| String | URL of the pipeline that was created. |
## DastScannerProfileCreatePayload
Autogenerated return type of DastScannerProfileCreate
...
...
ee/app/graphql/ee/types/mutation_type.rb
View file @
c18a76b6
...
...
@@ -22,6 +22,7 @@ module EE
mount_mutation
::
Mutations
::
InstanceSecurityDashboard
::
AddProject
mount_mutation
::
Mutations
::
InstanceSecurityDashboard
::
RemoveProject
mount_mutation
::
Mutations
::
Pipelines
::
RunDastScan
mount_mutation
::
Mutations
::
DastOnDemandScans
::
Create
mount_mutation
::
Mutations
::
DastSiteProfiles
::
Create
mount_mutation
::
Mutations
::
DastScannerProfiles
::
Create
mount_mutation
::
Mutations
::
Namespaces
::
IncreaseStorageTemporarily
...
...
ee/app/graphql/mutations/dast_on_demand_scans/create.rb
0 → 100644
View file @
c18a76b6
# frozen_string_literal: true
module
Mutations
module
DastOnDemandScans
class
Create
<
BaseMutation
InvalidGlobalID
=
Class
.
new
(
StandardError
)
include
ResolvesProject
graphql_name
'DastOnDemandScanCreate'
field
:pipeline_url
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
'URL of the pipeline that was created.'
argument
:full_path
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'The project the site profile belongs to.'
argument
:dast_site_profile_id
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'ID of the site profile to be used for the scan.'
authorize
:run_ondemand_dast_scan
def
resolve
(
full_path
:,
dast_site_profile_id
:)
project
=
authorized_find!
(
full_path:
full_path
)
raise_resource_not_available_error!
unless
Feature
.
enabled?
(
:security_on_demand_scans_feature_flag
,
project
)
dast_site_profile
=
find_dast_site_profile
(
project:
project
,
dast_site_profile_id:
dast_site_profile_id
)
dast_site
=
dast_site_profile
.
dast_site
service
=
Ci
::
RunDastScanService
.
new
(
project
,
current_user
)
result
=
service
.
execute
(
branch:
project
.
default_branch
,
target_url:
dast_site
.
url
)
if
result
.
success?
success_response
(
project:
project
,
pipeline:
result
.
payload
)
else
error_response
(
result
)
end
end
private
def
find_object
(
full_path
:)
resolve_project
(
full_path:
full_path
)
end
def
find_dast_site_profile
(
project
:,
dast_site_profile_id
:)
global_id
=
GlobalID
.
parse
(
dast_site_profile_id
)
raise
InvalidGlobalID
.
new
(
'Incorrect class'
)
unless
global_id
.
model_class
==
DastSiteProfile
project
.
dast_site_profiles
.
with_dast_site
.
find
(
global_id
.
model_id
)
end
def
success_response
(
project
:,
pipeline
:)
pipeline_url
=
Rails
.
application
.
routes
.
url_helpers
.
project_pipeline_url
(
project
,
pipeline
)
{
errors:
[],
pipeline_url:
pipeline_url
}
end
def
error_response
(
result
)
{
errors:
result
.
errors
}
end
end
end
end
ee/app/models/dast_site_profile.rb
View file @
c18a76b6
...
...
@@ -8,6 +8,8 @@ class DastSiteProfile < ApplicationRecord
validates
:project_id
,
:dast_site_id
,
presence:
true
validate
:dast_site_project_id_fk
scope
:with_dast_site
,
->
{
includes
(
:dast_site
)
}
private
def
dast_site_project_id_fk
...
...
ee/spec/factories/dast_site_profiles.rb
View file @
c18a76b6
...
...
@@ -5,11 +5,8 @@ FactoryBot.define do
name
{
FFaker
::
Product
.
product_name
}
before
(
:create
)
do
|
dast_site_profile
|
project
=
FactoryBot
.
create
(
:project
)
dast_site
=
FactoryBot
.
create
(
:dast_site
,
project:
project
)
dast_site_profile
.
project
=
project
dast_site_profile
.
dast_site
=
dast_site
dast_site_profile
.
project
||=
FactoryBot
.
create
(
:project
)
dast_site_profile
.
dast_site
||=
FactoryBot
.
create
(
:dast_site
,
project:
dast_site_profile
.
project
)
end
end
end
ee/spec/graphql/mutations/dast_on_demand_scans/create_spec.rb
0 → 100644
View file @
c18a76b6
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Mutations
::
DastOnDemandScans
::
Create
do
let
(
:group
)
{
create
(
:group
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
,
:repository
,
group:
group
)
}
let
(
:full_path
)
{
project
.
full_path
}
let
(
:dast_site_profile
)
{
create
(
:dast_site_profile
,
project:
project
)
}
let
(
:dast_site_profile_id
)
{
dast_site_profile
.
to_global_id
}
subject
(
:mutation
)
{
described_class
.
new
(
object:
nil
,
context:
{
current_user:
user
},
field:
nil
)
}
describe
'#resolve'
do
subject
do
mutation
.
resolve
(
full_path:
full_path
,
dast_site_profile_id:
dast_site_profile_id
)
end
context
'when on demand scan feature is enabled'
do
context
'when the project does not exist'
do
let
(
:full_path
)
{
SecureRandom
.
hex
}
it
'raises an exception'
do
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
context
'when the user is not associated with the project'
do
it
'raises an exception'
do
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
context
'when the user is an owner'
do
it
'has no errors'
do
group
.
add_owner
(
user
)
expect
(
subject
[
:errors
]).
to
be_empty
end
end
context
'when the user is a maintainer'
do
it
'has no errors'
do
project
.
add_maintainer
(
user
)
expect
(
subject
[
:errors
]).
to
be_empty
end
end
context
'when the user is a developer'
do
it
'has no errors'
do
project
.
add_developer
(
user
)
expect
(
subject
[
:errors
]).
to
be_empty
end
end
context
'when the user is a reporter'
do
it
'raises an exception'
do
project
.
add_reporter
(
user
)
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
context
'when the user is a guest'
do
it
'raises an exception'
do
project
.
add_guest
(
user
)
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
context
'when the user can run a dast scan'
do
before
do
project
.
add_developer
(
user
)
end
it
'returns a pipeline_url containing the correct path'
do
actual_url
=
subject
[
:pipeline_url
]
pipeline
=
Ci
::
Pipeline
.
last
expected_url
=
Rails
.
application
.
routes
.
url_helpers
.
project_pipeline_url
(
project
,
pipeline
)
expect
(
actual_url
).
to
eq
(
expected_url
)
end
context
'when the wrong type of gid is used'
do
let
(
:dast_site_profile_id
)
{
project
.
to_global_id
}
it
'raises an exception'
do
expect
{
subject
}.
to
raise_error
(
described_class
::
InvalidGlobalID
)
end
end
context
'when the dast_site_profile does not exist'
do
it
'raises an exception'
do
dast_site_profile
.
destroy!
expect
{
subject
}.
to
raise_error
(
ActiveRecord
::
RecordNotFound
)
end
end
context
'when on demand scan feature is not enabled'
do
it
'raises an exception'
do
stub_feature_flags
(
security_on_demand_scans_feature_flag:
false
)
expect
{
subject
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
end
end
end
end
end
ee/spec/models/dast_site_profile_spec.rb
View file @
c18a76b6
...
...
@@ -29,4 +29,18 @@ RSpec.describe DastSiteProfile, type: :model do
end
end
end
describe
'scopes'
do
describe
'.with_dast_site'
do
it
'eager loads the association'
do
subject
recorder
=
ActiveRecord
::
QueryRecorder
.
new
do
subject
.
dast_site
end
expect
(
recorder
.
count
).
to
be_zero
end
end
end
end
ee/spec/requests/api/graphql/mutations/dast_on_demand_scans/create_spec.rb
0 → 100644
View file @
c18a76b6
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'Running a DAST Scan'
do
include
GraphqlHelpers
let
(
:project
)
{
create
(
:project
,
:repository
,
creator:
current_user
)
}
let
(
:current_user
)
{
create
(
:user
)
}
let
(
:full_path
)
{
project
.
full_path
}
let
(
:dast_site_profile
)
{
create
(
:dast_site_profile
,
project:
project
)
}
let
(
:mutation
)
do
graphql_mutation
(
:dast_on_demand_scan_create
,
full_path:
full_path
,
dast_site_profile_id:
dast_site_profile
.
to_global_id
.
to_s
)
end
def
mutation_response
graphql_mutation_response
(
:dast_on_demand_scan_create
)
end
context
'when a user does not have access to the project'
do
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
'The resource that you are attempting to access does not '
\
'exist or you don\'t have permission to perform this action'
]
end
context
'when a user does not have access to run a dast scan on the project'
do
before
do
project
.
add_guest
(
current_user
)
end
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
'The resource that you are attempting to access does not '
\
"exist or you don't have permission to perform this action"
]
end
context
'when a user has access to run a dast scan on the project'
do
before
do
project
.
add_developer
(
current_user
)
end
it
'returns a pipeline_url containing the correct path'
do
post_graphql_mutation
(
mutation
,
current_user:
current_user
)
pipeline
=
Ci
::
Pipeline
.
last
expected_url
=
Rails
.
application
.
routes
.
url_helpers
.
project_pipeline_url
(
project
,
pipeline
)
expect
(
mutation_response
[
'pipelineUrl'
]).
to
eq
(
expected_url
)
end
context
'when pipeline creation fails'
do
before
do
allow_any_instance_of
(
Ci
::
Pipeline
).
to
receive
(
:created_successfully?
).
and_return
(
false
)
allow_any_instance_of
(
Ci
::
Pipeline
).
to
receive
(
:full_error_messages
).
and_return
(
'error message'
)
end
it_behaves_like
'a mutation that returns errors in the response'
,
errors:
[
'error message'
]
end
context
'when on demand scan feature is disabled'
do
before
do
stub_feature_flags
(
security_on_demand_scans_feature_flag:
false
)
end
it_behaves_like
'a mutation that returns top-level errors'
,
errors:
[
'The resource that you are attempting to access does not '
\
"exist or you don't have permission to perform this action"
]
end
end
end
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