diff options
52 files changed, 1203 insertions, 62 deletions
diff --git a/app/assets/javascripts/jira_import/components/jira_import_app.vue b/app/assets/javascripts/jira_import/components/jira_import_app.vue index 4b19c4d1b17..6efac949979 100644 --- a/app/assets/javascripts/jira_import/components/jira_import_app.vue +++ b/app/assets/javascripts/jira_import/components/jira_import_app.vue @@ -1,13 +1,25 @@ <script> import getJiraProjects from '../queries/getJiraProjects.query.graphql'; +import JiraImportSetup from './jira_import_setup.vue'; export default { name: 'JiraImportApp', + components: { + JiraImportSetup, + }, props: { + isJiraConfigured: { + type: Boolean, + required: true, + }, projectPath: { type: String, required: true, }, + setupIllustration: { + type: String, + required: true, + }, }, apollo: { getJiraImports: { @@ -18,11 +30,17 @@ export default { }; }, update: data => data.project.jiraImports, + skip() { + return !this.isJiraConfigured; + }, }, }, }; </script> <template> - <div></div> + <div> + <jira-import-setup v-if="!isJiraConfigured" :illustration="setupIllustration" /> + <div v-else></div> + </div> </template> diff --git a/app/assets/javascripts/jira_import/components/jira_import_setup.vue b/app/assets/javascripts/jira_import/components/jira_import_setup.vue new file mode 100644 index 00000000000..917930397f4 --- /dev/null +++ b/app/assets/javascripts/jira_import/components/jira_import_setup.vue @@ -0,0 +1,25 @@ +<script> +export default { + name: 'JiraImportSetup', + props: { + illustration: { + type: String, + required: true, + }, + }, +}; +</script> + +<template> + <div class="empty-state"> + <div class="svg-content"> + <img :src="illustration" :alt="__('Set up Jira Integration illustration')" /> + </div> + <div class="text-content d-flex flex-column align-items-center"> + <p>{{ __('You will first need to set up Jira Integration to use this feature.') }}</p> + <a class="btn btn-success" href="../services/jira/edit"> + {{ __('Set up Jira Integration') }} + </a> + </div> + </div> +</template> diff --git a/app/assets/javascripts/jira_import/index.js b/app/assets/javascripts/jira_import/index.js index a17313fd774..13b16b81c49 100644 --- a/app/assets/javascripts/jira_import/index.js +++ b/app/assets/javascripts/jira_import/index.js @@ -1,6 +1,7 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; +import { parseBoolean } from '~/lib/utils/common_utils'; import App from './components/jira_import_app.vue'; Vue.use(VueApollo); @@ -23,7 +24,9 @@ export default function mountJiraImportApp() { render(createComponent) { return createComponent(App, { props: { + isJiraConfigured: parseBoolean(el.dataset.isJiraConfigured), projectPath: el.dataset.projectPath, + setupIllustration: el.dataset.setupIllustration, }, }); }, diff --git a/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js b/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js new file mode 100644 index 00000000000..2fd047675b9 --- /dev/null +++ b/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js @@ -0,0 +1,3 @@ +import customMetrics from '~/custom_metrics'; + +document.addEventListener('DOMContentLoaded', customMetrics); diff --git a/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js b/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js new file mode 100644 index 00000000000..2fd047675b9 --- /dev/null +++ b/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js @@ -0,0 +1,3 @@ +import customMetrics from '~/custom_metrics'; + +document.addEventListener('DOMContentLoaded', customMetrics); diff --git a/app/assets/stylesheets/pages/reports.scss b/app/assets/stylesheets/pages/reports.scss index 390ebd48685..56194f0af67 100644 --- a/app/assets/stylesheets/pages/reports.scss +++ b/app/assets/stylesheets/pages/reports.scss @@ -63,15 +63,6 @@ list-style: none; padding: 0 1px; margin: 0; - - .license-item { - line-height: $gl-padding-32; - - .license-packages { - font-size: $label-font-size; - } - - } } .report-block-list-icon { diff --git a/app/controllers/projects/import/jira_controller.rb b/app/controllers/projects/import/jira_controller.rb index b5adef399c7..ca427928d85 100644 --- a/app/controllers/projects/import/jira_controller.rb +++ b/app/controllers/projects/import/jira_controller.rb @@ -7,6 +7,7 @@ module Projects before_action :jira_integration_configured? def show + @is_jira_configured = @project.jira_service.present? return if Feature.enabled?(:jira_issue_import_vue, @project) unless @project.latest_jira_import&.in_progress? @@ -39,12 +40,13 @@ module Projects private def jira_import_enabled? - return if Feature.enabled?(:jira_issue_import, @project) + return if @project.jira_issues_import_feature_flag_enabled? redirect_to project_issues_path(@project) end def jira_integration_configured? + return if Feature.enabled?(:jira_issue_import_vue, @project) return if @project.jira_service flash[:notice] = _("Configure the Jira integration first on your project's %{strong_start} Settings > Integrations > Jira%{strong_end} page." % diff --git a/app/graphql/resolvers/projects/jira_imports_resolver.rb b/app/graphql/resolvers/projects/jira_imports_resolver.rb index 9f71d4f187e..b0784b3cdf7 100644 --- a/app/graphql/resolvers/projects/jira_imports_resolver.rb +++ b/app/graphql/resolvers/projects/jira_imports_resolver.rb @@ -14,7 +14,7 @@ module Resolvers end def authorized_resource?(project) - return false unless Feature.enabled?(:jira_issue_import, project) + return false unless project.jira_issues_import_feature_flag_enabled? Ability.allowed?(context[:current_user], :admin_project, project) end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 42771eaa82a..9ef3d64f21a 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -123,6 +123,7 @@ module Clusters scope :managed, -> { where(managed: true) } scope :with_persisted_applications, -> { eager_load(*APPLICATIONS_ASSOCIATIONS) } scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) } + scope :with_management_project, -> { where.not(management_project: nil) } scope :for_project_namespace, -> (namespace_id) { joins(:projects).where(projects: { namespace_id: namespace_id }) } diff --git a/app/models/group_group_link.rb b/app/models/group_group_link.rb index 58c188369da..c233f59b1a6 100644 --- a/app/models/group_group_link.rb +++ b/app/models/group_group_link.rb @@ -13,6 +13,8 @@ class GroupGroupLink < ApplicationRecord validates :group_access, inclusion: { in: Gitlab::Access.all_values }, presence: true + scope :non_guests, -> { where('group_access > ?', Gitlab::Access::GUEST) } + def self.access_options Gitlab::Access.options_with_owner end diff --git a/app/models/project.rb b/app/models/project.rb index 1f968cdfad1..4cd92b119b4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -786,6 +786,10 @@ class Project < ApplicationRecord Feature.enabled?(:context_commits, default_enabled: true) end + def jira_issues_import_feature_flag_enabled? + Feature.enabled?(:jira_issue_import, self) + end + def team @team ||= ProjectTeam.new(self) end @@ -968,7 +972,7 @@ class Project < ApplicationRecord end def jira_import? - import_type == 'jira' && latest_jira_import.present? && Feature.enabled?(:jira_issue_import, self) + import_type == 'jira' && latest_jira_import.present? && jira_issues_import_feature_flag_enabled? end def gitlab_project_import? diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb index b4071c6d4a6..f1c491d1a05 100644 --- a/app/models/project_group_link.rb +++ b/app/models/project_group_link.rb @@ -3,11 +3,6 @@ class ProjectGroupLink < ApplicationRecord include Expirable - GUEST = 10 - REPORTER = 20 - DEVELOPER = 30 - MAINTAINER = 40 - belongs_to :project belongs_to :group @@ -18,6 +13,8 @@ class ProjectGroupLink < ApplicationRecord validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true validate :different_group + scope :non_guests, -> { where('group_access > ?', Gitlab::Access::GUEST) } + after_commit :refresh_group_members_authorized_projects alias_method :shared_with_group, :group @@ -27,7 +24,7 @@ class ProjectGroupLink < ApplicationRecord end def self.default_access - DEVELOPER + Gitlab::Access::DEVELOPER end def self.search(query) diff --git a/app/services/jira_import/start_import_service.rb b/app/services/jira_import/start_import_service.rb index fbbd2d883f0..134cef089e7 100644 --- a/app/services/jira_import/start_import_service.rb +++ b/app/services/jira_import/start_import_service.rb @@ -44,7 +44,7 @@ module JiraImport end def validate - return build_error_response(_('Jira import feature is disabled.')) unless Feature.enabled?(:jira_issue_import, project) + return build_error_response(_('Jira import feature is disabled.')) unless project.jira_issues_import_feature_flag_enabled? return build_error_response(_('You do not have permissions to run the import.')) unless user.can?(:admin_project, project) return build_error_response(_('Jira integration not configured.')) unless project.jira_service&.active? return build_error_response(_('Unable to find Jira project to import data from.')) if jira_project_key.blank? diff --git a/app/views/projects/import/jira/show.html.haml b/app/views/projects/import/jira/show.html.haml index cfc4baa1c25..6003f33f0ba 100644 --- a/app/views/projects/import/jira/show.html.haml +++ b/app/views/projects/import/jira/show.html.haml @@ -1,5 +1,7 @@ - if Feature.enabled?(:jira_issue_import_vue, @project) - .js-jira-import-root{ data: { project_path: @project.full_path } } + .js-jira-import-root{ data: { project_path: @project.full_path, + is_jira_configured: @is_jira_configured.to_s, + setup_illustration: image_path('illustrations/manual_action.svg') } } - else - title = _('Jira Issue Import') - page_title title diff --git a/app/views/projects/issues/import_csv/_button.html.haml b/app/views/projects/issues/import_csv/_button.html.haml index 0a352d26b0b..07c34b51037 100644 --- a/app/views/projects/issues/import_csv/_button.html.haml +++ b/app/views/projects/issues/import_csv/_button.html.haml @@ -1,6 +1,6 @@ - type = local_assigns.fetch(:type, :icon) -- if Feature.enabled?(:jira_issue_import, @project) +- if @project.jira_issues_import_feature_flag_enabled? .dropdown.btn-group %button.btn.rounded-right.text-center{ class: ('has-tooltip' if type == :icon), title: (_('Import issues') if type == :icon), data: { toggle: 'dropdown' }, 'aria-label' => _('Import issues'), 'aria-haspopup' => 'true', 'aria-expanded' => 'false' } diff --git a/app/workers/concerns/gitlab/jira_import/import_worker.rb b/app/workers/concerns/gitlab/jira_import/import_worker.rb index 169d3797b88..537300e6eba 100644 --- a/app/workers/concerns/gitlab/jira_import/import_worker.rb +++ b/app/workers/concerns/gitlab/jira_import/import_worker.rb @@ -26,7 +26,7 @@ module Gitlab def can_import?(project) return false unless project - return false if Feature.disabled?(:jira_issue_import, project) + return false unless project.jira_issues_import_feature_flag_enabled? project.latest_jira_import&.started? end diff --git a/app/workers/gitlab/jira_import/stage/start_import_worker.rb b/app/workers/gitlab/jira_import/stage/start_import_worker.rb index 1561ad90cc1..5b36feadbd1 100644 --- a/app/workers/gitlab/jira_import/stage/start_import_worker.rb +++ b/app/workers/gitlab/jira_import/stage/start_import_worker.rb @@ -25,7 +25,7 @@ module Gitlab def start_import return false unless project - return false if Feature.disabled?(:jira_issue_import, project) + return false unless project.jira_issues_import_feature_flag_enabled? return true if start(project.latest_jira_import) Gitlab::Import::Logger.info( diff --git a/changelogs/unreleased/119235-extra-cluster-usage-data.yml b/changelogs/unreleased/119235-extra-cluster-usage-data.yml new file mode 100644 index 00000000000..acb5f924239 --- /dev/null +++ b/changelogs/unreleased/119235-extra-cluster-usage-data.yml @@ -0,0 +1,5 @@ +--- +title: Add usage data metrics for instance level clusters and clusters with management projects +merge_request: 28510 +author: +type: added diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md index 9cb95559412..01af971d664 100644 --- a/doc/administration/high_availability/database.md +++ b/doc/administration/high_availability/database.md @@ -199,7 +199,7 @@ Few notes on the service itself: - Passwords will be stored in the following locations: - `/etc/gitlab/gitlab.rb`: hashed - `/var/opt/gitlab/pgbouncer/pg_auth`: hashed - - `/var/opt/gitlab/gitlab-consul/.pgpass`: plaintext + - `/var/opt/gitlab/consul/.pgpass`: plaintext ##### PostgreSQL information diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md index 34d2c40d1f9..aebbc95750d 100644 --- a/doc/api/api_resources.md +++ b/doc/api/api_resources.md @@ -71,8 +71,10 @@ The following API resources are available in the project context: | [Services](services.md) | `/projects/:id/services` | | [Tags](tags.md) | `/projects/:id/repository/tags` | | [Visual Review discussions](visual_review_discussions.md) **(STARTER**) | `/projects/:id/merge_requests/:merge_request_id/visual_review_discussions` | -| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities` | -| [Vulnerability Findings](vulnerability_findings.md) **(ULTIMATE)** | `/projects/:id/vulnerability_findings` | +| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE)** | `/vulnerabilities/:id` | +| [Vulnerability exports](vulnerability_exports.md) **(ULTIMATE)** | `/projects/:id/vulnerability_exports` | +| [Project vulnerabilities](project_vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities` | +| [Vulnerability findings](vulnerability_findings.md) **(ULTIMATE)** | `/projects/:id/vulnerability_findings` | | [Wikis](wikis.md) | `/projects/:id/wikis` | ## Group resources diff --git a/doc/api/project_vulnerabilities.md b/doc/api/project_vulnerabilities.md new file mode 100644 index 00000000000..84bbc789b0c --- /dev/null +++ b/doc/api/project_vulnerabilities.md @@ -0,0 +1,215 @@ +# Project Vulnerabilities API **(ULTIMATE)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/10242) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.6. + +CAUTION: **Caution:** +This API is currently in development and is protected by a **disabled** +[feature flag](../development/feature_flags/index.md). +On a self-managed GitLab instance, an administrator can enable it by starting the Rails console +(`sudo gitlab-rails console`) and then running the following command: `Feature.enable(:first_class_vulnerabilities)`. +To test if the Vulnerabilities API was successfully enabled, run the following command: +`Feature.enabled?(:first_class_vulnerabilities)`. + +CAUTION: **Caution:** +This API is in an alpha stage and considered unstable. +The response payload may be subject to change or breakage +across GitLab releases. + +Every API call to vulnerabilities must be [authenticated](README.md#authentication). + +Vulnerability permissions inherit permissions from their project. If a project is +private, and a user isn't a member of the project to which the vulnerability +belongs, requests to that project will return a `404 Not Found` status code. + +## Vulnerabilities pagination + +API results are paginated, and `GET` requests return 20 results at a time by default. + +Read more on [pagination](README.md#pagination). + +## List project vulnerabilities + +List all of a project's vulnerabilities. + +If an authenticated user does not have permission to +[use the Project Security Dashboard](../user/permissions.md#project-members-permissions), +`GET` requests for vulnerabilities of this project will result in a `403` status code. + +```plaintext +GET /projects/:id/vulnerabilities +``` + +| Attribute | Type | Required | Description | +| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | + +```bash +curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/vulnerabilities +``` + +Example response: + +```json +[ + { + "author_id": 1, + "confidence": "medium", + "created_at": "2020-04-07T14:01:04.655Z", + "description": null, + "dismissed_at": null, + "dismissed_by_id": null, + "due_date": null, + "finding": { + "confidence": "medium", + "created_at": "2020-04-07T14:01:04.630Z", + "id": 103, + "location_fingerprint": "228998b5db51d86d3b091939e2f5873ada0a14a1", + "metadata_version": "2.0", + "name": "Regular Expression Denial of Service in debug", + "primary_identifier_id": 135, + "project_fingerprint": "05e7cc9978ca495cf739a9f707ed34811e41c615", + "project_id": 24, + "raw_metadata": "{\"category\":\"dependency_scanning\",\"name\":\"Regular Expression Denial of Service\",\"message\":\"Regular Expression Denial of Service in debug\",\"description\":\"The debug module is vulnerable to regular expression denial of service when untrusted user input is passed into the `o` formatter. It takes around 50k characters to block for 2 seconds making this a low severity issue.\",\"cve\":\"yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a\",\"severity\":\"Unknown\",\"solution\":\"Upgrade to latest versions.\",\"scanner\":{\"id\":\"gemnasium\",\"name\":\"Gemnasium\"},\"location\":{\"file\":\"yarn.lock\",\"dependency\":{\"package\":{\"name\":\"debug\"},\"version\":\"1.0.5\"}},\"identifiers\":[{\"type\":\"gemnasium\",\"name\":\"Gemnasium-37283ed4-0380-40d7-ada7-2d994afcc62a\",\"value\":\"37283ed4-0380-40d7-ada7-2d994afcc62a\",\"url\":\"https://deps.sec.gitlab.com/packages/npm/debug/versions/1.0.5/advisories\"}],\"links\":[{\"url\":\"https://nodesecurity.io/advisories/534\"},{\"url\":\"https://github.com/visionmedia/debug/issues/501\"},{\"url\":\"https://github.com/visionmedia/debug/pull/504\"}],\"remediations\":[null]}", + "report_type": "dependency_scanning", + "scanner_id": 63, + "severity": "low", + "updated_at": "2020-04-07T14:01:04.664Z", + "uuid": "f1d528ae-d0cc-47f6-a72f-936cec846ae7", + "vulnerability_id": 103 + }, + "id": 103, + "last_edited_at": null, + "last_edited_by_id": null, + "project": { + "created_at": "2020-04-07T13:54:25.634Z", + "description": "", + "id": 24, + "name": "security-reports", + "name_with_namespace": "gitlab-org / security-reports", + "path": "security-reports", + "path_with_namespace": "gitlab-org/security-reports" + }, + "project_default_branch": "master", + "report_type": "dependency_scanning", + "resolved_at": null, + "resolved_by_id": null, + "resolved_on_default_branch": false, + "severity": "low", + "start_date": null, + "state": "detected", + "title": "Regular Expression Denial of Service in debug", + "updated_at": "2020-04-07T14:01:04.655Z", + "updated_by_id": null + } +] +``` + +## New vulnerability + +Creates a new vulnerability. + +If an authenticated user does not have a permission to +[create a new vulnerability](../user/permissions.md#project-members-permissions), +this request will result in a `403` status code. + +```plaintext +POST /projects/:id/vulnerabilities?finding_id=<your_finding_id> +``` + +| Attribute | Type | Required | Description | +| ------------------- | ----------------- | ---------- | -----------------------------------------------------------------------------------------------------------------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) which the authenticated user is a member of | +| `finding_id` | integer or string | yes | The ID of a Vulnerability Finding from which the new Vulnerability will be created | + +The other attributes of a newly created Vulnerability are populated from +its source Vulnerability Finding, or with these default values: + +| Attribute | Value | +|--------------|-------------------------------------------------------| +| `author` | The authenticated user | +| `title` | The `name` attribute of a Vulnerability Finding | +| `state` | `opened` | +| `severity` | The `severity` attribute of a Vulnerability Finding | +| `confidence` | The `confidence` attribute of a Vulnerability Finding | + +```shell +curl --header POST "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/vulnerabilities?finding_id=1 +``` + +Example response: + +```json +{ + "author_id": 1, + "confidence": "medium", + "created_at": "2020-04-07T14:01:04.655Z", + "description": null, + "dismissed_at": null, + "dismissed_by_id": null, + "due_date": null, + "finding": { + "confidence": "medium", + "created_at": "2020-04-07T14:01:04.630Z", + "id": 103, + "location_fingerprint": "228998b5db51d86d3b091939e2f5873ada0a14a1", + "metadata_version": "2.0", + "name": "Regular Expression Denial of Service in debug", + "primary_identifier_id": 135, + "project_fingerprint": "05e7cc9978ca495cf739a9f707ed34811e41c615", + "project_id": 24, + "raw_metadata": "{\"category\":\"dependency_scanning\",\"name\":\"Regular Expression Denial of Service\",\"message\":\"Regular Expression Denial of Service in debug\",\"description\":\"The debug module is vulnerable to regular expression denial of service when untrusted user input is passed into the `o` formatter. It takes around 50k characters to block for 2 seconds making this a low severity issue.\",\"cve\":\"yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a\",\"severity\":\"Unknown\",\"solution\":\"Upgrade to latest versions.\",\"scanner\":{\"id\":\"gemnasium\",\"name\":\"Gemnasium\"},\"location\":{\"file\":\"yarn.lock\",\"dependency\":{\"package\":{\"name\":\"debug\"},\"version\":\"1.0.5\"}},\"identifiers\":[{\"type\":\"gemnasium\",\"name\":\"Gemnasium-37283ed4-0380-40d7-ada7-2d994afcc62a\",\"value\":\"37283ed4-0380-40d7-ada7-2d994afcc62a\",\"url\":\"https://deps.sec.gitlab.com/packages/npm/debug/versions/1.0.5/advisories\"}],\"links\":[{\"url\":\"https://nodesecurity.io/advisories/534\"},{\"url\":\"https://github.com/visionmedia/debug/issues/501\"},{\"url\":\"https://github.com/visionmedia/debug/pull/504\"}],\"remediations\":[null]}", + "report_type": "dependency_scanning", + "scanner_id": 63, + "severity": "low", + "updated_at": "2020-04-07T14:01:04.664Z", + "uuid": "f1d528ae-d0cc-47f6-a72f-936cec846ae7", + "vulnerability_id": 103 + }, + "id": 103, + "last_edited_at": null, + "last_edited_by_id": null, + "project": { + "created_at": "2020-04-07T13:54:25.634Z", + "description": "", + "id": 24, + "name": "security-reports", + "name_with_namespace": "gitlab-org / security-reports", + "path": "security-reports", + "path_with_namespace": "gitlab-org/security-reports" + }, + "project_default_branch": "master", + "report_type": "dependency_scanning", + "resolved_at": null, + "resolved_by_id": null, + "resolved_on_default_branch": false, + "severity": "low", + "start_date": null, + "state": "detected", + "title": "Regular Expression Denial of Service in debug", + "updated_at": "2020-04-07T14:01:04.655Z", + "updated_by_id": null +} +``` + +### Errors + +This error occurs when a Finding chosen to create a Vulnerability from is not found, or +is already associated with a different Vulnerability: + +```plaintext +A Vulnerability Finding is not found or already attached to a different Vulnerability +``` + +Status code: `400` + +Example response: + +```json +{ + "message": { + "base": [ + "finding is not found or is already attached to a vulnerability" + ] + } +} +``` diff --git a/doc/api/vulnerabilities.md b/doc/api/vulnerabilities.md index 21b3a6f4c96..ff1a6a7ebcd 100644 --- a/doc/api/vulnerabilities.md +++ b/doc/api/vulnerabilities.md @@ -1,3 +1,224 @@ # Vulnerabilities API **(ULTIMATE)** -This document was moved to [another location](vulnerability_findings.md). +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/10242) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.6. + +NOTE: **Note:** +The former Vulnerabilities API was renamed to Vulnerability Findings API +and its documentation was moved to [a different location](vulnerability_findings.md). +This document now describes the new Vulnerabilities API that provides access to +[Standalone Vulnerabilities](https://gitlab.com/groups/gitlab-org/-/epics/634). + +CAUTION: **Caution:** +This API is currently in development and is protected by a **disabled** +[feature flag](../development/feature_flags/index.md). +On a self-managed GitLab instance, an administrator can enable it by starting the Rails console +(`sudo gitlab-rails console`) and then running the following command: `Feature.enable(:first_class_vulnerabilities)`. +To test if the Vulnerabilities API was successfully enabled, run the following command: +`Feature.enabled?(:first_class_vulnerabilities)`. + +CAUTION: **Caution:** +This API is in an alpha stage and considered unstable. +The response payload may be subject to change or breakage +across GitLab releases. + +Every API call to vulnerabilities must be [authenticated](README.md#authentication). + +Vulnerability permissions inherit permissions from their project. If a project is +private, and a user isn't a member of the project to which the vulnerability +belongs, requests to that project will return a `404 Not Found` status code. + +## Single vulnerability + +Gets a single vulnerability + +```plaintext +GET /vulnerabilities/:id +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer or string | yes | The ID of a Vulnerability to get | + +```shell +curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/vulnerabilities/1 +``` + +Example response: + +```json +{ + "id": 1, + "title": "Predictable pseudorandom number generator", + "description": null, + "state": "opened", + "severity": "medium", + "confidence": "medium", + "report_type": "sast", + "project": { + "id": 32, + "name": "security-reports", + "full_path": "/gitlab-examples/security/security-reports", + "full_name": "gitlab-examples / security / security-reports" + }, + "author_id": 1, + "updated_by_id": null, + "last_edited_by_id": null, + "closed_by_id": null, + "start_date": null, + "due_date": null, + "created_at": "2019-10-13T15:08:40.219Z", + "updated_at": "2019-10-13T15:09:40.382Z", + "last_edited_at": null, + "closed_at": null +} +``` + +## Confirm vulnerability + +Confirms a given vulnerability. Returns status code `304` if the vulnerability is already confirmed. + +If an authenticated user does not have permission to +[confirm vulnerabilities](../user/permissions.md#project-members-permissions), +this request will result in a `403` status code. + +```plaintext +POST /vulnerabilities/:id/confirm +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer or string | yes | The ID of a vulnerability to confirm | + +```shell +curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/vulnerabilities/5/confirm" +``` + +Example response: + +```json +{ + "id": 2, + "title": "Predictable pseudorandom number generator", + "description": null, + "state": "confirmed", + "severity": "medium", + "confidence": "medium", + "report_type": "sast", + "project": { + "id": 32, + "name": "security-reports", + "full_path": "/gitlab-examples/security/security-reports", + "full_name": "gitlab-examples / security / security-reports" + }, + "author_id": 1, + "updated_by_id": null, + "last_edited_by_id": null, + "closed_by_id": null, + "start_date": null, + "due_date": null, + "created_at": "2019-10-13T15:08:40.219Z", + "updated_at": "2019-10-13T15:09:40.382Z", + "last_edited_at": null, + "closed_at": null +} +``` + +## Resolve vulnerability + +Resolves a given vulnerability. Returns status code `304` if the vulnerability is already resolved. + +If an authenticated user does not have permission to +[resolve vulnerabilities](../user/permissions.md#project-members-permissions), +this request will result in a `403` status code. + +```plaintext +POST /vulnerabilities/:id/resolve +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer or string | yes | The ID of a Vulnerability to resolve | + +```shell +curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/vulnerabilities/5/resolve" +``` + +Example response: + +```json +{ + "id": 2, + "title": "Predictable pseudorandom number generator", + "description": null, + "state": "resolved", + "severity": "medium", + "confidence": "medium", + "report_type": "sast", + "project": { + "id": 32, + "name": "security-reports", + "full_path": "/gitlab-examples/security/security-reports", + "full_name": "gitlab-examples / security / security-reports" + }, + "author_id": 1, + "updated_by_id": null, + "last_edited_by_id": null, + "closed_by_id": null, + "start_date": null, + "due_date": null, + "created_at": "2019-10-13T15:08:40.219Z", + "updated_at": "2019-10-13T15:09:40.382Z", + "last_edited_at": null, + "closed_at": null +} +``` + +## Dismiss vulnerability + +Dismisses a given vulnerability. Returns status code `304` if the vulnerability is already dismissed. + +If an authenticated user does not have permission to +[dismiss vulnerabilities](../user/permissions.md#project-members-permissions), +this request will result in a `403` status code. + +```plaintext +POST /vulnerabilities/:id/dismiss +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer or string | yes | The ID of a vulnerability to dismiss | + +```shell +curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/vulnerabilities/5/dismiss" +``` + +Example response: + +```json +{ + "id": 2, + "title": "Predictable pseudorandom number generator", + "description": null, + "state": "closed", + "severity": "medium", + "confidence": "medium", + "report_type": "sast", + "project": { + "id": 32, + "name": "security-reports", + "full_path": "/gitlab-examples/security/security-reports", + "full_name": "gitlab-examples / security / security-reports" + }, + "author_id": 1, + "updated_by_id": null, + "last_edited_by_id": null, + "closed_by_id": null, + "start_date": null, + "due_date": null, + "created_at": "2019-10-13T15:08:40.219Z", + "updated_at": "2019-10-13T15:09:40.382Z", + "last_edited_at": null, + "closed_at": null +} +``` diff --git a/doc/api/vulnerability_exports.md b/doc/api/vulnerability_exports.md new file mode 100644 index 00000000000..f2666783087 --- /dev/null +++ b/doc/api/vulnerability_exports.md @@ -0,0 +1,138 @@ +# Project Vulnerabilities API **(ULTIMATE)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/197494) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10. + +CAUTION: **Caution:** +This API is currently in development and is protected by a **disabled** +[feature flag](../development/feature_flags/index.md). +On a self-managed GitLab instance, an administrator can enable it by starting the Rails console +(`sudo gitlab-rails console`) and then running the following command: `Feature.enable(:first_class_vulnerabilities)`. +To test if the Vulnerability Exports API was successfully enabled, run the following command: +`Feature.enabled?(:first_class_vulnerabilities)`. + +CAUTION: **Caution:** +This API is in an alpha stage and considered unstable. +The response payload may be subject to change or breakage +across GitLab releases. + +Every API call to vulnerability exports must be [authenticated](README.md#authentication). + +Vulnerability export permissions inherit permissions from their project. If a project is +private and a user isn't a member of the project to which the vulnerability +belongs, requests to that project return a `404 Not Found` status code. +Vulnerability exports can be only accessed by the export's author. + +## Create vulnerability export + +Creates a new vulnerability export. + +If an authenticated user doesn't have permission to +[create a new vulnerability](../user/permissions.md#project-members-permissions), +this request results in a `403` status code. + +```plaintext +POST /projects/:id/vulnerability_exports +``` + +| Attribute | Type | Required | Description | +| ------------------- | ----------------- | ---------- | -----------------------------------------------------------------------------------------------------------------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path](README.md#namespaced-path-encoding) of the project which the authenticated user is a member of | + +```shell +curl --header POST "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/vulnerability_exports +``` + +The created vulnerability export will be automatically deleted after 1 hour. + +Example response: + +```json +{ + "id": 2, + "created_at": "2020-03-30T09:35:38.746Z", + "project_id": 1, + "format": "csv", + "status": "created", + "started_at": null, + "finished_at": null, + "_links": { + "self": "https://gitlab.example.com/api/v4/projects/1/vulnerability_exports/2", + "download": "https://gitlab.example.com/api/v4/projects/1/vulnerability_exports/2/download" + } +} +``` + +## Get single vulnerability export + +Gets a single vulnerability export. + +```plaintext +POST /projects/:id/vulnerability_exports/:vulnerability_export_id +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer or string | yes | The vulnerability's ID | +| `vulnerability_export_id` | integer or string | yes | The vulnerability export's ID | + +```shell +curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/vulnerability_exports/2 +``` + +If the vulnerability export isn't finished, the response is `202 Accepted`. + +Example response: + +```json +{ + "id": 2, + "created_at": "2020-03-30T09:35:38.746Z", + "project_id": 1, + "format": "csv", + "status": "finished", + "started_at": "2020-03-30T09:36:54.469Z", + "finished_at": "2020-03-30T09:36:55.008Z", + "_links": { + "self": "https://gitlab.example.com/api/v4/projects/1/vulnerability_exports/2", + "download": "https://gitlab.example.com/api/v4/projects/1/vulnerability_exports/2/download" + } +} +``` + +## Download vulnerability export + +Downloads a single vulnerability export. + +```plaintext +POST /projects/:id/vulnerability_exports/:vulnerability_export_id/download +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer or string | yes | The vulnerability's ID | +| `vulnerability_export_id` | integer or string | yes | The vulnerability export's ID | + +```shell +curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/vulnerability_exports/2/download +``` + +The response will be `404 Not Found` if the vulnerability export is not finished yet or was not found. + +Example response: + +```csv +Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE +container_scanning,Clair,confirmed,CVE-2017-16997 in glibc,,CVE-2017-16997 in glibc,critical,CVE-2017-16997 +container_scanning,Clair,detected,CVE-2017-18269 in glibc,,CVE-2017-18269 in glibc,critical,CVE-2017-18269 +container_scanning,Clair,detected,CVE-2018-1000001 in glibc,,CVE-2018-1000001 in glibc,high,CVE-2018-1000001 +container_scanning,Clair,detected,CVE-2016-10228 in glibc,,CVE-2016-10228 in glibc,medium,CVE-2016-10228 +container_scanning,Clair,confirmed,CVE-2010-4052 in glibc,,CVE-2010-4052 in glibc,low,CVE-2010-4052 +container_scanning,Clair,detected,CVE-2018-18520 in elfutils,,CVE-2018-18520 in elfutils,low,CVE-2018-18520 +container_scanning,Clair,detected,CVE-2018-16869 in nettle,,CVE-2018-16869 in nettle,unknown,CVE-2018-16869 +dependency_scanning,Gemnasium,detected,Regular Expression Denial of Service in debug,,Regular Expression Denial of Service in debug,unknown,yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a +dependency_scanning,Gemnasium,detected,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,unknown,yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98 +sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,818bf5dacb291e15d9e6dc3c5ac32178:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:47 +sast,Find Security Bugs,detected,Cipher with no integrity,,Cipher with no integrity,medium,e6449b89335daf53c0db4c0219bc1634:CIPHER_INTEGRITY:src/main/java/com/gitlab/security_products/tests/App.java:29 +sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,e8ff1d01f74cd372f78da8f5247d3e73:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:41 +sast,Find Security Bugs,confirmed,ECB mode is insecure 2,,ECB mode is insecure,medium,ea0f905fc76f2739d5f10a1fd1e37a10:ECB_MODE:src/main/java/com/gitlab/security_products/tests/App.java:29 +``` diff --git a/doc/api/vulnerability_issue_links.md b/doc/api/vulnerability_issue_links.md new file mode 100644 index 00000000000..05213e788c4 --- /dev/null +++ b/doc/api/vulnerability_issue_links.md @@ -0,0 +1,217 @@ +# Vulnerability Issue links API **(ULTIMATE)** + +CAUTION: **Caution:** +This API is in an alpha stage and considered unstable. +The response payload may be subject to change or breakage +across GitLab releases. + +## List related issues + +Get a list of related issues of a given issue, sorted by the relationship creation datetime (ascending). +Issues will be filtered according to the user authorizations. + +```plaintext +GET /projects/:id/issues/:issue_iid/links +``` + +Parameters: + +| Attribute | Type | Required | Description | +|-------------|---------|----------|--------------------------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `issue_iid` | integer | yes | The internal ID of a project's issue | + +```json +[ + { + "id" : 84, + "iid" : 14, + "issue_link_id": 1 + "project_id" : 4, + "created_at" : "2016-01-07T12:44:33.959Z", + "title" : "Issues with auth", + "state" : "opened", + "assignees" : [], + "assignee" : null, + "labels" : [ + "bug" + ], + "author" : { + "name" : "Alexandra Bashirian", + "avatar_url" : null, + "state" : "active", + "web_url" : "https://gitlab.example.com/eileen.lowe", + "id" : 18, + "username" : "eileen.lowe" + }, + "description" : null, + "updated_at" : "2016-01-07T12:44:33.959Z", + "milestone" : null, + "subscribed" : true, + "user_notes_count": 0, + "due_date": null, + "web_url": "http://example.com/example/example/issues/14", + "confidential": false, + "weight": null, + } +] +``` + +## Create an issue link + +Creates a two-way relation between two issues. User must be allowed to update both issues in order to succeed. + +```plaintext +POST /projects/:id/issues/:issue_iid/links +``` + +| Attribute | Type | Required | Description | +|-------------|---------|----------|--------------------------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `issue_iid` | integer | yes | The internal ID of a project's issue | +| `target_project_id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) of a target project | +| `target_issue_iid` | integer or string | yes | The internal ID of a target project's issue | + +```json +{ + "source_issue" : { + "id" : 83, + "iid" : 11, + "project_id" : 4, + "created_at" : "2016-01-07T12:44:33.959Z", + "title" : "Issues with auth", + "state" : "opened", + "assignees" : [], + "assignee" : null, + "labels" : [ + "bug" + ], + "author" : { + "name" : "Alexandra Bashirian", + "avatar_url" : null, + "state" : "active", + "web_url" : "https://gitlab.example.com/eileen.lowe", + "id" : 18, + "username" : "eileen.lowe" + }, + "description" : null, + "updated_at" : "2016-01-07T12:44:33.959Z", + "milestone" : null, + "subscribed" : true, + "user_notes_count": 0, + "due_date": null, + "web_url": "http://example.com/example/example/issues/11", + "confidential": false, + "weight": null, + }, + "target_issue" : { + "id" : 84, + "iid" : 14, + "project_id" : 4, + "created_at" : "2016-01-07T12:44:33.959Z", + "title" : "Issues with auth", + "state" : "opened", + "assignees" : [], + "assignee" : null, + "labels" : [ + "bug" + ], + "author" : { + "name" : "Alexandra Bashirian", + "avatar_url" : null, + "state" : "active", + "web_url" : "https://gitlab.example.com/eileen.lowe", + "id" : 18, + "username" : "eileen.lowe" + }, + "description" : null, + "updated_at" : "2016-01-07T12:44:33.959Z", + "milestone" : null, + "subscribed" : true, + "user_notes_count": 0, + "due_date": null, + "web_url": "http://example.com/example/example/issues/14", + "confidential": false, + "weight": null, + } +} +``` + +## Delete an issue link + +Deletes an issue link, removing the two-way relationship. + +```plaintext +DELETE /projects/:id/issues/:issue_iid/links/:issue_link_id +``` + +| Attribute | Type | Required | Description | +|-------------|---------|----------|--------------------------------------| +| `id` | integer or string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `issue_iid` | integer | yes | The internal ID of a project's issue | +| `issue_link_id` | integer or string | yes | The ID of an issue relationship | + +```json +{ + "source_issue" : { + "id" : 83, + "iid" : 11, + "project_id" : 4, + "created_at" : "2016-01-07T12:44:33.959Z", + "title" : "Issues with auth", + "state" : "opened", + "assignees" : [], + "assignee" : null, + "labels" : [ + "bug" + ], + "author" : { + "name" : "Alexandra Bashirian", + "avatar_url" : null, + "state" : "active", + "web_url" : "https://gitlab.example.com/eileen.lowe", + "id" : 18, + "username" : "eileen.lowe" + }, + "description" : null, + "updated_at" : "2016-01-07T12:44:33.959Z", + "milestone" : null, + "subscribed" : true, + "user_notes_count": 0, + "due_date": null, + "web_url": "http://example.com/example/example/issues/11", + "confidential": false, + "weight": null, + }, + "target_issue" : { + "id" : 84, + "iid" : 14, + "project_id" : 4, + "created_at" : "2016-01-07T12:44:33.959Z", + "title" : "Issues with auth", + "state" : "opened", + "assignees" : [], + "assignee" : null, + "labels" : [ + "bug" + ], + "author" : { + "name" : "Alexandra Bashirian", + "avatar_url" : null, + "state" : "active", + "web_url" : "https://gitlab.example.com/eileen.lowe", + "id" : 18, + "username" : "eileen.lowe" + }, + "description" : null, + "updated_at" : "2016-01-07T12:44:33.959Z", + "milestone" : null, + "subscribed" : true, + "user_notes_count": 0, + "due_date": null, + "web_url": "http://example.com/example/example/issues/14", + "confidential": false, + "weight": null, + } +} +``` diff --git a/doc/development/packages.md b/doc/development/packages.md index 0880e053901..66b50ce12c8 100644 --- a/doc/development/packages.md +++ b/doc/development/packages.md @@ -63,6 +63,8 @@ The current state of existing package registries availability is: | Maven | Yes | Yes | Yes | | Conan | No - [open issue](https://gitlab.com/gitlab-org/gitlab/issues/11679) | No - [open issue](https://gitlab.com/gitlab-org/gitlab/issues/11679) | Yes | | NPM | No - [open issue](https://gitlab.com/gitlab-org/gitlab/issues/36853) | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/issues/36853) | +| NuGet | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36423) | No | +| PyPI | Yes | No | No | NOTE: **Note:** NPM is currently a hybrid of the instance level and group level. It is using the top-level group or namespace as the defining portion of the name diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md index cbfdf2d188c..f28bab6ad86 100644 --- a/doc/user/admin_area/settings/usage_statistics.md +++ b/doc/user/admin_area/settings/usage_statistics.md @@ -197,9 +197,11 @@ but commented out to help encourage others to add to it in the future. --> |clusters_enabled|counts|| |project_clusters_enabled|counts|| |group_clusters_enabled|counts|| +|instance_clusters_enabled|counts|| |clusters_disabled|counts|| |project_clusters_disabled|counts|| |group_clusters_disabled|counts|| +|instance_clusters_disabled|counts|| |clusters_platforms_eks|counts|| |clusters_platforms_gke|counts|| |clusters_platforms_user|counts|| @@ -211,6 +213,7 @@ but commented out to help encourage others to add to it in the future. --> |clusters_applications_runner|counts|| |clusters_applications_knative|counts|| |clusters_applications_elastic_stack|counts|| +|clusters_management_project|counts|| |in_review_folder|counts|| |grafana_integrated_projects|counts|| |groups|counts|| @@ -382,11 +385,14 @@ but commented out to help encourage others to add to it in the future. --> |clusters_applications_helm|usage_activity_by_stage|configure| |clusters_applications_ingress|usage_activity_by_stage|configure| |clusters_applications_knative|usage_activity_by_stage|configure| +|clusters_management_project|usage_activity_by_stage|configure| |clusters_disabled|usage_activity_by_stage|configure| |clusters_enabled|usage_activity_by_stage|configure| |clusters_platforms_gke|usage_activity_by_stage|configure| |clusters_platforms_eks|usage_activity_by_stage|configure| |clusters_platforms_user|usage_activity_by_stage|configure| +|instance_clusters_disabled|usage_activity_by_stage|configure| +|instance_clusters_enabled|usage_activity_by_stage|configure| |group_clusters_disabled|usage_activity_by_stage|configure| |group_clusters_enabled|usage_activity_by_stage|configure| |project_clusters_disabled|usage_activity_by_stage|configure| diff --git a/doc/user/application_security/offline_deployments/index.md b/doc/user/application_security/offline_deployments/index.md index db309357530..5a5f149a3bf 100644 --- a/doc/user/application_security/offline_deployments/index.md +++ b/doc/user/application_security/offline_deployments/index.md @@ -78,3 +78,4 @@ above. You can find more information at each of the pages below: - [Container scanning offline directions](../container_scanning/index.md#running-container-scanning-in-an-offline-environment) - [SAST offline directions](../sast/index.md#gitlab-sast-in-an-offline-environment) - [DAST offline directions](../dast/index.md#running-dast-in-an-offline-environment) +- [License Compliance offline directions](../../compliance/license_compliance/index.md#running-license-compliance-in-an-offline-environment) diff --git a/doc/user/application_security/vulnerabilities/img/standalone_vulnerability_page_v12_10.png b/doc/user/application_security/vulnerabilities/img/standalone_vulnerability_page_v12_10.png Binary files differnew file mode 100644 index 00000000000..0fdb8d1e201 --- /dev/null +++ b/doc/user/application_security/vulnerabilities/img/standalone_vulnerability_page_v12_10.png diff --git a/doc/user/application_security/vulnerabilities/index.md b/doc/user/application_security/vulnerabilities/index.md new file mode 100644 index 00000000000..5cb4f16e0d8 --- /dev/null +++ b/doc/user/application_security/vulnerabilities/index.md @@ -0,0 +1,69 @@ +--- +type: reference, howto +--- + +# Standalone Vulnerability pages + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13561) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10. + +CAUTION: **Warning:** +This feature is currently [Alpha](https://about.gitlab.com/handbook/product/#alpha-beta-ga). +You can begin using it, but it may receive important changes in the future. + +Each security vulnerability in the [Vulnerability List](../dependency_list/index.md) has its own standalone +page. + +![Standalone vulnerability page](img/standalone_vulnerability_page_v12_10.png) + +On the standalone vulnerability page, you can interact with the vulnerability in +several different ways: + +- [Change the Vulnerability Status](#changing-vulnerability-status) - You can change the + status of a vulnerability to **Detected**, **Confirmed**, **Dismissed**, or **Resolved**. +- [Create issue](#creating-an-issue-for-a-vulnerability) - Create a new issue with the + title and description prepopulated with information from the vulnerability report. + By default, such issues are [confidential](../../project/issues/confidential_issues.md). +- [Solution](#automatic-remediation-solutions-for-vulnerabilities) - For some vulnerabilities, + a solution is provided for how to fix the vulnerability. + +## Changing vulnerability status + +You can switch the status of a vulnerability using the **Status** dropdown to one of +the following values: + +| State | Description | +|-----------|-------------------------------------------------------------------| +| Detected | The default state for a newly discovered vulnerability | +| Confirmed | A user has seen this vulnerability and confirmed it to be real | +| Dismissed | A user has seen this vulnerability and dismissed it | +| Resolved | The vulnerability has been fixed and is no longer in the codebase | + +## Creating an issue for a vulnerability + +You can create an issue for a vulnerability by selecting the **Create issue** button. + +This creates a [confidential issue](../../project/issues/confidential_issues.md) in the +project the vulnerability came from, and prepopulates it with useful information from +the vulnerability report. After the issue is created, GitLab redirects you to the +issue page so you can edit, assign, or comment on the issue. + +## Automatic remediation solutions for vulnerabilities + +You can fix some vulnerabilities by applying the solution that GitLab automatically +generates for you. GitLab supports the following scanners: + +- [Dependency Scanning](../dependency_scanning/index.md): Automatic Patch creation + is only available for Node.js projects managed with `yarn`. +- [Container Scanning](../container_scanning/index.md). + +### Manually applying a suggested patch + +To apply a patch automatically generated by GitLab to fix a vulnerability: + +1. Open the issue created in [Create issue](#creating-an-issue-for-a-vulnerability). +1. In the **Issue description**, scroll to **Solution** and download the linked patch file. +1. Ensure your local project has the same commit checked out that was used to generate the patch. +1. Run `git apply remediation.patch` to apply the patch. +1. Verify and commit the changes to your branch. + +![Apply patch for dependency scanning](../img/vulnerability_solution.png) diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md index 485e9d8213d..9fcc9acf5ea 100644 --- a/doc/user/compliance/license_compliance/index.md +++ b/doc/user/compliance/license_compliance/index.md @@ -198,6 +198,22 @@ you can use the `MAVEN_CLI_OPTS` environment variable. Read more on [how to use private Maven repos](../../application_security/index.md#using-private-maven-repos). +You can also use `MAVEN_CLI_OPTS` to connect to a trusted Maven repository that uses a self-signed +or internally trusted certificate. For example: + +```yaml +include: + - template: License-Scanning.gitlab-ci.yml + +license_scanning: + variables: + MAVEN_CLI_OPTS: -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true -Dmaven.wagon.http.ssl.insecure=true +``` + +Alternatively, you can use a Java key store to verify the TLS connection. For instructions on how to +generate a key store file, see the +[Maven Guide to Remote repository access through authenticated HTTPS](http://maven.apache.org/guides/mini/guide-repository-ssl.html). + ### Selecting the version of Python > - [Introduced](https://gitlab.com/gitlab-org/security-products/license-management/-/merge_requests/36) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0. @@ -305,6 +321,9 @@ process: 1. Ensure the package registry is reachable from within the GitLab environment and that the package manager is configured to use your preferred package registry. +Additional [configuration](#using-private-maven-repos) may be needed for connecting to private Maven +repositories. + ## Project policies for License Compliance > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/5940) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.4. diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 76a33559666..fabe6fd40c9 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -57,7 +57,7 @@ The following table depicts the various user permission levels in a project. | View Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View License list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View licenses in Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | +| View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | | View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control-core) | ✓ | ✓ | ✓ | ✓ | ✓ | @@ -84,15 +84,15 @@ The following table depicts the various user permission levels in a project. | See a list of merge requests | | ✓ | ✓ | ✓ | ✓ | | View project statistics | | ✓ | ✓ | ✓ | ✓ | | View Error Tracking list | | ✓ | ✓ | ✓ | ✓ | -| Create/edit/delete [Releases](project/releases/index.md)| | | ✓ | ✓ | ✓ | +| Create new merge request | | ✓ | ✓ | ✓ | ✓ | | Pull from [Conan repository](packages/conan_repository/index.md), [Maven repository](packages/maven_repository/index.md), or [NPM registry](packages/npm_registry/index.md) **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | | Publish to [Conan repository](packages/conan_repository/index.md), [Maven repository](packages/maven_repository/index.md), or [NPM registry](packages/npm_registry/index.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ | -| Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ | +| Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ | +| Create/edit/delete [Releases](project/releases/index.md)| | | ✓ | ✓ | ✓ | | Create new branches | | | ✓ | ✓ | ✓ | | Push to non-protected branches | | | ✓ | ✓ | ✓ | | Force push to non-protected branches | | | ✓ | ✓ | ✓ | | Remove non-protected branches | | | ✓ | ✓ | ✓ | -| Create new merge request | | ✓ | ✓ | ✓ | ✓ | | Assign merge requests | | | ✓ | ✓ | ✓ | | Label merge requests | | | ✓ | ✓ | ✓ | | Lock merge request threads | | | ✓ | ✓ | ✓ | @@ -107,8 +107,12 @@ The following table depicts the various user permission levels in a project. | Remove a container registry image | | | ✓ | ✓ | ✓ | | Create/edit/delete project milestones | | | ✓ | ✓ | ✓ | | Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| View vulnerabilities in Dependency list **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| Create issue from vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| View vulnerability findings in Dependency list **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| Create issue from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| Dismiss vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| View vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| Create vulnerability from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| Resolve vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | | Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | | Apply code change suggestions | | | ✓ | ✓ | ✓ | | Create and edit wiki pages | | | ✓ | ✓ | ✓ | @@ -217,21 +221,21 @@ group. | View group epic **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ | | Create/edit group epic **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ | | Manage group labels | | ✓ | ✓ | ✓ | ✓ | +| See a container registry | | ✓ | ✓ | ✓ | ✓ | | Create project in group | | | ✓ (3) | ✓ (3) | ✓ (3) | | Create/edit/delete group milestones | | | ✓ | ✓ | ✓ | -| See a container registry | | ✓ | ✓ | ✓ | ✓ | | Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ | | Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ | +| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ | | Create subgroup | | | | ✓ (1) | ✓ | +| Edit epic comments (posted by any user) **(ULTIMATE)** | | | | ✓ (2) | ✓ (2) | | Edit group | | | | | ✓ | | Manage group level CI/CD variables | | | | | ✓ | | Manage group members | | | | | ✓ | | Remove group | | | | | ✓ | | Delete group epic **(ULTIMATE)** | | | | | ✓ | -| Edit epic comments (posted by any user) **(ULTIMATE)** | | | | ✓ (2) | ✓ (2) | | View group Audit Events | | | | | ✓ | | Disable notification emails | | | | | ✓ | -| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ | 1. Groups can be set to [allow either Owners or Owners and Maintainers to create subgroups](group/subgroups/index.md#creating-a-subgroup) diff --git a/lib/gitlab/git_access_result/custom_action.rb b/lib/gitlab/git_access_result/custom_action.rb index 336f3405f72..e03459ea7a1 100644 --- a/lib/gitlab/git_access_result/custom_action.rb +++ b/lib/gitlab/git_access_result/custom_action.rb @@ -10,7 +10,7 @@ module Gitlab # { # 'action' => 'geo_proxy_to_primary', # 'data' => { - # 'api_endpoints' => %w{geo/proxy_git_push_ssh/info_refs geo/proxy_git_push_ssh/push}, + # 'api_endpoints' => %w{geo/proxy_git_ssh/info_refs_receive_pack geo/proxy_git_ssh/receive_pack}, # 'gl_username' => user.username, # 'primary_repo' => geo_primary_http_url_to_repo(project_or_wiki) # } diff --git a/lib/gitlab/jira_import/base_importer.rb b/lib/gitlab/jira_import/base_importer.rb index afb443020b7..5fbdbbc08c1 100644 --- a/lib/gitlab/jira_import/base_importer.rb +++ b/lib/gitlab/jira_import/base_importer.rb @@ -6,7 +6,7 @@ module Gitlab attr_reader :project, :client, :formatter, :jira_project_key def initialize(project) - raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless Feature.enabled?(:jira_issue_import, project) + raise Projects::ImportService::Error, _('Jira import feature is disabled.') unless project.jira_issues_import_feature_flag_enabled? raise Projects::ImportService::Error, _('Jira integration not configured.') unless project.jira_service&.active? @jira_project_key = project.latest_jira_import&.jira_project_key diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb index 37688d6e0e7..9a7b4cc65f6 100644 --- a/lib/gitlab/tracking.rb +++ b/lib/gitlab/tracking.rb @@ -9,6 +9,13 @@ module Gitlab module ControllerConcern extend ActiveSupport::Concern + included do + # Tracking events from the template is not ideal and we are moving this to the client in https://gitlab.com/gitlab-org/gitlab/-/issues/213712 + # In the meantime, using this method from the view is frowned upon and this line will likely be removed + # in the near future + helper_method :track_event + end + protected def track_event(action = action_name, **args) diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 6c98f8f5585..f4afcd962af 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -68,9 +68,11 @@ module Gitlab clusters_enabled: count(::Clusters::Cluster.enabled), project_clusters_enabled: count(::Clusters::Cluster.enabled.project_type), group_clusters_enabled: count(::Clusters::Cluster.enabled.group_type), + instance_clusters_enabled: count(::Clusters::Cluster.enabled.instance_type), clusters_disabled: count(::Clusters::Cluster.disabled), project_clusters_disabled: count(::Clusters::Cluster.disabled.project_type), group_clusters_disabled: count(::Clusters::Cluster.disabled.group_type), + instance_clusters_disabled: count(::Clusters::Cluster.disabled.instance_type), clusters_platforms_eks: count(::Clusters::Cluster.aws_installed.enabled), clusters_platforms_gke: count(::Clusters::Cluster.gcp_installed.enabled), clusters_platforms_user: count(::Clusters::Cluster.user_provided.enabled), @@ -83,6 +85,7 @@ module Gitlab clusters_applications_knative: count(::Clusters::Applications::Knative.available), clusters_applications_elastic_stack: count(::Clusters::Applications::ElasticStack.available), clusters_applications_jupyter: count(::Clusters::Applications::Jupyter.available), + clusters_management_project: count(::Clusters::Cluster.with_management_project), in_review_folder: count(::Environment.in_review_folder), grafana_integrated_projects: count(GrafanaIntegration.enabled), groups: count(Group), diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 3aedf132df0..68210a23b60 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -931,6 +931,9 @@ msgstr "" msgid "Accept terms" msgstr "" +msgid "Acceptable for use in this project" +msgstr "" + msgid "Accepted MR" msgstr "" @@ -4001,6 +4004,9 @@ msgstr "" msgid "Class" msgstr "" +msgid "Class:" +msgstr "" + msgid "Classification Label (optional)" msgstr "" @@ -6645,6 +6651,11 @@ msgid_plural "Dependencies|%d vulnerabilities" msgstr[0] "" msgstr[1] "" +msgid "Dependencies|%d vulnerability detected" +msgid_plural "Dependencies|%d vulnerabilities detected" +msgstr[0] "" +msgstr[1] "" + msgid "Dependencies|%{remainingLicensesCount} more" msgstr "" @@ -6684,6 +6695,9 @@ msgstr "" msgid "Dependencies|The %{codeStartTag}dependency_scanning%{codeEndTag} job has failed and cannot generate the list. Please ensure the job is running properly and run the pipeline again." msgstr "" +msgid "Dependencies|Toggle vulnerability list" +msgstr "" + msgid "Dependencies|Unsupported file(s) detected" msgstr "" @@ -8999,6 +9013,9 @@ msgstr "" msgid "File upload error." msgstr "" +msgid "File:" +msgstr "" + msgid "Files" msgstr "" @@ -12000,6 +12017,15 @@ msgstr "" msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project." msgstr "" +msgid "LicenseManagement|Allowed" +msgstr "" + +msgid "LicenseManagement|Denied" +msgstr "" + +msgid "LicenseManagement|Uncategorized" +msgstr "" + msgid "Licensed Features" msgstr "" @@ -12173,6 +12199,9 @@ msgstr "" msgid "Localization" msgstr "" +msgid "Location" +msgstr "" + msgid "Lock" msgstr "" @@ -12752,6 +12781,9 @@ msgstr "" msgid "Method" msgstr "" +msgid "Method:" +msgstr "" + msgid "Metric was successfully added." msgstr "" @@ -13556,6 +13588,9 @@ msgstr "" msgid "No pods available" msgstr "" +msgid "No policy matches this license" +msgstr "" + msgid "No preview for this file type" msgstr "" @@ -14086,6 +14121,9 @@ msgstr "" msgid "Other visibility settings have been disabled by the administrator." msgstr "" +msgid "Out-of-compliance with this project's policies and should be removed" +msgstr "" + msgid "Outbound requests" msgstr "" @@ -17850,9 +17888,6 @@ msgstr "" msgid "SecurityConfiguration|Status" msgstr "" -msgid "SecurityDashboard| The security dashboard displays the latest security report. Use it to find and fix vulnerabilities." -msgstr "" - msgid "SecurityDashboard|%{firstProject} and %{secondProject}" msgstr "" @@ -17913,6 +17948,9 @@ msgstr "" msgid "SecurityDashboard|The security dashboard displays the latest security findings for projects you wish to monitor. Select \"Edit dashboard\" to add and remove projects." msgstr "" +msgid "SecurityDashboard|The security dashboard displays the latest security report. Use it to find and fix vulnerabilities." +msgstr "" + msgid "SecurityDashboard|Unable to add %{invalidProjects}" msgstr "" @@ -18324,6 +18362,12 @@ msgstr "" msgid "Set up CI/CD" msgstr "" +msgid "Set up Jira Integration" +msgstr "" + +msgid "Set up Jira Integration illustration" +msgstr "" + msgid "Set up a %{type} Runner automatically" msgstr "" @@ -23583,6 +23627,9 @@ msgstr "" msgid "You will be removed from existing projects/groups" msgstr "" +msgid "You will first need to set up Jira Integration to use this feature." +msgstr "" + msgid "You will lose all changes you've made to this file. This action cannot be undone." msgstr "" diff --git a/package.json b/package.json index 82a757e3a54..a0abec5643f 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,8 @@ "@babel/plugin-syntax-import-meta": "^7.8.3", "@babel/preset-env": "^7.8.4", "@gitlab/at.js": "1.5.5", - "@gitlab/svgs": "1.117.0", - "@gitlab/ui": "11.1.0", + "@gitlab/svgs": "1.119.0", + "@gitlab/ui": "11.2.1", "@gitlab/visual-review-tools": "1.5.1", "@sentry/browser": "^5.10.2", "@sourcegraph/code-host-integration": "0.0.34", diff --git a/spec/controllers/groups/shared_projects_controller_spec.rb b/spec/controllers/groups/shared_projects_controller_spec.rb index a4b2efa7c43..a31b5682ae0 100644 --- a/spec/controllers/groups/shared_projects_controller_spec.rb +++ b/spec/controllers/groups/shared_projects_controller_spec.rb @@ -13,7 +13,7 @@ describe Groups::SharedProjectsController do Projects::GroupLinks::CreateService.new( project, user, - link_group_access: ProjectGroupLink::DEVELOPER + link_group_access: Gitlab::Access::DEVELOPER ).execute(group) end diff --git a/spec/factories/group_group_links.rb b/spec/factories/group_group_links.rb index 0711a15b8dd..6f98886faff 100644 --- a/spec/factories/group_group_links.rb +++ b/spec/factories/group_group_links.rb @@ -4,6 +4,12 @@ FactoryBot.define do factory :group_group_link do shared_group { create(:group) } shared_with_group { create(:group) } - group_access { GroupMember::DEVELOPER } + group_access { Gitlab::Access::DEVELOPER } + + trait(:guest) { group_access { Gitlab::Access::GUEST } } + trait(:reporter) { group_access { Gitlab::Access::REPORTER } } + trait(:developer) { group_access { Gitlab::Access::DEVELOPER } } + trait(:owner) { group_access { Gitlab::Access::OWNER } } + trait(:maintainer) { group_access { Gitlab::Access::MAINTAINER } } end end diff --git a/spec/factories/project_group_links.rb b/spec/factories/project_group_links.rb index 3c8c7a34680..b9119a5788b 100644 --- a/spec/factories/project_group_links.rb +++ b/spec/factories/project_group_links.rb @@ -5,5 +5,10 @@ FactoryBot.define do project group expires_at { nil } + + trait(:guest) { group_access { Gitlab::Access::GUEST } } + trait(:reporter) { group_access { Gitlab::Access::REPORTER } } + trait(:developer) { group_access { Gitlab::Access::DEVELOPER } } + trait(:maintainer) { group_access { Gitlab::Access::MAINTAINER } } end end diff --git a/spec/factories/usage_data.rb b/spec/factories/usage_data.rb index da69a0fb844..b633038b83b 100644 --- a/spec/factories/usage_data.rb +++ b/spec/factories/usage_data.rb @@ -39,12 +39,14 @@ FactoryBot.define do gcp_cluster = create(:cluster_provider_gcp, :created).cluster create(:cluster_provider_aws, :created) create(:cluster_platform_kubernetes) + create(:cluster, :management_project, management_project: projects[0]) create(:cluster, :group) + create(:cluster, :instance, :production_environment) # Disabled clusters create(:cluster, :disabled) create(:cluster, :group, :disabled) - create(:cluster, :group, :disabled) + create(:cluster, :instance, :disabled) # Applications create(:clusters_applications_helm, :installed, cluster: gcp_cluster) diff --git a/spec/finders/group_descendants_finder_spec.rb b/spec/finders/group_descendants_finder_spec.rb index 8d3564ca3c0..a08772c6e7e 100644 --- a/spec/finders/group_descendants_finder_spec.rb +++ b/spec/finders/group_descendants_finder_spec.rb @@ -123,7 +123,7 @@ describe GroupDescendantsFinder do project = create(:project, namespace: group) other_project = create(:project) other_project.project_group_links.create(group: group, - group_access: ProjectGroupLink::MAINTAINER) + group_access: Gitlab::Access::MAINTAINER) expect(finder.execute).to contain_exactly(project) end diff --git a/spec/frontend/jira_import/components/jira_import_app_spec.js b/spec/frontend/jira_import/components/jira_import_app_spec.js new file mode 100644 index 00000000000..fb3ffe1ede3 --- /dev/null +++ b/spec/frontend/jira_import/components/jira_import_app_spec.js @@ -0,0 +1,38 @@ +import { shallowMount } from '@vue/test-utils'; +import JiraImportApp from '~/jira_import/components/jira_import_app.vue'; +import JiraImportSetup from '~/jira_import/components/jira_import_setup.vue'; + +describe('JiraImportApp', () => { + let wrapper; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('set up Jira integration page', () => { + beforeEach(() => { + wrapper = shallowMount(JiraImportApp, { + propsData: { + isJiraConfigured: true, + projectPath: 'gitlab-org/gitlab-test', + setupIllustration: 'illustration.svg', + }, + }); + }); + + it('is shown when Jira integration is not configured', () => { + wrapper.setProps({ + isJiraConfigured: false, + }); + + return wrapper.vm.$nextTick(() => { + expect(wrapper.find(JiraImportSetup).exists()).toBe(true); + }); + }); + + it('is not shown when Jira integration is configured', () => { + expect(wrapper.find(JiraImportSetup).exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/jira_import/components/jira_import_setup_spec.js b/spec/frontend/jira_import/components/jira_import_setup_spec.js new file mode 100644 index 00000000000..27366bd7e8a --- /dev/null +++ b/spec/frontend/jira_import/components/jira_import_setup_spec.js @@ -0,0 +1,28 @@ +import { shallowMount } from '@vue/test-utils'; +import JiraImportSetup from '~/jira_import/components/jira_import_setup.vue'; + +describe('JiraImportSetup', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(JiraImportSetup, { + propsData: { + illustration: 'illustration.svg', + }, + }); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('displays a message to the user', () => { + const message = 'You will first need to set up Jira Integration to use this feature.'; + expect(wrapper.find('p').text()).toBe(message); + }); + + it('contains button to set up Jira integration', () => { + expect(wrapper.find('a').text()).toBe('Set up Jira Integration'); + }); +}); diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 12199bc6d5a..9457e2cd549 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -58,13 +58,14 @@ describe Gitlab::UsageData, :aggregate_failures do expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2) expect(count_data[:incident_issues]).to eq(4) - expect(count_data[:clusters_enabled]).to eq(4) - expect(count_data[:project_clusters_enabled]).to eq(3) + expect(count_data[:clusters_enabled]).to eq(6) + expect(count_data[:project_clusters_enabled]).to eq(4) expect(count_data[:group_clusters_enabled]).to eq(1) + expect(count_data[:instance_clusters_enabled]).to eq(1) expect(count_data[:clusters_disabled]).to eq(3) expect(count_data[:project_clusters_disabled]).to eq(1) - expect(count_data[:group_clusters_disabled]).to eq(2) - expect(count_data[:group_clusters_enabled]).to eq(1) + expect(count_data[:group_clusters_disabled]).to eq(1) + expect(count_data[:instance_clusters_disabled]).to eq(1) expect(count_data[:clusters_platforms_eks]).to eq(1) expect(count_data[:clusters_platforms_gke]).to eq(1) expect(count_data[:clusters_platforms_user]).to eq(1) @@ -78,6 +79,7 @@ describe Gitlab::UsageData, :aggregate_failures do expect(count_data[:clusters_applications_elastic_stack]).to eq(1) expect(count_data[:grafana_integrated_projects]).to eq(2) expect(count_data[:clusters_applications_jupyter]).to eq(1) + expect(count_data[:clusters_management_project]).to eq(1) end it 'works when queries time out' do diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 8685838fdde..29c75186110 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -156,6 +156,22 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do end end + describe '.with_management_project' do + subject { described_class.with_management_project } + + context 'cluster has a management project' do + let!(:cluster) { create(:cluster, :management_project) } + + it { is_expected.to include(cluster) } + end + + context 'cluster does not have a management project' do + let!(:cluster) { create(:cluster) } + + it { is_expected.not_to include(cluster) } + end + end + describe '.for_project_namespace' do subject { described_class.for_project_namespace(namespace_id) } diff --git a/spec/models/group_group_link_spec.rb b/spec/models/group_group_link_spec.rb index a877cc803dd..1fbd399e82b 100644 --- a/spec/models/group_group_link_spec.rb +++ b/spec/models/group_group_link_spec.rb @@ -15,6 +15,22 @@ describe GroupGroupLink do it { is_expected.to belong_to(:shared_with_group) } end + describe 'scopes' do + describe '.non_guests' do + let!(:group_group_link_reporter) { create :group_group_link, :reporter } + let!(:group_group_link_maintainer) { create :group_group_link, :maintainer } + let!(:group_group_link_owner) { create :group_group_link, :owner } + let!(:group_group_link_guest) { create :group_group_link, :guest } + + it 'returns all records which are greater than Guests access' do + expect(described_class.non_guests).to match_array([ + group_group_link_reporter, group_group_link, + group_group_link_maintainer, group_group_link_owner + ]) + end + end + end + describe 'validation' do it { is_expected.to validate_presence_of(:shared_group) } diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index 63ce08c4d30..9c51180b55b 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -32,6 +32,23 @@ describe ProjectGroupLink do end end + describe 'scopes' do + describe '.non_guests' do + let!(:project_group_link_reporter) { create :project_group_link, :reporter } + let!(:project_group_link_maintainer) { create :project_group_link, :maintainer } + let!(:project_group_link_developer) { create :project_group_link } + let!(:project_group_link_guest) { create :project_group_link, :guest } + + it 'returns all records which are greater than Guests access' do + expect(described_class.non_guests).to match_array([ + project_group_link_reporter, + project_group_link_developer, + project_group_link_maintainer + ]) + end + end + end + describe "destroying a record", :delete do it "refreshes group users' authorized projects" do project = create(:project, :private) diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb index 0629d51154b..dc75fdab639 100644 --- a/spec/requests/api/internal/base_spec.rb +++ b/spec/requests/api/internal/base_spec.rb @@ -582,7 +582,7 @@ describe API::Internal::Base do { 'action' => 'geo_proxy_to_primary', 'data' => { - 'api_endpoints' => %w{geo/proxy_git_push_ssh/info_refs geo/proxy_git_push_ssh/push}, + 'api_endpoints' => %w{geo/proxy_git_ssh/info_refs_receive_pack geo/proxy_git_ssh/receive_pack}, 'gl_username' => 'testuser', 'primary_repo' => 'http://localhost:3000/testuser/repo.git' } diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb index 4d63cf12575..eff252ddda0 100644 --- a/spec/support/helpers/usage_data_helpers.rb +++ b/spec/support/helpers/usage_data_helpers.rb @@ -43,9 +43,11 @@ module UsageDataHelpers clusters_enabled project_clusters_enabled group_clusters_enabled + instance_clusters_enabled clusters_disabled project_clusters_disabled group_clusters_disabled + instance_clusters_disabled clusters_platforms_eks clusters_platforms_gke clusters_platforms_user @@ -58,6 +60,7 @@ module UsageDataHelpers clusters_applications_knative clusters_applications_elastic_stack clusters_applications_jupyter + clusters_management_project in_review_folder grafana_integrated_projects groups diff --git a/spec/support/shared_examples/models/concerns/blob_replicator_strategy_shared_examples.rb b/spec/support/shared_examples/models/concerns/blob_replicator_strategy_shared_examples.rb index 62b1b5791dc..8372ee9ac4a 100644 --- a/spec/support/shared_examples/models/concerns/blob_replicator_strategy_shared_examples.rb +++ b/spec/support/shared_examples/models/concerns/blob_replicator_strategy_shared_examples.rb @@ -52,6 +52,7 @@ RSpec.shared_examples 'a blob replicator' do replicator.calculate_checksum! expect(model_record.reload.verification_checksum).not_to be_nil + expect(model_record.reload.verified_at).not_to be_nil end it 'saves the error message and increments retry counter' do diff --git a/yarn.lock b/yarn.lock index acd0bcfd7e3..42a5c0d29c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -781,15 +781,15 @@ eslint-plugin-vue "^6.2.1" vue-eslint-parser "^7.0.0" -"@gitlab/svgs@1.117.0": - version "1.117.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.117.0.tgz#05239ddcf529c62ca29e1ec1a25a7e24efb98207" - integrity sha512-dGy/VWuRAFCTZX3Yqu1+RnAHTSUWafteIk/RMfUCN9B/EMbYzjhYsNy0NLVoZ23Rj/KGv1bUGHvyQCoPP6VzpA== - -"@gitlab/ui@11.1.0": - version "11.1.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-11.1.0.tgz#72dd6d4309909fd1874f8abc42be8365e875822e" - integrity sha512-lmHTIUIYuUSGiisvnndhpUASvXZokP8/1LBfws9qkbEFPnMIvJAxGRHo3F7dLjcDBCvy4xepgDFFjI6HNFhLWA== +"@gitlab/svgs@1.119.0": + version "1.119.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.119.0.tgz#ff35c160b1e726f4f1702a4a152712fb669cde4e" + integrity sha512-bI+kewDLJy1N0//BpUPMx3h5AqG6lfIiV53lxQP9ttn8j/jhyxigZXq1wZ901PI4/ALv9IY1DOSSuLouK4sJsQ== + +"@gitlab/ui@11.2.1": + version "11.2.1" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-11.2.1.tgz#c031c92204eb2a6036ae3c7482387f66c75524fd" + integrity sha512-AhDPYmrBtaW6Qu+inSjoMCWx+Ou3CVIhhGAEjyVsAG7rSOilevVMZui2IlSb6fPtLcXS8F78DTWjp3R1YgxxbQ== dependencies: "@babel/standalone" "^7.0.0" "@gitlab/vue-toasted" "^1.3.0" |