Commit 72dd03d1 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 7e9cac46 fdcf6a41
...@@ -277,7 +277,8 @@ ...@@ -277,7 +277,8 @@
"type": "string", "type": "string",
"format": "uri-reference", "format": "uri-reference",
"pattern": "\\.ya?ml$" "pattern": "\\.ya?ml$"
} },
"rules": { "$ref": "#/definitions/rules" }
}, },
"required": ["local"] "required": ["local"]
}, },
...@@ -491,7 +492,7 @@ ...@@ -491,7 +492,7 @@
}, },
"rules": { "rules": {
"type": "array", "type": "array",
"description": "rules allows for an array of individual rule objects to be evaluated in order, until one matches and dynamically provides attributes to the job.", "description": "Rules allows for an array of individual rule objects to be evaluated in order, until one matches and dynamically provides attributes to the job.",
"items": { "items": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
...@@ -625,17 +626,26 @@ ...@@ -625,17 +626,26 @@
] ]
}, },
"cache": { "cache": {
"oneOf": [ "properties": {
{ "when": {
"$ref": "#/definitions/cache_entry" "description": "Defines when to save the cache, based on the status of the job.",
}, "default": "on_success",
{ "oneOf": [
"type": "array", {
"items": { "enum": ["on_success"],
"$ref": "#/definitions/cache_entry" "description": "Save the cache only when the job succeeds."
} },
{
"enum": ["on_failure"],
"description": "Save the cache only when the job fails. "
},
{
"enum": ["always"],
"description": "Always save the cache. "
}
]
} }
] }
}, },
"cache_entry": { "cache_entry": {
"type": "object", "type": "object",
...@@ -1320,6 +1330,29 @@ ...@@ -1320,6 +1330,29 @@
} }
}, },
"required": ["artifact", "job"] "required": ["artifact", "job"]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"project": {
"description": "Path to another private project under the same GitLab instance, like `group/project` or `group/sub-group/project`.",
"type": "string",
"pattern": "\\S/\\S"
},
"ref": {
"description": "Branch/Tag/Commit hash for the target project.",
"minLength": 1,
"type": "string"
},
"file": {
"description": "Relative path from repository root (`/`) to the pipeline configuration YAML file.",
"type": "string",
"format": "uri-reference",
"pattern": "\\.ya?ml$"
}
},
"required": ["project", "file"]
} }
] ]
} }
......
...@@ -28,7 +28,7 @@ module Routing ...@@ -28,7 +28,7 @@ module Routing
when 'groups' when 'groups'
"/namespace:#{group.id}" "/namespace:#{group.id}"
when 'projects' when 'projects'
"/namespace:#{project.namespace.id}/project:#{project.id}" "/namespace:#{project.namespace_id}/project:#{project.id}"
when 'root' when 'root'
'' ''
else else
...@@ -44,7 +44,7 @@ module Routing ...@@ -44,7 +44,7 @@ module Routing
masked_url = "#{request.protocol}#{request.host_with_port}" masked_url = "#{request.protocol}#{request.host_with_port}"
if request_params.has_key?(:project_id) if request_params.has_key?(:project_id)
masked_url += "/namespace:#{project.namespace.id}/project:#{project.id}/-/#{namespace_type}" masked_url += "/namespace:#{project.namespace_id}/project:#{project.id}/-/#{namespace_type}"
end end
if request_params.has_key?(:id) if request_params.has_key?(:id)
......
...@@ -73,7 +73,6 @@ module TabHelper ...@@ -73,7 +73,6 @@ module TabHelper
# :action - One or more action names to check (optional). # :action - One or more action names to check (optional).
# :path - A shorthand path, such as 'dashboard#index', to check (optional). # :path - A shorthand path, such as 'dashboard#index', to check (optional).
# :html_options - Extra options to be passed to the list element (optional). # :html_options - Extra options to be passed to the list element (optional).
# :unless - Callable object to skip rendering the 'active' class on `li` element (optional).
# block - An optional block that will become the contents of the returned # block - An optional block that will become the contents of the returned
# `li` element. # `li` element.
# #
...@@ -118,11 +117,6 @@ module TabHelper ...@@ -118,11 +117,6 @@ module TabHelper
# nav_link(path: 'admin/appearances#show') { "Hello"} # nav_link(path: 'admin/appearances#show') { "Hello"}
# # => '<li class="active">Hello</li>' # # => '<li class="active">Hello</li>'
# #
# # Shorthand path + unless
# # Add `active` class when TreeController is requested, except the `index` action.
# nav_link(controller: 'tree', unless: -> { action_name?('index') }) { "Hello" }
# # => '<li class="active">Hello</li>'
#
# # When `TreeController#index` is requested # # When `TreeController#index` is requested
# # => '<li>Hello</li>' # # => '<li>Hello</li>'
# #
...@@ -151,8 +145,6 @@ module TabHelper ...@@ -151,8 +145,6 @@ module TabHelper
end end
def active_nav_link?(options) def active_nav_link?(options)
return false if options[:unless]&.call
controller = options.delete(:controller) controller = options.delete(:controller)
action = options.delete(:action) action = options.delete(:action)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Projects module Projects
class OverwriteProjectService < BaseService class OverwriteProjectService < BaseService
def execute(source_project) def execute(source_project)
return unless source_project && source_project.namespace == @project.namespace return unless source_project && source_project.namespace_id == @project.namespace_id
start_time = ::Gitlab::Metrics::System.monotonic_time start_time = ::Gitlab::Metrics::System.monotonic_time
...@@ -40,7 +40,7 @@ module Projects ...@@ -40,7 +40,7 @@ module Projects
duration = ::Gitlab::Metrics::System.monotonic_time - start_time duration = ::Gitlab::Metrics::System.monotonic_time - start_time
Gitlab::AppJsonLogger.info(class: self.class.name, Gitlab::AppJsonLogger.info(class: self.class.name,
namespace_id: source_project.namespace.id, namespace_id: source_project.namespace_id,
project_id: source_project.id, project_id: source_project.id,
duration_s: duration.to_f, duration_s: duration.to_f,
error: exception.class.name) error: exception.class.name)
......
...@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w ...@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference, howto type: reference, howto
--- ---
# Vault Authentication with GitLab OpenID Connect # Vault Authentication with GitLab OpenID Connect **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/22323) in GitLab 9.0 > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/22323) in GitLab 9.0
......
...@@ -20,7 +20,7 @@ A DAST job has two executing processes: ...@@ -20,7 +20,7 @@ A DAST job has two executing processes:
Enable the `DAST_DEBUG` CI/CD variable to debug scripts. This can help when troubleshooting the job, Enable the `DAST_DEBUG` CI/CD variable to debug scripts. This can help when troubleshooting the job,
and outputs statements indicating what percentage of the scan is complete. and outputs statements indicating what percentage of the scan is complete.
For details on using variables, see [Overriding the DAST template](index.md#customizing-the-dast-settings). For details on using variables, see [Overriding the DAST template](index.md#customize-dast-settings).
Debug mode of the ZAP server can be enabled using the `DAST_ZAP_LOG_CONFIGURATION` variable. Debug mode of the ZAP server can be enabled using the `DAST_ZAP_LOG_CONFIGURATION` variable.
The following table outlines examples of values that can be set and the effect that they have on the output that is logged. The following table outlines examples of values that can be set and the effect that they have on the output that is logged.
......
...@@ -483,6 +483,13 @@ When using `DAST_PATHS` and `DAST_PATHS_FILE`, note the following: ...@@ -483,6 +483,13 @@ When using `DAST_PATHS` and `DAST_PATHS_FILE`, note the following:
To perform a [full scan](#full-scan) on the listed paths, use the `DAST_FULL_SCAN_ENABLED` CI/CD variable. To perform a [full scan](#full-scan) on the listed paths, use the `DAST_FULL_SCAN_ENABLED` CI/CD variable.
### List URLs scanned
When DAST completes scanning, the merge request page states the number of URLs scanned.
Click **View details** to view the web console output which includes the list of scanned URLs.
![DAST Widget](img/dast_urls_scanned_v12_10.png)
### View details of a vulnerability detected by DAST ### View details of a vulnerability detected by DAST
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
...@@ -515,15 +522,20 @@ To view details of vulnerabilities detected by DAST: ...@@ -515,15 +522,20 @@ To view details of vulnerabilities detected by DAST:
| Links | Links to further details of the detected vulnerability. | | Links | Links to further details of the detected vulnerability. |
| Solution | Details of a recommended solution to the vulnerability (optional). | | Solution | Details of a recommended solution to the vulnerability (optional). |
### Customizing the DAST settings ## Customize DAST settings
You can customize the behavior of DAST using both CI/CD variables and command-line options. Use of CI/CD
variables overrides the values contained in the DAST template.
### Customize DAST using CI/CD variables
WARNING: WARNING:
Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/index.md#only--except) Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/index.md#only--except)
is no longer supported. When overriding the template, you must use [`rules`](../../../ci/yaml/index.md#rules) instead. is no longer supported. You must use [`rules`](../../../ci/yaml/index.md#rules) instead.
The DAST settings can be changed through CI/CD variables by using the The DAST settings can be changed through CI/CD variables by using the
[`variables`](../../../ci/yaml/index.md#variables) parameter in `.gitlab-ci.yml`. [`variables`](../../../ci/yaml/index.md#variables) parameter in `.gitlab-ci.yml`. For details of
These variables are documented in [available variables](#available-cicd-variables). all DAST CI/CD variables, read [Available CI/CD variables](#available-cicd-variables).
For example: For example:
...@@ -539,10 +551,10 @@ variables: ...@@ -539,10 +551,10 @@ variables:
Because the template is [evaluated before](../../../ci/yaml/index.md#include) the pipeline Because the template is [evaluated before](../../../ci/yaml/index.md#include) the pipeline
configuration, the last mention of the variable takes precedence. configuration, the last mention of the variable takes precedence.
#### Enabling and disabling rules #### Enable or disable rules
A complete list of the rules that DAST uses to scan for vulnerabilities can be A complete list of the rules that DAST uses to scan for vulnerabilities can be
found in the [ZAP docs](https://www.zaproxy.org/docs/alerts/). found in the [ZAP documentation](https://www.zaproxy.org/docs/alerts/).
`DAST_EXCLUDE_RULES` disables the rules with the given IDs. `DAST_EXCLUDE_RULES` disables the rules with the given IDs.
...@@ -559,7 +571,7 @@ can be found in [exclude_rules.yml](https://gitlab.com/gitlab-org/security-produ ...@@ -559,7 +571,7 @@ can be found in [exclude_rules.yml](https://gitlab.com/gitlab-org/security-produ
The lists for `DAST_EXCLUDE_RULES` and `DAST_ONLY_INCLUDE_RULES` **must** be enclosed in double The lists for `DAST_EXCLUDE_RULES` and `DAST_ONLY_INCLUDE_RULES` **must** be enclosed in double
quotes (`"`), otherwise they are interpreted as numeric values. quotes (`"`), otherwise they are interpreted as numeric values.
### Hide sensitive information #### Hide sensitive information
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1.
...@@ -573,7 +585,105 @@ authorization credentials. By default, the following headers are masked: ...@@ -573,7 +585,105 @@ authorization credentials. By default, the following headers are masked:
Using the [`DAST_MASK_HTTP_HEADERS` CI/CD variable](#available-cicd-variables), you can list the Using the [`DAST_MASK_HTTP_HEADERS` CI/CD variable](#available-cicd-variables), you can list the
headers whose values you want masked. For details on how to mask headers, see headers whose values you want masked. For details on how to mask headers, see
[Customizing the DAST settings](#customizing-the-dast-settings). [Customizing the DAST settings](#customize-dast-settings).
#### Available CI/CD variables
These CI/CD variables are specific to DAST. They can be used to customize the behavior of DAST to your requirements.
| CI/CD variable | Type | Description |
|:-------------------------------------------------|:--------------|:------------------------------|
| `DAST_ADVERTISE_SCAN` | boolean | Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334947) in GitLab 14.1. |
| `DAST_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080`. |
| `DAST_API_OPENAPI` | URL or string | The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/290241) in GitLab 13.12 and replaced by `DAST_API_OPENAPI`. To be removed in GitLab 15.0. The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_AUTH_REPORT` <sup>2</sup> | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
| `DAST_AUTH_EXCLUDE_URLS` <sup>2</sup> | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_URLS`. The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. |
| `DAST_AUTH_URL` <sup>1,2</sup> | URL | The URL of the page containing the sign-in HTML form on the target website. `DAST_USERNAME` and `DAST_PASSWORD` are submitted with the login form to create an authenticated scan. Not supported for API scans. Example: `https://login.example.com`. |
| `DAST_AUTH_VERIFICATION_LOGIN_FORM` <sup>2</sup> | boolean | Verifies successful authentication by checking for the lack of a login form once the login form has been submitted. |
| `DAST_AUTH_VERIFICATION_SELECTOR` <sup>2</sup> | selector | Verifies successful authentication by checking for presence of a selector once the login form has been submitted. Example: `css:.user-photo`. |
| `DAST_AUTH_VERIFICATION_URL` <sup>1,2</sup> | URL | A URL only accessible to logged in users that DAST can use to confirm successful authentication. If provided, DAST exits if it cannot access the URL. Example: `"http://example.com/loggedin_page"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false`. |
| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1,2</sup> | selector | Comma-separated list of selectors that will be clicked on prior to attempting to enter `DAST_USERNAME` and `DAST_PASSWORD` into the login form. Example: `"css:.navigation-menu,css:.login-menu-item"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326633) in GitLab 14.1. |
| `DAST_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
| `DAST_EXCLUDE_URLS` <sup>1,2</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. Example, `http://example.com/sign-out`. |
| `DAST_FIRST_SUBMIT_FIELD` <sup>2</sup> | string | The `id` or `name` of the element that when clicked submits the username form of a multi-page login process. For example, `css:button[type='user-submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` |
| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` |
| `DAST_HTML_REPORT` | string | The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | boolean | Set to `true` to include alpha passive and active scan rules. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MARKDOWN_REPORT` | string | The filename of the Markdown report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). |
| `DAST_MAX_URLS_PER_VULNERABILITY` | number | The maximum number of URLs reported for a single vulnerability. `DAST_MAX_URLS_PER_VULNERABILITY` is set to `50` by default. To list all the URLs set to `0`. [Introduced](https://gitlab.com/gitlab-org/security-products/dast/-/merge_requests/433) in GitLab 13.12. |
| `DAST_ONLY_INCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to configure the scan to run only them. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). Cannot be used when `DAST_EXCLUDE_RULES` is set. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250651) in GitLab 13.12. |
| `DAST_PASSWORD` <sup>1,2</sup> | string | The password to authenticate to in the website. Example: `P@55w0rd!` |
| `DAST_PASSWORD_FIELD` <sup>1,2</sup> | string | The selector of password field at the sign-in HTML form. Example: `id:password` |
| `DAST_PATHS` | string | Set to a comma-separated list of URLs for DAST to scan. For example, `/page1.html,/category1/page3.html,/page2.html`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4. |
| `DAST_PATHS_FILE` | string | The file path containing the paths within `DAST_WEBSITE` to scan. The file must be plain text with one path per line. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6. |
| `DAST_REQUEST_HEADERS` <sup>1</sup> | string | Set to a comma-separated list of request header names and values. Headers are added to every request made by DAST. For example, `Cache-control: no-cache,User-Agent: DAST/1.0` |
| `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. |
| `DAST_SPIDER_MINS` <sup>1</sup> | number | The maximum duration of the spider scan in minutes. Set to `0` for unlimited. Default: One minute, or unlimited when the scan is a full scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_SPIDER_START_AT_HOST` | boolean | Set to `false` to prevent DAST from resetting the target to its host before scanning. When `true`, non-host targets `http://test.site/some_path` is reset to `http://test.site` before scan. Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258805) in GitLab 13.6. |
| `DAST_SUBMIT_FIELD` <sup>2</sup> | string | The `id` or `name` of the element that when clicked submits the login form or the password form of a multi-page login process. For example, `css:button[type='submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_TARGET_AVAILABILITY_TIMEOUT` <sup>1</sup> | number | Time limit in seconds to wait for target availability. |
| `DAST_USE_AJAX_SPIDER` <sup>1</sup> | boolean | Set to `true` to use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_USERNAME` <sup>1,2</sup> | string | The username to authenticate to in the website. Example: `admin` |
| `DAST_USERNAME_FIELD` <sup>1,2</sup> | string | The selector of username field at the sign-in HTML form. Example: `name:username` |
| `DAST_XML_REPORT` | string | The filename of the XML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_WEBSITE` <sup>1</sup> | URL | The URL of the website to scan. The variable `DAST_API_OPENAPI` must be specified if this is omitted. |
| `DAST_ZAP_CLI_OPTIONS` | string | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_ZAP_LOG_CONFIGURATION` | string | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. Example: `log4j.logger.org.parosproxy.paros.network.HttpSender=DEBUG;log4j.logger.com.crawljax=DEBUG` |
| `SECURE_ANALYZERS_PREFIX` | URL | Set the Docker registry base address from which to download the analyzer. |
1. Available to an on-demand DAST scan.
1. Used for authentication.
### Customize DAST using command-line options
Not all DAST configuration is available via CI/CD variables. To find out all
possible options, run the following configuration.
Available command-line options are printed to the job log:
```yaml
include:
template: DAST.gitlab-ci.yml
dast:
script:
- /analyze --help
```
You must then overwrite the `script` command to pass in the appropriate
argument. For example, vulnerability definitions in alpha can be included with
`-a`. The following configuration includes those definitions:
```yaml
include:
template: DAST.gitlab-ci.yml
dast:
script:
- export DAST_WEBSITE=${DAST_WEBSITE:-$(cat environment_url.txt)}
- /analyze -a -t $DAST_WEBSITE
```
### Custom ZAProxy configuration
The ZAProxy server contains many [useful configurable values](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_245801885).
Many key/values for `-config` remain undocumented, but there is an untested list of
[possible keys](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_244981023).
Note that these options are not supported by DAST, and may break the DAST scan
when used. An example of how to rewrite the Authorization header value with `TOKEN` follows:
```yaml
include:
template: DAST.gitlab-ci.yml
variables:
DAST_ZAP_CLI_OPTIONS: "-config replacer.full_list(0).description=auth -config replacer.full_list(0).enabled=true -config replacer.full_list(0).matchtype=REQ_HEADER -config replacer.full_list(0).matchstr=Authorization -config replacer.full_list(0).regex=false -config replacer.full_list(0).replacement=TOKEN"
```
## Authentication ## Authentication
...@@ -747,59 +857,6 @@ dast: ...@@ -747,59 +857,6 @@ dast:
when: always when: always
``` ```
## Available CI/CD variables
These CI/CD variables are specific to DAST. They can be used to customize the behavior of DAST to your requirements.
| CI/CD variable | Type | Description |
|:-------------------------------------------------|:--------------|:------------------------------|
| `DAST_ADVERTISE_SCAN` | boolean | Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334947) in GitLab 14.1. |
| `DAST_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080`. |
| `DAST_API_OPENAPI` | URL or string | The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/290241) in GitLab 13.12 and replaced by `DAST_API_OPENAPI`. To be removed in GitLab 15.0. The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_AUTH_REPORT` <sup>2</sup> | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
| `DAST_AUTH_EXCLUDE_URLS` <sup>2</sup> | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_URLS`. The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. |
| `DAST_AUTH_URL` <sup>1,2</sup> | URL | The URL of the page containing the sign-in HTML form on the target website. `DAST_USERNAME` and `DAST_PASSWORD` are submitted with the login form to create an authenticated scan. Not supported for API scans. Example: `https://login.example.com`. |
| `DAST_AUTH_VERIFICATION_LOGIN_FORM` <sup>2</sup> | boolean | Verifies successful authentication by checking for the lack of a login form once the login form has been submitted. |
| `DAST_AUTH_VERIFICATION_SELECTOR` <sup>2</sup> | selector | Verifies successful authentication by checking for presence of a selector once the login form has been submitted. Example: `css:.user-photo`. |
| `DAST_AUTH_VERIFICATION_URL` <sup>1,2</sup> | URL | A URL only accessible to logged in users that DAST can use to confirm successful authentication. If provided, DAST exits if it cannot access the URL. Example: `"http://example.com/loggedin_page"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false`. |
| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1,2</sup> | selector | Comma-separated list of selectors that will be clicked on prior to attempting to enter `DAST_USERNAME` and `DAST_PASSWORD` into the login form. Example: `"css:.navigation-menu,css:.login-menu-item"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326633) in GitLab 14.1. |
| `DAST_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. The whole list **must** be enclosed in double quotes (`"`). Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
| `DAST_EXCLUDE_URLS` <sup>1,2</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. Example, `http://example.com/sign-out`. |
| `DAST_FIRST_SUBMIT_FIELD` <sup>2</sup> | string | The `id` or `name` of the element that when clicked submits the username form of a multi-page login process. For example, `css:button[type='user-submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` |
| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` |
| `DAST_HTML_REPORT` | string | The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | boolean | Set to `true` to include alpha passive and active scan rules. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MARKDOWN_REPORT` | string | The filename of the Markdown report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). |
| `DAST_MAX_URLS_PER_VULNERABILITY` | number | The maximum number of URLs reported for a single vulnerability. `DAST_MAX_URLS_PER_VULNERABILITY` is set to `50` by default. To list all the URLs set to `0`. [Introduced](https://gitlab.com/gitlab-org/security-products/dast/-/merge_requests/433) in GitLab 13.12. |
| `DAST_ONLY_INCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to configure the scan to run only them. The whole list **must** be enclosed in double quotes (`"`). Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). Cannot be used when `DAST_EXCLUDE_RULES` is set. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250651) in GitLab 13.12. |
| `DAST_PASSWORD` <sup>1,2</sup> | string | The password to authenticate to in the website. Example: `P@55w0rd!` |
| `DAST_PASSWORD_FIELD` <sup>1,2</sup> | string | The selector of password field at the sign-in HTML form. Example: `id:password` |
| `DAST_PATHS` | string | Set to a comma-separated list of URLs for DAST to scan. For example, `/page1.html,/category1/page3.html,/page2.html`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4. |
| `DAST_PATHS_FILE` | string | The file path containing the paths within `DAST_WEBSITE` to scan. The file must be plain text with one path per line. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6. |
| `DAST_REQUEST_HEADERS` <sup>1</sup> | string | Set to a comma-separated list of request header names and values. Headers are added to every request made by DAST. For example, `Cache-control: no-cache,User-Agent: DAST/1.0` |
| `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. |
| `DAST_SPIDER_MINS` <sup>1</sup> | number | The maximum duration of the spider scan in minutes. Set to `0` for unlimited. Default: One minute, or unlimited when the scan is a full scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_SPIDER_START_AT_HOST` | boolean | Set to `false` to prevent DAST from resetting the target to its host before scanning. When `true`, non-host targets `http://test.site/some_path` is reset to `http://test.site` before scan. Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258805) in GitLab 13.6. |
| `DAST_SUBMIT_FIELD` <sup>2</sup> | string | The `id` or `name` of the element that when clicked submits the login form or the password form of a multi-page login process. For example, `css:button[type='submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_TARGET_AVAILABILITY_TIMEOUT` <sup>1</sup> | number | Time limit in seconds to wait for target availability. |
| `DAST_USE_AJAX_SPIDER` <sup>1</sup> | boolean | Set to `true` to use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_USERNAME` <sup>1,2</sup> | string | The username to authenticate to in the website. Example: `admin` |
| `DAST_USERNAME_FIELD` <sup>1,2</sup> | string | The selector of username field at the sign-in HTML form. Example: `name:username` |
| `DAST_XML_REPORT` | string | The filename of the XML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_WEBSITE` <sup>1</sup> | URL | The URL of the website to scan. The variable `DAST_API_OPENAPI` must be specified if this is omitted. |
| `DAST_ZAP_CLI_OPTIONS` | string | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_ZAP_LOG_CONFIGURATION` | string | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. Example: `log4j.logger.org.parosproxy.paros.network.HttpSender=DEBUG;log4j.logger.com.crawljax=DEBUG` |
| `SECURE_ANALYZERS_PREFIX` | URL | Set the Docker registry base address from which to download the analyzer. |
1. Available to an on-demand DAST scan.
1. Used for authentication.
### Selectors ### Selectors
Selectors are used by CI/CD variables to specify the location of an element displayed on a page in a browser. Selectors are used by CI/CD variables to specify the location of an element displayed on a page in a browser.
...@@ -848,51 +905,6 @@ When using selectors to locate specific fields we recommend you avoid searching ...@@ -848,51 +905,6 @@ When using selectors to locate specific fields we recommend you avoid searching
- XPath searches as they are less performant than other selector searches. - XPath searches as they are less performant than other selector searches.
- Unscoped searches, such as those beginning with `css:*` and `xpath://*`. - Unscoped searches, such as those beginning with `css:*` and `xpath://*`.
### DAST command-line options
Not all DAST configuration is available via CI/CD variables. To find out all
possible options, run the following configuration.
Available command-line options are printed to the job log:
```yaml
include:
template: DAST.gitlab-ci.yml
dast:
script:
- /analyze --help
```
You must then overwrite the `script` command to pass in the appropriate
argument. For example, vulnerability definitions in alpha can be included with
`-a`. The following configuration includes those definitions:
```yaml
include:
template: DAST.gitlab-ci.yml
dast:
script:
- export DAST_WEBSITE=${DAST_WEBSITE:-$(cat environment_url.txt)}
- /analyze -a -t $DAST_WEBSITE
```
### Custom ZAProxy configuration
The ZAProxy server contains many [useful configurable values](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_245801885).
Many key/values for `-config` remain undocumented, but there is an untested list of
[possible keys](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_244981023).
Note that these options are not supported by DAST, and may break the DAST scan
when used. An example of how to rewrite the Authorization header value with `TOKEN` follows:
```yaml
include:
template: DAST.gitlab-ci.yml
variables:
DAST_ZAP_CLI_OPTIONS: "-config replacer.full_list(0).description=auth -config replacer.full_list(0).enabled=true -config replacer.full_list(0).matchtype=REQ_HEADER -config replacer.full_list(0).matchstr=Authorization -config replacer.full_list(0).regex=false -config replacer.full_list(0).replacement=TOKEN"
```
### Bleeding-edge vulnerability definitions ### Bleeding-edge vulnerability definitions
ZAP first creates rules in the `alpha` class. After a testing period with ZAP first creates rules in the `alpha` class. After a testing period with
...@@ -1306,7 +1318,7 @@ If a scanner profile is linked to a security policy, a user cannot delete the pr ...@@ -1306,7 +1318,7 @@ If a scanner profile is linked to a security policy, a user cannot delete the pr
page. See [Scan Execution Policies](../policies/index.md#scan-execution-policy-editor) page. See [Scan Execution Policies](../policies/index.md#scan-execution-policy-editor)
for more information. for more information.
### Auditing ## Auditing
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1.
...@@ -1318,13 +1330,6 @@ and DAST site profiles are included in the [audit log](../../../administration/a ...@@ -1318,13 +1330,6 @@ and DAST site profiles are included in the [audit log](../../../administration/a
The DAST tool outputs a report file in JSON format by default. However, this tool can also generate reports in The DAST tool outputs a report file in JSON format by default. However, this tool can also generate reports in
Markdown, HTML, and XML. For more information, see the [schema for DAST reports](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dast-report-format.json). Markdown, HTML, and XML. For more information, see the [schema for DAST reports](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dast-report-format.json).
### List of URLs scanned
When DAST completes scanning, the merge request page states the number of URLs scanned.
Click **View details** to view the web console output which includes the list of scanned URLs.
![DAST Widget](img/dast_urls_scanned_v12_10.png)
### JSON ### JSON
WARNING: WARNING:
......
...@@ -51,6 +51,10 @@ class Dast::ProfileSchedule < ApplicationRecord ...@@ -51,6 +51,10 @@ class Dast::ProfileSchedule < ApplicationRecord
self.class.active_for_project(project_id) self.class.active_for_project(project_id)
end end
def owner_valid?
Ability.allowed?(owner, :create_on_demand_dast_scan, project)
end
private private
def deactivate! def deactivate!
......
...@@ -52,7 +52,9 @@ module AppSec ...@@ -52,7 +52,9 @@ module AppSec
def update_or_create_schedule! def update_or_create_schedule!
if schedule if schedule
schedule.update!(schedule_input_params) attributes = schedule_input_params
attributes = attributes.merge(user_id: current_user.id) unless schedule.owner_valid?
schedule.update!(attributes)
else else
::Dast::ProfileSchedule.new( ::Dast::ProfileSchedule.new(
dast_profile: dast_profile, dast_profile: dast_profile,
......
...@@ -35,7 +35,7 @@ module Security ...@@ -35,7 +35,7 @@ module Security
security_policy_target_project_id: project.id, security_policy_target_project_id: project.id,
name: "#{project.name} - Security policy project", name: "#{project.name} - Security policy project",
description: "This project is automatically generated to manage security policies for the project.", description: "This project is automatically generated to manage security policies for the project.",
namespace_id: project.namespace.id, namespace_id: project.namespace_id,
initialize_with_readme: true, initialize_with_readme: true,
container_registry_enabled: false, container_registry_enabled: false,
packages_enabled: false, packages_enabled: false,
......
...@@ -9,6 +9,7 @@ RSpec.describe AppSec::Dast::Profiles::UpdateService do ...@@ -9,6 +9,7 @@ RSpec.describe AppSec::Dast::Profiles::UpdateService do
let_it_be(:dast_site_profile) { create(:dast_site_profile, project: project) } let_it_be(:dast_site_profile) { create(:dast_site_profile, project: project) }
let_it_be(:dast_scanner_profile) { create(:dast_scanner_profile, project: project) } let_it_be(:dast_scanner_profile) { create(:dast_scanner_profile, project: project) }
let_it_be(:plan_limits) { create(:plan_limits, :default_plan) } let_it_be(:plan_limits) { create(:plan_limits, :default_plan) }
let_it_be(:scheduler_owner) { create(:user, name: 'Scheduler Owner') }
let(:default_params) do let(:default_params) do
{ {
...@@ -59,7 +60,7 @@ RSpec.describe AppSec::Dast::Profiles::UpdateService do ...@@ -59,7 +60,7 @@ RSpec.describe AppSec::Dast::Profiles::UpdateService do
context 'when the user can run a DAST scan' do context 'when the user can run a DAST scan' do
before do before do
project.add_developer(user) project.add_users([user, scheduler_owner], :developer)
end end
it 'communicates success' do it 'communicates success' do
...@@ -127,24 +128,69 @@ RSpec.describe AppSec::Dast::Profiles::UpdateService do ...@@ -127,24 +128,69 @@ RSpec.describe AppSec::Dast::Profiles::UpdateService do
end end
context 'when associated schedule is present' do context 'when associated schedule is present' do
before do let_it_be_with_reload(:dast_profile_schedule) { create(:dast_profile_schedule, project: project, dast_profile: dast_profile, owner: scheduler_owner) }
create(:dast_profile_schedule, dast_profile: dast_profile)
end
it 'updates the dast profile schedule' do it 'updates the dast profile schedule' do
updated_schedule = subject.payload[:dast_profile_schedule].reload subject
aggregate_failures do aggregate_failures do
expect(updated_schedule.active).to eq(params[:dast_profile_schedule][:active]) expect(dast_profile_schedule.active).to eq(params[:dast_profile_schedule][:active])
expect(updated_schedule.starts_at.to_i).to eq(params[:dast_profile_schedule][:starts_at].to_i) expect(dast_profile_schedule.starts_at.to_i).to eq(params[:dast_profile_schedule][:starts_at].to_i)
expect(updated_schedule.timezone).to eq(params[:dast_profile_schedule][:timezone]) expect(dast_profile_schedule.timezone).to eq(params[:dast_profile_schedule][:timezone])
expect(updated_schedule.cadence).to eq(params[:dast_profile_schedule][:cadence].stringify_keys) expect(dast_profile_schedule.cadence).to eq(params[:dast_profile_schedule][:cadence].stringify_keys)
end end
end end
it 'creates the audit event' do it 'creates the audit event' do
expect { subject }.to change { AuditEvent.where(target_id: dast_profile.dast_profile_schedule.id).count } expect { subject }.to change { AuditEvent.where(target_id: dast_profile.dast_profile_schedule.id).count }
end end
context 'when the owner is valid' do
it 'does not updates the schedule owner' do
subject
expect(dast_profile_schedule.user_id).to eq(scheduler_owner.id)
end
end
context 'when the owner was deleted' do
before do
scheduler_owner.destroy!
subject.payload[:dast_profile_schedule].reload
end
it 'updates the schedule owner' do
subject
expect(dast_profile_schedule.user_id).to eq(user.id)
end
end
context 'when the owner permission was downgraded' do
before do
project.add_guest(scheduler_owner)
end
it 'updates the schedule owner' do
subject
expect(dast_profile_schedule.user_id).to eq(user.id)
end
end
context 'when the owner was removed from the project' do
before do
stub_feature_flags(member_destroy_async_auth_refresh: false)
project.team.truncate
project.add_developer(user)
end
it 'updates the schedule owner' do
subject
expect(dast_profile_schedule.user_id).to eq(user.id)
end
end
end end
end end
......
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
grouped_items = issuables.group_by do |issuable| grouped_items = issuables.group_by do |issuable|
if issuable.project.id == project.id if issuable.project.id == project.id
:project_ref :project_ref
elsif issuable.project.namespace.id == project.namespace.id elsif issuable.project.namespace_id == project.namespace_id
:namespace_ref :namespace_ref
else else
:full_ref :full_ref
......
...@@ -6,6 +6,7 @@ RSpec.describe ::Routing::PseudonymizationHelper do ...@@ -6,6 +6,7 @@ RSpec.describe ::Routing::PseudonymizationHelper do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) } let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:project) { create(:project, group: group) } let_it_be(:project) { create(:project, group: group) }
let_it_be(:subproject) { create(:project, group: subgroup) }
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
...@@ -56,16 +57,16 @@ RSpec.describe ::Routing::PseudonymizationHelper do ...@@ -56,16 +57,16 @@ RSpec.describe ::Routing::PseudonymizationHelper do
end end
context 'with controller for groups with subgroups and project' do context 'with controller for groups with subgroups and project' do
let(:masked_url) { "http://test.host/namespace:#{subgroup.id}/project:#{project.id}"} let(:masked_url) { "http://test.host/namespace:#{subgroup.id}/project:#{subproject.id}"}
before do before do
allow(helper).to receive(:group).and_return(subgroup) allow(helper).to receive(:group).and_return(subgroup)
allow(helper.project).to receive(:namespace).and_return(subgroup) allow(helper).to receive(:project).and_return(subproject)
allow(Rails.application.routes).to receive(:recognize_path).and_return({ allow(Rails.application.routes).to receive(:recognize_path).and_return({
controller: 'projects', controller: 'projects',
action: 'show', action: 'show',
namespace_id: subgroup.name, namespace_id: subgroup.name,
id: project.name id: subproject.name
}) })
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