Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-26 18:11:45 +00:00
parent 60a260df41
commit 013a89081d
21 changed files with 370 additions and 330 deletions

View File

@ -1,5 +1,5 @@
<script> <script>
import { MEMBER_TYPES } from '../../constants'; import { MEMBER_TYPES, EE_ACTION_BUTTONS } from 'ee_else_ce/members/constants';
import AccessRequestActionButtons from '../action_buttons/access_request_action_buttons.vue'; import AccessRequestActionButtons from '../action_buttons/access_request_action_buttons.vue';
import GroupActionButtons from '../action_buttons/group_action_buttons.vue'; import GroupActionButtons from '../action_buttons/group_action_buttons.vue';
import InviteActionButtons from '../action_buttons/invite_action_buttons.vue'; import InviteActionButtons from '../action_buttons/invite_action_buttons.vue';
@ -12,6 +12,8 @@ export default {
GroupActionButtons, GroupActionButtons,
InviteActionButtons, InviteActionButtons,
AccessRequestActionButtons, AccessRequestActionButtons,
BannedActionButtons: () =>
import('ee_component/members/components/action_buttons/banned_action_buttons.vue'),
}, },
props: { props: {
member: { member: {
@ -42,6 +44,7 @@ export default {
[MEMBER_TYPES.group]: 'group-action-buttons', [MEMBER_TYPES.group]: 'group-action-buttons',
[MEMBER_TYPES.invite]: 'invite-action-buttons', [MEMBER_TYPES.invite]: 'invite-action-buttons',
[MEMBER_TYPES.accessRequest]: 'access-request-action-buttons', [MEMBER_TYPES.accessRequest]: 'access-request-action-buttons',
...EE_ACTION_BUTTONS,
}; };
return dictionary[this.memberType]; return dictionary[this.memberType];

View File

@ -9,6 +9,8 @@ export const EE_APP_OPTIONS = {};
// Overridden in EE // Overridden in EE
export const EE_TABS = []; export const EE_TABS = [];
export const EE_ACTION_BUTTONS = {};
export const FIELD_KEY_ACCOUNT = 'account'; export const FIELD_KEY_ACCOUNT = 'account';
export const FIELD_KEY_SOURCE = 'source'; export const FIELD_KEY_SOURCE = 'source';
export const FIELD_KEY_GRANTED = 'granted'; export const FIELD_KEY_GRANTED = 'granted';

View File

@ -171,7 +171,7 @@ module IssuableActions
discussions = Discussion.build_collection(notes, issuable) discussions = Discussion.build_collection(notes, issuable)
if issuable.is_a?(MergeRequest) if issuable.is_a?(MergeRequest)
render_cached(discussions, with: discussion_serializer, cache_context: -> (_) { discussion_cache_context }, context: self) render_mr_discussions(discussions, discussion_serializer, discussion_cache_context)
elsif issuable.is_a?(Issue) elsif issuable.is_a?(Issue)
render json: discussion_serializer.represent(discussions, context: self) if stale?(etag: [discussion_cache_context, discussions]) render json: discussion_serializer.represent(discussions, context: self) if stale?(etag: [discussion_cache_context, discussions])
else else
@ -182,6 +182,24 @@ module IssuableActions
private private
def render_mr_discussions(discussions, serializer, cache_context)
if Feature.enabled?(:mr_discussions_http_cache, project)
return unless stale?(etag: [cache_context, discussions])
if Feature.enabled?(:disabled_mr_discussions_redis_cache, project)
render json: serializer.represent(discussions, context: self)
else
render_cached_discussions(discussions, serializer, cache_context)
end
else
render_cached_discussions(discussions, serializer, cache_context)
end
end
def render_cached_discussions(discussions, serializer, cache_context)
render_cached(discussions, with: serializer, cache_context: -> (_) { cache_context }, context: self)
end
def paginated_discussions def paginated_discussions
return if params[:per_page].blank? return if params[:per_page].blank?
return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, project) return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, project)

View File

@ -14,7 +14,7 @@ module Resolvers
response = ::ErrorTracking::IssueDetailsService.new( response = ::ErrorTracking::IssueDetailsService.new(
project, project,
current_user, current_user,
{ issue_id: id.model_id } { issue_id: id.model_id, tracking_event: :error_tracking_view_details }
).execute ).execute
issue = response[:issue] issue = response[:issue]
issue.gitlab_project = project if issue issue.gitlab_project = project if issue

View File

@ -182,7 +182,7 @@ module GroupsHelper
def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false) def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false)
link_to(group_path(group), class: "group-path #{'breadcrumb-item-text' unless for_dropdown} js-breadcrumb-item-text #{'hidable' if hidable}") do link_to(group_path(group), class: "group-path #{'breadcrumb-item-text' unless for_dropdown} js-breadcrumb-item-text #{'hidable' if hidable}") do
icon = group_icon(group, class: "avatar-tile", width: 15, height: 15) if (group.try(:avatar_url) || show_avatar) && !Rails.env.test? icon = group_icon(group, alt: group.name, class: "avatar-tile", width: 15, height: 15) if group.try(:avatar_url) || show_avatar
[icon, simple_sanitize(group.name)].join.html_safe [icon, simple_sanitize(group.name)].join.html_safe
end end
end end

