diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a5b80c7ca55..b7c00e180fd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ stages: # in cases where jobs require Docker-in-Docker, the job # definition must be extended with `.use-docker-in-docker` default: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" tags: - gitlab-org # All jobs are interruptible by default diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 084a48a7fc6..27f56cd8667 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -11,7 +11,7 @@ extends: - .frontend-base - .assets-compile-cache - image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.27-lfs-2.9-node-12.x-yarn-1.21-graphicsmagick-1.3.34 + image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.28-lfs-2.9-node-12.x-yarn-1.21-graphicsmagick-1.3.34 variables: WEBPACK_VENDOR_DLL: "true" stage: prepare diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index 3101a42c058..ae8db21c99c 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -64,7 +64,7 @@ policy: pull .use-pg11: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" services: - name: postgres:11.6 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -73,7 +73,7 @@ POSTGRES_HOST_AUTH_METHOD: trust .use-pg12: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34" services: - name: postgres:12 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -82,7 +82,7 @@ POSTGRES_HOST_AUTH_METHOD: trust .use-pg11-ee: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" services: - name: postgres:11.6 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -92,7 +92,7 @@ POSTGRES_HOST_AUTH_METHOD: trust .use-pg12-ee: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34" services: - name: postgres:12 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] diff --git a/.gitlab/issue_templates/Security Release.md b/.gitlab/issue_templates/Security Release Tracking Issue.md similarity index 70% rename from .gitlab/issue_templates/Security Release.md rename to .gitlab/issue_templates/Security Release Tracking Issue.md index b06f31f0e9a..3d21b85c82f 100644 --- a/.gitlab/issue_templates/Security Release.md +++ b/.gitlab/issue_templates/Security Release Tracking Issue.md @@ -8,12 +8,6 @@ Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X` ------- -## Releases tasks - -- https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/release-manager.md -- https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md -- https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/security-engineer.md - ## Version issues: 12.2.X, 12.1.X, 12.0.X: {release task link} @@ -25,12 +19,9 @@ your security issues as related to this release tracking issue. You can do this in the "Linked issues" section below this issue description. :warning: If your security issues are not marked as related to this release -tracking issue, their merge requests may not be included in the security +tracking issue, their merge requests will not be included in the security release. -## QA -{QA issue link} - ## Blog post Dev: {https://dev.gitlab.org/gitlab/www-gitlab-com/merge_requests/ link}
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md index 89539289dcb..d21da6a161b 100644 --- a/.gitlab/issue_templates/Security developer workflow.md +++ b/.gitlab/issue_templates/Security developer workflow.md @@ -28,8 +28,8 @@ After your merge request has been approved according to our [approval guidelines * You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation] - [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template]. * Every merge request will have its own set of TODOs, so make sure to complete those. -- [ ] On the "Related merge requests" section, ensure all MRs are linked to this issue. - * This section should only list the merge requests created for this issue: One targeting `master` and the 3 backports. +- [ ] On the "Related merge requests" section, ensure that `4` merge requests are associated: The one targeting `master` and the `3` backports. +- [ ] If this issue requires less than `4` merge requests, post a message on the Security Release Tracking Issue and ping the Release Managers. ## Documentation and final details diff --git a/Gemfile b/Gemfile index f346bdfac70..9a23c4f7d11 100644 --- a/Gemfile +++ b/Gemfile @@ -464,9 +464,9 @@ end # Gitaly GRPC protocol definitions gem 'gitaly', '~> 13.3.0-rc1' -gem 'grpc', '~> 1.24.0' +gem 'grpc', '~> 1.30.2' -gem 'google-protobuf', '~> 3.8.0' +gem 'google-protobuf', '~> 3.12' gem 'toml-rb', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 5f4f5252f5a..257cfb6b52c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -450,9 +450,9 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.0) signet (~> 0.12) - google-protobuf (3.8.0) - googleapis-common-protos-types (1.0.4) - google-protobuf (~> 3.0) + google-protobuf (3.12.4) + googleapis-common-protos-types (1.0.5) + google-protobuf (~> 3.11) googleauth (0.12.0) faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) @@ -491,8 +491,8 @@ GEM graphql (~> 1.6) html-pipeline (~> 2.8) sass (~> 3.4) - grpc (1.24.0) - google-protobuf (~> 3.8) + grpc (1.30.2) + google-protobuf (~> 3.12) googleapis-common-protos-types (~> 1.0) gssapi (1.2.0) ffi (>= 1.0.1) @@ -1278,7 +1278,7 @@ DEPENDENCIES gitlab_omniauth-ldap (~> 2.1.1) gon (~> 6.2) google-api-client (~> 0.33) - google-protobuf (~> 3.8.0) + google-protobuf (~> 3.12) gpgme (~> 2.0.19) grape (= 1.4.0) grape-entity (~> 0.7.1) @@ -1287,7 +1287,7 @@ DEPENDENCIES graphiql-rails (~> 1.4.10) graphql (~> 1.10.5) graphql-docs (~> 1.6.0) - grpc (~> 1.24.0) + grpc (~> 1.30.2) gssapi guard-rspec haml_lint (~> 0.34.0) diff --git a/app/assets/javascripts/blob/file_template_mediator.js b/app/assets/javascripts/blob/file_template_mediator.js index d2c0ef330e4..c9051338972 100644 --- a/app/assets/javascripts/blob/file_template_mediator.js +++ b/app/assets/javascripts/blob/file_template_mediator.js @@ -7,6 +7,7 @@ import BlobCiYamlSelector from './template_selectors/ci_yaml_selector'; import DockerfileSelector from './template_selectors/dockerfile_selector'; import GitignoreSelector from './template_selectors/gitignore_selector'; import LicenseSelector from './template_selectors/license_selector'; +import MetricsDashboardSelector from './template_selectors/metrics_dashboard_selector'; import toast from '~/vue_shared/plugins/global_toast'; import { __ } from '~/locale'; import initPopover from '~/blob/suggest_gitlab_ci_yml'; @@ -30,6 +31,7 @@ export default class FileTemplateMediator { this.templateSelectors = [ GitignoreSelector, BlobCiYamlSelector, + MetricsDashboardSelector, DockerfileSelector, LicenseSelector, ].map(TemplateSelectorClass => new TemplateSelectorClass({ mediator: this })); diff --git a/app/assets/javascripts/blob/template_selectors/metrics_dashboard_selector.js b/app/assets/javascripts/blob/template_selectors/metrics_dashboard_selector.js new file mode 100644 index 00000000000..b4accaadfa3 --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/metrics_dashboard_selector.js @@ -0,0 +1,28 @@ +import FileTemplateSelector from '../file_template_selector'; + +export default class MetricsDashboardSelector extends FileTemplateSelector { + constructor({ mediator }) { + super(mediator); + this.config = { + key: 'metrics-dashboard-yaml', + name: '.metrics-dashboard.yml', + pattern: /(.metrics-dashboard.yml)/, + type: 'metrics_dashboard_ymls', + dropdown: '.js-metrics-dashboard-selector', + wrapper: '.js-metrics-dashboard-selector-wrap', + }; + } + + initDropdown() { + this.$dropdown.glDropdown({ + data: this.$dropdown.data('data'), + filterable: true, + selectable: true, + search: { + fields: ['name'], + }, + clicked: options => this.reportSelectionName(options), + text: item => item.name, + }); + } +} diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue index c3b0e00ca38..14c71f73291 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue @@ -210,6 +210,7 @@ export default { v-model="key" :token-list="$options.tokenList" :label-text="__('Key')" + data-qa-selector="ci_variable_key_field" /> diff --git a/app/assets/javascripts/monitoring/components/dashboard_header.vue b/app/assets/javascripts/monitoring/components/dashboard_header.vue index 7ac35809b99..6fbf2084911 100644 --- a/app/assets/javascripts/monitoring/components/dashboard_header.vue +++ b/app/assets/javascripts/monitoring/components/dashboard_header.vue @@ -407,6 +407,7 @@ export default { right class="gl-flex-grow-1" data-testid="actions-menu" + data-qa-selector="actions_menu_dropdown" :title="s__('Metrics|Create dashboard')" :icon="'plus-square'" > diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss index cc826bb6c21..1c88883142d 100644 --- a/app/assets/stylesheets/pages/editor.scss +++ b/app/assets/stylesheets/pages/editor.scss @@ -187,7 +187,8 @@ .gitignore-selector, .gitlab-ci-yml-selector, .dockerfile-selector, - .template-type-selector { + .template-type-selector, + .metrics-dashboard-selector { display: inline-block; vertical-align: top; font-family: $regular_font; diff --git a/app/presenters/packages/detail/package_presenter.rb b/app/presenters/packages/detail/package_presenter.rb index 4d9b3f294ed..631ee173188 100644 --- a/app/presenters/packages/detail/package_presenter.rb +++ b/app/presenters/packages/detail/package_presenter.rb @@ -50,7 +50,9 @@ module Packages user: build_user_info(pipeline_info.user), project: { name: pipeline_info.project.name, - web_url: pipeline_info.project.web_url + web_url: pipeline_info.project.web_url, + pipeline_url: Gitlab::Routing.url_helpers.project_pipeline_url(pipeline_info.project, pipeline_info), + commit_url: Gitlab::Routing.url_helpers.project_commit_url(pipeline_info.project, pipeline_info.sha) } } end diff --git a/app/views/projects/blob/_template_selectors.html.haml b/app/views/projects/blob/_template_selectors.html.haml index ba8029ac32a..2aefcdc5762 100644 --- a/app/views/projects/blob/_template_selectors.html.haml +++ b/app/views/projects/blob/_template_selectors.html.haml @@ -7,6 +7,8 @@ = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-license-selector qa-license-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: licenses_for_select(@project), project: @project.name, fullname: @project.namespace.human_name } } ) .gitignore-selector.js-gitignore-selector-wrap.js-template-selector-wrap.hidden = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-gitignore-selector qa-gitignore-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: gitignore_names(@project) } } ) + .metrics-dashboard-selector.js-metrics-dashboard-selector-wrap.js-template-selector-wrap.hidden + = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-metrics-dashboard-selector qa-metrics-dashboard-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: metrics_dashboard_ymls(@project) } } ) #gitlab-ci-yml-selector.gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.js-template-selector-wrap.hidden = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-gitlab-ci-yml-selector qa-gitlab-ci-yml-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls(@project) } } ) .dockerfile-selector.js-dockerfile-selector-wrap.js-template-selector-wrap.hidden diff --git a/changelogs/unreleased/36302-add-internal-api-for-getting-personal-access-tokens.yml b/changelogs/unreleased/36302-add-internal-api-for-getting-personal-access-tokens.yml new file mode 100644 index 00000000000..008615ba01b --- /dev/null +++ b/changelogs/unreleased/36302-add-internal-api-for-getting-personal-access-tokens.yml @@ -0,0 +1,5 @@ +--- +title: "Add internal api for getting personal access tokens from gitlab-shell" +merge_request: 36302 +author: Taylan Develioglu @tdevelioglu +type: added diff --git a/changelogs/unreleased/jivanvl-add-yaml-template-standard-editor.yml b/changelogs/unreleased/jivanvl-add-yaml-template-standard-editor.yml new file mode 100644 index 00000000000..fb72c36ffdc --- /dev/null +++ b/changelogs/unreleased/jivanvl-add-yaml-template-standard-editor.yml @@ -0,0 +1,5 @@ +--- +title: Add metrics dashboard templates for the standard file blob selector +merge_request: 37519 +author: +type: added diff --git a/changelogs/unreleased/optimise-extractsref-when-there-is-no-path.yml b/changelogs/unreleased/optimise-extractsref-when-there-is-no-path.yml new file mode 100644 index 00000000000..63d3d2ce357 --- /dev/null +++ b/changelogs/unreleased/optimise-extractsref-when-there-is-no-path.yml @@ -0,0 +1,5 @@ +--- +title: Remove some unnecessary Redis calls on commit lists +merge_request: 38343 +author: +type: performance diff --git a/changelogs/unreleased/pks-git-v2-28-0.yml b/changelogs/unreleased/pks-git-v2-28-0.yml new file mode 100644 index 00000000000..266efa8fdda --- /dev/null +++ b/changelogs/unreleased/pks-git-v2-28-0.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade CI to Git v2.28.0 +merge_request: 38152 +author: +type: added diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md index 669f5e363d2..2747fb0cc04 100644 --- a/doc/administration/packages/container_registry.md +++ b/doc/administration/packages/container_registry.md @@ -456,7 +456,7 @@ you can pull from the Container Registry, but you cannot push. sudo aws --endpoint-url https://your-object-storage-backend.com s3 ls ``` - If you are using AWS as your back end, you do not need the [`--endpoint-url`](https://docs.aws.amazon.com/cli/latest/reference/#:~:text=--endpoint-url). + If you are using AWS as your back end, you do not need the [`--endpoint-url`](https://docs.aws.amazon.com/cli/latest/reference/#options). 1. Copy initial data to your S3 bucket, for example with the `aws` CLI [`cp`](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/cp.html) or [`sync`](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/sync.html) diff --git a/doc/development/code_review.md b/doc/development/code_review.md index 5753b96c774..2159f7a9ed5 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -281,12 +281,16 @@ first time. ### Assigning a merge request for a review When you are ready to have your merge request reviewed, -you should default to assigning it to a reviewer from your group or team for the first review, -however, you can also assign it to any reviewer. The list of reviewers can be found on [Engineering projects](https://about.gitlab.com/handbook/engineering/projects/) page. +you should request an initial review by assigning it to a reviewer from your group or team. +However, you can also assign it to any reviewer. The list of reviewers can be found on [Engineering projects](https://about.gitlab.com/handbook/engineering/projects/) page. You can also use `workflow::ready for review` label. That means that your merge request is ready to be reviewed and any reviewer can pick it. It is recommended to use that label only if there isn't time pressure and make sure the merge request is assigned to a reviewer. -When your merge request was reviewed and can be passed to a maintainer, you should default to choosing a maintainer with [domain expertise](#domain-experts), and otherwise follow the Reviewer Roulette recommendation or use the label `ready for merge`. +When your merge request receives an approval from the first reviewer it can be passed to a maintainer. You should default to choosing a maintainer with [domain expertise](#domain-experts), and otherwise follow the Reviewer Roulette recommendation or use the label `ready for merge`. + +Sometimes, a maintainer may not be available for review. They could be out of the office or [at capacity](#review-response-slo). +You can and should check the maintainer’s availability in their profile. If the maintainer recommended by +the roulette is not available, choose someone else from that list. It is responsibility of the author of a merge request that the merge request is reviewed. If it stays in `ready for review` state too long it is recommended to assign it to a specific reviewer. diff --git a/doc/development/internal_api.md b/doc/development/internal_api.md index d220a2d46fb..c51bf66be46 100644 --- a/doc/development/internal_api.md +++ b/doc/development/internal_api.md @@ -1,3 +1,10 @@ +--- +stage: Create +group: Source Code +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers" +type: reference, api +--- + # Internal API The internal API is used by different GitLab components, it can not be @@ -24,10 +31,11 @@ authentication. ## Git Authentication -This is called by Gitaly and GitLab-shell to check access to a +This is called by [Gitaly](https://gitlab.com/gitlab-org/gitaly) and +[GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell) to check access to a repository. -When called from GitLab-shell no changes are passed and the internal +When called from GitLab Shell no changes are passed and the internal API replies with the information needed to pass the request on to Gitaly. @@ -40,13 +48,13 @@ POST /internal/allowed | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| -| `key_id` | string | no | ID of the SSH-key used to connect to GitLab-shell | -| `username` | string | no | Username from the certificate used to connect to GitLab-Shell | +| `key_id` | string | no | ID of the SSH-key used to connect to GitLab Shell | +| `username` | string | no | Username from the certificate used to connect to GitLab Shell | | `project` | string | no (if `gl_repository` is passed) | Path to the project | | `gl_repository` | string | no (if `project` is passed) | Repository identifier (e.g. `project-7`) | | `protocol` | string | yes | SSH when called from GitLab-shell, HTTP or SSH when called from Gitaly | | `action` | string | yes | Git command being run (`git-upload-pack`, `git-receive-pack`, `git-upload-archive`) | -| `changes` | string | yes | ` ` when called from Gitaly, The magic string `_any` when called from GitLab Shell | +| `changes` | string | yes | ` ` when called from Gitaly, the magic string `_any` when called from GitLab Shell | | `check_ip` | string | no | IP address from which call to GitLab Shell was made | Example request: @@ -84,17 +92,17 @@ Example response: ### Known consumers - Gitaly -- GitLab-shell +- GitLab Shell ## LFS Authentication -This is the endpoint that gets called from GitLab-shell to provide +This is the endpoint that gets called from GitLab Shell to provide information for LFS clients when the repository is accessed over SSH. | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| -| `key_id` | string | no | ID of the SSH-key used to connect to GitLab-shell | -| `username`| string | no | Username from the certificate used to connect to GitLab-Shell | +| `key_id` | string | no | ID of the SSH-key used to connect to GitLab Shell | +| `username`| string | no | Username from the certificate used to connect to GitLab Shell | | `project` | string | no | Path to the project | Example request: @@ -114,17 +122,17 @@ curl --request POST --header "Gitlab-Shared-Secret: " --da ### Known consumers -- GitLab-shell +- GitLab Shell ## Authorized Keys Check -This endpoint is called by the GitLab-shell authorized keys +This endpoint is called by the GitLab Shell authorized keys check. Which is called by OpenSSH for [fast SSH key lookup](../administration/operations/fast_ssh_key_lookup.md). | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| -| `key` | string | yes | SSH key as passed by OpenSSH to GitLab-shell | +| `key` | string | yes | SSH key as passed by OpenSSH to GitLab Shell | ```plaintext GET /internal/authorized_keys @@ -149,7 +157,7 @@ Example response: ### Known consumers -- GitLab-shell +- GitLab Shell ## Get user for user ID or key @@ -159,7 +167,7 @@ discovers the user associated with an SSH key. | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| | `key_id` | integer | no | The ID of the SSH key used as found in the authorized-keys file or through the `/authorized_keys` check | -| `username` | string | no | Username of the user being looked up, used by GitLab-shell when authenticating using a certificate | +| `username` | string | no | Username of the user being looked up, used by GitLab Shell when authenticating using a certificate | ```plaintext GET /internal/discover @@ -183,12 +191,12 @@ Example response: ### Known consumers -- GitLab-shell +- GitLab Shell ## Instance information This gets some generic information about the instance. This is used -by Geo nodes to get information about each other +by Geo nodes to get information about each other. ```plaintext GET /internal/check @@ -214,12 +222,12 @@ Example response: ### Known consumers - GitLab Geo -- GitLab-shell's `bin/check` +- GitLab Shell's `bin/check` ## Get new 2FA recovery codes using an SSH key -This is called from GitLab-shell and allows users to get new 2FA -recovery codes based on their SSH key +This is called from GitLab Shell and allows users to get new 2FA +recovery codes based on their SSH key. | Attribute | Type | Required | Description | |:----------|:-------|:---------|:------------| @@ -258,7 +266,45 @@ Example response: ### Known consumers -- GitLab-shell +- GitLab Shell + +## Get new personal access-token + +This is called from GitLab Shell and allows users to generate a new +personal access token. + +| Attribute | Type | Required | Description | +|:----------|:-------|:---------|:------------| +| `name` | string | yes | The name of the new token | +| `scopes` | string array | yes | The authorization scopes for the new token, these must be valid token scopes | +| `expires_at` | string | no | The expiry date for the new token | +| `key_id` | integer | no | The ID of the SSH key used as found in the authorized-keys file or through the `/authorized_keys` check | +| `user_id` | integer | no | User\_id for which to generate the new token | + +```plaintext +POST /internal/personal_access_token +``` + +Example request: + +```shell +curl --request POST --header "Gitlab-Shared-Secret: " --data "user_id=29&name=mytokenname&scopes[]=read_user&scopes[]=read_repository&expires_at=2020-07-24" http://localhost:3001/api/v4/internal/personal_access_token +``` + +Example response: + +```json +{ + "success": true, + "token": "Hf_79B288hRv_3-TSD1R", + "scopes": ["read_user","read_repository"], + "expires_at": "2020-07-24" +} +``` + +### Known consumers + +- GitLab Shell ## Incrementing counter on pre-receive diff --git a/doc/install/installation.md b/doc/install/installation.md index f444f297514..b2da1e0eac9 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -134,7 +134,7 @@ Make sure you have the right version of Git installed: # Install Git sudo apt-get install -y git-core -# Make sure Git is version 2.27.0 or higher (minimal supported version is 2.25.0) +# Make sure Git is version 2.28.0 or higher git --version ``` @@ -181,9 +181,9 @@ sudo make install # Download and compile from source cd /tmp -curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.27.0.tar.gz -echo '77ded85cbe42b1ffdc2578b460a1ef5d23bcbc6683eabcafbb0d394dffe2e787 git-2.27.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.27.0.tar.gz -cd git-2.27.0/ +curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz +echo 'f914c60a874d466c1e18467c864a910dd4ea22281ba6d4d58077cb0c3f115170 git-2.28.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.28.0.tar.gz +cd git-2.28.0/ ./configure --with-libpcre make prefix=/usr/local all diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 25a81f9987b..2587aaf1843 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -56,8 +56,7 @@ The minimum required Go version is 1.13. From GitLab 13.1: -- Git 2.25.x and later is required. -- Git 2.27.x and later [is recommended](https://gitlab.com/gitlab-org/gitaly/-/issues/2829). +- Git 2.28.x and later [is required](https://gitlab.com/gitlab-org/gitaly/-/issues/2959). ### Node.js versions diff --git a/doc/update/README.md b/doc/update/README.md index a82563bfefe..9dd2f1c51a2 100644 --- a/doc/update/README.md +++ b/doc/update/README.md @@ -222,6 +222,11 @@ possible. ## Version specific upgrading instructions +### 13.3.0 + +In 13.3.0, you must upgrade to at least Git v2.28. Previously, the minimum +required version was Git v2.24. + ### 13.2.0 GitLab installations that have multiple web nodes will need to be diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md index af461b93910..5fc4528e4c9 100644 --- a/doc/update/upgrading_from_source.md +++ b/doc/update/upgrading_from_source.md @@ -124,7 +124,7 @@ rm go1.13.5.linux-amd64.tar.gz CAUTION: **Caution:** From GitLab 13.1, you must use at least Git v2.24 (previous minimum version was v2.22). -Git v2.26 is recommended. +From GitLab 13.3, you must use at least Git v2.28. To check you are running the minimum required Git version, see [Git versions](../install/requirements.md#git-versions). @@ -132,7 +132,7 @@ To check you are running the minimum required Git version, see In Debian or Ubuntu: ```shell -# Make sure Git is version 2.24.0 or higher +# Make sure Git is version 2.28.0 or higher git --version # Remove packaged Git @@ -152,9 +152,9 @@ make install # Download and compile from source cd /tmp -curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.26.0.tar.gz -echo 'aa168c2318e7187cd295a645f7370cc6d71a324aafc932f80f00c780b6a26bed git-2.26.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.26.0.tar.gz -cd git-2.26.0/ +curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz +echo 'f914c60a874d466c1e18467c864a910dd4ea22281ba6d4d58077cb0c3f115170 git-2.28.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.28.0.tar.gz +cd git-2.28.0/ ./configure --with-libpcre make prefix=/usr/local all diff --git a/doc/user/admin_area/custom_project_templates.md b/doc/user/admin_area/custom_project_templates.md index d194ca42215..f39e5b198e7 100644 --- a/doc/user/admin_area/custom_project_templates.md +++ b/doc/user/admin_area/custom_project_templates.md @@ -1,6 +1,6 @@ --- -stage: Plan -group: Project Management +stage: Manage +group: Import info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers type: reference --- diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md index 3fa3b1a44b8..23f1ee825fd 100644 --- a/doc/user/application_security/coverage_fuzzing/index.md +++ b/doc/user/application_security/coverage_fuzzing/index.md @@ -116,6 +116,45 @@ of the GitLab artifacts system, GitLab saves in a corpus directory the new test generates. In any subsequent runs, GitLab also reuses the generated corpus together with the seed corpus. +### Reports JSON format + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220062) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.3 as an [Alpha feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#alpha). + +The `gitlab-cov-fuzz` tool emits a JSON report file. For more information, see the +[schema for this report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/coverage-fuzzing-report-format.json). + +You can download the JSON report file from the CI pipelines page. For more information, see +[Downloading artifacts](../../../ci/pipelines/job_artifacts.md#downloading-artifacts). + +Here's an example Coverage Fuzzing report: + +```json-doc +{ + "version": "v1.0.8", + "regression": false, + "exit_code": -1, + "vulnerabilities": [ + { + "category": "coverage_fuzzing", + "message": "Heap-buffer-overflow\nREAD 1", + "description": "Heap-buffer-overflow\nREAD 1", + "severity": "Critical", + "stacktrace_snippet": "INFO: Seed: 3415817494\nINFO: Loaded 1 modules (7 inline 8-bit counters): 7 [0x10eee2470, 0x10eee2477), \nINFO: Loaded 1 PC tables (7 PCs): 7 [0x10eee2478,0x10eee24e8), \nINFO: 5 files found in corpus\nINFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes\nINFO: seed corpus: files: 5 min: 1b max: 4b total: 14b rss: 26Mb\n#6\tINITED cov: 7 ft: 7 corp: 5/14b exec/s: 0 rss: 26Mb\n=================================================================\n==43405==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000001573 at pc 0x00010eea205a bp 0x7ffee0d5e090 sp 0x7ffee0d5e088\nREAD of size 1 at 0x602000001573 thread T0\n #0 0x10eea2059 in FuzzMe(unsigned char const*, unsigned long) fuzz_me.cc:9\n #1 0x10eea20ba in LLVMFuzzerTestOneInput fuzz_me.cc:13\n #2 0x10eebe020 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:556\n #3 0x10eebd765 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) FuzzerLoop.cpp:470\n #4 0x10eebf966 in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:698\n #5 0x10eec0665 in fuzzer::Fuzzer::Loop(std::__1::vector\u003cfuzzer::SizedFile, fuzzer::fuzzer_allocator\u003cfuzzer::SizedFile\u003e \u003e\u0026) FuzzerLoop.cpp:830\n #6 0x10eead0cd in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:829\n #7 0x10eedaf82 in main FuzzerMain.cpp:19\n #8 0x7fff684fecc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)\n\n0x602000001573 is located 0 bytes to the right of 3-byte region [0x602000001570,0x602000001573)\nallocated by thread T0 here:\n #0 0x10ef92cfd in wrap__Znam+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x50cfd)\n #1 0x10eebdf31 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) FuzzerLoop.cpp:541\n #2 0x10eebd765 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) FuzzerLoop.cpp:470\n #3 0x10eebf966 in fuzzer::Fuzzer::MutateAndTestOne() FuzzerLoop.cpp:698\n #4 0x10eec0665 in fuzzer::Fuzzer::Loop(std::__1::vector\u003cfuzzer::SizedFile, fuzzer::fuzzer_allocator\u003cfuzzer::SizedFile\u003e \u003e\u0026) FuzzerLoop.cpp:830\n #5 0x10eead0cd in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) FuzzerDriver.cpp:829\n #6 0x10eedaf82 in main FuzzerMain.cpp:19\n #7 0x7fff684fecc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)\n\nSUMMARY: AddressSanitizer: heap-buffer-overflow fuzz_me.cc:9 in FuzzMe(unsigned char const*, unsigned long)\nShadow bytes around the buggy address:\n 0x1c0400000250: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000260: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000270: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000280: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n 0x1c0400000290: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa\n=\u003e0x1c04000002a0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa[03]fa\n 0x1c04000002b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x1c04000002f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\nShadow byte legend (one shadow byte represents 8 application bytes):\n Addressable: 00\n Partially addressable: 01 02 03 04 05 06 07 \n Heap left redzone: fa\n Freed heap region: fd\n Stack left redzone: f1\n Stack mid redzone: f2\n Stack right redzone: f3\n Stack after return: f5\n Stack use after scope: f8\n Global redzone: f9\n Global init order: f6\n Poisoned by user: f7\n Container overflow: fc\n Array cookie: ac\n Intra object redzone: bb\n ASan internal: fe\n Left alloca redzone: ca\n Right alloca redzone: cb\n Shadow gap: cc\n==43405==ABORTING\nMS: 1 EraseBytes-; base unit: de3a753d4f1def197604865d76dba888d6aefc71\n0x46,0x55,0x5a,\nFUZ\nartifact_prefix='./crashes/'; Test unit written to ./crashes/crash-0eb8e4ed029b774d80f2b66408203801cb982a60\nBase64: RlVa\nstat::number_of_executed_units: 122\nstat::average_exec_per_sec: 0\nstat::new_units_added: 0\nstat::slowest_unit_time_sec: 0\nstat::peak_rss_mb: 28", + "scanner": { + "id": "libFuzzer", + "name": "libFuzzer" + }, + "location": { + "crash_address": "0x602000001573", + "crash_state": "FuzzMe\nstart\nstart+0x0\n\n", + "crash_type": "Heap-buffer-overflow\nREAD 1" + }, + "tool": "libFuzzer" + } + ] +} +``` + ### Additional Configuration The `gitlab-cov-fuzz` command passes all arguments it receives to the underlying fuzzing engine. You diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md index bcf2ab66978..0e0731528be 100644 --- a/doc/user/project/issues/managing_issues.md +++ b/doc/user/project/issues/managing_issues.md @@ -287,3 +287,7 @@ To add an issue to an [iteration](../../group/iterations/index.md): 1. In an issue sidebar, click **Edit** next to **Iteration**. A dropdown appears. 1. Click an iteration you'd like to associate this issue with. + +You can also use the `/iteration` +[quick action](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics) +in a comment or description field. diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index e99675d26a6..518cf472b50 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -44,7 +44,7 @@ The following quick actions are applicable to descriptions, discussions and thre | `/duplicate <#issue>` | ✓ | | | Close this issue and mark as a duplicate of another issue. **(CORE)** Also, mark both as related. **(STARTER)** | | `/epic ` | ✓ | | | Add to epic ``. The `` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. **(PREMIUM)** | | `/estimate <w
d h m>` | ✓ | ✓ | | Set time estimate. For example, `/estimate 1w 3d 2h 14m`. | -| `/iteration *iteration:iteration` | ✓ | | | Set iteration ([Introduced in GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/196795)) **(STARTER)** | +| `/iteration *iteration:"iteration name"` | ✓ | | | Set iteration. For example, to set the `Late in July` iteration: `/iteration *iteration:"Late in July"` ([introduced in GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/196795)). **(STARTER)** | | `/label ~label1 ~label2` | ✓ | ✓ | ✓ | Add one or more labels. Label names can also start without a tilde (`~`), but mixed syntax is not supported. | | `/lock` | ✓ | ✓ | | Lock the thread. | | `/merge` | | ✓ | | Merge changes. Depending on the project setting, this may be [when the pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md), adding to a [Merge Train](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md), etc. | @@ -60,7 +60,7 @@ The following quick actions are applicable to descriptions, discussions and thre | `/remove_due_date` | ✓ | | | Remove due date. | | `/remove_epic` | ✓ | | | Remove from epic. **(PREMIUM)** | | `/remove_estimate` | ✓ | ✓ | | Remove time estimate. | -| `/remove_iteration` | ✓ | | | Remove iteration ([Introduced in GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/196795)) **(STARTER)** | +| `/remove_iteration` | ✓ | | | Remove iteration ([introduced in GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/196795)) **(STARTER)** | | `/remove_milestone` | ✓ | ✓ | | Remove milestone. | | `/remove_parent_epic` | | | ✓ | Remove parent epic from epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab/-/issues/10556)). **(ULTIMATE)** | | `/remove_time_spent` | ✓ | ✓ | | Remove time spent. | diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index b69930b447c..b7ce1eba3f9 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -117,7 +117,7 @@ module API return unless %w[git-receive-pack git-upload-pack git-upload-archive].include?(action) { - repository: repository.gitaly_repository, + repository: repository.gitaly_repository.to_h, address: Gitlab::GitalyClient.address(repository.shard), token: Gitlab::GitalyClient.token(repository.shard), features: Feature::Gitaly.server_feature_flags diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb index f2fb88d0d55..17599c72243 100644 --- a/lib/api/internal/base.rb +++ b/lib/api/internal/base.rb @@ -18,6 +18,10 @@ module API UNKNOWN_CHECK_RESULT_ERROR = 'Unknown check result'.freeze + VALID_PAT_SCOPES = Set.new( + Gitlab::Auth::API_SCOPES + Gitlab::Auth::REPOSITORY_SCOPES + Gitlab::Auth::REGISTRY_SCOPES + ).freeze + helpers do def response_with_status(code: 200, success: true, message: nil, **extra_options) status code @@ -194,6 +198,60 @@ module API { success: true, recovery_codes: codes } end + post '/personal_access_token' do + status 200 + + actor.update_last_used_at! + user = actor.user + + if params[:key_id] + unless actor.key + break { success: false, message: 'Could not find the given key' } + end + + if actor.key.is_a?(DeployKey) + break { success: false, message: 'Deploy keys cannot be used to create personal access tokens' } + end + + unless user + break { success: false, message: 'Could not find a user for the given key' } + end + elsif params[:user_id] && user.nil? + break { success: false, message: 'Could not find the given user' } + end + + if params[:name].blank? + break { success: false, message: "No token name specified" } + end + + if params[:scopes].blank? + break { success: false, message: "No token scopes specified" } + end + + invalid_scope = params[:scopes].find { |scope| VALID_PAT_SCOPES.exclude?(scope.to_sym) } + + if invalid_scope + valid_scopes = VALID_PAT_SCOPES.map(&:to_s).sort + break { success: false, message: "Invalid scope: '#{invalid_scope}'. Valid scopes are: #{valid_scopes}" } + end + + begin + expires_at = params[:expires_at].presence && Date.parse(params[:expires_at]) + rescue ArgumentError + break { success: false, message: "Invalid token expiry date: '#{params[:expires_at]}'" } + end + + access_token = nil + + ::Users::UpdateService.new(current_user, user: user).execute! do |user| + access_token = user.personal_access_tokens.create!( + name: params[:name], scopes: params[:scopes], expires_at: expires_at + ) + end + + { success: true, token: access_token.token, scopes: access_token.scopes, expires_at: access_token.expires_at } + end + post '/pre_receive' do status 200 diff --git a/lib/extracts_ref.rb b/lib/extracts_ref.rb index 346ed6b6f60..fe7cd633837 100644 --- a/lib/extracts_ref.rb +++ b/lib/extracts_ref.rb @@ -47,6 +47,10 @@ module ExtractsRef if id =~ /^(\h{40})(.+)/ # If the ref appears to be a SHA, we're done, just split the string pair = $~.captures + elsif id.exclude?('/') + # If the ID contains no slash, we must have a ref and no path, so + # we can skip the Redis calls below + pair = [id, ''] else # Otherwise, attempt to detect the ref using a list of the repository_container's # branches and tags @@ -71,12 +75,10 @@ module ExtractsRef end end - pair[0] = pair[0].strip - - # Remove ending slashes from path - pair[1].gsub!(%r{^/|/$}, '') - - pair + [ + pair[0].strip, + pair[1].gsub(%r{^/|/$}, '') # Remove leading and trailing slashes from path + ] end # Assigns common instance variables for views working with Git tree-ish objects diff --git a/lib/gitlab/checks/lfs_check.rb b/lib/gitlab/checks/lfs_check.rb index f81c215d847..227169ae755 100644 --- a/lib/gitlab/checks/lfs_check.rb +++ b/lib/gitlab/checks/lfs_check.rb @@ -7,7 +7,6 @@ module Gitlab ERROR_MESSAGE = 'LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".' def validate! - return unless Feature.enabled?(:lfs_check, default_enabled: true) return unless project.lfs_enabled? return if skip_lfs_integrity_check diff --git a/lib/gitlab/diff/stats_cache.rb b/lib/gitlab/diff/stats_cache.rb index a918fc08201..eb0ef4200dc 100644 --- a/lib/gitlab/diff/stats_cache.rb +++ b/lib/gitlab/diff/stats_cache.rb @@ -29,7 +29,7 @@ module Gitlab return if cache.exist?(key) return unless stats - cache.write(key, stats.as_json, expires_in: EXPIRATION) + cache.write(key, stats.map(&:to_h).as_json, expires_in: EXPIRATION) clear_memoization(:cached_values) end diff --git a/lib/system_check/app/git_version_check.rb b/lib/system_check/app/git_version_check.rb index 08c8df9b044..a1191d89adb 100644 --- a/lib/system_check/app/git_version_check.rb +++ b/lib/system_check/app/git_version_check.rb @@ -7,7 +7,7 @@ module SystemCheck set_check_pass -> { "yes (#{self.current_version})" } def self.required_version - @required_version ||= Gitlab::VersionInfo.parse('2.22.0') + @required_version ||= Gitlab::VersionInfo.parse('2.28.0') end def self.current_version diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 49d30286c4c..40da523132b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7548,12 +7548,21 @@ msgstr "" msgid "DastProfiles|Could not create the site profile. Please try again." msgstr "" +msgid "DastProfiles|Could not update the site profile. Please try again." +msgstr "" + msgid "DastProfiles|Do you want to discard this site profile?" msgstr "" +msgid "DastProfiles|Do you want to discard your changes?" +msgstr "" + msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed" msgstr "" +msgid "DastProfiles|Edit site profile" +msgstr "" + msgid "DastProfiles|Error fetching the profiles list. Please check your network connection and try again." msgstr "" diff --git a/qa/qa/page/project/operations/metrics/show.rb b/qa/qa/page/project/operations/metrics/show.rb index e9e4923a0e2..ee5f42147f6 100644 --- a/qa/qa/page/project/operations/metrics/show.rb +++ b/qa/qa/page/project/operations/metrics/show.rb @@ -20,6 +20,7 @@ module QA element :environments_dropdown element :edit_dashboard_button element :range_picker_dropdown + element :actions_menu_dropdown end view 'app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue' do @@ -60,8 +61,8 @@ module QA end def duplicate_dashboard(save_as = 'test_duplication.yml', commit_option = 'Commit to master branch') - click_element :dashboards_filter_dropdown - click_on 'Duplicate dashboard' + click_element :actions_menu_dropdown + click_on 'Duplicate current dashboard' fill_element :duplicate_dashboard_filename_field, "#{SecureRandom.hex(8)}-#{save_as}" choose commit_option within('.modal-content') { click_button(class: 'btn-success') } diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb index de268b14aa2..aef9800e876 100644 --- a/qa/qa/page/project/settings/ci_variables.rb +++ b/qa/qa/page/project/settings/ci_variables.rb @@ -23,7 +23,7 @@ module QA end def fill_variable(key, value, masked) - fill_element :ci_variable_key_field, key + within_element(:ci_variable_key_field) { find('input').set key } fill_element :ci_variable_value_field, value click_ci_variable_save_button end diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb index 41baaa02544..fd342503a5c 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/229724', type: :investigating } do + RSpec.describe 'Verify' do describe 'Add or Remove CI variable via UI', :smoke do let!(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb index e57a08ffe21..9d9a75c22be 100644 --- a/spec/features/projects/show/user_manages_notifications_spec.rb +++ b/spec/features/projects/show/user_manages_notifications_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do click_notifications_button expect(find('.update-notification.is-active')).to have_content('On mention') - expect(find('.notifications-icon use')[:'xlink:href']).to end_with('#notifications') + expect(page).to have_css('.notifications-icon[data-testid="notifications-icon"]') end it 'changes the notification setting to disabled' do @@ -32,7 +32,7 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do wait_for_requests - expect(find('.notifications-icon use')[:'xlink:href']).to end_with('#notifications-off') + expect(page).to have_css('.notifications-icon[data-testid="notifications-off-icon"]') end context 'custom notification settings' do diff --git a/spec/frontend/jobs/components/log/mock_data.js b/spec/frontend/jobs/components/log/mock_data.js index a6a767f7921..eb8c4fe8bc9 100644 --- a/spec/frontend/jobs/components/log/mock_data.js +++ b/spec/frontend/jobs/components/log/mock_data.js @@ -34,7 +34,7 @@ export const utilsMockData = [ content: [ { text: - 'Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.27-lfs-2.9-chrome-83-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34', + 'Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34', }, ], section: 'prepare-executor', diff --git a/spec/graphql/mutations/commits/create_spec.rb b/spec/graphql/mutations/commits/create_spec.rb index bb0b8c577b0..fb1baafe7bd 100644 --- a/spec/graphql/mutations/commits/create_spec.rb +++ b/spec/graphql/mutations/commits/create_spec.rb @@ -147,7 +147,7 @@ RSpec.describe Mutations::Commits::Create do it 'returns errors' do expect(mutated_commit).to be_nil - expect(subject[:errors]).to eq(['3:UserCommitFiles: empty CommitMessage']) + expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/) end end diff --git a/spec/lib/gitlab/checks/lfs_check_spec.rb b/spec/lib/gitlab/checks/lfs_check_spec.rb index 713858e0e35..cdd4ed3cbaa 100644 --- a/spec/lib/gitlab/checks/lfs_check_spec.rb +++ b/spec/lib/gitlab/checks/lfs_check_spec.rb @@ -27,18 +27,6 @@ RSpec.describe Gitlab::Checks::LfsCheck do allow(project).to receive(:lfs_enabled?).and_return(true) end - context 'with lfs_check feature disabled' do - before do - stub_feature_flags(lfs_check: false) - end - - it 'skips integrity check' do - expect_any_instance_of(Gitlab::Git::LfsChanges).not_to receive(:new_pointers) - - subject.validate! - end - end - context 'deletion' do let(:changes) { { oldrev: oldrev, ref: ref } } diff --git a/spec/lib/gitlab/diff/stats_cache_spec.rb b/spec/lib/gitlab/diff/stats_cache_spec.rb index 451fd52c084..5b01c1913bf 100644 --- a/spec/lib/gitlab/diff/stats_cache_spec.rb +++ b/spec/lib/gitlab/diff/stats_cache_spec.rb @@ -9,6 +9,7 @@ RSpec.describe Gitlab::Diff::StatsCache, :use_clean_rails_memory_store_caching d let(:cachable_key) { 'cachecachecache' } let(:stat) { Gitaly::DiffStats.new(path: 'temp', additions: 10, deletions: 15) } let(:stats) { Gitlab::Git::DiffStatsCollection.new([stat]) } + let(:serialized_stats) { stats.map(&:to_h).as_json } let(:cache) { Rails.cache } describe '#read' do @@ -38,7 +39,7 @@ RSpec.describe Gitlab::Diff::StatsCache, :use_clean_rails_memory_store_caching d it 'writes the stats' do expect(cache) .to receive(:write) - .with(key, stats.as_json, expires_in: described_class::EXPIRATION) + .with(key, serialized_stats, expires_in: described_class::EXPIRATION) .and_call_original stats_cache.write_if_empty(stats) @@ -53,7 +54,7 @@ RSpec.describe Gitlab::Diff::StatsCache, :use_clean_rails_memory_store_caching d it 'writes the stats' do expect(cache) .to receive(:write) - .with(key, stats.as_json, expires_in: described_class::EXPIRATION) + .with(key, serialized_stats, expires_in: described_class::EXPIRATION) .and_call_original stats_cache.write_if_empty(stats) diff --git a/spec/presenters/packages/detail/package_presenter_spec.rb b/spec/presenters/packages/detail/package_presenter_spec.rb index 732d8d0f6ad..a29942c3dac 100644 --- a/spec/presenters/packages/detail/package_presenter_spec.rb +++ b/spec/presenters/packages/detail/package_presenter_spec.rb @@ -9,6 +9,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do let(:presenter) { described_class.new(package) } let_it_be(:user_info) { { name: user.name, avatar_url: user.avatar_url } } + let!(:expected_package_files) do package.package_files.map do |file| { @@ -19,6 +20,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do } end end + let(:pipeline_info) do pipeline = package.build_info.pipeline { @@ -30,11 +32,15 @@ RSpec.describe ::Packages::Detail::PackagePresenter do user: user_info, project: { name: pipeline.project.name, - web_url: pipeline.project.web_url + web_url: pipeline.project.web_url, + pipeline_url: include("pipelines/#{pipeline.id}"), + commit_url: include("commit/#{pipeline.sha}") } } end + let!(:dependency_links) { [] } + let!(:expected_package_details) do { id: package.id, @@ -56,7 +62,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do let(:expected_package_details) { super().merge(pipeline: pipeline_info) } it 'returns details with pipeline' do - expect(presenter.detail_view).to eq expected_package_details + expect(presenter.detail_view).to match expected_package_details end end @@ -91,6 +97,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do let_it_be(:package) { create(:nuget_package, project: project) } let_it_be(:dependency_link) { create(:packages_dependency_link, package: package) } let_it_be(:nuget_dependency) { create(:nuget_dependency_link_metadatum, dependency_link: dependency_link) } + let_it_be(:expected_link) do { name: dependency_link.dependency.name, @@ -98,6 +105,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do target_framework: nuget_dependency.target_framework } end + let_it_be(:dependency_links) { [expected_link] } it 'returns the correct dependency link' do diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb index 6f5eb3e992a..f410d82fed1 100644 --- a/spec/requests/api/internal/base_spec.rb +++ b/spec/requests/api/internal/base_spec.rb @@ -120,6 +120,138 @@ RSpec.describe API::Internal::Base do end end + describe 'POST /internal/personal_access_token' do + it 'returns an error message when the key does not exist' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: non_existing_record_id + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Could not find the given key') + end + + it 'returns an error message when the key is a deploy key' do + deploy_key = create(:deploy_key) + + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: deploy_key.id + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Deploy keys cannot be used to create personal access tokens') + end + + it 'returns an error message when the user does not exist' do + key_without_user = create(:key, user: nil) + + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key_without_user.id + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Could not find a user for the given key') + expect(json_response['token']).to be_nil + end + + it 'returns an error message when given an non existent user' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + user_id: 0 + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq("Could not find the given user") + end + + it 'returns an error message when no name parameter is received' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key.id + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq("No token name specified") + end + + it 'returns an error message when no scopes parameter is received' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key.id, + name: 'newtoken' + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq("No token scopes specified") + end + + it 'returns an error message when expires_at contains an invalid date' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key.id, + name: 'newtoken', + scopes: ['api'], + expires_at: 'invalid-date' + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq("Invalid token expiry date: 'invalid-date'") + end + + it 'returns an error message when it receives an invalid scope' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key.id, + name: 'newtoken', + scopes: %w(read_api badscope read_repository) + } + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to match(/\AInvalid scope: 'badscope'. Valid scopes are: /) + end + + it 'returns a token without expiry when the expires_at parameter is missing' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key.id, + name: 'newtoken', + scopes: %w(read_api read_repository) + } + + expect(json_response['success']).to be_truthy + expect(json_response['token']).to match(/\A\S{20}\z/) + expect(json_response['scopes']).to match_array(%w(read_api read_repository)) + expect(json_response['expires_at']).to be_nil + end + + it 'returns a token with expiry when it receives a valid expires_at parameter' do + post api('/internal/personal_access_token'), + params: { + secret_token: secret_token, + key_id: key.id, + name: 'newtoken', + scopes: %w(read_api read_repository), + expires_at: '9001-11-17' + } + + expect(json_response['success']).to be_truthy + expect(json_response['token']).to match(/\A\S{20}\z/) + expect(json_response['scopes']).to match_array(%w(read_api read_repository)) + expect(json_response['expires_at']).to eq('9001-11-17') + end + end + describe "POST /internal/lfs_authenticate" do before do project.add_developer(user) diff --git a/spec/support/shared_examples/path_extraction_shared_examples.rb b/spec/support/shared_examples/path_extraction_shared_examples.rb index 19c6f2404e5..8b14c9b9896 100644 --- a/spec/support/shared_examples/path_extraction_shared_examples.rb +++ b/spec/support/shared_examples/path_extraction_shared_examples.rb @@ -88,9 +88,16 @@ RSpec.shared_examples 'extracts refs' do expect(extract_ref('stable')).to eq(['stable', '']) end - it 'extracts the longest matching ref' do - expect(extract_ref('release/app/v1.0.0/README.md')).to eq( - ['release/app/v1.0.0', 'README.md']) + it 'does not fetch ref names when there is no slash' do + expect(self).not_to receive(:ref_names) + + extract_ref('master') + end + + it 'fetches ref names when there is a slash' do + expect(self).to receive(:ref_names).and_call_original + + extract_ref('release/app/v1.0.0') end end @@ -113,6 +120,11 @@ RSpec.shared_examples 'extracts refs' do it 'falls back to a primitive split for an invalid ref' do expect(extract_ref('stable/CHANGELOG')).to eq(%w(stable CHANGELOG)) end + + it 'extracts the longest matching ref' do + expect(extract_ref('release/app/v1.0.0/README.md')).to eq( + ['release/app/v1.0.0', 'README.md']) + end end end end