提交 636eb695 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 6217d197
......@@ -2,6 +2,7 @@
import { mapState, mapActions } from 'vuex';
import {
GlAlert,
GlIcon,
GlDropdown,
GlDropdownItem,
GlDropdownHeader,
......@@ -21,6 +22,7 @@ const events = {
export default {
components: {
GlAlert,
GlIcon,
GlDropdown,
GlDropdownItem,
GlDropdownHeader,
......@@ -60,20 +62,31 @@ export default {
selectedDashboardText() {
return this.selectedDashboard.display_name;
},
filteredDashboards() {
return this.allDashboards.filter(({ display_name }) =>
return this.allDashboards.filter(({ display_name = '' }) =>
display_name.toLowerCase().includes(this.searchTerm.toLowerCase()),
);
},
shouldShowNoMsgContainer() {
return this.filteredDashboards.length === 0;
},
starredDashboards() {
return this.filteredDashboards.filter(({ starred }) => starred);
},
nonStarredDashboards() {
return this.filteredDashboards.filter(({ starred }) => !starred);
},
okButtonText() {
return this.loading ? s__('Metrics|Duplicating...') : s__('Metrics|Duplicate');
},
},
methods: {
...mapActions('monitoringDashboard', ['duplicateSystemDashboard']),
dashboardDisplayName(dashboard) {
return dashboard.display_name || dashboard.path || '';
},
selectDashboard(dashboard) {
this.$emit(events.selectDashboard, dashboard);
},
......@@ -127,15 +140,34 @@ export default {
v-model="searchTerm"
class="m-2"
/>
<div class="flex-fill overflow-auto">
<gl-dropdown-item
v-for="dashboard in filteredDashboards"
v-for="dashboard in starredDashboards"
:key="dashboard.path"
:active="dashboard.path === selectedDashboard.path"
active-class="is-active"
@click="selectDashboard(dashboard)"
>
<div class="d-flex">
{{ dashboardDisplayName(dashboard) }}
<gl-icon class="text-muted ml-auto" name="star" />
</div>
</gl-dropdown-item>
<gl-dropdown-divider
v-if="starredDashboards.length && nonStarredDashboards.length"
ref="starredListDivider"
/>
<gl-dropdown-item
v-for="dashboard in nonStarredDashboards"
:key="dashboard.path"
:active="dashboard.path === selectedDashboard.path"
active-class="is-active"
@click="selectDashboard(dashboard)"
>
{{ dashboard.display_name || dashboard.path }}
{{ dashboardDisplayName(dashboard) }}
</gl-dropdown-item>
</div>
......
# frozen_string_literal: true
module Metrics
class UsersStarredDashboardsFinder
def initialize(user:, project:, params: {})
@user, @project, @params = user, project, params
end
def execute
return ::Metrics::UsersStarredDashboard.none unless Ability.allowed?(user, :read_metrics_user_starred_dashboard, project)
items = starred_dashboards
items = by_project(items)
by_dashboard(items)
end
private
attr_reader :user, :project, :params
def by_project(items)
items.for_project(project)
end
def by_dashboard(items)
return items unless params[:dashboard_path]
items.merge(starred_dashboards.for_project_dashboard(project, params[:dashboard_path]))
end
def starred_dashboards
@starred_dashboards ||= user.metrics_users_starred_dashboards
end
end
end
......@@ -13,6 +13,11 @@ module Types
null: false,
description: 'Internal ID of the alert'
field :issue_iid,
GraphQL::ID_TYPE,
null: true,
description: 'Internal ID of the GitLab issue attached to the alert'
field :title,
GraphQL::STRING_TYPE,
null: true,
......
......@@ -92,6 +92,8 @@ module AlertManagement
end
end
delegate :iid, to: :issue, prefix: true, allow_nil: true
scope :for_iid, -> (iid) { where(iid: iid) }
scope :for_status, -> (status) { where(status: status) }
scope :for_fingerprint, -> (project, fingerprint) { where(project: project, fingerprint: fingerprint) }
......
......@@ -11,5 +11,8 @@ module Metrics
validates :project_id, presence: true
validates :dashboard_path, presence: true, length: { maximum: 255 }
validates :dashboard_path, uniqueness: { scope: %i[user_id project_id] }
scope :for_project, ->(project) { where(project: project) }
scope :for_project_dashboard, ->(project, path) { for_project(project).where(dashboard_path: path) }
end
end
......@@ -269,6 +269,8 @@ class ProjectPolicy < BasePolicy
enable :read_prometheus
enable :read_environment
enable :read_deployment
enable :create_metrics_user_starred_dashboard
enable :read_metrics_user_starred_dashboard
end
rule { owner | admin | guest | group_member }.prevent :request_access
......
# frozen_string_literal: true
# Create Metrics::UsersStarredDashboard entry for given user based on matched dashboard_path, project
module Metrics
module UsersStarredDashboards
class CreateService < ::BaseService
include Stepable
steps :authorize_create_action,
:parse_dashboard_path,
:create
def initialize(user, project, dashboard_path)
@user, @project, @dashboard_path = user, project, dashboard_path
end
def execute
keys = %i[status message starred_dashboard]
status, message, dashboards = execute_steps.values_at(*keys)
if status != :success
ServiceResponse.error(message: message)
else
ServiceResponse.success(payload: dashboards)
end
end
private
attr_reader :user, :project, :dashboard_path
def authorize_create_action(_options)
if Ability.allowed?(user, :create_metrics_user_starred_dashboard, project)
success(user: user, project: project)
else
error(s_('Metrics::UsersStarredDashboards|You are not authorized to add star to this dashboard'))
end
end
def parse_dashboard_path(options)
if dashboard_path_exists?
options[:dashboard_path] = dashboard_path
success(options)
else
error(s_('Metrics::UsersStarredDashboards|Dashboard with requested path can not be found'))
end
end
def create(options)
starred_dashboard = build_starred_dashboard_from(options)
if starred_dashboard.save
success(starred_dashboard: starred_dashboard)
else
error(starred_dashboard.errors.messages)
end
end
def build_starred_dashboard_from(options)
Metrics::UsersStarredDashboard.new(
user: options.fetch(:user),
project: options.fetch(:project),
dashboard_path: options.fetch(:dashboard_path)
)
end
def dashboard_path_exists?
Gitlab::Metrics::Dashboard::Finder
.find_all_paths(project)
.any? { |dashboard| dashboard[:path] == dashboard_path }
end
end
end
end
---
title: Add the global var SECURE_ANALYZERS_PREFIX
merge_request: 28617
author:
type: added
---
title: Exposes issue IID in Alert Management Alert's GraphQL endpoint
merge_request: 31313
author:
type: added
......@@ -177,6 +177,11 @@ type AlertManagementAlert {
"""
iid: ID!
"""
Internal ID of the GitLab issue attached to the alert
"""
issueIid: ID
"""
Monitoring tool the alert came from
"""
......
......@@ -504,6 +504,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "issueIid",
"description": "Internal ID of the GitLab issue attached to the alert",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "monitoringTool",
"description": "Monitoring tool the alert came from",
......
......@@ -59,6 +59,7 @@ Describes an alert from the project's Alert Management
| `eventCount` | Int | Number of events of this alert |
| `hosts` | String! => Array | List of hosts the alert came from |
| `iid` | ID! | Internal ID of the alert |
| `issueIid` | ID | Internal ID of the GitLab issue attached to the alert |
| `monitoringTool` | String | Monitoring tool the alert came from |
| `service` | String | Service the alert came from |
| `severity` | AlertManagementSeverity | Severity of the alert |
......
......@@ -169,6 +169,7 @@ using environment variables.
| Environment Variable | Description | Default |
| ------ | ------ | ------ |
| `SECURE_ANALYZERS_PREFIX` | Set the Docker registry base address from which to download the analyzer. | `"registry.gitlab.com/gitlab-org/security-products/analyzers"` |
| `KLAR_TRACE` | Set to true to enable more verbose output from klar. | `"false"` |
| `CLAIR_TRACE` | Set to true to enable more verbose output from the clair server process. | `"false"` |
| `DOCKER_USER` | Username for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_USER` |
......@@ -183,7 +184,7 @@ using environment variables.
| `CLAIR_DB_IMAGE` | The Docker image name and tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes, or to refer to a locally hosted vulnerabilities database for an on-premise offline installation. | `arminc/clair-db:latest` |
| `CLAIR_DB_IMAGE_TAG` | (**DEPRECATED - use `CLAIR_DB_IMAGE` instead**) The Docker image tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` |
| `DOCKERFILE_PATH` | The path to the `Dockerfile` to be used for generating remediations. By default, the scanner will look for a file named `Dockerfile` in the root directory of the project, so this variable should only be configured if your `Dockerfile` is in a non-standard location, such as a subdirectory. See [Solutions for vulnerabilities](#solutions-for-vulnerabilities-auto-remediation) for more details. | `Dockerfile` |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs that you want to trust. | "" |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs that you want to trust. | "" |
### Overriding the Container Scanning template
......
......@@ -438,7 +438,8 @@ don't forget to add `stage: dast` when you override the template job definition.
DAST can be [configured](#customizing-the-dast-settings) using environment variables.
| Environment variable | Required | Description |
|-----------------------------| ----------|--------------------------------------------------------------------------------|
|-----------------------------| -----------|--------------------------------------------------------------------------------|
| `SECURE_ANALYZERS_PREFIX` | no | Set the Docker registry base address from which to download the analyzer. |
| `DAST_WEBSITE` | no| The URL of the website to scan. `DAST_API_SPECIFICATION` must be specified if this is omitted. |
| `DAST_API_SPECIFICATION` | no | The API specification to import. `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_AUTH_URL` | no | The authentication URL of the website to scan. Not supported for API scans. |
......@@ -563,6 +564,8 @@ dast:
The DAST job should now use local copies of the DAST analyzers to scan your code and generate
security reports without requiring internet access.
Alternatively, you can use the variable `SECURE_ANALYZERS_PREFIX` to override the base registry address of the `dast` image.
## Reports
The DAST job can emit various reports.
......
......@@ -43,7 +43,7 @@ include:
template: Dependency-Scanning.gitlab-ci.yml
variables:
DS_ANALYZER_IMAGE_PREFIX: my-docker-registry/gl-images
SECURE_ANALYZERS_PREFIX: my-docker-registry/gl-images
```
This configuration requires that your custom registry provides images for all
......
......@@ -140,7 +140,8 @@ The following variables allow configuration of global dependency scanning settin
| Environment variable | Description |
| --------------------------------------- |------------ |
| `DS_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `DS_ANALYZER_IMAGE_PREFIX` | **DEPRECATED:** Use `SECURE_ANALYZERS_PREFIX` instead. |
| `DS_DEFAULT_ANALYZERS` | Override the names of the official default images. Read more about [customizing analyzers](analyzers.md). |
| `DS_DISABLE_DIND` | Disable Docker-in-Docker and run analyzers [individually](#disabling-docker-in-docker-for-dependency-scanning).|
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs to trust. |
......@@ -168,7 +169,7 @@ The following variables are used for configuring specific analyzers (used for a
| `GEMNASIUM_DB_LOCAL_PATH` | `gemnasium` | `/gemnasium-db` | Path to local Gemnasium database. |
| `GEMNASIUM_DB_REMOTE_URL` | `gemnasium` | `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git` | Repository URL for fetching the Gemnasium database. |
| `GEMNASIUM_DB_REF_NAME` | `gemnasium` | `master` | Branch name for remote repository database. `GEMNASIUM_DB_REMOTE_URL` is required. |
| `DS_REMEDIATE` | `gemnasium` | `"true"` | Enable automatic remediation of vulnerable dependencies. |
| `DS_REMEDIATE` | `gemnasium` | `"true"` | Enable automatic remediation of vulnerable dependencies. |
| `PIP_INDEX_URL` | `gemnasium-python` | `https://pypi.org/simple` | Base URL of Python Package Index. |
| `PIP_EXTRA_INDEX_URL` | `gemnasium-python` | | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma-separated. |
| `PIP_REQUIREMENTS_FILE` | `gemnasium-python` | | Pip requirements file to be scanned. |
......@@ -176,9 +177,9 @@ The following variables are used for configuring specific analyzers (used for a
| `DS_PIP_DEPENDENCY_PATH` | `gemnasium-python` | | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12412) in GitLab 12.2) |
| `DS_PYTHON_VERSION` | `retire.js` | | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12296) in GitLab 12.1)|
| `MAVEN_CLI_OPTS` | `gemnasium-maven` | `"-DskipTests --batch-mode"` | List of command line arguments that will be passed to `maven` by the analyzer. See an example for [using private repositories](../index.md#using-private-maven-repos). |
| `GRADLE_CLI_OPTS` | `gemnasium-maven` | | List of command line arguments that will be passed to `gradle` by the analyzer. |
| `SBT_CLI_OPTS` | `gemnasium-maven` | | List of command-line arguments that the analyzer will pass to `sbt`. |
| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `"false"` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running Dependency Scanning in an offline, air-gapped environment.|
| `GRADLE_CLI_OPTS` | `gemnasium-maven` | | List of command line arguments that will be passed to `gradle` by the analyzer. |
| `SBT_CLI_OPTS` | `gemnasium-maven` | | List of command-line arguments that the analyzer will pass to `sbt`. |
| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `"false"` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running Dependency Scanning in an offline, air-gapped environment.|
| `BUNDLER_AUDIT_ADVISORY_DB_URL` | `bundler-audit` | `https://github.com/rubysec/ruby-advisory-db` | URL of the advisory database used by bundler-audit. |
| `BUNDLER_AUDIT_ADVISORY_DB_REF_NAME` | `bundler-audit` | `master` | Git ref for the advisory database specified by `BUNDLER_AUDIT_ADVISORY_DB_URL`. |
| `RETIREJS_JS_ADVISORY_DB` | `retire.js` | `https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository.json` | Path or URL to `retire.js` JS vulnerability data file. Note that if the URL hosting the data file uses a custom SSL certificate, for example in an offline installation, you can pass the certificate in the `ADDITIONAL_CA_CERT_BUNDLE` environment variable. |
......
......@@ -44,6 +44,12 @@ To add Container Scanning, follow the steps listed in the [Container Scanning do
To further configure any of the other scanners, refer to each scanner's documentation.
### Override the default registry base address
By default, GitLab security scanners use `registry.gitlab.com/gitlab-org/security-products/analyzers` as the
base address for Docker images. You can override this globally by setting the variable
`SECURE_ANALYZERS_PREFIX` to another location. Note that this affects all scanners at once.
## Security scanning tools
GitLab uses the following tools to scan and report known vulnerabilities found in your project.
......
......@@ -52,7 +52,7 @@ include:
- template: SAST.gitlab-ci.yml
variables:
SAST_ANALYZER_IMAGE_PREFIX: my-docker-registry/gl-images
SECURE_ANALYZERS_PREFIX: my-docker-registry/gl-images
```
This configuration requires that your custom registry provides images for all
......
......@@ -293,8 +293,9 @@ The following are Docker image-related variables.
| Environment variable | Description |
|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `SAST_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `SAST_ANALYZER_IMAGE_TAG` | **DEPRECATED:** Override the Docker tag of the default images. Read more about [customizing analyzers](analyzers.md). |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `SAST_ANALYZER_IMAGE_PREFIX` | **DEPRECATED**: Use `SECURE_ANALYZERS_PREFIX` instead. |
| `SAST_ANALYZER_IMAGE_TAG` | **DEPRECATED:** Override the Docker tag of the default images. Read more about [customizing analyzers](analyzers.md). |
| `SAST_DEFAULT_ANALYZERS` | Override the names of default images. Read more about [customizing analyzers](analyzers.md). |
| `SAST_DISABLE_DIND` | Disable Docker in Docker and run analyzers [individually](#disabling-docker-in-docker-for-sast). |
......@@ -575,7 +576,7 @@ include:
- template: SAST.gitlab-ci.yml
variables:
SAST_ANALYZER_IMAGE_PREFIX: "localhost:5000/analyzers"
SECURE_ANALYZERS_PREFIX: "localhost:5000/analyzers"
SAST_DISABLE_DIND: "true"
```
......
......@@ -133,16 +133,17 @@ The License Compliance settings can be changed through [environment variables](#
License Compliance can be configured using environment variables.
| Environment variable | Required | Description |
|-----------------------|----------|-------------|
| `ADDITIONAL_CA_CERT_BUNDLE` | no | Bundle of trusted CA certificates (currently supported in Python projects). |
| `GRADLE_CLI_OPTS` | no | Additional arguments for the gradle executable. If not supplied, defaults to `--exclude-task=test`. |
| `LICENSE_FINDER_CLI_OPTS` | no | Additional arguments for the `license_finder` executable. For example, if your project has both Golang and Ruby code stored in different directories and you want to only scan the Ruby code, you can update your `.gitlab-ci-yml` template to specify which project directories to scan, like `LICENSE_FINDER_CLI_OPTS: '--debug --aggregate-paths=. ruby'`. |
| `LM_JAVA_VERSION` | no | Version of Java. If set to `11`, Maven and Gradle use Java 11 instead of Java 8. |
| `LM_PYTHON_VERSION` | no | Version of Python. If set to `3`, dependencies are installed using Python 3 instead of Python 2.7. |
| `MAVEN_CLI_OPTS` | no | Additional arguments for the mvn executable. If not supplied, defaults to `-DskipTests`. |
| `PIP_INDEX_URL` | no | Base URL of Python Package Index (default: `https://pypi.org/simple/`). |
| `SETUP_CMD` | no | Custom setup for the dependency installation (experimental). |
| Environment variable | Required | Description |
|-----------------------------|----------|-------------|
| `SECURE_ANALYZERS_PREFIX` | no | Set the Docker registry base address to download the analyzer from. |
| `ADDITIONAL_CA_CERT_BUNDLE` | no | Bundle of trusted CA certificates (currently supported in Pip, Pipenv, Maven, Gradle, and NPM projects). |
| `GRADLE_CLI_OPTS` | no | Additional arguments for the gradle executable. If not supplied, defaults to `--exclude-task=test`. |
| `LICENSE_FINDER_CLI_OPTS` | no | Additional arguments for the `license_finder` executable. For example, if your project has both Golang and Ruby code stored in different directories and you want to only scan the Ruby code, you can update your `.gitlab-ci-yml` template to specify which project directories to scan, like `LICENSE_FINDER_CLI_OPTS: '--debug --aggregate-paths=. ruby'`. |
| `LM_JAVA_VERSION` | no | Version of Java. If set to `11`, Maven and Gradle use Java 11 instead of Java 8. |
| `LM_PYTHON_VERSION` | no | Version of Python. If set to `3`, dependencies are installed using Python 3 instead of Python 2.7. |
| `MAVEN_CLI_OPTS` | no | Additional arguments for the mvn executable. If not supplied, defaults to `-DskipTests`. |
| `PIP_INDEX_URL` | no | Base URL of Python Package Index (default: `https://pypi.org/simple/`). |
| `SETUP_CMD` | no | Custom setup for the dependency installation (experimental). |
### Installing custom dependencies
......@@ -294,6 +295,37 @@ If you have a private Python repository you can use the `PIP_INDEX_URL` [environ
to specify its location. It's also possible to provide a custom `pip.conf` for
[additional configuration](#custom-root-certificates-for-python).
### Configuring NPM projects
You can configure NPM projects by using an [`.npmrc`](https://docs.npmjs.com/configuring-npm/npmrc.html)
file.
#### Using private NPM registries
If you have a private NPM registry you can use the
[`registry`](https://docs.npmjs.com/using-npm/config#registry)
setting to specify its location.
For example:
```text
registry = https://npm.example.com
```
#### Custom root certificates for NPM
You can supply a custom root certificate to complete TLS verification by using the
`ADDITIONAL_CA_CERT_BUNDLE` [environment variable](#available-variables).
To disable TLS verification you can provide the [`strict-ssl`](https://docs.npmjs.com/using-npm/config#strict-ssl)
setting.
For example:
```text
strict-ssl = false
```
### Migration from `license_management` to `license_scanning`
In GitLab 12.8 a new name for `license_management` job was introduced. This change was made to improve clarity around the purpose of the scan, which is to scan and collect the types of licenses present in a projects dependencies.
......@@ -386,8 +418,8 @@ license_scanning:
The License Compliance job should now use local copies of the License Compliance analyzers to scan
your code and generate security reports, without requiring internet access.
Additional configuration may be needed for connecting to [private Maven repositories](#using-private-maven-repos)
and [private Python repositories](#using-private-python-repos).
Additional configuration may be needed for connecting to [private Maven repositories](#using-private-maven-repos),
[private NPM registries](#using-private-npm-registries), and [private Python repositories](#using-private-python-repos).
Exact name matches are required for [project policies](#project-policies-for-license-compliance)
when running in an offline environment ([see related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/212388)).
......
......@@ -36,6 +36,24 @@ Using the GitLab project Kubernetes integration, you can:
- View [Logs](#logs).
- Run serverless workloads on [Kubernetes with Knative](serverless/index.md).
### Supported cluster versions
GitLab is committed to support at least two production-ready Kubernetes minor versions at any given time. We regularly review the versions we support, and provide a four-month deprecation period before we remove support of a specific version. The range of supported versions is based on the evaluation of:
- Our own needs.
- The versions supported by major managed Kubernetes providers.
- The versions [supported by the Kubernetes community](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions).
Currently, GitLab supports the following Kubernetes versions:
- 1.15
- 1.14
- 1.13 (deprecated, support ends on November 22, 2020)
- 1.12 (deprecated, support ends on September 22, 2020)
NOTE: **Note:**
Some GitLab features may support versions outside the range provided here.
### Deploy Boards **(PREMIUM)**
GitLab's Deploy Boards offer a consolidated view of the current health and
......
......@@ -197,6 +197,23 @@ There are 2 methods to specify a variable in a query or dashboard:
1. Variables can be specified using the [Liquid template format](https://shopify.dev/docs/liquid/reference/basics), for example `{{ci_environment_slug}}` ([added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20793) in GitLab 12.6).
1. You can also enclose it in quotation marks with curly braces with a leading percent, for example `"%{ci_environment_slug}"`. This method is deprecated though and support will be [removed in the next major release](https://gitlab.com/gitlab-org/gitlab/issues/37990).
#### Query Variables from URL
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214500) in GitLab 13.0.
GitLab supports setting custom variables through URL parameters. Surround the variable
name with double curly braces (`{{example}}`) to interpolate the variable in a query:
```plaintext
avg(sum(container_memory_usage_bytes{container_name!="{{pod}}"}) by (job)) without (job) /1024/1024/1024'
```
The URL for this query would be:
```plaintext
http://gitlab.com/<user>/<project>/-/environments/<environment_id>/metrics?dashboard=.gitlab%2Fdashboards%2Fcustom.yml&pod=POD
```
#### Editing additional metrics from the dashboard
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/208976) in GitLab 12.9.
......
# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/container_scanning/
variables:
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
CS_MAJOR_VERSION: 2
container_scanning:
stage: test
image: registry.gitlab.com/gitlab-org/security-products/analyzers/klar:$CS_MAJOR_VERSION
image: $SECURE_ANALYZERS_PREFIX/klar:$CS_MAJOR_VERSION
variables:
# By default, use the latest clair vulnerabilities database, however, allow it to be overridden here with a specific image
# to enable container scanning to run offline, or to provide a consistent list of vulnerabilities for integration testing purposes
CLAIR_DB_IMAGE_TAG: "latest"
CLAIR_DB_IMAGE: "arminc/clair-db:$CLAIR_DB_IMAGE_TAG"
CLAIR_DB_IMAGE: "$SECURE_ANALYZERS_PREFIX/clair-vulnerabilities-db:$CLAIR_DB_IMAGE_TAG"
# Override the GIT_STRATEGY variable in your `.gitlab-ci.yml` file and set it to `fetch` if you want to provide a `clair-whitelist.yml`
# file. See https://docs.gitlab.com/ee/user/application_security/container_scanning/index.html#overriding-the-container-scanning-template
# for details
......
......@@ -12,11 +12,14 @@ stages:
variables:
DAST_VERSION: 1
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
dast:
stage: dast
image:
name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION"
name: "$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION"
variables:
GIT_STRATEGY: none
allow_failure: true
......
......@@ -5,8 +5,13 @@
# How to set: https://docs.gitlab.com/ee/ci/yaml/#variables
variables:
SECURITY_SCANNER_IMAGE_PREFIX: "registry.gitlab.com/gitlab-org/security-products"
DS_ANALYZER_IMAGE_PREFIX: "$SECURITY_SCANNER_IMAGE_PREFIX/analyzers"
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
# Deprecated, use SECURE_ANALYZERS_PREFIX instead
DS_ANALYZER_IMAGE_PREFIX: "$SECURE_ANALYZERS_PREFIX"
DS_DEFAULT_ANALYZERS: "bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python"
DS_MAJOR_VERSION: 2
DS_DISABLE_DIND: "false"
......@@ -67,7 +72,7 @@ dependency_scanning:
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
"$SECURITY_SCANNER_IMAGE_PREFIX/dependency-scanning:$DS_MAJOR_VERSION" /code
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$DS_MAJOR_VERSION" /code
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json
......
......@@ -5,13 +5,17 @@
# How to set: https://docs.gitlab.com/ee/ci/yaml/#variables
variables:
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
LICENSE_MANAGEMENT_SETUP_CMD: '' # If needed, specify a command to setup your environment with a custom package manager.
LICENSE_MANAGEMENT_VERSION: 3
license_scanning:
stage: test
image:
name: "registry.gitlab.com/gitlab-org/security-products/license-management:$LICENSE_MANAGEMENT_VERSION"
name: "$SECURE_ANALYZERS_PREFIX/license-finder:$LICENSE_MANAGEMENT_VERSION"
entrypoint: [""]
variables:
LM_REPORT_FILE: gl-license-scanning-report.json
......
......@@ -5,7 +5,13 @@
# How to set: https://docs.gitlab.com/ee/ci/yaml/#variables
variables:
SAST_ANALYZER_IMAGE_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
# Deprecated, use SECURE_ANALYZERS_PREFIX instead
SAST_ANALYZER_IMAGE_PREFIX: "$SECURE_ANALYZERS_PREFIX"
SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex, kubesec"
SAST_ANALYZER_IMAGE_TAG: 2
SAST_DISABLE_DIND: "false"
......
......@@ -16,7 +16,7 @@ variables:
bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex, kubesec,
bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python,
klar, clair-vulnerabilities-db,
license-management,
license-finder,
dast
SECURE_BINARIES_DOWNLOAD_IMAGES: "true"
......@@ -39,7 +39,7 @@ variables:
script:
- docker info
- env
- if [ -z "$SECURE_BINARIES_IMAGE" ]; then export SECURE_BINARIES_IMAGE=${SECURE_BINARIES_IMAGE:-"registry.gitlab.com/gitlab-org/security-products/${CI_JOB_NAME}:${SECURE_BINARIES_ANALYZER_VERSION}"}; fi
- if [ -z "$SECURE_BINARIES_IMAGE" ]; then export SECURE_BINARIES_IMAGE=${SECURE_BINARIES_IMAGE:-"registry.gitlab.com/gitlab-org/security-products/analyzers/${CI_JOB_NAME}:${SECURE_BINARIES_ANALYZER_VERSION}"}; fi
- docker pull ${SECURE_BINARIES_IMAGE}
- mkdir -p output/$(dirname ${CI_JOB_NAME})
- |
......@@ -62,98 +62,98 @@ variables:
# SAST jobs
#
analyzers/bandit:
bandit:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bbandit\b/
analyzers/brakeman:
brakeman:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bbrakeman\b/
analyzers/gosec:
gosec:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bgosec\b/
analyzers/spotbugs:
spotbugs:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bspotbugs\b/
analyzers/flawfinder:
flawfinder:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bflawfinder\b/
analyzers/phpcs-security-audit:
phpcs-security-audit:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bphpcs-security-audit\b/
analyzers/security-code-scan:
security-code-scan:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bsecurity-code-scan\b/
analyzers/nodejs-scan:
nodejs-scan:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bnodejs-scan\b/
analyzers/eslint:
eslint:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\beslint\b/
analyzers/tslint:
tslint:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\btslint\b/
analyzers/secrets:
secrets:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bsecrets\b/
analyzers/sobelow:
sobelow:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bsobelow\b/
analyzers/pmd-apex:
pmd-apex:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bsecrets\b/
analyzers/kubesec:
kubesec:
extends: .download_images
only:
variables:
......@@ -163,14 +163,14 @@ analyzers/kubesec:
# Container Scanning jobs
#
analyzers/klar:
klar:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bklar\b/
analyzers/clair-vulnerabilities-db:
clair-vulnerabilities-db:
extends: .download_images
only:
variables:
......@@ -184,35 +184,35 @@ analyzers/clair-vulnerabilities-db:
# Dependency Scanning jobs
#
analyzers/bundler-audit:
bundler-audit:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bbundler-audit\b/
analyzers/retire.js:
retire.js:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bretire\.js\b/
analyzers/gemnasium:
gemnasium:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bgemnasium\b/
analyzers/gemnasium-maven:
gemnasium-maven:
extends: .download_images
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bgemnasium-maven\b/
analyzers/gemnasium-python:
gemnasium-python:
extends: .download_images
only:
variables:
......@@ -223,14 +223,14 @@ analyzers/gemnasium-python:
# License Scanning
#
license-management:
license-finder:
extends: .download_images
variables:
SECURE_BINARIES_ANALYZER_VERSION: "3"
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\blicense-management\b/
$SECURE_BINARIES_ANALYZERS =~ /\blicense-finder\b/
#
# DAST
......@@ -238,9 +238,9 @@ license-management:
dast:
extends: .download_images
variables:
SECURE_BINARIES_ANALYZER_VERSION: "1"
only:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bdast\b/
variables:
SECURE_BINARIES_ANALYZER_VERSION: 1
......@@ -4,7 +4,7 @@ module Gitlab
module UsageDataCounters
class WebIdeCounter
extend RedisCounter
KNOWN_EVENTS = %i[commits views merge_requests previews].freeze
KNOWN_EVENTS = %i[commits views merge_requests previews terminals].freeze
PREFIX = 'web_ide'
class << self
......@@ -20,6 +20,10 @@ module Gitlab
increment(redis_key('views'))
end
def increment_terminals_count
increment(redis_key('terminals'))
end
def increment_previews_count
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
......
......@@ -13259,6 +13259,12 @@ msgstr ""
msgid "Metrics::Dashboard::Annotation|You are not authorized to delete this annotation"
msgstr ""
msgid "Metrics::UsersStarredDashboards|Dashboard with requested path can not be found"
msgstr ""
msgid "Metrics::UsersStarredDashboards|You are not authorized to add star to this dashboard"
msgstr ""
msgid "Metrics|Add metric"
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Metrics::UsersStarredDashboardsFinder do
describe '#execute' do
subject(:starred_dashboards) { described_class.new(user: user, project: project, params: params).execute }
let_it_be(:user) { create(:user) }
let(:project) { create(:project) }
let(:dashboard_path) { 'config/prometheus/common_metrics.yml' }
let(:params) { {} }
context 'there are no starred dashboard records' do
it 'returns empty array' do
expect(starred_dashboards).to be_empty
end
end
context 'with annotation records' do
let!(:starred_dashboard_1) { create(:metrics_users_starred_dashboard, user: user, project: project) }
let!(:starred_dashboard_2) { create(:metrics_users_starred_dashboard, user: user, project: project, dashboard_path: dashboard_path) }
let!(:other_project_dashboard) { create(:metrics_users_starred_dashboard, user: user, dashboard_path: dashboard_path) }
let!(:other_user_dashboard) { create(:metrics_users_starred_dashboard, project: project, dashboard_path: dashboard_path) }
context 'user without read access to project' do
it 'returns empty relation' do
expect(starred_dashboards).to be_empty
end
end
context 'user with read access to project' do
before do
project.add_reporter(user)
end
it 'loads starred dashboards' do
expect(starred_dashboards).to contain_exactly starred_dashboard_1, starred_dashboard_2
end
context 'when the dashboard_path filter is present' do
let(:params) do
{
dashboard_path: dashboard_path
}
end
it 'loads filtered starred dashboards' do
expect(starred_dashboards).to contain_exactly starred_dashboard_2
end
end
end
end
end
end
import { shallowMount } from '@vue/test-utils';
import { GlDropdownItem, GlModal, GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { GlDropdownItem, GlModal, GlLoadingIcon, GlAlert, GlIcon } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue';
......@@ -9,36 +9,45 @@ import { dashboardGitResponse } from '../mock_data';
const defaultBranch = 'master';
function createComponent(props, opts = {}) {
const storeOpts = {
methods: {
duplicateSystemDashboard: jest.fn(),
},
computed: {
allDashboards: () => dashboardGitResponse,
},
};
return shallowMount(DashboardsDropdown, {
propsData: {
...props,
defaultBranch,
},
sync: false,
...storeOpts,
...opts,
});
}
const starredDashboards = dashboardGitResponse.filter(({ starred }) => starred);
const notStarredDashboards = dashboardGitResponse.filter(({ starred }) => !starred);
describe('DashboardsDropdown', () => {
let wrapper;
let mockDashboards;
function createComponent(props, opts = {}) {
const storeOpts = {
methods: {
duplicateSystemDashboard: jest.fn(),
},
computed: {
allDashboards: () => mockDashboards,
},
};
return shallowMount(DashboardsDropdown, {
propsData: {
...props,
defaultBranch,
},
sync: false,
...storeOpts,
...opts,
});
}
const findItems = () => wrapper.findAll(GlDropdownItem);
const findItemAt = i => wrapper.findAll(GlDropdownItem).at(i);
const findSearchInput = () => wrapper.find({ ref: 'monitorDashboardsDropdownSearch' });
const findNoItemsMsg = () => wrapper.find({ ref: 'monitorDashboardsDropdownMsg' });
const findStarredListDivider = () => wrapper.find({ ref: 'starredListDivider' });
const setSearchTerm = searchTerm => wrapper.setData({ searchTerm });
beforeEach(() => {
mockDashboards = dashboardGitResponse;
});
describe('when it receives dashboards data', () => {
beforeEach(() => {
wrapper = createComponent();
......@@ -48,10 +57,14 @@ describe('DashboardsDropdown', () => {
expect(findItems().length).toEqual(dashboardGitResponse.length);
});
it('displays items with the dashboard display name', () => {
expect(findItemAt(0).text()).toBe(dashboardGitResponse[0].display_name);
expect(findItemAt(1).text()).toBe(dashboardGitResponse[1].display_name);
expect(findItemAt(2).text()).toBe(dashboardGitResponse[2].display_name);
it('displays items with the dashboard display name, with starred dashboards first', () => {
expect(findItemAt(0).text()).toBe(starredDashboards[0].display_name);
expect(findItemAt(1).text()).toBe(notStarredDashboards[0].display_name);
expect(findItemAt(2).text()).toBe(notStarredDashboards[1].display_name);
});
it('displays separator between starred and not starred dashboards', () => {
expect(findStarredListDivider().exists()).toBe(true);
});
it('displays a search input', () => {
......@@ -81,6 +94,60 @@ describe('DashboardsDropdown', () => {
});
});
describe('when the dashboard is missing a display name', () => {
beforeEach(() => {
mockDashboards = dashboardGitResponse.map(d => ({ ...d, display_name: undefined }));
wrapper = createComponent();
});
it('displays items with the dashboard path, with starred dashboards first', () => {
expect(findItemAt(0).text()).toBe(starredDashboards[0].path);
expect(findItemAt(1).text()).toBe(notStarredDashboards[0].path);
expect(findItemAt(2).text()).toBe(notStarredDashboards[1].path);
});
});
describe('when it receives starred dashboards', () => {
beforeEach(() => {
mockDashboards = starredDashboards;
wrapper = createComponent();
});
it('displays an item for each dashboard', () => {
expect(findItems().length).toEqual(starredDashboards.length);
});
it('displays a star icon', () => {
const star = findItemAt(0).find(GlIcon);
expect(star.exists()).toBe(true);
expect(star.attributes('name')).toBe('star');
});
it('displays no separator between starred and not starred dashboards', () => {
expect(findStarredListDivider().exists()).toBe(false);
});
});
describe('when it receives only not-starred dashboards', () => {
beforeEach(() => {
mockDashboards = notStarredDashboards;
wrapper = createComponent();
});
it('displays an item for each dashboard', () => {
expect(findItems().length).toEqual(notStarredDashboards.length);
});
it('displays no star icon', () => {
const star = findItemAt(0).find(GlIcon);
expect(star.exists()).toBe(false);
});
it('displays no separator between starred and not starred dashboards', () => {
expect(findStarredListDivider().exists()).toBe(false);
});
});
describe('when a system dashboard is selected', () => {
let duplicateDashboardAction;
let modalDirective;
......@@ -260,7 +327,7 @@ describe('DashboardsDropdown', () => {
expect(wrapper.emitted().selectDashboard).toBeTruthy();
});
it('emits a "selectDashboard" event with dashboard information', () => {
expect(wrapper.emitted().selectDashboard[0]).toEqual([dashboardGitResponse[1]]);
expect(wrapper.emitted().selectDashboard[0]).toEqual([dashboardGitResponse[0]]);
});
});
});
......@@ -34,6 +34,7 @@ const customDashboardsData = new Array(30).fill(null).map((_, idx) => ({
system_dashboard: false,
project_blob_path: `${mockProjectDir}/blob/master/dashboards/.gitlab/dashboards/dashboard_${idx}.yml`,
path: `.gitlab/dashboards/dashboard_${idx}.yml`,
starred: false,
}));
export const mockDashboardsErrorResponse = {
......@@ -323,6 +324,16 @@ export const dashboardGitResponse = [
system_dashboard: true,
project_blob_path: null,
path: 'config/prometheus/common_metrics.yml',
starred: false,
},
{
default: false,
display_name: 'dashboard.yml',
can_edit: true,
system_dashboard: false,
project_blob_path: `${mockProjectDir}/-/blob/master/.gitlab/dashboards/dashboard.yml`,
path: '.gitlab/dashboards/dashboard.yml',
starred: true,
},
...customDashboardsData,
];
......
......@@ -10,6 +10,7 @@ describe GitlabSchema.types['AlertManagementAlert'] do
it 'exposes the expected fields' do
expected_fields = %i[
iid
issue_iid
title
description
severity
......
......@@ -26,6 +26,10 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st
it_behaves_like 'counter examples', 'views'
end
describe 'terminals counter' do
it_behaves_like 'counter examples', 'terminals'
end
describe 'previews counter' do
let(:setting_enabled) { true }
......@@ -56,6 +60,7 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st
merge_requests = 3
views = 2
previews = 4
terminals = 1
before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
......@@ -64,6 +69,7 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st
merge_requests.times { described_class.increment_merge_requests_count }
views.times { described_class.increment_views_count }
previews.times { described_class.increment_previews_count }
terminals.times { described_class.increment_terminals_count }
end
it 'can report all totals' do
......@@ -71,7 +77,8 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st
web_ide_commits: commits,
web_ide_views: views,
web_ide_merge_requests: merge_requests,
web_ide_previews: previews
web_ide_previews: previews,
web_ide_terminals: terminals
)
end
end
......
......@@ -17,4 +17,23 @@ describe Metrics::UsersStarredDashboard do
it { is_expected.to validate_length_of(:dashboard_path).is_at_most(255) }
it { is_expected.to validate_uniqueness_of(:dashboard_path).scoped_to(%i[user_id project_id]) }
end
context 'scopes' do
let_it_be(:project) { create(:project) }
let_it_be(:starred_dashboard_a) { create(:metrics_users_starred_dashboard, project: project, dashboard_path: 'path_a') }
let_it_be(:starred_dashboard_b) { create(:metrics_users_starred_dashboard, project: project, dashboard_path: 'path_b') }
let_it_be(:starred_dashboard_c) { create(:metrics_users_starred_dashboard, dashboard_path: 'path_b') }
describe '#for_project' do
it 'selects only starred dashboards belonging to project' do
expect(described_class.for_project(project)).to contain_exactly starred_dashboard_a, starred_dashboard_b
end
end
describe '#for_project_dashboard' do
it 'selects only starred dashboards belonging to project with given dashboard path' do
expect(described_class.for_project_dashboard(project, 'path_b')).to contain_exactly starred_dashboard_b
end
end
end
end
......@@ -501,6 +501,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with guest' do
......@@ -527,6 +529,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with guest' do
......@@ -535,6 +539,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with anonymous' do
......@@ -543,6 +549,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
end
end
......@@ -557,6 +565,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with guest' do
......@@ -583,6 +593,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with guest' do
......@@ -591,6 +603,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with anonymous' do
......@@ -611,6 +625,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with guest' do
......@@ -633,6 +649,8 @@ describe ProjectPolicy do
it { is_expected.to be_allowed(:metrics_dashboard) }
it { is_expected.to be_allowed(:read_prometheus) }
it { is_expected.to be_allowed(:read_deployment) }
it { is_expected.to be_allowed(:read_metrics_user_starred_dashboard) }
it { is_expected.to be_allowed(:create_metrics_user_starred_dashboard) }
end
context 'with guest' do
......
......@@ -7,7 +7,7 @@ describe 'getting Alert Management Alerts' do
let_it_be(:payload) { { 'custom' => { 'alert' => 'payload' } } }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:current_user) { create(:user) }
let_it_be(:alert_1) { create(:alert_management_alert, :all_fields, :resolved, project: project, severity: :low) }
let_it_be(:alert_1) { create(:alert_management_alert, :all_fields, :resolved, project: project, issue: nil, severity: :low) }
let_it_be(:alert_2) { create(:alert_management_alert, :all_fields, project: project, severity: :critical, payload: payload) }
let_it_be(:other_project_alert) { create(:alert_management_alert, :all_fields) }
......@@ -58,6 +58,7 @@ describe 'getting Alert Management Alerts' do
it 'returns the correct properties of the alerts' do
expect(first_alert).to include(
'iid' => alert_2.iid.to_s,
'issueIid' => alert_2.issue_iid.to_s,
'title' => alert_2.title,
'description' => alert_2.description,
'severity' => alert_2.severity.upcase,
......@@ -74,6 +75,8 @@ describe 'getting Alert Management Alerts' do
)
expect(second_alert).to include(
'iid' => alert_1.iid.to_s,
'issueIid' => nil,
'status' => 'RESOLVED',
'endedAt' => alert_1.ended_at.strftime('%Y-%m-%dT%H:%M:%SZ')
)
......
# frozen_string_literal: true
require 'spec_helper'
describe Metrics::UsersStarredDashboards::CreateService do
let_it_be(:user) { create(:user) }
let(:dashboard_path) { 'config/prometheus/common_metrics.yml' }
let(:service_instance) { described_class.new(user, project, dashboard_path) }
let(:project) { create(:project) }
let(:starred_dashboard_params) do
{
user: user,
project: project,
dashboard_path: dashboard_path
}
end
shared_examples 'prevented starred dashboard creation' do |message|
it 'returns error response', :aggregate_failures do
expect(Metrics::UsersStarredDashboard).not_to receive(:new)
response = service_instance.execute
expect(response.status).to be :error
expect(response.message).to eql message
end
end
describe '.execute' do
context 'with anonymous user' do
it_behaves_like 'prevented starred dashboard creation', 'You are not authorized to add star to this dashboard'
end
context 'with reporter user' do
before do
project.add_reporter(user)
end
context 'incorrect dashboard_path' do
let(:dashboard_path) { 'something_incorrect.yml' }
it_behaves_like 'prevented starred dashboard creation', 'Dashboard with requested path can not be found'
end
context 'with valid dashboard path' do
it 'creates starred dashboard and returns success response', :aggregate_failures do
expect_next_instance_of(Metrics::UsersStarredDashboard, starred_dashboard_params) do |starred_dashboard|
expect(starred_dashboard).to receive(:save).and_return true
end
response = service_instance.execute
expect(response.status).to be :success
end
context 'Metrics::UsersStarredDashboard has validation errors' do
it 'returns error response', :aggregate_failures do
expect_next_instance_of(Metrics::UsersStarredDashboard, starred_dashboard_params) do |starred_dashboard|
expect(starred_dashboard).to receive(:save).and_return(false)
expect(starred_dashboard).to receive(:errors).and_return(double(messages: { base: ['Model validation error'] }))
end
response = service_instance.execute
expect(response.status).to be :error
expect(response.message).to eql(base: ['Model validation error'])
end
end
end
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册