View File

@ -0,0 +1,8 @@
---
name: disabled_mr_discussions_redis_cache
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92752
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368366
milestone: '15.3'
type: development
group: group::code review
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: mr_discussions_http_cache
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92752
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368363
milestone: '15.3'
type: development
group: group::code review
default_enabled: false

View File

@ -56,6 +56,7 @@ exceptions:
- DML - DML
- DNS - DNS
- DOM - DOM
- DORA
- DSA - DSA
- DSL - DSL
- DVCS - DVCS

View File

@ -17,20 +17,6 @@ Troubleshooting Elasticsearch requires:
- Knowledge of common terms. - Knowledge of common terms.
- Establishing within which category the problem fits. - Establishing within which category the problem fits.
## Common terminology
- **Lucene**: A full-text search library written in Java.
- **Near real time (NRT)**: Refers to the slight latency from the time to index a
document to the time when it becomes searchable.
- **Cluster**: A collection of one or more nodes that work together to hold all
the data, providing indexing and search capabilities.
- **Node**: A single server that works as part of a cluster.
- **Index**: A collection of documents that have somewhat similar characteristics.
- **Document**: A basic unit of information that can be indexed.
- **Shards**: Fully-functional and independent subdivisions of indices. Each shard is actually
a Lucene index.
- **Replicas**: Failover mechanisms that duplicate indices.
## Troubleshooting workflows ## Troubleshooting workflows
The type of problem will determine what steps to take. The possible troubleshooting workflows are for: The type of problem will determine what steps to take. The possible troubleshooting workflows are for:

View File

@ -150,10 +150,10 @@ Dockerfiles to build and deploy <https://docs.gitlab.com>. It is heavily inspire
| Dockerfile | Docker image | Description | | Dockerfile | Docker image | Description |
|:---------------------------------------------------------------------------------------------------------------------------|:------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |:---------------------------------------------------------------------------------------------------------------------------|:------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`Dockerfile.bootstrap`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/Dockerfile.bootstrap) | `gitlab-docs:bootstrap` | Contains all the dependencies that are needed to build the website. If the gems are updated and `Gemfile{,.lock}` changes, the image must be rebuilt. | | [`bootstrap.Dockerfile`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/bootstrap.Dockerfile) | `gitlab-docs:bootstrap` | Contains all the dependencies that are needed to build the website. If the gems are updated and `Gemfile{,.lock}` changes, the image must be rebuilt. |
| [`Dockerfile.builder.onbuild`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/Dockerfile.builder.onbuild) | `gitlab-docs:builder-onbuild` | Base image to build the docs website. It uses `ONBUILD` to perform all steps and depends on `gitlab-docs:bootstrap`. | | [`builder.onbuild.Dockerfile`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/builder.onbuild.Dockerfile) | `gitlab-docs:builder-onbuild` | Base image to build the docs website. It uses `ONBUILD` to perform all steps and depends on `gitlab-docs:bootstrap`. |
| [`Dockerfile.nginx.onbuild`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/Dockerfile.nginx.onbuild) | `gitlab-docs:nginx-onbuild` | Base image to use for building documentation archives. It uses `ONBUILD` to perform all required steps to copy the archive, and relies upon its parent `Dockerfile.builder.onbuild` that is invoked when building single documentation archives (see the `Dockerfile` of each branch) | | [`nginx.onbuild.Dockerfile`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/nginx.onbuild.Dockerfile) | `gitlab-docs:nginx-onbuild` | Base image to use for building documentation archives. It uses `ONBUILD` to perform all required steps to copy the archive, and relies upon its parent `Dockerfile.builder.onbuild` that is invoked when building single documentation archives (see the `Dockerfile` of each branch) |
| [`Dockerfile.archives`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/Dockerfile.archives) | `gitlab-docs:archives` | Contains all the versions of the website in one archive. It copies all generated HTML files from every version in one location. | | [`archives.Dockerfile`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/dockerfiles/archives.Dockerfile) | `gitlab-docs:archives` | Contains all the versions of the website in one archive. It copies all generated HTML files from every version in one location. |
### How to build the images ### How to build the images

View File

