From 636eb69592af287dd76876e6fc3c898ad1af33f6 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 11 May 2020 18:09:55 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../components/dashboards_dropdown.vue | 38 +++++- .../users_starred_dashboards_finder.rb | 35 ++++++ .../types/alert_management/alert_type.rb | 5 + app/models/alert_management/alert.rb | 2 + app/models/metrics/users_starred_dashboard.rb | 3 + app/policies/project_policy.rb | 2 + .../create_service.rb | 74 +++++++++++ .../28617-add-global-sec-prefix.yml | 5 + ...-iid-in-alert-management-alert-graphql.yml | 5 + .../graphql/reference/gitlab_schema.graphql | 5 + doc/api/graphql/reference/gitlab_schema.json | 14 +++ doc/api/graphql/reference/index.md | 1 + .../container_scanning/index.md | 3 +- doc/user/application_security/dast/index.md | 5 +- .../dependency_scanning/analyzers.md | 2 +- .../dependency_scanning/index.md | 11 +- doc/user/application_security/index.md | 6 + .../application_security/sast/analyzers.md | 2 +- doc/user/application_security/sast/index.md | 7 +- .../compliance/license_compliance/index.md | 56 +++++++-- doc/user/project/clusters/index.md | 18 +++ doc/user/project/integrations/prometheus.md | 17 +++ .../Security/Container-Scanning.gitlab-ci.yml | 8 +- .../ci/templates/Security/DAST.gitlab-ci.yml | 5 +- .../Dependency-Scanning.gitlab-ci.yml | 11 +- .../Security/License-Scanning.gitlab-ci.yml | 6 +- .../ci/templates/Security/SAST.gitlab-ci.yml | 8 +- .../Security/Secure-Binaries.gitlab-ci.yml | 54 ++++---- .../usage_data_counters/web_ide_counter.rb | 6 +- locale/gitlab.pot | 6 + .../users_starred_dashboards_finder_spec.rb | 55 ++++++++ .../components/dashboards_dropdown_spec.js | 119 ++++++++++++++---- spec/frontend/monitoring/mock_data.js | 11 ++ .../types/alert_management/alert_type_spec.rb | 1 + .../web_ide_counter_spec.rb | 9 +- .../metrics/users_starred_dashboard_spec.rb | 19 +++ spec/policies/project_policy_spec.rb | 18 +++ .../project/alert_management/alerts_spec.rb | 5 +- .../create_service_spec.rb | 72 +++++++++++ 39 files changed, 638 insertions(+), 91 deletions(-) create mode 100644 app/finders/metrics/users_starred_dashboards_finder.rb create mode 100644 app/services/metrics/users_starred_dashboards/create_service.rb create mode 100644 changelogs/unreleased/28617-add-global-sec-prefix.yml create mode 100644 changelogs/unreleased/expose-issue-iid-in-alert-management-alert-graphql.yml create mode 100644 spec/finders/metrics/users_starred_dashboards_finder_spec.rb create mode 100644 spec/services/metrics/users_starred_dashboards/create_service_spec.rb diff --git a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue index 8f3e0a6ec75..9ef4b93d543 100644 --- a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue +++ b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue @@ -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" /> +
+
+ {{ dashboardDisplayName(dashboard) }} + +
+
+ + + + - {{ dashboard.display_name || dashboard.path }} + {{ dashboardDisplayName(dashboard) }}
diff --git a/app/finders/metrics/users_starred_dashboards_finder.rb b/app/finders/metrics/users_starred_dashboards_finder.rb new file mode 100644 index 00000000000..7244c51f9a7 --- /dev/null +++ b/app/finders/metrics/users_starred_dashboards_finder.rb @@ -0,0 +1,35 @@ +# 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 diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb index c0283e6d476..a766fb3236d 100644 --- a/app/graphql/types/alert_management/alert_type.rb +++ b/app/graphql/types/alert_management/alert_type.rb @@ -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, diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb index e1a6b507906..94764f6d249 100644 --- a/app/models/alert_management/alert.rb +++ b/app/models/alert_management/alert.rb @@ -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) } diff --git a/app/models/metrics/users_starred_dashboard.rb b/app/models/metrics/users_starred_dashboard.rb index 6242dcb94bc..07748eb1431 100644 --- a/app/models/metrics/users_starred_dashboard.rb +++ b/app/models/metrics/users_starred_dashboard.rb @@ -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 diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index a8105ae6f7c..a5813124bb1 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -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 diff --git a/app/services/metrics/users_starred_dashboards/create_service.rb b/app/services/metrics/users_starred_dashboards/create_service.rb new file mode 100644 index 00000000000..7784ed4eb4e --- /dev/null +++ b/app/services/metrics/users_starred_dashboards/create_service.rb @@ -0,0 +1,74 @@ +# 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 diff --git a/changelogs/unreleased/28617-add-global-sec-prefix.yml b/changelogs/unreleased/28617-add-global-sec-prefix.yml new file mode 100644 index 00000000000..a348e94e638 --- /dev/null +++ b/changelogs/unreleased/28617-add-global-sec-prefix.yml @@ -0,0 +1,5 @@ +--- +title: Add the global var SECURE_ANALYZERS_PREFIX +merge_request: 28617 +author: +type: added diff --git a/changelogs/unreleased/expose-issue-iid-in-alert-management-alert-graphql.yml b/changelogs/unreleased/expose-issue-iid-in-alert-management-alert-graphql.yml new file mode 100644 index 00000000000..8c72c58f51a --- /dev/null +++ b/changelogs/unreleased/expose-issue-iid-in-alert-management-alert-graphql.yml @@ -0,0 +1,5 @@ +--- +title: Exposes issue IID in Alert Management Alert's GraphQL endpoint +merge_request: 31313 +author: +type: added diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 81b27a17aec..0e8ff39d9b2 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -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 """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 344edccb711..af04b0138ea 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -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", diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index f289a057cbc..481d0a06233 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -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 | diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index 78a362cd32a..1623a2410dc 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -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 diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md index 753af98c219..e9680ce3913 100644 --- a/doc/user/application_security/dast/index.md +++ b/doc/user/application_security/dast/index.md @@ -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. diff --git a/doc/user/application_security/dependency_scanning/analyzers.md b/doc/user/application_security/dependency_scanning/analyzers.md index 26352f21cfb..474f9339d0b 100644 --- a/doc/user/application_security/dependency_scanning/analyzers.md +++ b/doc/user/application_security/dependency_scanning/analyzers.md @@ -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 diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 8819093eb23..ce7b962a943 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -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. | diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md index 7f82434fc4e..ceae827fb75 100644 --- a/doc/user/application_security/index.md +++ b/doc/user/application_security/index.md @@ -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. diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md index 4de58de4304..08078a66719 100644 --- a/doc/user/application_security/sast/analyzers.md +++ b/doc/user/application_security/sast/analyzers.md @@ -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 diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md index 33740f8c6e8..698a96bf607 100644 --- a/doc/user/application_security/sast/index.md +++ b/doc/user/application_security/sast/index.md @@ -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" ``` diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md index 9f77b3baad0..e6994deeffe 100644 --- a/doc/user/compliance/license_compliance/index.md +++ b/doc/user/compliance/license_compliance/index.md @@ -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)). diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 51fe3fbf168..639bf7e447d 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -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 diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md index 8fca670eb41..0edd736cc3b 100644 --- a/doc/user/project/integrations/prometheus.md +++ b/doc/user/project/integrations/prometheus.md @@ -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///-/environments//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. diff --git a/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml index 6efb6b4e273..7075cb28a2c 100644 --- a/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml @@ -1,16 +1,20 @@ # 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 diff --git a/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml index fd762234163..a2fb604cb87 100644 --- a/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml @@ -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 diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml index eb8dee0166a..401be1aa7bf 100644 --- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml @@ -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 diff --git a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml index abf7e342144..9259abcd849 100644 --- a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml @@ -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 diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml index 7207922def8..894fcfd75be 100644 --- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml @@ -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" diff --git a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml index 5a29ced2314..b6c05c61db1 100644 --- a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml @@ -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 diff --git a/lib/gitlab/usage_data_counters/web_ide_counter.rb b/lib/gitlab/usage_data_counters/web_ide_counter.rb index 720c7327c9a..14fe5d4e70b 100644 --- a/lib/gitlab/usage_data_counters/web_ide_counter.rb +++ b/lib/gitlab/usage_data_counters/web_ide_counter.rb @@ -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? diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a787e93f889..a0c11e1e354 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/spec/finders/metrics/users_starred_dashboards_finder_spec.rb b/spec/finders/metrics/users_starred_dashboards_finder_spec.rb new file mode 100644 index 00000000000..c32b8c2d335 --- /dev/null +++ b/spec/finders/metrics/users_starred_dashboards_finder_spec.rb @@ -0,0 +1,55 @@ +# 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 diff --git a/spec/frontend/monitoring/components/dashboards_dropdown_spec.js b/spec/frontend/monitoring/components/dashboards_dropdown_spec.js index 0bcfabe6415..25b31a793f7 100644 --- a/spec/frontend/monitoring/components/dashboards_dropdown_spec.js +++ b/spec/frontend/monitoring/components/dashboards_dropdown_spec.js @@ -1,5 +1,5 @@ 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]]); }); }); }); diff --git a/spec/frontend/monitoring/mock_data.js b/spec/frontend/monitoring/mock_data.js index 0db69ca7d8d..f846d5aaea5 100644 --- a/spec/frontend/monitoring/mock_data.js +++ b/spec/frontend/monitoring/mock_data.js @@ -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, ]; diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb index 65291f31422..9c326f30e3c 100644 --- a/spec/graphql/types/alert_management/alert_type_spec.rb +++ b/spec/graphql/types/alert_management/alert_type_spec.rb @@ -10,6 +10,7 @@ describe GitlabSchema.types['AlertManagementAlert'] do it 'exposes the expected fields' do expected_fields = %i[ iid + issue_iid title description severity diff --git a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb index 920d1d23567..ee6224eca68 100644 --- a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb @@ -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 diff --git a/spec/models/metrics/users_starred_dashboard_spec.rb b/spec/models/metrics/users_starred_dashboard_spec.rb index 0823027efdb..6cb14ae569e 100644 --- a/spec/models/metrics/users_starred_dashboard_spec.rb +++ b/spec/models/metrics/users_starred_dashboard_spec.rb @@ -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 diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 4e15af7e0b5..13f6ad13c2b 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -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 diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb index 6baa9d4b2f9..cafa7366411 100644 --- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb +++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb @@ -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') ) diff --git a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb new file mode 100644 index 00000000000..eac4965ba44 --- /dev/null +++ b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb @@ -0,0 +1,72 @@ +# 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 -- GitLab