Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
66fc7ba6f3
commit
e7e44c0e4c
2
Gemfile
2
Gemfile
|
@ -2,7 +2,7 @@
|
|||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'rails', '~> 6.1.4.4'
|
||||
gem 'rails', '~> 6.1.4.6'
|
||||
|
||||
gem 'bootsnap', '~> 1.9.1', require: false
|
||||
|
||||
|
|
108
Gemfile.lock
108
Gemfile.lock
|
@ -11,63 +11,63 @@ GEM
|
|||
RedCloth (4.3.2)
|
||||
acme-client (2.0.9)
|
||||
faraday (>= 0.17, < 2.0.0)
|
||||
actioncable (6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
actioncable (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
activejob (= 6.1.4.4)
|
||||
activerecord (= 6.1.4.4)
|
||||
activestorage (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
actionmailbox (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activestorage (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
actionview (= 6.1.4.4)
|
||||
activejob (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
actionmailer (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
actionview (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.1.4.4)
|
||||
actionview (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
actionpack (6.1.4.6)
|
||||
actionview (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
activerecord (= 6.1.4.4)
|
||||
activestorage (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
actiontext (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activestorage (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
actionview (6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
activejob (6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
activerecord (6.1.4.4)
|
||||
activemodel (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
activemodel (6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
activerecord (6.1.4.6)
|
||||
activemodel (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
activerecord-explain-analyze (0.1.0)
|
||||
activerecord (>= 4)
|
||||
pg
|
||||
activestorage (6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
activejob (= 6.1.4.4)
|
||||
activerecord (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
activestorage (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
marcel (~> 1.0.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (6.1.4.4)
|
||||
activesupport (6.1.4.6)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
|
@ -967,20 +967,20 @@ GEM
|
|||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-timeout (0.5.2)
|
||||
rails (6.1.4.4)
|
||||
actioncable (= 6.1.4.4)
|
||||
actionmailbox (= 6.1.4.4)
|
||||
actionmailer (= 6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
actiontext (= 6.1.4.4)
|
||||
actionview (= 6.1.4.4)
|
||||
activejob (= 6.1.4.4)
|
||||
activemodel (= 6.1.4.4)
|
||||
activerecord (= 6.1.4.4)
|
||||
activestorage (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
rails (6.1.4.6)
|
||||
actioncable (= 6.1.4.6)
|
||||
actionmailbox (= 6.1.4.6)
|
||||
actionmailer (= 6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
actiontext (= 6.1.4.6)
|
||||
actionview (= 6.1.4.6)
|
||||
activejob (= 6.1.4.6)
|
||||
activemodel (= 6.1.4.6)
|
||||
activerecord (= 6.1.4.6)
|
||||
activestorage (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 6.1.4.4)
|
||||
railties (= 6.1.4.6)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
|
@ -994,9 +994,9 @@ GEM
|
|||
rails-i18n (6.0.0)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 7)
|
||||
railties (6.1.4.4)
|
||||
actionpack (= 6.1.4.4)
|
||||
activesupport (= 6.1.4.4)
|
||||
railties (6.1.4.6)
|
||||
actionpack (= 6.1.4.6)
|
||||
activesupport (= 6.1.4.6)
|
||||
method_source
|
||||
rake (>= 0.13)
|
||||
thor (~> 1.0)
|
||||
|
@ -1580,7 +1580,7 @@ DEPENDENCIES
|
|||
rack-oauth2 (~> 1.16.0)
|
||||
rack-proxy (~> 0.6.0)
|
||||
rack-timeout (~> 0.5.1)
|
||||
rails (~> 6.1.4.4)
|
||||
rails (~> 6.1.4.6)
|
||||
rails-controller-testing
|
||||
rails-i18n (~> 6.0)
|
||||
rainbow (~> 3.0)
|
||||
|
|
|
@ -266,7 +266,7 @@ export default {
|
|||
>
|
||||
<span class="gl-font-lg">·</span>
|
||||
<span data-testid="vsa-stage-event-date">
|
||||
{{ s__('OpenedNDaysAgo|Opened') }}
|
||||
{{ s__('OpenedNDaysAgo|Created') }}
|
||||
<gl-link class="gl-text-black-normal" :href="item.url">{{
|
||||
item.createdAt
|
||||
}}</gl-link>
|
||||
|
|
|
@ -102,7 +102,7 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
<span>
|
||||
{{ __('Opened') }}
|
||||
{{ __('Created') }}
|
||||
<time-ago-tooltip data-testid="startTimeItem" :time="createdAt" />
|
||||
{{ __('by') }}
|
||||
</span>
|
||||
|
|
|
@ -40,7 +40,7 @@ module Projects
|
|||
avenues = [authorizable_project_members]
|
||||
|
||||
avenues << if project.personal?
|
||||
project_owner_acting_as_maintainer
|
||||
project_owner
|
||||
else
|
||||
authorizable_group_members
|
||||
end
|
||||
|
@ -85,9 +85,15 @@ module Projects
|
|||
Member.from_union(members)
|
||||
end
|
||||
|
||||
def project_owner_acting_as_maintainer
|
||||
# workaround until we migrate Project#owners to have membership with
|
||||
# OWNER access level
|
||||
def project_owner
|
||||
user_id = project.namespace.owner.id
|
||||
access_level = Gitlab::Access::MAINTAINER
|
||||
access_level = if ::Feature.enabled?(:personal_project_owner_with_owner_access, default_enabled: :yaml)
|
||||
Gitlab::Access::OWNER
|
||||
else
|
||||
Gitlab::Access::MAINTAINER
|
||||
end
|
||||
|
||||
Member
|
||||
.from(generate_from_statement([[user_id, access_level]])) # rubocop: disable CodeReuse/ActiveRecord
|
||||
|
|
|
@ -8,8 +8,14 @@ module SelectForProjectAuthorization
|
|||
select("projects.id AS project_id", "members.access_level")
|
||||
end
|
||||
|
||||
def select_as_maintainer_for_project_authorization
|
||||
select(["projects.id AS project_id", "#{Gitlab::Access::MAINTAINER} AS access_level"])
|
||||
# workaround until we migrate Project#owners to have membership with
|
||||
# OWNER access level
|
||||
def select_project_owner_for_project_authorization
|
||||
if ::Feature.enabled?(:personal_project_owner_with_owner_access, default_enabled: :yaml)
|
||||
select(["projects.id AS project_id", "#{Gitlab::Access::OWNER} AS access_level"])
|
||||
else
|
||||
select(["projects.id AS project_id", "#{Gitlab::Access::MAINTAINER} AS access_level"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -459,7 +459,7 @@ class Project < ApplicationRecord
|
|||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
delegate :members, to: :team, prefix: true
|
||||
delegate :add_user, :add_users, to: :team
|
||||
delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_role, to: :team
|
||||
delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_owner, :add_role, to: :team
|
||||
delegate :group_runners_enabled, :group_runners_enabled=, to: :ci_cd_settings, allow_nil: true
|
||||
delegate :root_ancestor, to: :namespace, allow_nil: true
|
||||
delegate :last_pipeline, to: :commit, allow_nil: true
|
||||
|
|
|
@ -23,6 +23,10 @@ class ProjectTeam
|
|||
add_user(user, :maintainer, current_user: current_user)
|
||||
end
|
||||
|
||||
def add_owner(user, current_user: nil)
|
||||
add_user(user, :owner, current_user: current_user)
|
||||
end
|
||||
|
||||
def add_role(user, role, current_user: nil)
|
||||
public_send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend
|
||||
end
|
||||
|
@ -103,7 +107,9 @@ class ProjectTeam
|
|||
if group
|
||||
group.owners
|
||||
else
|
||||
[project.owner]
|
||||
# workaround until we migrate Project#owners to have membership with
|
||||
# OWNER access level
|
||||
Array.wrap(fetch_members(Gitlab::Access::OWNER)) | Array.wrap(project.owner)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ module Members
|
|||
module Projects
|
||||
class CreatorService < Members::CreatorService
|
||||
def self.access_levels
|
||||
Gitlab::Access.sym_options
|
||||
Gitlab::Access.sym_options_with_owner
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -14,6 +14,7 @@ module NotificationRecipients
|
|||
return [] unless project
|
||||
|
||||
add_recipients(project.team.maintainers, :mention, nil)
|
||||
add_recipients(project.team.owners, :mention, nil)
|
||||
end
|
||||
|
||||
def acting_user
|
||||
|
|
|
@ -147,7 +147,11 @@ module Projects
|
|||
priority: UserProjectAccessChangedService::LOW_PRIORITY
|
||||
)
|
||||
else
|
||||
@project.add_maintainer(@project.namespace.owner, current_user: current_user)
|
||||
if ::Feature.enabled?(:personal_project_owner_with_owner_access, default_enabled: :yaml)
|
||||
@project.add_owner(@project.namespace.owner, current_user: current_user)
|
||||
else
|
||||
@project.add_maintainer(@project.namespace.owner, current_user: current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
- page_title _('Monitor Settings')
|
||||
- breadcrumb_title _('Monitor Settings')
|
||||
|
||||
.gl-alert.gl-alert-danger.gl-mb-5
|
||||
- removal_epic_link_url = 'https://gitlab.com/groups/gitlab-org/-/epics/7188'
|
||||
- removal_epic_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer" class="gl-link">'.html_safe % { url: removal_epic_link_url }
|
||||
- opstrace_link_url = 'https://gitlab.com/groups/gitlab-org/-/epics/6976'
|
||||
- opstrace_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer" class="gl-link">'.html_safe % { url: opstrace_link_url }
|
||||
- link_end = '</a>'.html_safe
|
||||
.gl-alert-container
|
||||
= sprite_icon('error', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
|
||||
.gl-alert-content
|
||||
.gl-alert-title
|
||||
= s_('Deprecations|Feature deprecation and removal')
|
||||
.gl-alert-body
|
||||
%p
|
||||
= html_escape(s_('Deprecations|The metrics, logs and tracing features were deprecated in GitLab 14.7, and are %{removal_link_start} scheduled for removal %{link_end} in GitLab 15.0. For information on a possible replacement, %{opstrace_link_start} learn more about Opstrace %{link_end}.')) % {removal_link_start: removal_epic_link_start, opstrace_link_start: opstrace_link_start, link_end: link_end }
|
||||
|
||||
= render 'projects/settings/operations/metrics_dashboard'
|
||||
= render 'projects/settings/operations/tracing'
|
||||
= render 'projects/settings/operations/error_tracking'
|
||||
|
|
|
@ -9,4 +9,5 @@ raise "METRICS_SERVER_TARGET cannot be blank" if target.blank?
|
|||
metrics_dir = ENV["prometheus_multiproc_dir"] || File.absolute_path("tmp/prometheus_multiproc_dir/#{target}")
|
||||
wipe_metrics_dir = Gitlab::Utils.to_boolean(ENV['WIPE_METRICS_DIR']) || false
|
||||
|
||||
Process.wait(MetricsServer.spawn(target, metrics_dir: metrics_dir, wipe_metrics_dir: wipe_metrics_dir))
|
||||
server = MetricsServer.new(target, metrics_dir, wipe_metrics_dir)
|
||||
server.start
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343917
|
|||
milestone: '14.5'
|
||||
type: development
|
||||
group: group::container security
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: personal_project_owner_with_owner_access
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78193
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351919
|
||||
milestone: '14.8'
|
||||
type: development
|
||||
group: group::workspace
|
||||
default_enabled: false
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: prohibit_hexadecimal_branch_names
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/28439ca4b1dd14f22a5a6ad14530f6bf1046f8bc
|
||||
rollout_issue_url:
|
||||
milestone: '12.10'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: true
|
|
@ -185,17 +185,17 @@ This allows you to create a single file. For creating multiple files with a sing
|
|||
POST /projects/:id/repository/files/:file_path
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `file_path` | string | yes | URL encoded full path to new file. Ex. `lib%2Fclass%2Erb`. |
|
||||
| `branch` | string | yes | Name of the branch |
|
||||
| `start_branch` | string | no | Name of the branch to start the new commit from |
|
||||
| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
|
||||
| `author_email` | string | no | Specify the commit author's email address |
|
||||
| `author_name` | string | no | Specify the commit author's name |
|
||||
| `content` | string | yes | File content |
|
||||
| `commit_message` | string | yes | Commit message |
|
||||
| Attribute | Type | Required | Description |
|
||||
| ---------------- | -------------- | -------- | ----------- |
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
|
||||
| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
|
||||
| `branch` | string | yes | Name of the new branch to create. The commit is added to this branch. |
|
||||
| `start_branch` | string | no | Name of the base branch to create the new branch from. |
|
||||
| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
|
||||
| `author_email` | string | no | The commit author's email address. |
|
||||
| `author_name` | string | no | The commit author's name. |
|
||||
| `content` | string | yes | The file's content. |
|
||||
| `commit_message` | string | yes | The commit message. |
|
||||
|
||||
```shell
|
||||
curl --request POST --header 'PRIVATE-TOKEN: <your_access_token>' \
|
||||
|
@ -222,18 +222,18 @@ This allows you to update a single file. For updating multiple files with a sing
|
|||
PUT /projects/:id/repository/files/:file_path
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------|
|
||||
| Attribute | Type | Required | Description |
|
||||
| ---------------- | -------------- | -------- | ----------- |
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `file_path` | string | yes | URL encoded full path to new file. Ex. `lib%2Fclass%2Erb`. |
|
||||
| `branch` | string | yes | Name of the branch |
|
||||
| `start_branch` | string | no | Name of the branch to start the new commit from |
|
||||
| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
|
||||
| `author_email` | string | no | Specify the commit author's email address |
|
||||
| `author_name` | string | no | Specify the commit author's name |
|
||||
| `content` | string | yes | File content |
|
||||
| `commit_message` | string | yes | Commit message |
|
||||
| `last_commit_id` | string | no | Last known file commit ID |
|
||||
| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
|
||||
| `branch` | string | yes | Name of the new branch to create. The commit is added to this branch. |
|
||||
| `start_branch` | string | no | Name of the base branch to create the new branch from. |
|
||||
| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
|
||||
| `author_email` | string | no | The commit author's email address. |
|
||||
| `author_name` | string | no | The commit author's name. |
|
||||
| `content` | string | yes | The file's content. |
|
||||
| `commit_message` | string | yes | The commit message. |
|
||||
| `last_commit_id` | string | no | Last known file commit ID. |
|
||||
|
||||
```shell
|
||||
curl --request PUT --header 'PRIVATE-TOKEN: <your_access_token>' \
|
||||
|
@ -270,16 +270,16 @@ This allows you to delete a single file. For deleting multiple files with a sing
|
|||
DELETE /projects/:id/repository/files/:file_path
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `file_path` | string | yes | URL encoded full path to new file. Ex. `lib%2Fclass%2Erb`. |
|
||||
| `branch` | string | yes | Name of the branch |
|
||||
| `start_branch` | string | no | Name of the branch to start the new commit from |
|
||||
| `author_email` | string | no | Specify the commit author's email address. |
|
||||
| `author_name` | string | no | Specify the commit author's name. |
|
||||
| `commit_message` | string | yes | Commit message. |
|
||||
| `last_commit_id` | string | no | Last known file commit ID. |
|
||||
| Attribute | Type | Required | Description |
|
||||
| ---------------- | -------------- | -------- | ----------- |
|
||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
|
||||
| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
|
||||
| `branch` | string | yes | Name of the new branch to create. The commit is added to this branch. |
|
||||
| `start_branch` | string | no | Name of the base branch to create the new branch from. |
|
||||
| `author_email` | string | no | The commit author's email address. |
|
||||
| `author_name` | string | no | The commit author's name. |
|
||||
| `commit_message` | string | yes | The commit message. |
|
||||
| `last_commit_id` | string | no | Last known file commit ID. |
|
||||
|
||||
```shell
|
||||
curl --request DELETE --header 'PRIVATE-TOKEN: <your_access_token>' \
|
||||
|
|
|
@ -398,3 +398,14 @@ end
|
|||
|
||||
1. Be sure to update the [GitLab CE/EE documentation](../administration/logs.md) and the [GitLab.com
|
||||
runbooks](https://gitlab.com/gitlab-com/runbooks/blob/master/docs/logging/README.md).
|
||||
|
||||
## Control logging visibility
|
||||
|
||||
An increase in the logs can cause a growing backlog of unacknowledged messages. When adding new log messages, make sure they don't increase the overall volume of logging by more than 10%.
|
||||
|
||||
### Deprecation notices
|
||||
|
||||
If the expected volume of deprecation notices is large:
|
||||
|
||||
- Only log them in the development environment.
|
||||
- If needed, log them in the testing environment.
|
||||
|
|
|
@ -58,7 +58,7 @@ You can configure the following security controls:
|
|||
- [API Fuzzing](../api_fuzzing/index.md)
|
||||
- Select **Enable API Fuzzing** to use API Fuzzing for the current project. For more details, read [API Fuzzing](../../../user/application_security/api_fuzzing/index.md#enable-web-api-fuzzing).
|
||||
- [Coverage Fuzzing](../coverage_fuzzing/index.md)
|
||||
- Can be configured with `.gitlab-ci.yml`. For more details, read [Coverage Fuzzing](../../../user/application_security/coverage_fuzzing/index.md#configuration).
|
||||
- Can be configured with `.gitlab-ci.yml`. For more details, read [Coverage Fuzzing](../../../user/application_security/coverage_fuzzing/index.md#enable-coverage-guided-fuzz-testing).
|
||||
|
||||
## Compliance **(ULTIMATE)**
|
||||
|
||||
|
|
|
@ -22,8 +22,14 @@ The fuzz testing process:
|
|||
1. Compiles the target application.
|
||||
1. Runs the instrumented application, using the `gitlab-cov-fuzz` tool.
|
||||
1. Parses and analyzes the exception information output by the fuzzer.
|
||||
1. Downloads the [corpus](../terminology/index.md#corpus) and crash events from previous pipelines.
|
||||
1. Downloads the [corpus](../terminology/index.md#corpus) from either:
|
||||
- The previous pipelines.
|
||||
- If `COVFUZZ_USE_REGISTRY` is set to `true`, the [corpus registry](#corpus-registry).
|
||||
1. Downloads crash events from previous pipeline.
|
||||
1. Outputs the parsed crash events and data to the `gl-coverage-fuzzing-report.json` file.
|
||||
1. Updates the corpus, either:
|
||||
- In the job's pipeline.
|
||||
- If `COVFUZZ_USE_REGISTRY` is set to `true`, in the corpus registry.
|
||||
|
||||
The results of the coverage-guided fuzz testing are available in the CI/CD pipeline.
|
||||
|
||||
|
@ -43,9 +49,20 @@ You can use the following fuzzing engines to test the specified languages.
|
|||
| Python | [`pythonfuzz`](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/pythonfuzz) | [pythonfuzz-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/pythonfuzz-fuzzing-example) |
|
||||
| AFL (any language that works on top of AFL) | [AFL](https://lcamtuf.coredump.cx/afl/) | [afl-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/afl-fuzzing-example) |
|
||||
|
||||
## Configuration
|
||||
## Confirm status of coverage-guided fuzz testing
|
||||
|
||||
To enable coverage-guided fuzz testing, edit the `.gitlab-ci.yml` file:
|
||||
To confirm the status of coverage-guided fuzz testing:
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Security & Compliance > Configuration**.
|
||||
1. In the **Coverage Fuzzing** section the status is:
|
||||
- **Not configured**
|
||||
- **Enabled**
|
||||
- A prompt to upgrade to GitLab Ultimate.
|
||||
|
||||
## Enable coverage-guided fuzz testing
|
||||
|
||||
To enable coverage-guided fuzz testing, edit `.gitlab-ci.yml`:
|
||||
|
||||
1. Add the `fuzz` stage to the list of stages.
|
||||
|
||||
|
@ -98,10 +115,13 @@ Use the following variables to configure coverage-guided fuzz testing in your CI
|
|||
|
||||
| CI/CD variable | Description |
|
||||
|---------------------------|---------------------------------------------------------------------------------|
|
||||
| `COVFUZZ_ADDITIONAL_ARGS` | Arguments passed to `gitlab-cov-fuzz`. Used to customize the behavior of the underlying fuzzing engine. Read the fuzzing engine's documentation for a complete list of arguments. |
|
||||
| `COVFUZZ_ADDITIONAL_ARGS` | Arguments passed to `gitlab-cov-fuzz`. Used to customize the behavior of the underlying fuzzing engine. Read the fuzzing engine's documentation for a complete list of arguments. |
|
||||
| `COVFUZZ_BRANCH` | The branch on which long-running fuzzing jobs are to be run. On all other branches, only fuzzing regression tests are run. Default: Repository's default branch. |
|
||||
| `COVFUZZ_SEED_CORPUS` | Path to a seed corpus directory. Default: empty. |
|
||||
| `COVFUZZ_URL_PREFIX` | Path to the `gitlab-cov-fuzz` repository cloned for use with an offline environment. You should only change this value when using an offline environment. Default: `https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz/-/raw`. |
|
||||
| `COVFUZZ_USE_REGISTRY` | Set to `true` to have the corpus stored in the GitLab corpus registry. The variables `COVFUZZ_CORPUS_NAME` and `COVFUZZ_GITLAB_TOKEN` are required if this variable is set to `true`. Default: `false`. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5017) in GitLab 14.8. |
|
||||
| `COVFUZZ_CORPUS_NAME` | Name of the corpus to be used in the job. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5017) in GitLab 14.8. |
|
||||
| `COVFUZZ_GITLAB_TOKEN` | Environment variable configured with [Personal Access Token](../../../user/profile/personal_access_tokens.md#create-a-personal-access-token) with API read/write access. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5017) in GitLab 14.8. |
|
||||
|
||||
#### Seed corpus
|
||||
|
||||
|
@ -122,7 +142,91 @@ Each fuzzing step outputs these artifacts:
|
|||
You can download the JSON report file from the CI/CD pipelines page. For more information, see
|
||||
[Downloading artifacts](../../../ci/pipelines/job_artifacts.md#download-job-artifacts).
|
||||
|
||||
### Coverage-guided fuzz testing report
|
||||
## Corpus registry
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5017) in GitLab 14.8.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is available. To hide the feature, ask an
|
||||
administrator to [disable the feature flags](../../../administration/feature_flags.md) named
|
||||
`corpus_management` and `corpus_management_ui`. On GitLab.com, this feature is available.
|
||||
|
||||
The corpus registry is a library of corpuses. Corpuses in a project's registry are available to
|
||||
all jobs in that project. A project-wide registry is a more efficient way to manage corpuses than
|
||||
the default option of one corpus per job.
|
||||
|
||||
The corpus registry uses the package registry to store the project's corpuses. Corpuses stored in
|
||||
the registry are hidden to ensure data integrity.
|
||||
|
||||
In the GitLab UI, with corpus management you can:
|
||||
|
||||
- View details of the corpus registry.
|
||||
- Download a corpus.
|
||||
- Delete a corpus.
|
||||
- Create a new corpus.
|
||||
|
||||
When you download a corpus, the file is named `artifacts.zip`, regardless of the filename used when
|
||||
the corpus was initially uploaded. This file contains only the corpus, which is different to the
|
||||
artifacts files you can download from the CI/CD pipeline.
|
||||
|
||||
### View details of the corpus registry
|
||||
|
||||
To view details of the corpus registry:
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Security & Compliance > Configuration**.
|
||||
1. In the **Coverage Fuzzing** section, select **Manage corpus**.
|
||||
|
||||
### Create a corpus in the corpus registry
|
||||
|
||||
To create a corpus in the corpus registry, either:
|
||||
|
||||
- Create a corpus in a pipeline
|
||||
- Upload an existing corpus file
|
||||
|
||||
#### Create a corpus in a pipeline
|
||||
|
||||
To create a corpus in a pipeline:
|
||||
|
||||
1. In the `.gitlab-ci.yml` file, edit the `my_fuzz_target` job.
|
||||
1. Set the following variables:
|
||||
- Set `COVFUZZ_USE_REGISTRY` to `true`.
|
||||
- Set `COVFUZZ_CORPUS_NAME` to name the corpus.
|
||||
- Set `COVFUZZ_GITLAB_TOKEN` to the value of the personal access token.
|
||||
|
||||
After the `my_fuzz_target` job runs, the corpus is stored in the corpus registry, with the name
|
||||
provided by the `COVFUZZ_CORPUS_NAME` variable. The corpus is updated on every pipeline run.
|
||||
|
||||
#### Upload a corpus file
|
||||
|
||||
To upload an existing corpus file:
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Security & Compliance > Configuration**.
|
||||
1. In the **Coverage Fuzzing** section, select **Manage corpus**.
|
||||
1. Select **New corpus**.
|
||||
1. Complete the fields.
|
||||
1. Select **Upload file**.
|
||||
1. Select **Add**.
|
||||
|
||||
You can now reference the corpus in the `.gitlab-ci.yml` file. Ensure the value used in the
|
||||
`COVFUZZ_CORPUS_NAME` variable matches exactly the name given to the uploaded corpus file.
|
||||
|
||||
### Use a corpus stored in the corpus registry
|
||||
|
||||
To use a corpus stored in the corpus registry, you must reference it by its name. To confirm the
|
||||
name of the relevant corpus, view details of the corpus registry.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- [Enable coverage-guide fuzz testing](#enable-coverage-guided-fuzz-testing) in the project.
|
||||
|
||||
1. Set the following variables in the `.gitlab-ci.yml` file:
|
||||
- Set `COVFUZZ_USE_REGISTRY` to `true`.
|
||||
- Set `COVFUZZ_CORPUS_NAME` to the name of the corpus.
|
||||
- Set `COVFUZZ_GITLAB_TOKEN` to the value of the personal access token.
|
||||
|
||||
## Coverage-guided fuzz testing report
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220062) in GitLab 13.3 as an [Alpha feature](../../../policy/alpha-beta-support.md#alpha-features).
|
||||
|
||||
|
@ -255,3 +359,16 @@ vulnerability:
|
|||
engines listed in [Supported fuzzing engines and languages](#supported-fuzzing-engines-and-languages).
|
||||
|
||||
<!-- vale gitlab.Acronyms = YES -->
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error "Unable to extract corpus folder from artifacts zip file"
|
||||
|
||||
If you see this error message, and `COVFUZZ_USE_REGISTRY` is set to `true`, ensure that the uploaded
|
||||
corpus file extracts into a folder named `corpus`.
|
||||
|
||||
### Error "400 Bad request - Duplicate package is not allowed"
|
||||
|
||||
If you see this error message when running the fuzzing job with `COVFUZZ_USE_REGISTRY` set to `true`,
|
||||
ensure that duplicates are allowed. For more details, see
|
||||
[duplicate Generic packages](../../packages/generic_packages/#do-not-allow-duplicate-generic-packages).
|
||||
|
|
|
@ -196,7 +196,7 @@ see the [related epic](https://gitlab.com/groups/gitlab-org/-/epics/4739).
|
|||
|
||||
### View vulnerabilities in cluster images **(ULTIMATE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6346) in GitLab 14.8 [with a flag](../../../../administration/feature_flags.md) named `cluster_vulnerabilities`. Disabled by default.
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6346) in GitLab 14.8 [with a flag](../../../../administration/feature_flags.md) named `cluster_vulnerabilities`. Enabled by default.
|
||||
|
||||
Users with at least the [Developer role](../../../permissions.md)
|
||||
can view cluster vulnerabilities. You can access them through the [vulnerability report](../../../application_security/vulnerabilities/index.md)
|
||||
|
|
|
@ -280,10 +280,15 @@ To view the activity feed in Atom format, select the
|
|||
|
||||
## Share a group with another group
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18328) in GitLab 12.7.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18328) in GitLab 12.7.
|
||||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../feature_flags.md). Disabled by default.
|
||||
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
|
||||
|
||||
NOTE:
|
||||
In GitLab 13.11, you can [replace this form with a modal window](#share-a-group-modal-window).
|
||||
FLAG:
|
||||
On self-managed GitLab, by default the modal window feature is available.
|
||||
To hide the feature, ask an administrator to [disable the feature flag](../../administration/feature_flags.md)
|
||||
named `invite_members_group_modal`.
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
Similar to how you [share a project with a group](../project/members/share_project_with_groups.md),
|
||||
you can share a group with another group. Members get direct access
|
||||
|
@ -293,35 +298,14 @@ To share a given group, for example, `Frontend` with another group, for example,
|
|||
`Engineering`:
|
||||
|
||||
1. Go to the `Frontend` group.
|
||||
1. From the left menu, select **Group information > Members**.
|
||||
1. Select the **Invite group** tab.
|
||||
1. On the left sidebar, select **Group information > Members**.
|
||||
1. Select **Invite a group**.
|
||||
1. In the **Select a group to invite** list, select `Engineering`.
|
||||
1. For the **Max role**, select a [role](../permissions.md).
|
||||
1. Select a [role](../permissions.md).
|
||||
1. Select **Invite**.
|
||||
|
||||
All the members of the `Engineering` group are added to the `Frontend` group.
|
||||
|
||||
### Share a group modal window
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11.
|
||||
> - [Deployed behind a feature flag](../feature_flags.md), disabled by default.
|
||||
> - Enabled on GitLab.com.
|
||||
> - Recommended for production use.
|
||||
> - Replaces the existing form with buttons to open a modal window.
|
||||
> - To use in GitLab self-managed instances, ask a GitLab administrator to [enable it](../project/members/index.md#enable-or-disable-modal-window).
|
||||
|
||||
WARNING:
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
|
||||
In GitLab 13.11, you can optionally replace the sharing form with a modal window.
|
||||
To share a group after enabling this feature:
|
||||
|
||||
1. Go to your group's page.
|
||||
1. On the left sidebar, go to **Group information > Members**, and then select **Invite a group**.
|
||||
1. Select a group, and select a **Max role**.
|
||||
1. Optional. Select an **Access expiration date**.
|
||||
1. Select **Invite**.
|
||||
|
||||
## Manage group memberships via LDAP **(PREMIUM SELF)**
|
||||
|
||||
Group syncing allows LDAP groups to be mapped to GitLab groups. This provides more control over per-group user management. To configure group syncing, edit the `group_base` **DN** (`'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org'`). This **OU** contains all groups that will be associated with GitLab groups.
|
||||
|
|
|
@ -33,14 +33,27 @@ usernames. A GitLab administrator can configure the GitLab instance to
|
|||
|
||||
## Project members permissions
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219299) in GitLab 14.8, personal namespace owners appear with Owner role in new projects in their namespace. Introduced [with a flag](../administration/feature_flags.md) named `personal_project_owner_with_owner_access`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, personal namespace owners appearing with the Owner role in new projects in their namespace is disabled. To make it available,
|
||||
ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `personal_project_owner_with_owner_access`.
|
||||
The feature is not ready for production use.
|
||||
On GitLab.com, this feature is not available.
|
||||
|
||||
A user's role determines what permissions they have on a project. The Owner role provides all permissions but is
|
||||
available only:
|
||||
|
||||
- For group owners. The role is inherited for a group's projects.
|
||||
- For Administrators.
|
||||
|
||||
Personal namespace owners have the same permissions as an Owner, but are displayed with the Maintainer role on projects created in their personal namespace.
|
||||
For more information, see [projects members documentation](project/members/index.md).
|
||||
Personal [namespace](group/index.md#namespaces) owners:
|
||||
|
||||
- Are displayed as having the Maintainer role on projects in the namespace, but have the same permissions as a user with the Owner role.
|
||||
- (Disabled by default) In GitLab 14.8 and later, for new projects in the namespace, are displayed as having the Owner role.
|
||||
|
||||
For more information about how to manage project members, see
|
||||
[members of a project](project/members/index.md).
|
||||
|
||||
The following table lists project permissions available for each role:
|
||||
|
||||
|
|
|
@ -12,6 +12,15 @@ Each member gets a role, which determines what they can do in the project.
|
|||
|
||||
## Add users to a project
|
||||
|
||||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../../feature_flags.md). Disabled by default.
|
||||
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default the modal window feature is available.
|
||||
To hide the feature, ask an administrator to [disable the feature flag](../../../administration/feature_flags.md)
|
||||
named `invite_members_group_modal`.
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
Add users to a project so they become members and have permission
|
||||
to perform actions.
|
||||
|
||||
|
@ -21,11 +30,12 @@ Prerequisite:
|
|||
|
||||
To add a user to a project:
|
||||
|
||||
1. Go to your project and select **Project information > Members**.
|
||||
1. On the **Invite member** tab, under **GitLab member or Email address**, type the username or email address.
|
||||
In GitLab 13.11 and later, you can [replace this form with a modal window](#add-a-member-modal-window).
|
||||
1. Select a [role](../../permissions.md).
|
||||
1. Optional. Choose an expiration date. On that date, the user can no longer access the project.
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Project information > Members**.
|
||||
1. Select **Invite members**.
|
||||
1. Enter an email address and select a [role](../../permissions.md).
|
||||
1. Optional. Select an **Access expiration date**.
|
||||
On that date, the user can no longer access the project.
|
||||
1. Select **Invite**.
|
||||
|
||||
If the user has a GitLab account, they are added to the members list.
|
||||
|
@ -40,6 +50,15 @@ using the email address the invitation was sent to.
|
|||
|
||||
## Add groups to a project
|
||||
|
||||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../../feature_flags.md). Disabled by default.
|
||||
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default the modal window feature is available.
|
||||
To hide the feature, ask an administrator to [disable the feature flag](../../../administration/feature_flags.md)
|
||||
named `invite_members_group_modal`.
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
When you add a group to a project, each user in the group gets access to the project.
|
||||
Each user's access is based on:
|
||||
|
||||
|
@ -54,9 +73,10 @@ To add groups to a project:
|
|||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Project information > Members**.
|
||||
1. On the **Invite group** tab, under **Select a group to invite**, choose a group.
|
||||
1. Select the highest max [role](../../permissions.md) for users in the group.
|
||||
1. Optional. Choose an expiration date. On that date, the user can no longer access the project.
|
||||
1. Select **Invite a group**.
|
||||
1. Select a group.
|
||||
1. Select the highest [role](../../permissions.md) for users in the group.
|
||||
1. Optional. Select an **Access expiration date**. On that date, the group can no longer access the project.
|
||||
1. Select **Invite**.
|
||||
|
||||
The members of the group are not displayed on the **Members** tab.
|
||||
|
@ -203,40 +223,3 @@ Prerequisite:
|
|||
## Share a project with a group
|
||||
|
||||
Instead of adding users one by one, you can [share a project with an entire group](share_project_with_groups.md).
|
||||
|
||||
### Add a member modal window
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 [with a flag](../../feature_flags.md). Disabled by default.
|
||||
> - Replaces the existing form with buttons to open a modal window.
|
||||
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is available.
|
||||
To hide the feature, ask an administrator to [disable the feature flag](#enable-or-disable-modal-window).
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Project information > Members**.
|
||||
1. Select **Invite members**.
|
||||
1. Enter an email address and select a role.
|
||||
1. Optional. Select an **Access expiration date**.
|
||||
1. Select **Invite**.
|
||||
|
||||
### Enable or disable modal window **(FREE SELF)**
|
||||
|
||||
The modal window for adding a member is under development and is ready for production use. It is
|
||||
deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||
can enable it.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:invite_members_group_modal)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:invite_members_group_modal)
|
||||
```
|
||||
|
|
|
@ -33,7 +33,13 @@ module Gitlab
|
|||
MAINTAINER_SUBGROUP_ACCESS = 1
|
||||
|
||||
class << self
|
||||
delegate :values, to: :options
|
||||
def values
|
||||
if ::Feature.enabled?(:personal_project_owner_with_owner_access, default_enabled: :yaml)
|
||||
options_with_owner.values
|
||||
else
|
||||
options.values
|
||||
end
|
||||
end
|
||||
|
||||
def all_values
|
||||
options_with_owner.values
|
||||
|
|
|
@ -41,7 +41,6 @@ module Gitlab
|
|||
|
||||
def prohibited_branch_checks
|
||||
return if deletion?
|
||||
return unless Feature.enabled?(:prohibit_hexadecimal_branch_names, project, default_enabled: true)
|
||||
|
||||
if branch_name =~ /\A\h{40}\z/
|
||||
raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_hex_branch_name]
|
||||
|
|
|
@ -22,7 +22,7 @@ module Gitlab
|
|||
user.projects_with_active_memberships.select_for_project_authorization,
|
||||
|
||||
# The personal projects of the user.
|
||||
user.personal_projects.select_as_maintainer_for_project_authorization,
|
||||
user.personal_projects.select_project_owner_for_project_authorization,
|
||||
|
||||
# Projects that belong directly to any of the groups the user has
|
||||
# access to.
|
||||
|
|
|
@ -12510,10 +12510,10 @@ msgstr ""
|
|||
msgid "DevopsAdoption|At least one deploy"
|
||||
msgstr ""
|
||||
|
||||
msgid "DevopsAdoption|At least one issue opened"
|
||||
msgid "DevopsAdoption|At least one issue created"
|
||||
msgstr ""
|
||||
|
||||
msgid "DevopsAdoption|At least one merge request opened"
|
||||
msgid "DevopsAdoption|At least one merge request created"
|
||||
msgstr ""
|
||||
|
||||
msgid "DevopsAdoption|At least one pipeline successfully run"
|
||||
|
@ -17143,7 +17143,7 @@ msgstr ""
|
|||
msgid "Group: %{name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupActivityMetrics|Issues opened"
|
||||
msgid "GroupActivityMetrics|Issues created"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupActivityMetrics|Last 90 days"
|
||||
|
@ -17152,7 +17152,7 @@ msgstr ""
|
|||
msgid "GroupActivityMetrics|Members added"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupActivityMetrics|Merge Requests opened"
|
||||
msgid "GroupActivityMetrics|Merge Requests created"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupActivityMetrics|Recent activity"
|
||||
|
@ -20164,6 +20164,9 @@ msgstr ""
|
|||
msgid "IssueAnalytics|Assignees"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssueAnalytics|Created by"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssueAnalytics|Due date"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20176,9 +20179,6 @@ msgstr ""
|
|||
msgid "IssueAnalytics|Milestone"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssueAnalytics|Opened by"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssueAnalytics|Status"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20302,10 +20302,10 @@ msgstr ""
|
|||
msgid "IssuesAnalytics|Avg/Month:"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssuesAnalytics|Issues opened"
|
||||
msgid "IssuesAnalytics|Issues created"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssuesAnalytics|Issues opened per month"
|
||||
msgid "IssuesAnalytics|Issues created per month"
|
||||
msgstr ""
|
||||
|
||||
msgid "IssuesAnalytics|Last 12 months"
|
||||
|
@ -25429,7 +25429,7 @@ msgstr ""
|
|||
msgid "Opened issues"
|
||||
msgstr ""
|
||||
|
||||
msgid "OpenedNDaysAgo|Opened"
|
||||
msgid "OpenedNDaysAgo|Created"
|
||||
msgstr ""
|
||||
|
||||
msgid "Opens in a new window"
|
||||
|
@ -43756,9 +43756,6 @@ msgstr ""
|
|||
msgid "open issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "opened %{timeAgo}"
|
||||
msgstr ""
|
||||
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -6,8 +6,23 @@ require_relative 'dependencies'
|
|||
|
||||
class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
||||
class << self
|
||||
def spawn(target, metrics_dir:, wipe_metrics_dir: false, trapped_signals: [])
|
||||
raise "Target must be one of [puma,sidekiq]" unless %w(puma sidekiq).include?(target)
|
||||
def spawn(target, metrics_dir:, gitlab_config: nil, wipe_metrics_dir: false)
|
||||
ensure_valid_target!(target)
|
||||
|
||||
cmd = "#{Rails.root}/bin/metrics-server"
|
||||
env = {
|
||||
'METRICS_SERVER_TARGET' => target,
|
||||
'WIPE_METRICS_DIR' => wipe_metrics_dir ? '1' : '0'
|
||||
}
|
||||
env['GITLAB_CONFIG'] = gitlab_config if gitlab_config
|
||||
|
||||
Process.spawn(env, cmd, err: $stderr, out: $stdout, pgroup: true).tap do |pid|
|
||||
Process.detach(pid)
|
||||
end
|
||||
end
|
||||
|
||||
def fork(target, metrics_dir:, wipe_metrics_dir: false, reset_signals: [])
|
||||
ensure_valid_target!(target)
|
||||
|
||||
pid = Process.fork
|
||||
|
||||
|
@ -15,7 +30,7 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
|||
# Remove any custom signal handlers the parent process had registered, since we do
|
||||
# not want to inherit them, and Ruby forks with a `clone` that has the `CLONE_SIGHAND`
|
||||
# flag set.
|
||||
Gitlab::ProcessManagement.modify_signals(trapped_signals, 'DEFAULT')
|
||||
Gitlab::ProcessManagement.modify_signals(reset_signals, 'DEFAULT')
|
||||
|
||||
server = MetricsServer.new(target, metrics_dir, wipe_metrics_dir)
|
||||
# This rewrites /proc/cmdline, since otherwise tools like `top` will show the
|
||||
|
@ -29,6 +44,12 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
|||
|
||||
pid
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_valid_target!(target)
|
||||
raise "Target must be one of [puma,sidekiq]" unless %w(puma sidekiq).include?(target)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(target, metrics_dir, wipe_metrics_dir)
|
||||
|
@ -40,7 +61,7 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
|||
def start
|
||||
::Prometheus::Client.configure do |config|
|
||||
config.multiprocess_files_dir = @metrics_dir
|
||||
config.pid_provider = proc { "#{@target}_exporter" }
|
||||
config.pid_provider = proc { name }
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(@metrics_dir, mode: 0700)
|
||||
|
@ -57,16 +78,18 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
|||
case @target
|
||||
when 'puma'
|
||||
Gitlab::Metrics::Exporter::WebExporter.instance(**default_opts)
|
||||
else
|
||||
exporter_class = "Gitlab::Metrics::Exporter::#{@target.camelize}Exporter".constantize
|
||||
when 'sidekiq'
|
||||
settings = Settings.new(Settings.monitoring[name])
|
||||
exporter_class.instance(settings, **default_opts)
|
||||
Gitlab::Metrics::Exporter::SidekiqExporter.instance(settings, **default_opts)
|
||||
end
|
||||
|
||||
exporter.start
|
||||
end
|
||||
|
||||
def name
|
||||
"#{@target}_exporter"
|
||||
case @target
|
||||
when 'puma' then 'web_exporter'
|
||||
when 'sidekiq' then 'sidekiq_exporter'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
"@gitlab/svgs": "2.5.0",
|
||||
"@gitlab/ui": "36.1.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "6.1.4-1",
|
||||
"@rails/ujs": "6.1.4-1",
|
||||
"@rails/actioncable": "6.1.4-6",
|
||||
"@rails/ujs": "6.1.4-6",
|
||||
"@sentry/browser": "5.30.0",
|
||||
"@sourcegraph/code-host-integration": "0.0.60",
|
||||
"@tiptap/core": "^2.0.0-beta.171",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'gitlab-qa', require: 'gitlab/qa'
|
||||
gem 'activesupport', '~> 6.1.4.1' # This should stay in sync with the root's Gemfile
|
||||
gem 'activesupport', '~> 6.1.4.6' # This should stay in sync with the root's Gemfile
|
||||
gem 'allure-rspec', '~> 2.15.0'
|
||||
gem 'capybara', '~> 3.35.0'
|
||||
gem 'capybara-screenshot', '~> 1.0.23'
|
||||
|
|
|
@ -2,7 +2,7 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
abstract_type (0.0.7)
|
||||
activesupport (6.1.4.1)
|
||||
activesupport (6.1.4.6)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
|
@ -226,6 +226,7 @@ GEM
|
|||
rack (2.2.3)
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rainbow (3.0.0)
|
||||
rake (13.0.6)
|
||||
regexp_parser (2.1.1)
|
||||
representable (3.1.1)
|
||||
|
@ -321,7 +322,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (~> 6.1.4.1)
|
||||
activesupport (~> 6.1.4.6)
|
||||
airborne (~> 0.3.4)
|
||||
allure-rspec (~> 2.15.0)
|
||||
capybara (~> 3.35.0)
|
||||
|
@ -339,6 +340,7 @@ DEPENDENCIES
|
|||
parallel (~> 1.19)
|
||||
parallel_tests (~> 2.29)
|
||||
pry-byebug (~> 3.5.1)
|
||||
rainbow (~> 3.0.0)
|
||||
rake (~> 13)
|
||||
rest-client (~> 2.1.0)
|
||||
rotp (~> 3.1.0)
|
||||
|
|
|
@ -191,11 +191,11 @@ module Gitlab
|
|||
return unless metrics_server_enabled?
|
||||
|
||||
@logger.info("Starting metrics server on port #{sidekiq_exporter_port}")
|
||||
@metrics_server_pid = MetricsServer.spawn(
|
||||
@metrics_server_pid = MetricsServer.fork(
|
||||
'sidekiq',
|
||||
metrics_dir: @metrics_dir,
|
||||
wipe_metrics_dir: wipe_metrics_dir,
|
||||
trapped_signals: TERMINATE_SIGNALS + FORWARD_SIGNALS
|
||||
reset_signals: TERMINATE_SIGNALS + FORWARD_SIGNALS
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -38,13 +38,7 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do
|
|||
config_file.write(YAML.dump(config))
|
||||
config_file.close
|
||||
|
||||
env = {
|
||||
'GITLAB_CONFIG' => config_file.path,
|
||||
'METRICS_SERVER_TARGET' => target,
|
||||
'WIPE_METRICS_DIR' => '1',
|
||||
'prometheus_multiproc_dir' => metrics_dir
|
||||
}
|
||||
@pid = Process.spawn(env, 'bin/metrics-server', pgroup: true)
|
||||
@pid = MetricsServer.spawn(target, metrics_dir: metrics_dir, gitlab_config: config_file.path, wipe_metrics_dir: true)
|
||||
end
|
||||
|
||||
after do
|
||||
|
|
|
@ -303,7 +303,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
end
|
||||
|
||||
it 'does not start a sidekiq metrics server' do
|
||||
expect(MetricsServer).not_to receive(:spawn)
|
||||
expect(MetricsServer).not_to receive(:fork)
|
||||
|
||||
cli.run(%w(foo))
|
||||
end
|
||||
|
@ -320,7 +320,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
end
|
||||
|
||||
it 'does not start a sidekiq metrics server' do
|
||||
expect(MetricsServer).not_to receive(:spawn)
|
||||
expect(MetricsServer).not_to receive(:fork)
|
||||
|
||||
cli.run(%w(foo))
|
||||
end
|
||||
|
@ -350,7 +350,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
end
|
||||
|
||||
it 'does not start a sidekiq metrics server' do
|
||||
expect(MetricsServer).not_to receive(:spawn)
|
||||
expect(MetricsServer).not_to receive(:fork)
|
||||
|
||||
cli.run(%w(foo))
|
||||
end
|
||||
|
@ -376,7 +376,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
end
|
||||
|
||||
it 'does not start a sidekiq metrics server' do
|
||||
expect(MetricsServer).not_to receive(:spawn)
|
||||
expect(MetricsServer).not_to receive(:fork)
|
||||
|
||||
cli.run(%w(foo))
|
||||
end
|
||||
|
@ -406,9 +406,9 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
|
||||
specify do
|
||||
if start_metrics_server
|
||||
expect(MetricsServer).to receive(:spawn).with('sidekiq', metrics_dir: metrics_dir, wipe_metrics_dir: true, trapped_signals: trapped_signals)
|
||||
expect(MetricsServer).to receive(:fork).with('sidekiq', metrics_dir: metrics_dir, wipe_metrics_dir: true, reset_signals: trapped_signals)
|
||||
else
|
||||
expect(MetricsServer).not_to receive(:spawn)
|
||||
expect(MetricsServer).not_to receive(:fork)
|
||||
end
|
||||
|
||||
cli.run(%w(foo))
|
||||
|
@ -421,7 +421,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
let(:sidekiq_exporter_enabled) { true }
|
||||
|
||||
it 'does not start the server' do
|
||||
expect(MetricsServer).not_to receive(:spawn)
|
||||
expect(MetricsServer).not_to receive(:fork)
|
||||
|
||||
cli.run(%w(foo --dryrun))
|
||||
end
|
||||
|
@ -434,7 +434,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
|
||||
before do
|
||||
allow(cli).to receive(:sleep).with(a_kind_of(Numeric))
|
||||
allow(MetricsServer).to receive(:spawn).and_return(99)
|
||||
allow(MetricsServer).to receive(:fork).and_return(99)
|
||||
cli.start_metrics_server
|
||||
end
|
||||
|
||||
|
@ -453,8 +453,8 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
|||
allow(Gitlab::ProcessManagement).to receive(:all_alive?).with(an_instance_of(Array)).and_return(false)
|
||||
allow(cli).to receive(:stop_metrics_server)
|
||||
|
||||
expect(MetricsServer).to receive(:spawn).with(
|
||||
'sidekiq', metrics_dir: metrics_dir, wipe_metrics_dir: false, trapped_signals: trapped_signals
|
||||
expect(MetricsServer).to receive(:fork).with(
|
||||
'sidekiq', metrics_dir: metrics_dir, wipe_metrics_dir: false, reset_signals: trapped_signals
|
||||
)
|
||||
|
||||
cli.start_loop
|
||||
|
|
|
@ -665,7 +665,7 @@ RSpec.describe Projects::ProjectMembersController do
|
|||
sign_in(user)
|
||||
end
|
||||
|
||||
it 'does not create a member' do
|
||||
it 'creates a member' do
|
||||
expect do
|
||||
post :create, params: {
|
||||
user_ids: stranger.id,
|
||||
|
@ -673,7 +673,9 @@ RSpec.describe Projects::ProjectMembersController do
|
|||
access_level: Member::OWNER,
|
||||
project_id: project
|
||||
}
|
||||
end.to change { project.members.count }.by(0)
|
||||
end.to change { project.members.count }.by(1)
|
||||
|
||||
expect(project.team_members).to include(user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,21 +11,40 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do
|
|||
context 'for a personal project' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
shared_examples_for 'includes access level of the owner of the project as Maintainer' do
|
||||
it 'includes access level of the owner of the project as Maintainer' do
|
||||
expect(subject).to(
|
||||
contain_exactly(
|
||||
hash_including(
|
||||
'user_id' => project.namespace.owner.id,
|
||||
'access_level' => Gitlab::Access::MAINTAINER
|
||||
shared_examples_for 'includes access level of the owner of the project' do
|
||||
context 'when personal_project_owner_with_owner_access feature flag is enabled' do
|
||||
it 'includes access level of the owner of the project as Owner' do
|
||||
expect(subject).to(
|
||||
contain_exactly(
|
||||
hash_including(
|
||||
'user_id' => project.namespace.owner.id,
|
||||
'access_level' => Gitlab::Access::OWNER
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when personal_project_owner_with_owner_access feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(personal_project_owner_with_owner_access: false)
|
||||
end
|
||||
|
||||
it 'includes access level of the owner of the project as Maintainer' do
|
||||
expect(subject).to(
|
||||
contain_exactly(
|
||||
hash_including(
|
||||
'user_id' => project.namespace.owner.id,
|
||||
'access_level' => Gitlab::Access::MAINTAINER
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the project owner is a member of the project' do
|
||||
it_behaves_like 'includes access level of the owner of the project as Maintainer'
|
||||
it_behaves_like 'includes access level of the owner of the project'
|
||||
end
|
||||
|
||||
context 'when the project owner is not explicitly a member of the project' do
|
||||
|
@ -33,7 +52,7 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do
|
|||
project.members.find_by(user_id: project.namespace.owner.id).destroy!
|
||||
end
|
||||
|
||||
it_behaves_like 'includes access level of the owner of the project as Maintainer'
|
||||
it_behaves_like 'includes access level of the owner of the project'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -84,17 +103,32 @@ RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do
|
|||
|
||||
context 'for a project within a group' do
|
||||
context 'project in a root group' do
|
||||
it 'includes access levels of users who are direct members of the parent group' do
|
||||
group_member = create(:group_member, :developer, source: group)
|
||||
context 'includes access levels of users who are direct members of the parent group' do
|
||||
it 'when access level is developer' do
|
||||
group_member = create(:group_member, :developer, source: group)
|
||||
|
||||
expect(subject).to(
|
||||
include(
|
||||
hash_including(
|
||||
'user_id' => group_member.user.id,
|
||||
'access_level' => Gitlab::Access::DEVELOPER
|
||||
expect(subject).to(
|
||||
include(
|
||||
hash_including(
|
||||
'user_id' => group_member.user.id,
|
||||
'access_level' => Gitlab::Access::DEVELOPER
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'when access level is owner' do
|
||||
group_member = create(:group_member, :owner, source: group)
|
||||
|
||||
expect(subject).to(
|
||||
include(
|
||||
hash_including(
|
||||
'user_id' => group_member.user.id,
|
||||
'access_level' => Gitlab::Access::OWNER
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -40,15 +40,6 @@ RSpec.describe Gitlab::Checks::BranchCheck do
|
|||
expect { subject.validate! }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context "the feature flag is disabled" do
|
||||
it "doesn't prohibit a 40-character hexadecimal branch name" do
|
||||
stub_feature_flags(prohibit_hexadecimal_branch_names: false)
|
||||
allow(subject).to receive(:branch_name).and_return("267208abfe40e546f5e847444276f7d43a39503e")
|
||||
|
||||
expect { subject.validate! }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'protected branches check' do
|
||||
|
|
|
@ -47,13 +47,15 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
|
|||
end
|
||||
|
||||
def loggable_data(count:, db_count: nil)
|
||||
keys = %w[
|
||||
database_name = Ci::ApplicationRecord.connection.pool.db_config.name
|
||||
|
||||
keys = %W[
|
||||
expensive_operation_duration_s
|
||||
expensive_operation_db_count
|
||||
expensive_operation_db_primary_count
|
||||
expensive_operation_db_primary_duration_s
|
||||
expensive_operation_db_main_count
|
||||
expensive_operation_db_main_duration_s
|
||||
expensive_operation_db_#{database_name}_count
|
||||
expensive_operation_db_#{database_name}_duration_s
|
||||
]
|
||||
|
||||
data = keys.each.with_object({}) do |key, accumulator|
|
||||
|
@ -75,7 +77,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
|
|||
end
|
||||
|
||||
context 'with a single query' do
|
||||
let(:operation) { -> { Project.count } }
|
||||
let(:operation) { -> { Ci::Pipeline.count } }
|
||||
|
||||
it { is_expected.to eq(operation.call) }
|
||||
|
||||
|
|
|
@ -439,6 +439,12 @@ RSpec.describe Gitlab::Database::Migrations::BackgroundMigrationHelpers do
|
|||
end
|
||||
|
||||
context 'when the migration is running against the ci database', if: Gitlab::Database.has_config?(:ci) do
|
||||
around do |example|
|
||||
Gitlab::Database::SharedModel.using_connection(::Ci::ApplicationRecord.connection) do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'helpers that enqueue background migrations', BackgroundMigration::CiDatabaseWorker, 'ci'
|
||||
end
|
||||
|
||||
|
|
|
@ -34,12 +34,28 @@ RSpec.describe Gitlab::ProjectAuthorizations do
|
|||
.to include(owned_project.id, other_project.id, group_project.id)
|
||||
end
|
||||
|
||||
it 'includes the correct access levels' do
|
||||
mapping = map_access_levels(authorizations)
|
||||
context 'when personal_project_owner_with_owner_access feature flag is enabled' do
|
||||
it 'includes the correct access levels' do
|
||||
mapping = map_access_levels(authorizations)
|
||||
|
||||
expect(mapping[owned_project.id]).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(mapping[other_project.id]).to eq(Gitlab::Access::REPORTER)
|
||||
expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER)
|
||||
expect(mapping[owned_project.id]).to eq(Gitlab::Access::OWNER)
|
||||
expect(mapping[other_project.id]).to eq(Gitlab::Access::REPORTER)
|
||||
expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when personal_project_owner_with_owner_access feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(personal_project_owner_with_owner_access: false)
|
||||
end
|
||||
|
||||
it 'includes the correct access levels' do
|
||||
mapping = map_access_levels(authorizations)
|
||||
|
||||
expect(mapping[owned_project.id]).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(mapping[other_project.id]).to eq(Gitlab::Access::REPORTER)
|
||||
expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -36,13 +36,13 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
|||
|
||||
%w(puma sidekiq).each do |target|
|
||||
context "when targeting #{target}" do
|
||||
describe '.spawn' do
|
||||
describe '.fork' do
|
||||
context 'when in parent process' do
|
||||
it 'forks into a new process and detaches it' do
|
||||
expect(Process).to receive(:fork).and_return(99)
|
||||
expect(Process).to receive(:detach).with(99)
|
||||
|
||||
described_class.spawn(target, metrics_dir: metrics_dir)
|
||||
described_class.fork(target, metrics_dir: metrics_dir)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -58,13 +58,47 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
|||
expect(server).to receive(:start)
|
||||
end
|
||||
|
||||
described_class.spawn(target, metrics_dir: metrics_dir)
|
||||
described_class.fork(target, metrics_dir: metrics_dir)
|
||||
end
|
||||
|
||||
it 'resets signal handlers from parent process' do
|
||||
expect(Gitlab::ProcessManagement).to receive(:modify_signals).with(%i[A B], 'DEFAULT')
|
||||
|
||||
described_class.spawn(target, metrics_dir: metrics_dir, trapped_signals: %i[A B])
|
||||
described_class.fork(target, metrics_dir: metrics_dir, reset_signals: %i[A B])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.spawn' do
|
||||
let(:expected_env) do
|
||||
{
|
||||
'METRICS_SERVER_TARGET' => target,
|
||||
'WIPE_METRICS_DIR' => '0'
|
||||
}
|
||||
end
|
||||
|
||||
it 'spawns a new server process and returns its PID' do
|
||||
expect(Process).to receive(:spawn).with(
|
||||
expected_env,
|
||||
end_with('bin/metrics-server'),
|
||||
hash_including(pgroup: true)
|
||||
).and_return(99)
|
||||
expect(Process).to receive(:detach).with(99)
|
||||
|
||||
pid = described_class.spawn(target, metrics_dir: metrics_dir)
|
||||
|
||||
expect(pid).to eq(99)
|
||||
end
|
||||
|
||||
context 'when path to gitlab.yml is passed' do
|
||||
it 'sets the GITLAB_CONFIG environment variable' do
|
||||
expect(Process).to receive(:spawn).with(
|
||||
expected_env.merge('GITLAB_CONFIG' => 'path/to/config/gitlab.yml'),
|
||||
end_with('bin/metrics-server'),
|
||||
hash_including(pgroup: true)
|
||||
).and_return(99)
|
||||
|
||||
described_class.spawn(target, metrics_dir: metrics_dir, gitlab_config: 'path/to/config/gitlab.yml')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -72,6 +106,14 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
|||
end
|
||||
|
||||
context 'when targeting invalid target' do
|
||||
describe '.fork' do
|
||||
it 'raises an error' do
|
||||
expect { described_class.fork('unsupported', metrics_dir: metrics_dir) }.to(
|
||||
raise_error('Target must be one of [puma,sidekiq]')
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.spawn' do
|
||||
it 'raises an error' do
|
||||
expect { described_class.spawn('unsupported', metrics_dir: metrics_dir) }.to(
|
||||
|
@ -81,64 +123,86 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
|||
end
|
||||
end
|
||||
|
||||
describe '#start' do
|
||||
let(:exporter_class) { Class.new(Gitlab::Metrics::Exporter::BaseExporter) }
|
||||
let(:exporter_double) { double('fake_exporter', start: true) }
|
||||
let(:settings) { { "fake_exporter" => { "enabled" => true } } }
|
||||
shared_examples 'a metrics exporter' do |target, expected_name|
|
||||
describe '#start' do
|
||||
let(:exporter_double) { double('exporter', start: true) }
|
||||
let(:wipe_metrics_dir) { true }
|
||||
|
||||
subject(:metrics_server) { described_class.new('fake', metrics_dir, true)}
|
||||
subject(:metrics_server) { described_class.new(target, metrics_dir, wipe_metrics_dir) }
|
||||
|
||||
before do
|
||||
stub_const('Gitlab::Metrics::Exporter::FakeExporter', exporter_class)
|
||||
expect(exporter_class).to receive(:instance).with(
|
||||
settings['fake_exporter'], gc_requests: true, synchronous: true
|
||||
).and_return(exporter_double)
|
||||
expect(Settings).to receive(:monitoring).and_return(settings)
|
||||
end
|
||||
it 'configures ::Prometheus::Client' do
|
||||
metrics_server.start
|
||||
|
||||
it 'configures ::Prometheus::Client' do
|
||||
metrics_server.start
|
||||
expect(prometheus_config.multiprocess_files_dir).to eq metrics_dir
|
||||
expect(::Prometheus::Client.configuration.pid_provider.call).to eq expected_name
|
||||
end
|
||||
|
||||
expect(prometheus_config.multiprocess_files_dir).to eq metrics_dir
|
||||
expect(::Prometheus::Client.configuration.pid_provider.call).to eq 'fake_exporter'
|
||||
end
|
||||
it 'ensures that metrics directory exists in correct mode (0700)' do
|
||||
expect(FileUtils).to receive(:mkdir_p).with(metrics_dir, mode: 0700)
|
||||
|
||||
it 'ensures that metrics directory exists in correct mode (0700)' do
|
||||
expect(FileUtils).to receive(:mkdir_p).with(metrics_dir, mode: 0700)
|
||||
metrics_server.start
|
||||
end
|
||||
|
||||
metrics_server.start
|
||||
end
|
||||
context 'when wipe_metrics_dir is true' do
|
||||
it 'removes any old metrics files' do
|
||||
FileUtils.touch("#{metrics_dir}/remove_this.db")
|
||||
|
||||
context 'when wipe_metrics_dir is true' do
|
||||
subject(:metrics_server) { described_class.new('fake', metrics_dir, true)}
|
||||
expect { metrics_server.start }.to change { Dir.empty?(metrics_dir) }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
|
||||
it 'removes any old metrics files' do
|
||||
FileUtils.touch("#{metrics_dir}/remove_this.db")
|
||||
context 'when wipe_metrics_dir is false' do
|
||||
let(:wipe_metrics_dir) { false }
|
||||
|
||||
expect { metrics_server.start }.to change { Dir.empty?(metrics_dir) }.from(false).to(true)
|
||||
it 'does not remove any old metrics files' do
|
||||
FileUtils.touch("#{metrics_dir}/remove_this.db")
|
||||
|
||||
expect { metrics_server.start }.not_to change { Dir.empty?(metrics_dir) }.from(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'starts a metrics server' do
|
||||
expect(exporter_double).to receive(:start)
|
||||
|
||||
metrics_server.start
|
||||
end
|
||||
|
||||
it 'starts a RubySampler instance' do
|
||||
expect(ruby_sampler_double).to receive(:start)
|
||||
|
||||
subject.start
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wipe_metrics_dir is false' do
|
||||
subject(:metrics_server) { described_class.new('fake', metrics_dir, false)}
|
||||
describe '#name' do
|
||||
let(:exporter_double) { double('exporter', start: true) }
|
||||
|
||||
it 'does not remove any old metrics files' do
|
||||
FileUtils.touch("#{metrics_dir}/remove_this.db")
|
||||
subject(:name) { described_class.new(target, metrics_dir, true).name }
|
||||
|
||||
expect { metrics_server.start }.not_to change { Dir.empty?(metrics_dir) }.from(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'starts a metrics server' do
|
||||
expect(exporter_double).to receive(:start)
|
||||
|
||||
metrics_server.start
|
||||
end
|
||||
|
||||
it 'starts a RubySampler instance' do
|
||||
expect(ruby_sampler_double).to receive(:start)
|
||||
|
||||
subject.start
|
||||
it { is_expected.to eq(expected_name) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'for puma' do
|
||||
before do
|
||||
allow(Gitlab::Metrics::Exporter::WebExporter).to receive(:instance).with(
|
||||
gc_requests: true, synchronous: true
|
||||
).and_return(exporter_double)
|
||||
end
|
||||
|
||||
it_behaves_like 'a metrics exporter', 'puma', 'web_exporter'
|
||||
end
|
||||
|
||||
context 'for sidekiq' do
|
||||
let(:settings) { { "sidekiq_exporter" => { "enabled" => true } } }
|
||||
|
||||
before do
|
||||
allow(::Settings).to receive(:monitoring).and_return(settings)
|
||||
allow(Gitlab::Metrics::Exporter::SidekiqExporter).to receive(:instance).with(
|
||||
settings['sidekiq_exporter'], gc_requests: true, synchronous: true
|
||||
).and_return(exporter_double)
|
||||
end
|
||||
|
||||
it_behaves_like 'a metrics exporter', 'sidekiq', 'sidekiq_exporter'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -225,7 +225,7 @@ RSpec.describe ProjectTeam do
|
|||
let_it_be(:maintainer) { create(:user) }
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:guest) { create(:user) }
|
||||
let_it_be(:project) { create(:project, namespace: maintainer.namespace) }
|
||||
let_it_be(:project) { create(:project, group: create(:group)) }
|
||||
let_it_be(:access_levels) { [Gitlab::Access::DEVELOPER, Gitlab::Access::MAINTAINER] }
|
||||
|
||||
subject(:members_with_access_levels) { project.team.members_with_access_levels(access_levels) }
|
||||
|
|
|
@ -3717,7 +3717,7 @@ RSpec.describe User do
|
|||
|
||||
context 'with min_access_level' do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:project) { create(:project, :private, namespace: user.namespace) }
|
||||
let!(:project) { create(:project, :private, group: create(:group)) }
|
||||
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
|
|
@ -675,13 +675,30 @@ RSpec.describe API::Members do
|
|||
end
|
||||
|
||||
context 'adding owner to project' do
|
||||
it 'returns 403' do
|
||||
expect do
|
||||
post api("/projects/#{project.id}/members", maintainer),
|
||||
params: { user_id: stranger.id, access_level: Member::OWNER }
|
||||
context 'when personal_project_owner_with_owner_access feature flag is enabled' do
|
||||
it 'returns created status' do
|
||||
expect do
|
||||
post api("/projects/#{project.id}/members", maintainer),
|
||||
params: { user_id: stranger.id, access_level: Member::OWNER }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
end.not_to change { project.members.count }
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
end.to change { project.members.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when personal_project_owner_with_owner_access feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(personal_project_owner_with_owner_access: false)
|
||||
end
|
||||
|
||||
it 'returns created status' do
|
||||
expect do
|
||||
post api("/projects/#{project.id}/members", maintainer),
|
||||
params: { user_id: stranger.id, access_level: Member::OWNER }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
end.not_to change { project.members.count }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
it 'is called' do
|
||||
ProjectAuthorization.delete_all
|
||||
|
||||
expect(callback).to receive(:call).with(project.id, Gitlab::Access::MAINTAINER).once
|
||||
expect(callback).to receive(:call).with(project.id, Gitlab::Access::OWNER).once
|
||||
|
||||
service.execute
|
||||
end
|
||||
|
@ -60,20 +60,20 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
|
||||
to_be_removed = [project2.id]
|
||||
to_be_added = [
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER }
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::OWNER }
|
||||
]
|
||||
|
||||
expect(service.execute).to eq([to_be_removed, to_be_added])
|
||||
end
|
||||
|
||||
it 'finds duplicate entries that has to be removed' do
|
||||
[Gitlab::Access::MAINTAINER, Gitlab::Access::REPORTER].each do |access_level|
|
||||
[Gitlab::Access::OWNER, Gitlab::Access::REPORTER].each do |access_level|
|
||||
user.project_authorizations.create!(project: project, access_level: access_level)
|
||||
end
|
||||
|
||||
to_be_removed = [project.id]
|
||||
to_be_added = [
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER }
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::OWNER }
|
||||
]
|
||||
|
||||
expect(service.execute).to eq([to_be_removed, to_be_added])
|
||||
|
@ -85,7 +85,7 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
|
||||
to_be_removed = [project.id]
|
||||
to_be_added = [
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER }
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::OWNER }
|
||||
]
|
||||
|
||||
expect(service.execute).to eq([to_be_removed, to_be_added])
|
||||
|
@ -143,16 +143,16 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
end
|
||||
|
||||
it 'sets the keys to the project IDs' do
|
||||
expect(hash.keys).to eq([project.id])
|
||||
expect(hash.keys).to match_array([project.id])
|
||||
end
|
||||
|
||||
it 'sets the values to the access levels' do
|
||||
expect(hash.values).to eq([Gitlab::Access::MAINTAINER])
|
||||
expect(hash.values).to match_array([Gitlab::Access::OWNER])
|
||||
end
|
||||
|
||||
context 'personal projects' do
|
||||
it 'includes the project with the right access level' do
|
||||
expect(hash[project.id]).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(hash[project.id]).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -242,7 +242,7 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
value = hash.values[0]
|
||||
|
||||
expect(value.project_id).to eq(project.id)
|
||||
expect(value.access_level).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(value.access_level).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -267,7 +267,7 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
end
|
||||
|
||||
it 'includes the access level for every row' do
|
||||
expect(row.access_level).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(row.access_level).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -283,7 +283,7 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
rows = service.fresh_authorizations.to_a
|
||||
|
||||
expect(rows.length).to eq(1)
|
||||
expect(rows.first.access_level).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(rows.first.access_level).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
|
||||
context 'every returned row' do
|
||||
|
@ -294,7 +294,7 @@ RSpec.describe AuthorizedProjectUpdate::FindRecordsDueForRefreshService do
|
|||
end
|
||||
|
||||
it 'includes the access level' do
|
||||
expect(row.access_level).to eq(Gitlab::Access::MAINTAINER)
|
||||
expect(row.access_level).to eq(Gitlab::Access::OWNER)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,8 +9,8 @@ RSpec.describe Members::Projects::CreatorService do
|
|||
end
|
||||
|
||||
describe '.access_levels' do
|
||||
it 'returns Gitlab::Access.sym_options' do
|
||||
expect(described_class.access_levels).to eq(Gitlab::Access.sym_options)
|
||||
it 'returns Gitlab::Access.sym_options_with_owner' do
|
||||
expect(described_class.access_levels).to eq(Gitlab::Access.sym_options_with_owner)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3312,7 +3312,7 @@ RSpec.describe NotificationService, :mailer do
|
|||
describe "##{sym}" do
|
||||
subject(:notify!) { notification.send(sym, domain) }
|
||||
|
||||
it 'emails current watching maintainers' do
|
||||
it 'emails current watching maintainers and owners' do
|
||||
expect(Notify).to receive(:"#{sym}_email").at_least(:once).and_call_original
|
||||
|
||||
notify!
|
||||
|
@ -3410,7 +3410,7 @@ RSpec.describe NotificationService, :mailer do
|
|||
reset_delivered_emails!
|
||||
end
|
||||
|
||||
it 'emails current watching maintainers' do
|
||||
it 'emails current watching maintainers and owners' do
|
||||
notification.remote_mirror_update_failed(remote_mirror)
|
||||
|
||||
should_only_email(u_maintainer1, u_maintainer2, u_owner)
|
||||
|
|
|
@ -116,14 +116,34 @@ RSpec.describe Projects::CreateService, '#execute' do
|
|||
end
|
||||
|
||||
context 'user namespace' do
|
||||
it 'creates a project in user namespace' do
|
||||
project = create_project(user, opts)
|
||||
context 'when personal_project_owner_with_owner_access feature flag is enabled' do
|
||||
it 'creates a project in user namespace' do
|
||||
project = create_project(user, opts)
|
||||
|
||||
expect(project).to be_valid
|
||||
expect(project.first_owner).to eq(user)
|
||||
expect(project.team.maintainers).to include(user)
|
||||
expect(project.namespace).to eq(user.namespace)
|
||||
expect(project.project_namespace).to be_in_sync_with_project(project)
|
||||
expect(project).to be_valid
|
||||
expect(project.first_owner).to eq(user)
|
||||
expect(project.team.maintainers).not_to include(user)
|
||||
expect(project.team.owners).to contain_exactly(user)
|
||||
expect(project.namespace).to eq(user.namespace)
|
||||
expect(project.project_namespace).to be_in_sync_with_project(project)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when personal_project_owner_with_owner_access feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(personal_project_owner_with_owner_access: false)
|
||||
end
|
||||
|
||||
it 'creates a project in user namespace' do
|
||||
project = create_project(user, opts)
|
||||
|
||||
expect(project).to be_valid
|
||||
expect(project.first_owner).to eq(user)
|
||||
expect(project.team.maintainers).to contain_exactly(user)
|
||||
expect(project.team.owners).to contain_exactly(user)
|
||||
expect(project.namespace).to eq(user.namespace)
|
||||
expect(project.project_namespace).to be_in_sync_with_project(project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -162,7 +182,7 @@ RSpec.describe Projects::CreateService, '#execute' do
|
|||
expect(project).to be_persisted
|
||||
expect(project.owner).to eq(user)
|
||||
expect(project.first_owner).to eq(user)
|
||||
expect(project.team.maintainers).to contain_exactly(user)
|
||||
expect(project.team.owners).to contain_exactly(user)
|
||||
expect(project.namespace).to eq(user.namespace)
|
||||
expect(project.project_namespace).to be_in_sync_with_project(project)
|
||||
end
|
||||
|
|
|
@ -52,7 +52,7 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do
|
|||
it 'is called' do
|
||||
ProjectAuthorization.delete_all
|
||||
|
||||
expect(callback).to receive(:call).with(project.id, Gitlab::Access::MAINTAINER).once
|
||||
expect(callback).to receive(:call).with(project.id, Gitlab::Access::OWNER).once
|
||||
|
||||
service.execute
|
||||
end
|
||||
|
@ -73,7 +73,7 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do
|
|||
to_be_removed = [project_authorization.project_id]
|
||||
|
||||
to_be_added = [
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER }
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::OWNER }
|
||||
]
|
||||
|
||||
expect(service).to receive(:update_authorizations)
|
||||
|
@ -83,14 +83,14 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do
|
|||
end
|
||||
|
||||
it 'removes duplicate entries' do
|
||||
[Gitlab::Access::MAINTAINER, Gitlab::Access::REPORTER].each do |access_level|
|
||||
[Gitlab::Access::OWNER, Gitlab::Access::REPORTER].each do |access_level|
|
||||
user.project_authorizations.create!(project: project, access_level: access_level)
|
||||
end
|
||||
|
||||
to_be_removed = [project.id]
|
||||
|
||||
to_be_added = [
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER }
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::OWNER }
|
||||
]
|
||||
expect(service).to(
|
||||
receive(:update_authorizations)
|
||||
|
@ -103,7 +103,7 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do
|
|||
project_authorization = ProjectAuthorization.where(
|
||||
project_id: project.id,
|
||||
user_id: user.id,
|
||||
access_level: Gitlab::Access::MAINTAINER)
|
||||
access_level: Gitlab::Access::OWNER)
|
||||
expect(project_authorization).to exist
|
||||
end
|
||||
|
||||
|
@ -116,7 +116,7 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do
|
|||
to_be_removed = [project_authorization.project_id]
|
||||
|
||||
to_be_added = [
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::MAINTAINER }
|
||||
{ user_id: user.id, project_id: project.id, access_level: Gitlab::Access::OWNER }
|
||||
]
|
||||
|
||||
expect(service).to receive(:update_authorizations)
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -1436,15 +1436,15 @@
|
|||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590"
|
||||
integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ==
|
||||
|
||||
"@rails/actioncable@6.1.4-1":
|
||||
version "6.1.4-1"
|
||||
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.1.4-1.tgz#69982e7f352d732f71fda0cc01b7ba8269c9945b"
|
||||
integrity sha512-b6sLoMop3gX22Wm2P5LPpKcZGwsf1ZoAGS+g1HrTrdlsZ/ENOKIBiSNnHOJajHwcYlF0TefBs7e7jIYZHVYihQ==
|
||||
"@rails/actioncable@6.1.4-6":
|
||||
version "6.1.4-6"
|
||||
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.1.4-6.tgz#22dd0f60e634f237f2a19d031f4e7afa26a924b4"
|
||||
integrity sha512-cGwo5AWlEg6Q5JeUl2r8cmgaSlJtgR9BOOGF7Yb1PyKOinuWod6PW6UeQLgXf+n2MNiWz+yqldb1m3+Aun/2lg==
|
||||
|
||||
"@rails/ujs@6.1.4-1":
|
||||
version "6.1.4-1"
|
||||
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.1.4-1.tgz#37507fe288a1c7c3a593602aa4dea42e5cb5797f"
|
||||
integrity sha512-Fewm2wHk1n6Kf4E86dzzHDJOFg4EWcSHH3FsMEGs59bTdmf7099mjkOssOQtBqju4R39iaAOQNui7r8P+Q5Dgg==
|
||||
"@rails/ujs@6.1.4-6":
|
||||
version "6.1.4-6"
|
||||
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.1.4-6.tgz#244520a1580b5791cebc81471978bc6b3c8966c0"
|
||||
integrity sha512-j2ejw0ShVHiDWtq1Yv1PGX/GFCDiXX+5YiUY2Z17eeMJhQkxXeg3maQZkkT5OT/YBOI+jiWqtp03GM1Hdp/arA==
|
||||
|
||||
"@sentry/browser@5.30.0":
|
||||
version "5.30.0"
|
||||
|
|
Loading…
Reference in New Issue