@ -1116,6 +1116,36 @@ include a visual representation to help readers understand it, you can:
an area of the screen. an area of the screen.
- Create a short video of the interaction and link to it. - Create a short video of the interaction and link to it.
## Emojis
Don't use the Markdown emoji format, for example `:smile:`, for any purpose. Use
[GitLab SVG icons](#gitlab-svg-icons) instead.
Use of emoji in Markdown requires GitLab Flavored Markdown, which is not supported by Kramdown,
the Markdown rendering engine used for GitLab documentation.
## GitLab SVG icons
> [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/384) in GitLab 12.7.
You can use icons from the [GitLab SVG library](https://gitlab-org.gitlab.io/gitlab-svgs/)
directly in the documentation. For example, `**{tanuki}**` renders as: **{tanuki}**.
In most cases, you should avoid using the icons in text.
However, you can use an icon when hover text is the only
available way to describe a UI element. For example, **Delete** or **Edit** buttons
often have hover text only.
When you do use an icon, start with the hover text and follow it with the SVG reference in parentheses.
- Avoid: `Select **{pencil}** **Edit**.` This generates as: Select **{pencil}** **Edit**.
- Use instead: `Select **Edit** (**{pencil}**).` This generates as: Select **Edit** (**{pencil}**).
Do not use words to describe the icon:
- Avoid: `Select **Erase job log** (the trash icon).`
- Use instead: `Select **Erase job log** (**{remove}**).` This generates as: Select **Erase job log** (**{remove}**).
## Videos ## Videos
Adding GitLab YouTube video tutorials to the documentation is highly Adding GitLab YouTube video tutorials to the documentation is highly
@ -1197,28 +1227,6 @@ different mobile devices.
`/help`, because the GitLab Markdown processor doesn't support iframes. It's `/help`, because the GitLab Markdown processor doesn't support iframes. It's
hidden on the documentation site, but is displayed by `/help`. hidden on the documentation site, but is displayed by `/help`.
## GitLab SVG icons
> [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/384) in GitLab 12.7.
You can use icons from the [GitLab SVG library](https://gitlab-org.gitlab.io/gitlab-svgs/)
directly in the documentation. For example, `**{tanuki}**` renders as: **{tanuki}**.
In most cases, you should avoid using the icons in text.
However, you can use an icon when hover text is the only
available way to describe a UI element. For example, **Delete** or **Edit** buttons
often have hover text only.
When you do use an icon, start with the hover text and follow it with the SVG reference in parentheses.
- Avoid: `Select **{pencil}** **Edit**.` This generates as: Select **{pencil}** **Edit**.
- Use instead: `Select **Edit** (**{pencil}**).` This generates as: Select **Edit** (**{pencil}**).
Do not use words to describe the icon:
- Avoid: `Select **Erase job log** (the trash icon).`
- Use instead: `Select **Erase job log** (**{remove}**).` This generates as: Select **Erase job log** (**{remove}**).
## Alert boxes ## Alert boxes
Use alert boxes to call attention to information. Use them sparingly, and never have an alert box immediately follow another alert box. Use alert boxes to call attention to information. Use them sparingly, and never have an alert box immediately follow another alert box.

View File

@ -24,6 +24,20 @@ integration are logs. The most relevant logs for this integration are:
Here are some common pitfalls and how to overcome them. Here are some common pitfalls and how to overcome them.
## Common terminology
- **Lucene**: A full-text search library written in Java.
- **Near real time (NRT)**: Refers to the slight latency from the time to index a
document to the time when it becomes searchable.
- **Cluster**: A collection of one or more nodes that work together to hold all
the data, providing indexing and search capabilities.
- **Node**: A single server that works as part of a cluster.
- **Index**: A collection of documents that have somewhat similar characteristics.
- **Document**: A basic unit of information that can be indexed.
- **Shards**: Fully-functional and independent subdivisions of indices. Each shard is actually
a Lucene index.
- **Replicas**: Failover mechanisms that duplicate indices.
## How can I verify that my GitLab instance is using Elasticsearch? ## How can I verify that my GitLab instance is using Elasticsearch?
There are a couple of ways to achieve that: There are a couple of ways to achieve that:

View File

@ -700,101 +700,21 @@ The results are stored in `gl-container-scanning-report.json`.
## Reports JSON format ## Reports JSON format
The container scanning tool emits a JSON report file. For more information, see the The container scanning tool emits JSON reports which the [GitLab Runner](https://docs.gitlab.com/runner/)
[schema for this report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/container-scanning-report-format.json). recognizes through the [`artifacts:reports`](../../../ci/yaml/#artifactsreports)
keyword in the CI configuration file.
Here's an example container scanning report: Once the CI job finishes, the Runner uploads these reports to GitLab, which are then available in
the CI Job artifacts. In GitLab Ultimate, these reports can be viewed in the corresponding [pipeline](../vulnerability_report/pipeline.md)
and become part of the [Vulnerability Report](../vulnerability_report/).
```json-doc These reports must follow a format defined in the
{ [security report schemas](https://gitlab.com/gitlab-org/security-products/security-report-schemas/). See:
"version": "14.0.0",
"vulnerabilities": [ - [Latest schema for the container scanning report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/container-scanning-report-format.json).
{ - [Example container scanning report](https://gitlab.com/gitlab-examples/security/security-reports/-/blob/master/samples/container-scanning.json)
"id": "df52bc8ce9a2ae56bbcb0c4ecda62123fbd6f69b",
"category": "container_scanning", For more information, see [Security scanner integration](../../../development/integrations/secure.md).
"message": "CVE-2019-3462 in apt-1.4.8",
"description": "Incorrect sanitation of the 302 redirect field in HTTP transport method of apt versions 1.4.8 and earlier can lead to content injection by a MITM attacker, potentially leading to remote code execution on the target machine.",
"severity": "High",
"confidence": "Unknown",
"solution": "Upgrade apt from 1.4.8 to 1.4.9",
"scanner": {
"id": "trivy",
"name": "trivy"
},
"location": {
"dependency": {
"package": {
"name": "apt"
},
"version": "1.4.8"
},
"operating_system": "debian:9.4",
"image": "registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e",
"default_branch_image": "registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0:latest"
},
"identifiers": [
{
"type": "cve",
"name": "CVE-2019-3462",
"value": "CVE-2019-3462",
"url": "http://www.securityfocus.com/bid/106690"
}
],
"links": [
{
"url": "http://www.securityfocus.com/bid/106690"
},
{
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-3462"
},
{
"url": "https://lists.apache.org/thread.html/8338a0f605bdbb3a6098bb76f666a95fc2b2f53f37fa1ecc89f1146f@%3Cdevnull.infra.apache.org%3E"
},
{
"url": "https://lists.debian.org/debian-lts-announce/2019/01/msg00013.html"
},
{
"url": "https://lists.debian.org/debian-lts-announce/2019/01/msg00014.html"
},
{
"url": "https://security.netapp.com/advisory/ntap-20190125-0002/"
},
{
"url": "https://usn.ubuntu.com/3863-1/"
},
{
"url": "https://usn.ubuntu.com/3863-2/"
},
{
"url": "https://usn.ubuntu.com/usn/usn-3863-1"
},
{
"url": "https://usn.ubuntu.com/usn/usn-3863-2"
},
{
"url": "https://www.debian.org/security/2019/dsa-4371"
}
]
}
],
"remediations": []
"scan": {
"scanner": {
"id": "trivy",
"name": "Trivy",
"url": "https://github.com/aquasecurity/trivy/",
"vendor": {
"name": "GitLab"
},
"version": "0.16.0"
},
"type": "container_scanning",
"start_time": "2021-04-14T19:45:58",
"end_time": "2021-04-14T19:46:18",
"status": "success"
}
}
```
## Security Dashboard ## Security Dashboard

View File

@ -41349,6 +41349,9 @@ msgstr ""
msgid "Unauthenticated web rate limit period in seconds" msgid "Unauthenticated web rate limit period in seconds"
msgstr "" msgstr ""
msgid "Unban"
msgstr ""
msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?" msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
msgstr "" msgstr ""
@ -42167,6 +42170,9 @@ msgstr ""
msgid "User was successfully removed from project." msgid "User was successfully removed from project."
msgstr "" msgstr ""
msgid "User was successfully unbanned."
msgstr ""
msgid "User was successfully updated." msgid "User was successfully updated."
msgstr "" msgstr ""

View File

@ -113,7 +113,7 @@
"dateformat": "^5.0.1", "dateformat": "^5.0.1",
"deckar01-task_list": "^2.3.1", "deckar01-task_list": "^2.3.1",
"diff": "^3.4.0", "diff": "^3.4.0",
"dompurify": "^2.3.9", "dompurify": "^2.3.10",
"dropzone": "^4.2.0", "dropzone": "^4.2.0",
"editorconfig": "^0.15.3", "editorconfig": "^0.15.3",
"emoji-regex": "^10.0.0", "emoji-regex": "^10.0.0",

View File

@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe GroupsHelper do RSpec.describe GroupsHelper do
include ApplicationHelper include ApplicationHelper
include AvatarsHelper
describe '#group_icon_url' do describe '#group_icon_url' do
it 'returns an url for the avatar' do it 'returns an url for the avatar' do
@ -135,6 +136,37 @@ RSpec.describe GroupsHelper do
end end
end end
describe '#group_title_link' do
let_it_be(:group) { create(:group, :with_avatar) }
let(:raw_link) { group_title_link(group, show_avatar: true) }
let(:document) { Nokogiri::HTML.parse(raw_link) }
describe 'link' do
subject(:link) { document.css('.group-path').first }
it 'uses the group name as innerText' do
expect(link.inner_text).to eq(group.name)
end
it 'links to the group path' do
expect(link.attr('href')).to eq(group_path(group))
end
end
describe 'icon' do
subject(:icon) { document.css('.avatar-tile').first }
it 'specifies the group name as the alt text' do
expect(icon.attr('alt')).to eq(group.name)
end
it 'uses the group\'s avatar_url' do
expect(icon.attr('src')).to eq(group.avatar_url)
end
end
end
describe '#share_with_group_lock_help_text' do describe '#share_with_group_lock_help_text' do
context 'traversal queries' do context 'traversal queries' do
let_it_be_with_reload(:root_group) { create(:group) } let_it_be_with_reload(:root_group) { create(:group) }

View File

@ -87,7 +87,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end end
context 'when IP is already banned' do context 'when IP is already banned' do
subject { gl_auth.find_for_git_client('username', 'password', project: nil, ip: 'ip') } subject { gl_auth.find_for_git_client('username-does-not-matter', 'password-does-not-matter', project: nil, ip: 'ip') }
before do before do
expect_next_instance_of(Gitlab::Auth::IpRateLimiter) do |rate_limiter| expect_next_instance_of(Gitlab::Auth::IpRateLimiter) do |rate_limiter|
@ -219,16 +219,16 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end end
it 'recognizes master passwords' do it 'recognizes master passwords' do
user = create(:user, password: 'password') user = create(:user)
expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities) expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end end
include_examples 'user login operation with unique ip limit' do include_examples 'user login operation with unique ip limit' do
let(:user) { create(:user, password: 'password') } let(:user) { create(:user) }
def operation def operation
expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities) expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end end
end end
@ -502,8 +502,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
user = create( user = create(
:user, :user,
:blocked, :blocked,
username: 'normal_user', username: 'normal_user'
password: 'my-secret'
) )
expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')) expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
@ -512,7 +511,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context 'when 2fa is enabled globally' do context 'when 2fa is enabled globally' do
let_it_be(:user) do let_it_be(:user) do
create(:user, username: 'normal_user', password: 'my-secret', otp_grace_period_started_at: 1.day.ago) create(:user, username: 'normal_user', otp_grace_period_started_at: 1.day.ago)
end end
before do before do
@ -536,7 +535,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context 'when 2fa is enabled personally' do context 'when 2fa is enabled personally' do
let(:user) do let(:user) do
create(:user, :two_factor, username: 'normal_user', password: 'my-secret', otp_grace_period_started_at: 1.day.ago) create(:user, :two_factor, username: 'normal_user', otp_grace_period_started_at: 1.day.ago)
end end
it 'fails' do it 'fails' do
@ -548,8 +547,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it 'goes through lfs authentication' do it 'goes through lfs authentication' do
user = create( user = create(
:user, :user,
username: 'normal_user', username: 'normal_user'
password: 'my-secret'
) )
expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')) expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
@ -559,8 +557,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it 'goes through oauth authentication when the username is oauth2' do it 'goes through oauth authentication when the username is oauth2' do
user = create( user = create(
:user, :user,
username: 'oauth2', username: 'oauth2'
password: 'my-secret'
) )
expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')) expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
@ -635,7 +632,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context 'when deploy token and user have the same username' do context 'when deploy token and user have the same username' do
let(:username) { 'normal_user' } let(:username) { 'normal_user' }
let(:user) { create(:user, username: username, password: 'my-secret') } let(:user) { create(:user, username: username) }
let(:deploy_token) { create(:deploy_token, username: username, read_registry: false, projects: [project]) } let(:deploy_token) { create(:deploy_token, username: username, read_registry: false, projects: [project]) }
it 'succeeds for the token' do it 'succeeds for the token' do
@ -648,7 +645,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it 'succeeds for the user' do it 'succeeds for the user' do
auth_success = { actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities } auth_success = { actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities }
expect(gl_auth.find_for_git_client(username, 'my-secret', project: project, ip: 'ip')) expect(gl_auth.find_for_git_client(username, user.password, project: project, ip: 'ip'))
.to have_attributes(auth_success) .to have_attributes(auth_success)
end end
end end
@ -834,72 +831,64 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end end
describe 'find_with_user_password' do describe 'find_with_user_password' do
let!(:user) do let!(:user) { create(:user, username: username) }
create(:user,
username: username,
password: password,
password_confirmation: password)
end
let(:username) { 'John' } # username isn't lowercase, test this let(:username) { 'John' } # username isn't lowercase, test this
let(:password) { 'my-secret' }
it "finds user by valid login/password" do it "finds user by valid login/password" do
expect(gl_auth.find_with_user_password(username, password)).to eql user expect(gl_auth.find_with_user_password(username, user.password)).to eql user
end end
it 'finds user by valid email/password with case-insensitive email' do it 'finds user by valid email/password with case-insensitive email' do
expect(gl_auth.find_with_user_password(user.email.upcase, password)).to eql user expect(gl_auth.find_with_user_password(user.email.upcase, user.password)).to eql user
end end
it 'finds user by valid username/password with case-insensitive username' do it 'finds user by valid username/password with case-insensitive username' do
expect(gl_auth.find_with_user_password(username.upcase, password)).to eql user expect(gl_auth.find_with_user_password(username.upcase, user.password)).to eql user
end end
it "does not find user with invalid password" do it "does not find user with invalid password" do
password = 'wrong' expect(gl_auth.find_with_user_password(username, 'incorrect_password')).not_to eql user
expect(gl_auth.find_with_user_password(username, password)).not_to eql user
end end
it "does not find user with invalid login" do it "does not find user with invalid login" do
user = 'wrong' username = 'wrong'
expect(gl_auth.find_with_user_password(username, password)).not_to eql user expect(gl_auth.find_with_user_password(username, user.password)).not_to eql user
end end
include_examples 'user login operation with unique ip limit' do include_examples 'user login operation with unique ip limit' do
def operation def operation
expect(gl_auth.find_with_user_password(username, password)).to eq(user) expect(gl_auth.find_with_user_password(username, user.password)).to eq(user)
end end
end end
it 'finds the user in deactivated state' do it 'finds the user in deactivated state' do
user.deactivate! user.deactivate!
expect(gl_auth.find_with_user_password(username, password)).to eql user expect(gl_auth.find_with_user_password(username, user.password)).to eql user
end end
it "does not find user in blocked state" do it "does not find user in blocked state" do
user.block user.block
expect(gl_auth.find_with_user_password(username, password)).not_to eql user expect(gl_auth.find_with_user_password(username, user.password)).not_to eql user
end end
it 'does not find user in locked state' do it 'does not find user in locked state' do
user.lock_access! user.lock_access!
expect(gl_auth.find_with_user_password(username, password)).not_to eql user expect(gl_auth.find_with_user_password(username, user.password)).not_to eql user
end end
it "does not find user in ldap_blocked state" do it "does not find user in ldap_blocked state" do
user.ldap_block user.ldap_block
expect(gl_auth.find_with_user_password(username, password)).not_to eql user expect(gl_auth.find_with_user_password(username, user.password)).not_to eql user
end end
it 'does not find user in blocked_pending_approval state' do it 'does not find user in blocked_pending_approval state' do
user.block_pending_approval user.block_pending_approval
expect(gl_auth.find_with_user_password(username, password)).not_to eql user expect(gl_auth.find_with_user_password(username, user.password)).not_to eql user
end end
context 'with increment_failed_attempts' do context 'with increment_failed_attempts' do
@ -917,7 +906,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
user.save! user.save!
expect do expect do
gl_auth.find_with_user_password(username, password, increment_failed_attempts: true) gl_auth.find_with_user_password(username, user.password, increment_failed_attempts: true)
user.reload user.reload
end.to change(user, :failed_attempts).from(2).to(0) end.to change(user, :failed_attempts).from(2).to(0)
end end
@ -946,7 +935,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
user.save! user.save!
expect do expect do
gl_auth.find_with_user_password(username, password, increment_failed_attempts: true) gl_auth.find_with_user_password(username, user.password, increment_failed_attempts: true)
user.reload user.reload
end.not_to change(user, :failed_attempts) end.not_to change(user, :failed_attempts)
end end
@ -961,7 +950,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it "tries to autheticate with db before ldap" do it "tries to autheticate with db before ldap" do
expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login) expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login)
expect(gl_auth.find_with_user_password(username, password)).to eq(user) expect(gl_auth.find_with_user_password(username, user.password)).to eq(user)
end end
it "does not find user by using ldap as fallback to for authentication" do it "does not find user by using ldap as fallback to for authentication" do
@ -983,7 +972,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end end
it "does not find user by valid login/password" do it "does not find user by valid login/password" do
expect(gl_auth.find_with_user_password(username, password)).to be_nil expect(gl_auth.find_with_user_password(username, user.password)).to be_nil
end end
context "with ldap enabled" do context "with ldap enabled" do
@ -992,7 +981,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end end
it "does not find non-ldap user by valid login/password" do it "does not find non-ldap user by valid login/password" do
expect(gl_auth.find_with_user_password(username, password)).to be_nil expect(gl_auth.find_with_user_password(username, user.password)).to be_nil
end end
end end
end end

View File

@ -34,6 +34,8 @@ RSpec.describe 'getting a detailed sentry error' do
context 'when data is loading via reactive cache' do context 'when data is loading via reactive cache' do
before do before do
expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
end end
@ -48,6 +50,10 @@ RSpec.describe 'getting a detailed sentry error' do
.to receive(:issue_details) .to receive(:issue_details)
.and_return({ issue: sentry_detailed_error }) .and_return({ issue: sentry_detailed_error })
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
.with('error_tracking_view_details', values: current_user.id)
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
end end

View File

@ -16,9 +16,16 @@ RSpec.describe 'merge requests discussions' do
login_as(user) login_as(user)
end end
# rubocop:disable RSpec/InstanceVariable
def send_request def send_request
get discussions_namespace_project_merge_request_path(namespace_id: project.namespace, project_id: project, id: merge_request.iid) get(
discussions_namespace_project_merge_request_path(namespace_id: project.namespace, project_id: project, id: merge_request.iid),
headers: { 'If-None-Match' => @etag }
)
@etag = response.etag
end end
# rubocop:enable RSpec/InstanceVariable
it 'returns 200' do it 'returns 200' do
send_request send_request
@ -63,11 +70,6 @@ RSpec.describe 'merge requests discussions' do
let!(:award_emoji) { create(:award_emoji, awardable: first_note) } let!(:award_emoji) { create(:award_emoji, awardable: first_note) }
let!(:author_membership) { project.add_maintainer(author) } let!(:author_membership) { project.add_maintainer(author) }
before do
# Make a request to cache the discussions
send_request
end
shared_examples 'cache miss' do shared_examples 'cache miss' do
it 'does not hit a warm cache' do it 'does not hit a warm cache' do
expect_next_instance_of(DiscussionSerializer) do |serializer| expect_next_instance_of(DiscussionSerializer) do |serializer|
@ -80,176 +82,213 @@ RSpec.describe 'merge requests discussions' do
end end
end end
it 'gets cached on subsequent requests' do shared_examples 'cache hit' do
expect_next_instance_of(DiscussionSerializer) do |serializer| it 'gets cached on subsequent requests' do
expect(serializer).not_to receive(:represent) expect_next_instance_of(DiscussionSerializer) do |serializer|
end expect(serializer).not_to receive(:represent)
end
send_request send_request
end
context 'when a note in a discussion got updated' do
before do
first_note.update!(updated_at: 1.minute.from_now)
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end end
end end
context 'when a note in a discussion got its reference state updated' do context 'when mr_discussions_http_cache and disabled_mr_discussions_redis_cache are enabled' do
before do before do
reference.close! send_request
end end
it_behaves_like 'cache miss' do it_behaves_like 'cache hit'
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when a note in a discussion got resolved' do context 'when a note in a discussion got updated' do
before do before do
travel_to(1.minute.from_now) do first_note.update!(updated_at: 1.minute.from_now)
first_note.resolve!(user) end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end end
end end
it_behaves_like 'cache miss' do context 'when a note in a discussion got its reference state updated' do
let(:changed_notes) { [first_note, second_note] } before do
end reference.close!
end end
context 'when a note is added to a discussion' do it_behaves_like 'cache miss' do
let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) } let(:changed_notes) { [first_note, second_note] }
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note, third_note] }
end
end
context 'when a note is removed from a discussion' do
before do
second_note.destroy!
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note] }
end
end
context 'when an emoji is awarded to a note in discussion' do
before do
travel_to(1.minute.from_now) do
create(:award_emoji, awardable: first_note)
end end
end end
it_behaves_like 'cache miss' do context 'when a note in a discussion got resolved' do
let(:changed_notes) { [first_note, second_note] } before do
end travel_to(1.minute.from_now) do
end first_note.resolve!(user)
end
end
context 'when an award emoji is removed from a note in discussion' do it_behaves_like 'cache miss' do
before do let(:changed_notes) { [first_note, second_note] }
travel_to(1.minute.from_now) do
award_emoji.destroy!
end end
end end
it_behaves_like 'cache miss' do context 'when a note is added to a discussion' do
let(:changed_notes) { [first_note, second_note] } let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) }
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note, third_note] }
end
end
context 'when a note is removed from a discussion' do
before do
second_note.destroy!
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note] }
end
end
context 'when an emoji is awarded to a note in discussion' do
before do
travel_to(1.minute.from_now) do
create(:award_emoji, awardable: first_note)
end
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when an award emoji is removed from a note in discussion' do
before do
travel_to(1.minute.from_now) do
award_emoji.destroy!
end
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when the diff note position changes' do
before do
# This replicates a position change wherein timestamps aren't updated
# which is why `Gitlab::Timeless.timeless` is utilized. This is the
# same approach being used in Discussions::UpdateDiffPositionService
# which is responsible for updating the positions of diff discussions
# when MR updates.
first_note.position = Gitlab::Diff::Position.new(
old_path: first_note.position.old_path,
new_path: first_note.position.new_path,
old_line: first_note.position.old_line,
new_line: first_note.position.new_line + 1,
diff_refs: first_note.position.diff_refs
)
Gitlab::Timeless.timeless(first_note, &:save)
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when the HEAD diff note position changes' do
before do
# This replicates a DiffNotePosition change. This is the same approach
# being used in Discussions::CaptureDiffNotePositionService which is
# responsible for updating/creating DiffNotePosition of a diff discussions
# in relation to HEAD diff.
new_position = Gitlab::Diff::Position.new(
old_path: first_note.position.old_path,
new_path: first_note.position.new_path,
old_line: first_note.position.old_line,
new_line: first_note.position.new_line + 1,
diff_refs: first_note.position.diff_refs
)
DiffNotePosition.create_or_update_for(
first_note,
diff_type: :head,
position: new_position,
line_code: 'bd4b7bfff3a247ccf6e3371c41ec018a55230bcc_534_521'
)
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when author detail changes' do
before do
author.update!(name: "#{author.name} (Updated)")
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when author status changes' do
before do
Users::SetStatusService.new(author, message: "updated status").execute
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when author role changes' do
before do
Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(author_membership)
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when current_user role changes' do
before do
Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(project.member(user))
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end end
end end
context 'when the diff note position changes' do context 'when mr_discussions_http_cache is disabled' do
before do before do
# This replicates a position change wherein timestamps aren't updated stub_feature_flags(mr_discussions_http_cache: false)
# which is why `Gitlab::Timeless.timeless` is utilized. This is the send_request
# same approach being used in Discussions::UpdateDiffPositionService
# which is responsible for updating the positions of diff discussions
# when MR updates.
first_note.position = Gitlab::Diff::Position.new(
old_path: first_note.position.old_path,
new_path: first_note.position.new_path,
old_line: first_note.position.old_line,
new_line: first_note.position.new_line + 1,
diff_refs: first_note.position.diff_refs
)
Gitlab::Timeless.timeless(first_note, &:save)
end end
it_behaves_like 'cache miss' do it_behaves_like 'cache hit'
let(:changed_notes) { [first_note, second_note] }
end
end end
context 'when the HEAD diff note position changes' do context 'when disabled_mr_discussions_redis_cache is disabled' do
before do before do
# This replicates a DiffNotePosition change. This is the same approach stub_feature_flags(disabled_mr_discussions_redis_cache: false)
# being used in Discussions::CaptureDiffNotePositionService which is send_request
# responsible for updating/creating DiffNotePosition of a diff discussions
# in relation to HEAD diff.
new_position = Gitlab::Diff::Position.new(
old_path: first_note.position.old_path,
new_path: first_note.position.new_path,
old_line: first_note.position.old_line,
new_line: first_note.position.new_line + 1,
diff_refs: first_note.position.diff_refs
)
DiffNotePosition.create_or_update_for(
first_note,
diff_type: :head,
position: new_position,
line_code: 'bd4b7bfff3a247ccf6e3371c41ec018a55230bcc_534_521'
)
end end
it_behaves_like 'cache miss' do it_behaves_like 'cache hit'
let(:changed_notes) { [first_note, second_note] }
end
end end
context 'when author detail changes' do context 'when mr_discussions_http_cache and disabled_mr_discussions_redis_cache are disabled' do
before do before do
author.update!(name: "#{author.name} (Updated)") stub_feature_flags(mr_discussions_http_cache: false, disabled_mr_discussions_redis_cache: false)
send_request
end end
it_behaves_like 'cache miss' do it_behaves_like 'cache hit'
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when author status changes' do
before do
Users::SetStatusService.new(author, message: "updated status").execute
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when author role changes' do
before do
Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(author_membership)
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end
context 'when current_user role changes' do
before do
Members::UpdateService.new(owner, access_level: Gitlab::Access::GUEST).execute(project.member(user))
end
it_behaves_like 'cache miss' do
let(:changed_notes) { [first_note, second_note] }
end
end end
end end
end end

View File

@ -9001,9 +9001,9 @@ tapable@^1.0.0, tapable@^1.1.3:
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
tar@^6.0.2: tar@^6.0.2:
version "6.1.0" version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
dependencies: dependencies:
chownr "^2.0.0" chownr "^2.0.0"
fs-minipass "^2.0.0" fs-minipass "^2.0.0"

View File

@ -5076,10 +5076,10 @@ dompurify@2.3.6:
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875"
integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg== integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==
dompurify@^2.3.9: dompurify@^2.3.10, dompurify@^2.3.9:
version "2.3.9" version "2.3.10"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.9.tgz#a4be5e7278338d6db09922dffcf6182cd099d70a" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.10.tgz#901f7390ffe16a91a5a556b94043314cd4850385"
integrity sha512-3zOnuTwup4lPV/GfGS6UzG4ub9nhSYagR/5tB3AvDEwqyy5dtyCM2dVjwGDCnrPerXifBKTYh/UWCGKK7ydhhw== integrity sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g==
domutils@^2.5.2, domutils@^2.6.0: domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0" version "2.6.0"
@ -12007,9 +12007,9 @@ tapable@^1.0.0, tapable@^1.1.3:
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
tar@^6.0.2: tar@^6.0.2:
version "6.0.5" version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
dependencies: dependencies:
chownr "^2.0.0" chownr "^2.0.0"
fs-minipass "^2.0.0" fs-minipass "^2.0.0"