Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5b4e0ca32c
commit
20625a2433
|
|
@ -1804,7 +1804,6 @@ Layout/LineLength:
|
|||
- 'ee/spec/requests/api/related_epic_links_spec.rb'
|
||||
- 'ee/spec/requests/api/releases_spec.rb'
|
||||
- 'ee/spec/requests/api/resource_iteration_events_spec.rb'
|
||||
- 'ee/spec/requests/api/search_spec.rb'
|
||||
- 'ee/spec/requests/api/settings_spec.rb'
|
||||
- 'ee/spec/requests/api/status_checks_spec.rb'
|
||||
- 'ee/spec/requests/api/users_spec.rb'
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ Performance/MapCompact:
|
|||
- 'ee/lib/gitlab/ci/reports/metrics/reports_comparer.rb'
|
||||
- 'ee/lib/gitlab/search/aggregation_parser.rb'
|
||||
- 'ee/spec/models/ee/member_spec.rb'
|
||||
- 'ee/spec/requests/api/search_spec.rb'
|
||||
- 'haml_lint/linter/no_plain_nodes.rb'
|
||||
- 'lib/api/entities/feature.rb'
|
||||
- 'lib/api/helpers/common_helpers.rb'
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ Rails/Pluck:
|
|||
- 'ee/spec/requests/api/protected_environments_spec.rb'
|
||||
- 'ee/spec/requests/api/protected_tags_spec.rb'
|
||||
- 'ee/spec/requests/api/releases_spec.rb'
|
||||
- 'ee/spec/requests/api/search_spec.rb'
|
||||
- 'ee/spec/requests/api/status_checks_spec.rb'
|
||||
- 'ee/spec/requests/api/users_spec.rb'
|
||||
- 'ee/spec/requests/api/vulnerabilities_spec.rb'
|
||||
|
|
|
|||
|
|
@ -470,7 +470,6 @@ RSpec/BeforeAllRoleAssignment:
|
|||
- 'ee/spec/requests/api/related_epic_links_spec.rb'
|
||||
- 'ee/spec/requests/api/repositories_spec.rb'
|
||||
- 'ee/spec/requests/api/saml_group_links_spec.rb'
|
||||
- 'ee/spec/requests/api/search_spec.rb'
|
||||
- 'ee/spec/requests/api/todos_spec.rb'
|
||||
- 'ee/spec/requests/api/vulnerabilities_spec.rb'
|
||||
- 'ee/spec/requests/api/vulnerability_exports_spec.rb'
|
||||
|
|
|
|||
51
CHANGELOG.md
51
CHANGELOG.md
|
|
@ -2,6 +2,23 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 17.4.2 (2024-10-09)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Drop project_id not null constraint ci_deleted_objects](https://gitlab.com/gitlab-org/security/gitlab/-/commit/e02a0c065456a51ad57a93d56150271cc4dd442e)
|
||||
|
||||
### Security (8 changes)
|
||||
|
||||
- [Do not create a pipeline on MR refresh if source branch was deleted](https://gitlab.com/gitlab-org/security/gitlab/-/commit/66c4e57a3494686a9dc6058d2348074b465f5dd3) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4522))
|
||||
- [Escape OAuth application name on authorize page](https://gitlab.com/gitlab-org/security/gitlab/-/commit/293bb1f70c681b75672e0b41af84ab5ae47d1e1e) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4517))
|
||||
- [Prevent guest access to project templates](https://gitlab.com/gitlab-org/security/gitlab/-/commit/544398bdf7ea2b81100f8b95496f14d9b4698db8) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4477))
|
||||
- [Remove access to local requests via cube query service](https://gitlab.com/gitlab-org/security/gitlab/-/commit/86894edacdaf1cad4b0e85f71918109d48013ccb) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4492))
|
||||
- [External webhook token should be set](https://gitlab.com/gitlab-org/security/gitlab/-/commit/70fb8bebe2e8f1b85d625a8e496515c3f7e0e6d8) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4510))
|
||||
- [Skip content when listing conflict files with types](https://gitlab.com/gitlab-org/security/gitlab/-/commit/c19d8a96d103680ec874327c1631e179e17da06a) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4513))
|
||||
- [Hide version info from unauthorized users](https://gitlab.com/gitlab-org/security/gitlab/-/commit/0dd81e22f819f916c50cf531fa769000e9b5941b) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4500))
|
||||
- [Prevent deploy keys from pushing code to an archived project](https://gitlab.com/gitlab-org/security/gitlab/-/commit/ed7a5173cae50f610d2c0263197f7996653cfc10) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4486))
|
||||
|
||||
## 17.4.1 (2024-09-24)
|
||||
|
||||
### Fixed (2 changes)
|
||||
|
|
@ -872,6 +889,23 @@ entry.
|
|||
|
||||
- [Update learn more link and docs formatting](https://gitlab.com/gitlab-org/gitlab/-/commit/6f536fdb20c2d2b96124afe693042c91483a32b2) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/164889))
|
||||
|
||||
## 17.3.5 (2024-10-09)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Ensure levels is an array](https://gitlab.com/gitlab-org/security/gitlab/-/commit/74594891f31984feaaae6a069f057d6f48a489a6)
|
||||
|
||||
### Security (8 changes)
|
||||
|
||||
- [Do not create a pipeline on MR refresh if source branch was deleted](https://gitlab.com/gitlab-org/security/gitlab/-/commit/c36869b2e5cb0f88793bec7e20ded3e4d005f942) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4523))
|
||||
- [Escape OAuth application name on authorize page](https://gitlab.com/gitlab-org/security/gitlab/-/commit/b5a704563f746e5c61301d3a7db0eab68d434e24) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4518))
|
||||
- [Prevent guest access to project templates](https://gitlab.com/gitlab-org/security/gitlab/-/commit/92d177e2c5aaafb4f74bc2ceafe39b9a068e803d) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4449))
|
||||
- [Remove access to local requests via cube query service](https://gitlab.com/gitlab-org/security/gitlab/-/commit/7043d0116cbf2051907dfd88d56ed3f847ab95b2) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4493))
|
||||
- [External webhook token should be set](https://gitlab.com/gitlab-org/security/gitlab/-/commit/77c2a678acfc6fded56c6e10147701b6ef7aaeb5) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4511))
|
||||
- [Skip content when listing conflict files with types](https://gitlab.com/gitlab-org/security/gitlab/-/commit/2b559425cb195a78007db930cbbf8450b5254c89) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4514))
|
||||
- [Hide version info from unauthorized users](https://gitlab.com/gitlab-org/security/gitlab/-/commit/94e70d423789a50fc8e172b002bf1428593bbc51) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4501))
|
||||
- [Prevent deploy keys from pushing code to an archived project](https://gitlab.com/gitlab-org/security/gitlab/-/commit/3cd52356b4b1194e7108af832d5da4087e4be05c) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4487))
|
||||
|
||||
## 17.3.4 (2024-09-24)
|
||||
|
||||
### Security (3 changes)
|
||||
|
|
@ -1662,6 +1696,23 @@ No changes.
|
|||
- [Dynamically gets the column type for assertion](https://gitlab.com/gitlab-org/gitlab/-/commit/1389a3daffd104925cce71776903cbf527723222) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159099))
|
||||
- [Quarantine a flaky test](https://gitlab.com/gitlab-org/gitlab/-/commit/c94fca35b909440ec66ea35c97ab11aa847dde58) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158180))
|
||||
|
||||
## 17.2.9 (2024-10-09)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Ensure levels is an array](https://gitlab.com/gitlab-org/security/gitlab/-/commit/d5450d020895b9fab3c7c6ad4191001308590899)
|
||||
|
||||
### Security (8 changes)
|
||||
|
||||
- [Do not create a pipeline on MR refresh if source branch was deleted](https://gitlab.com/gitlab-org/security/gitlab/-/commit/3dd89a71b436e8218a5d159a1dd75cb2de078129) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4524))
|
||||
- [Escape OAuth application name on authorize page](https://gitlab.com/gitlab-org/security/gitlab/-/commit/b5cf4d286ae83033912e342177a501ffc2ad6a53) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4519))
|
||||
- [Prevent guest access to project templates](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9666414231dbfc03eb0711ec501b7d02665120df) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4450))
|
||||
- [Remove access to local requests via cube query service](https://gitlab.com/gitlab-org/security/gitlab/-/commit/1a46c8c1753f08ba55e8a0d2fbcbc710feecf898) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4494))
|
||||
- [External webhook token should be set](https://gitlab.com/gitlab-org/security/gitlab/-/commit/c795ea96a4dac381cf434aa7e3f379907ec6366d) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4512))
|
||||
- [Skip content when listing conflict files with types](https://gitlab.com/gitlab-org/security/gitlab/-/commit/c7f598b42b0c6cd68cdcdb8b79293e7e2b22b457) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4515))
|
||||
- [Hide version info from unauthorized users](https://gitlab.com/gitlab-org/security/gitlab/-/commit/0184d4e9c665c209e1c67eff2da9059e17304f1d) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4502))
|
||||
- [Prevent deploy keys from pushing code to an archived project](https://gitlab.com/gitlab-org/security/gitlab/-/commit/0a5dc2f0b302123a941a4676eedd52c3423ef73b) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4488))
|
||||
|
||||
## 17.2.8 (2024-09-24)
|
||||
|
||||
### Security (3 changes)
|
||||
|
|
|
|||
|
|
@ -48,19 +48,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
itemGroups() {
|
||||
return {
|
||||
versionCheck: {
|
||||
items: [
|
||||
{
|
||||
text: this.$options.i18n.version,
|
||||
href: helpPagePath('update/index'),
|
||||
version: `${this.sidebarData.gitlab_version.major}.${this.sidebarData.gitlab_version.minor}`,
|
||||
extraAttrs: {
|
||||
...this.trackingAttrs('version_help_dropdown'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
const groups = {
|
||||
helpLinks: {
|
||||
items: [
|
||||
{
|
||||
|
|
@ -157,6 +145,23 @@ export default {
|
|||
].filter(Boolean),
|
||||
},
|
||||
};
|
||||
|
||||
if (this.sidebarData.show_version_check) {
|
||||
groups.versionCheck = {
|
||||
items: [
|
||||
{
|
||||
text: this.$options.i18n.version,
|
||||
href: helpPagePath('update/index'),
|
||||
version: `${this.sidebarData.gitlab_version.major}.${this.sidebarData.gitlab_version.minor}`,
|
||||
extraAttrs: {
|
||||
...this.trackingAttrs('version_help_dropdown'),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return groups;
|
||||
},
|
||||
updateSeverity() {
|
||||
return this.sidebarData.gitlab_version_check?.severity;
|
||||
|
|
|
|||
|
|
@ -266,7 +266,12 @@ module DiffHelper
|
|||
return unless merge_request.cannot_be_merged? && merge_request.source_branch_exists? && merge_request.target_branch_exists?
|
||||
|
||||
cached_conflicts_with_types do
|
||||
conflicts_service = MergeRequests::Conflicts::ListService.new(merge_request, allow_tree_conflicts: true) # rubocop:disable CodeReuse/ServiceClass
|
||||
# We set skip_content to true since we don't really need the content to list the conflicts and their types
|
||||
conflicts_service = MergeRequests::Conflicts::ListService.new( # rubocop:disable CodeReuse/ServiceClass
|
||||
merge_request,
|
||||
allow_tree_conflicts: true,
|
||||
skip_content: true
|
||||
)
|
||||
|
||||
{}.tap do |h|
|
||||
conflicts_service.conflicts.files.each do |file|
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ module SidebarsHelper
|
|||
end
|
||||
|
||||
def super_sidebar_logged_out_context(panel:, panel_type:) # rubocop:disable Metrics/AbcSize
|
||||
{
|
||||
super_sidebar_instance_version_data.merge(super_sidebar_whats_new_data).merge({
|
||||
is_logged_in: false,
|
||||
context_switcher_links: context_switcher_links,
|
||||
current_menu_items: panel.super_sidebar_menu_items,
|
||||
|
|
@ -51,16 +51,12 @@ module SidebarsHelper
|
|||
support_path: support_url,
|
||||
docs_path: help_docs_path,
|
||||
display_whats_new: display_whats_new?,
|
||||
whats_new_most_recent_release_items_count: whats_new_most_recent_release_items_count,
|
||||
whats_new_version_digest: whats_new_version_digest,
|
||||
show_version_check: show_version_check?,
|
||||
gitlab_version: Gitlab.version_info,
|
||||
gitlab_version_check: gitlab_version_check,
|
||||
search: search_data,
|
||||
panel_type: panel_type,
|
||||
shortcut_links: shortcut_links,
|
||||
terms: terms_link
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
def super_sidebar_logged_in_context(user, group:, project:, panel:, panel_type:) # rubocop:disable Metrics/AbcSize
|
||||
|
|
@ -126,6 +122,24 @@ module SidebarsHelper
|
|||
})
|
||||
end
|
||||
|
||||
def super_sidebar_instance_version_data
|
||||
return {} unless show_version_check?
|
||||
|
||||
{
|
||||
gitlab_version: Gitlab.version_info,
|
||||
gitlab_version_check: gitlab_version_check
|
||||
}
|
||||
end
|
||||
|
||||
def super_sidebar_whats_new_data
|
||||
return {} unless display_whats_new?
|
||||
|
||||
{
|
||||
whats_new_most_recent_release_items_count: whats_new_most_recent_release_items_count,
|
||||
whats_new_version_digest: whats_new_version_digest
|
||||
}
|
||||
end
|
||||
|
||||
def work_items_modal_data(group)
|
||||
return unless group && group.id
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,11 @@ module Auth
|
|||
return if path.has_repository?
|
||||
return unless actions.include?('push')
|
||||
|
||||
find_or_create_repository_from_path(path)
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def find_or_create_repository_from_path(path)
|
||||
ContainerRepository.find_or_create_from_path!(path)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ class IssuableBaseService < ::BaseContainerService
|
|||
elsif author_id
|
||||
issuable.author_id = author_id
|
||||
else
|
||||
issuable.author = current_user
|
||||
issuable.author ||= current_user
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ module MergeRequests
|
|||
@conflicts ||=
|
||||
Gitlab::Conflict::FileCollection.new(
|
||||
merge_request,
|
||||
allow_tree_conflicts: params[:allow_tree_conflicts]
|
||||
allow_tree_conflicts: params[:allow_tree_conflicts],
|
||||
skip_content: params[:skip_content]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ module MergeRequests
|
|||
mark_mr_as_draft_from_commits(mr)
|
||||
execute_mr_web_hooks(mr)
|
||||
# Run at the end of the loop to avoid any potential contention on the MR object
|
||||
refresh_pipelines_on_merge_requests(mr)
|
||||
refresh_pipelines_on_merge_requests(mr) unless @push.branch_removed?
|
||||
merge_request_activity_counter.track_mr_including_ci_config(user: mr.author, merge_request: mr)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
.gl-ml-auto.gl-mr-auto{ class: 'sm:gl-w-1/2' }
|
||||
.gl-items-center
|
||||
.gl-text-size-h1
|
||||
= html_escape(_('%{client_name} is requesting access to your account on %{title}.')) % { title: brand_title.html_safe, client_name: "<strong>#{html_escape(@pre_auth.client.name)}</strong>".html_safe }
|
||||
= safe_format(_('%{strong_start}%{client_name}%{strong_end} is requesting access to your account on %{title}.'),
|
||||
{ client_name: @pre_auth.client.name, title: brand_title },
|
||||
tag_pair(tag.strong, :strong_start, :strong_end))
|
||||
.gl-flex.gl-items-center.gl-gap-2.gl-py-5
|
||||
= render Pajamas::AvatarComponent.new(current_user, size: 24, avatar_options: { data: { testid: 'user_avatar_content' }, title: current_user.username })
|
||||
.gl-pl-1
|
||||
|
|
@ -12,7 +14,9 @@
|
|||
- if current_user.admin?
|
||||
= render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
|
||||
- c.with_body do
|
||||
= html_escape(_('You are an administrator, which means authorizing access to %{client_name} will allow it to interact with GitLab as an administrator as well.')) % { client_name: "<strong>#{html_escape(@pre_auth.client.name)}</strong>".html_safe }
|
||||
= safe_format(_('You are an administrator, which means authorizing access to %{strong_start}%{client_name}%{strong_end} will allow it to interact with GitLab as an administrator as well.'),
|
||||
{ client_name: @pre_auth.client.name },
|
||||
tag_pair(tag.strong, :strong_start, :strong_end))
|
||||
- if @pre_auth.scopes
|
||||
- @pre_auth.scopes.each do |scope|
|
||||
%strong= t scope, scope: [:doorkeeper, :scopes]
|
||||
|
|
@ -26,12 +30,17 @@
|
|||
- else
|
||||
%p.gl-text-orange-500
|
||||
= sprite_icon('warning-solid')
|
||||
= html_escape(_('Make sure you trust %{client_name} before authorizing.')) % { client_name: "<strong>#{html_escape(@pre_auth.client.name)}</strong>".html_safe }
|
||||
= safe_format(_('Make sure you trust %{strong_start}%{client_name}%{strong_end} before authorizing.'),
|
||||
{ client_name: @pre_auth.client.name },
|
||||
tag_pair(tag.strong, :strong_start, :strong_end))
|
||||
%p
|
||||
= html_escape(_('%{owner} %{created_date} ago.')) % { owner: auth_app_owner_text(@pre_auth.client.application.owner), created_date: time_ago_in_words(@pre_auth.client.application.created_at.to_date) }
|
||||
= safe_format(_('%{owner} %{created_date} ago.'),
|
||||
{ owner: auth_app_owner_text(@pre_auth.client.application.owner),
|
||||
created_date: time_ago_in_words(@pre_auth.client.application.created_at.to_date) })
|
||||
- domain = URI.parse(@pre_auth.redirect_uri).host.gsub(/^www\./, '')
|
||||
- if @pre_auth.redirect_uri.start_with?('http://', 'https://') && domain != 'localhost'
|
||||
= html_escape(_('You will be redirected to %{domain} after authorizing.')) % { domain: "<strong>#{domain}</strong>".html_safe }
|
||||
= safe_format(_('You will be redirected to %{strong_start}%{domain}%{strong_end} after authorizing.'),
|
||||
{ domain: domain }, tag_pair(tag.strong, :strong_start, :strong_end))
|
||||
%div
|
||||
= form_tag oauth_authorization_path, method: :post, class: 'gl-inline-block gl-pr-3' do
|
||||
= hidden_field_tag :client_id, @pre_auth.client.uid
|
||||
|
|
@ -44,8 +53,8 @@
|
|||
= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method
|
||||
= render Pajamas::ButtonComponent.new(type: :submit,
|
||||
variant: :confirm,
|
||||
button_options: {testid: 'authorization-button'}) do
|
||||
= html_escape(_('Authorize %{client_name}')) % { client_name: @pre_auth.client.name.html_safe }
|
||||
button_options: { data: { testid: 'authorization-button' }}) do
|
||||
= safe_format(_('Authorize %{client_name}'), { client_name: @pre_auth.client.name })
|
||||
= form_tag oauth_authorization_path, method: :delete, class: 'gl-inline-block' do
|
||||
= hidden_field_tag :client_id, @pre_auth.client.uid
|
||||
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
|
||||
|
|
|
|||
|
|
@ -100,6 +100,52 @@ Example response:
|
|||
]
|
||||
```
|
||||
|
||||
## Add deploy key
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** Self-managed, GitLab Dedicated
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/478476) in GitLab 17.5.
|
||||
|
||||
Create a deploy key for the GitLab instance. This endpoint requires administrator
|
||||
access.
|
||||
|
||||
```plaintext
|
||||
POST /deploy_keys
|
||||
```
|
||||
|
||||
Supported attributes:
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|:--------------|:---------|:---------|:----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `key` | string | yes | New deploy key |
|
||||
| `title` | string | yes | New deploy key's title |
|
||||
| `expires_at` | datetime | no | Expiration date for the deploy key. Does not expire if no value is provided. Expected in ISO 8601 format (`2024-12-31T08:00:00Z`) |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" \
|
||||
--data '{"title": "My deploy key", "key": "ssh-rsa AAAA...", "expired_at": "2024-12-31T08:00:00Z"}' \
|
||||
"https://gitlab.example.com/api/v4/deploy_keys/"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id" : 5,
|
||||
"title" : "My deploy key",
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNJAkI3Wdf0r13c8a5pEExB2YowPWCSVzfZV22pNBc1CuEbyYLHpUyaD0GwpGvFdx2aP7lMEk35k6Rz3ccBF6jRaVJyhsn5VNnW92PMpBJ/P1UebhXwsFHdQf5rTt082cSxWuk61kGWRQtk4ozt/J2DF/dIUVaLvc+z4HomT41fQ==",
|
||||
"fingerprint": "4a:9d:64:15:ed:3a:e6:07:6e:89:36:b3:3b:03:05:d9",
|
||||
"fingerprint_sha256": "SHA256:Jrs3LD1Ji30xNLtTVf9NDCj7kkBgPBb2pjvTZ3HfIgU",
|
||||
"usage_type": "auth_and_signing",
|
||||
"created_at": "2024-10-03T01:32:21.992Z",
|
||||
"expires_at": "2024-12-31T08:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
## List deploy keys for project
|
||||
|
||||
Get a list of a project's deploy keys.
|
||||
|
|
@ -236,7 +282,7 @@ Example response:
|
|||
}
|
||||
```
|
||||
|
||||
## Add deploy key
|
||||
## Add deploy key for a project
|
||||
|
||||
Creates a new deploy key for a project.
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ Go pseudo versions are not supported. A project dependency that references a Go
|
|||
never considered as affected because this might result in false negatives.
|
||||
|
||||
RPM versions containing `^` are not supported. Work to support these versions is tracked in [issue 459969](https://gitlab.com/gitlab-org/gitlab/-/issues/459969).
|
||||
APK versions containing leading zeros are not supported. Work to support these versions is tracked in [issue 471509](https://gitlab.com/gitlab-org/gitlab/-/issues/471509)
|
||||
APK versions containing leading zeros are not supported. Work to support these versions is tracked in [issue 471509](https://gitlab.com/gitlab-org/gitlab/-/issues/471509).
|
||||
|
||||
RPM packages in Red Hat distributions are not supported. Work to support this use case is tracked in [epic 12980](https://gitlab.com/groups/gitlab-org/-/epics/12980).
|
||||
|
||||
## How to generate a CycloneDX SBOM report
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ GitLab Advanced SAST includes the following features:
|
|||
- Cross-file analysis: Tracks data flow across different files, discovering vulnerabilities at a deeper level.
|
||||
- Sanitizer detection: Avoid false positive results in case the user input is properly sanitized.
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview of GitLab Advanced SAST and how it works, see [GitLab Advanced SAST: Accelerating Vulnerability Resolution](https://youtu.be/xDa1MHOcyn8).
|
||||
|
||||
For a product tour, see the [GitLab Advanced SAST product tour](https://gitlab.navattic.com/advanced-sast).
|
||||
|
||||
## Supported languages
|
||||
|
|
@ -137,6 +140,20 @@ To enable Advanced SAST by using the pipeline editor:
|
|||
|
||||
Pipelines now include an Advanced SAST job.
|
||||
|
||||
## Vulnerability code flow
|
||||
|
||||
For some vulnerabilities detected by Advanced SAST, a **Code flow** tab is available in the [Vulnerability Page](../vulnerabilities/index.md).
|
||||
A vulnerability's code flow is the path the data takes from the user input (source) to the vulnerable line of code (sink),
|
||||
through all assignments, manipulation, and sanitization. This information helps you understand and evaluate the
|
||||
vulnerability's context, impact, and risk.
|
||||
|
||||
The **Code flow** tab shows:
|
||||
|
||||
- The steps from source to sink.
|
||||
- The relevant files, including code snippets.
|
||||
|
||||

|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues while using GitLab Advanced SAST, refer to the [troubleshooting guide](troubleshooting.md).
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ Audit event types belong to the following product categories.
|
|||
|
||||
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
|
||||
|:------------|:------------|:------------------|:---------|:--------------|:--------------|
|
||||
| [`container_repository_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156037) | Triggered when a container repository is first pushed to the registry | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [17.5](https://gitlab.com/gitlab-org/gitlab/-/issues/362290) | Project |
|
||||
| [`container_repository_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/152967) | Triggered when a project's container registry is deleted | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [17.2](https://gitlab.com/gitlab-org/gitlab/-/issues/362290) | Project |
|
||||
| [`container_repository_deletion_marked`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/152967) | Triggered when a project's container repository is marked for deletion | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [17.2](https://gitlab.com/gitlab-org/gitlab/-/issues/362290) | Project |
|
||||
| [`container_repository_tags_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156066) | Triggered when a project's container repository tag is deleted | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [17.2](https://gitlab.com/gitlab-org/gitlab/-/issues/362290) | Project |
|
||||
|
|
|
|||
|
|
@ -47,6 +47,33 @@ module API
|
|||
with: Entities::DeployKey, include_projects_with_write_access: true, include_projects_with_readonly_access: true
|
||||
end
|
||||
|
||||
desc 'Create a deploy key' do
|
||||
detail 'Create a deploy key for the GitLab instance. This endpoint requires administrator access.'
|
||||
success Entities::DeployKey
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' }
|
||||
]
|
||||
tags deploy_keys_tags
|
||||
end
|
||||
params do
|
||||
requires :key, type: String, desc: 'New deploy key'
|
||||
requires :title, type: String, desc: "New deploy key's title"
|
||||
optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
|
||||
end
|
||||
post "deploy_keys" do
|
||||
authenticated_as_admin!
|
||||
|
||||
deploy_key = ::DeployKeys::CreateService.new(current_user, declared_params.merge(public: true)).execute
|
||||
|
||||
if deploy_key.persisted?
|
||||
present deploy_key, with: Entities::DeployKey
|
||||
else
|
||||
render_validation_error!(deploy_key)
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ module API
|
|||
|
||||
feature_category :source_code_management
|
||||
|
||||
helpers do
|
||||
def authorize_template_permissions!
|
||||
permission = params[:type] == 'issues' ? :read_project : :download_code
|
||||
|
||||
authorize! permission, user_project, "Your current role does not have the required permissions to access the #{params[:type]} template. Contact your project administrator for assistance."
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
|
||||
requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|issues|merge_requests) of the template'
|
||||
|
|
@ -32,6 +40,8 @@ module API
|
|||
use :pagination
|
||||
end
|
||||
get ':id/templates/:type' do
|
||||
authorize_template_permissions!
|
||||
|
||||
templates = TemplateFinder.all_template_names(user_project, params[:type]).values.flatten
|
||||
|
||||
present paginate(::Kaminari.paginate_array(templates)), with: Entities::TemplatesList
|
||||
|
|
@ -60,6 +70,8 @@ module API
|
|||
end
|
||||
|
||||
get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do
|
||||
authorize_template_permissions!
|
||||
|
||||
begin
|
||||
template = TemplateFinder.build(
|
||||
params[:type],
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ module Gitlab
|
|||
def name
|
||||
@name || _('Deploy Token')
|
||||
end
|
||||
|
||||
def impersonated?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ module Gitlab
|
|||
|
||||
attr_reader :merge_request, :resolver
|
||||
|
||||
def initialize(merge_request, allow_tree_conflicts: false)
|
||||
def initialize(merge_request, allow_tree_conflicts: false, skip_content: false)
|
||||
our_commit = merge_request.source_branch_head.raw
|
||||
their_commit = merge_request.target_branch_head.raw
|
||||
@target_repo = merge_request.target_project.repository
|
||||
@source_repo = merge_request.source_project.repository.raw
|
||||
@our_commit_id = our_commit.id
|
||||
@their_commit_id = their_commit.id
|
||||
@resolver = Gitlab::Git::Conflict::Resolver.new(@target_repo.raw, @our_commit_id, @their_commit_id, allow_tree_conflicts: allow_tree_conflicts)
|
||||
@resolver = Gitlab::Git::Conflict::Resolver.new(@target_repo.raw, @our_commit_id, @their_commit_id, allow_tree_conflicts: allow_tree_conflicts, skip_content: skip_content)
|
||||
@merge_request = merge_request
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,16 +9,22 @@ module Gitlab
|
|||
ConflictSideMissing = Class.new(StandardError)
|
||||
ResolutionError = Class.new(StandardError)
|
||||
|
||||
def initialize(target_repository, our_commit_oid, their_commit_oid, allow_tree_conflicts: false)
|
||||
def initialize(target_repository, our_commit_oid, their_commit_oid, allow_tree_conflicts: false, skip_content: false)
|
||||
@target_repository = target_repository
|
||||
@our_commit_oid = our_commit_oid
|
||||
@their_commit_oid = their_commit_oid
|
||||
@allow_tree_conflicts = allow_tree_conflicts
|
||||
@skip_content = skip_content
|
||||
end
|
||||
|
||||
def conflicts
|
||||
@conflicts ||= wrapped_gitaly_errors do
|
||||
gitaly_conflicts_client(@target_repository).list_conflict_files(allow_tree_conflicts: @allow_tree_conflicts).to_a
|
||||
gitaly_conflicts_client(@target_repository)
|
||||
.list_conflict_files(
|
||||
allow_tree_conflicts: @allow_tree_conflicts,
|
||||
skip_content: @skip_content
|
||||
)
|
||||
.to_a
|
||||
rescue GRPC::FailedPrecondition => e
|
||||
raise Gitlab::Git::Conflict::Resolver::ConflictSideMissing, e.message
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ module Gitlab
|
|||
upload_pack_disabled_over_http: 'Pulling over HTTP is not allowed.',
|
||||
receive_pack_disabled_over_http: 'Pushing over HTTP is not allowed.',
|
||||
read_only: 'The repository is temporarily read-only. Please try again later.',
|
||||
archived: "You can't push code to an archived project.",
|
||||
cannot_push_to_read_only: "You can't push code to a read-only GitLab instance.",
|
||||
push_code: 'You are not allowed to push code to this project.'
|
||||
}.freeze
|
||||
|
|
@ -341,6 +342,10 @@ module Gitlab
|
|||
raise ForbiddenError, error_message(:read_only)
|
||||
end
|
||||
|
||||
if project&.archived?
|
||||
raise ForbiddenError, error_message(:archived)
|
||||
end
|
||||
|
||||
if deploy_key?
|
||||
unless deploy_key.can_push_to?(project)
|
||||
raise ForbiddenError, error_message(:deploy_key_upload)
|
||||
|
|
|
|||
|
|
@ -636,9 +636,6 @@ msgstr[1] ""
|
|||
msgid "%{chartTitle} no data series"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{client_name} is requesting access to your account on %{title}."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{codeStart}$%{codeEnd} will be treated as the start of a reference to another variable."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -1363,6 +1360,9 @@ msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%{strong_start}%{client_name}%{strong_end} is requesting access to your account on %{title}."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{strong_start}%{commit_count}%{strong_end} Commit"
|
||||
msgid_plural "%{strong_start}%{commit_count}%{strong_end} Commits"
|
||||
msgstr[0] ""
|
||||
|
|
@ -32776,7 +32776,7 @@ msgstr ""
|
|||
msgid "Make sure you save it - you won't be able to access it again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Make sure you trust %{client_name} before authorizing."
|
||||
msgid "Make sure you trust %{strong_start}%{client_name}%{strong_end} before authorizing."
|
||||
msgstr ""
|
||||
|
||||
msgid "Makes this %{type} confidential."
|
||||
|
|
@ -63005,7 +63005,7 @@ msgstr ""
|
|||
msgid "You are already impersonating another user"
|
||||
msgstr ""
|
||||
|
||||
msgid "You are an administrator, which means authorizing access to %{client_name} will allow it to interact with GitLab as an administrator as well."
|
||||
msgid "You are an administrator, which means authorizing access to %{strong_start}%{client_name}%{strong_end} will allow it to interact with GitLab as an administrator as well."
|
||||
msgstr ""
|
||||
|
||||
msgid "You are attempting to delete a file that has been previously updated."
|
||||
|
|
@ -63608,7 +63608,7 @@ msgstr ""
|
|||
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
|
||||
msgstr ""
|
||||
|
||||
msgid "You will be redirected to %{domain} after authorizing."
|
||||
msgid "You will be redirected to %{strong_start}%{domain}%{strong_end} after authorizing."
|
||||
msgstr ""
|
||||
|
||||
msgid "You will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
|
||||
|
|
|
|||
|
|
@ -3,21 +3,81 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'OAuth Provider', feature_category: :system_access do
|
||||
def visit_oauth_authorization_path
|
||||
visit oauth_authorization_path(
|
||||
client_id: application.uid,
|
||||
redirect_uri: application.redirect_uri.split.first,
|
||||
response_type: 'code',
|
||||
state: 'my_state',
|
||||
scope: 'read_user'
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
describe 'Standard OAuth Authorization' do
|
||||
let(:application) { create(:oauth_application, scopes: 'read_user') }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
|
||||
visit oauth_authorization_path(
|
||||
client_id: application.uid,
|
||||
redirect_uri: application.redirect_uri.split.first,
|
||||
response_type: 'code',
|
||||
state: 'my_state',
|
||||
scope: 'read_user'
|
||||
)
|
||||
visit_oauth_authorization_path
|
||||
end
|
||||
|
||||
it_behaves_like 'Secure OAuth Authorizations'
|
||||
end
|
||||
|
||||
context 'when the OAuth application has HTML in the name' do
|
||||
let(:client_name) { '<img src=x onerror=alert(1)>' }
|
||||
let(:application) { create(:oauth_application, name: client_name, scopes: 'read_user') }
|
||||
let(:user) { create(:admin) }
|
||||
|
||||
before do
|
||||
visit_oauth_authorization_path
|
||||
end
|
||||
|
||||
it 'sanitizes the HTML in the authorize button' do
|
||||
within_testid('authorization-button') do
|
||||
expect(page).to have_content(format(_('Authorize %{client_name}'), client_name: client_name))
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Layout/LineLength -- It is a string
|
||||
it 'sanitizes the HTML in the warning text' do
|
||||
expect(page).to have_content(
|
||||
format(
|
||||
_('You are an administrator, which means authorizing access to %{client_name} will allow it to interact with GitLab as an administrator as well.'),
|
||||
client_name: client_name
|
||||
)
|
||||
)
|
||||
end
|
||||
# rubocop:enable Layout/LineLength
|
||||
|
||||
it 'sanitizes the trust text HTML' do
|
||||
expect(page).to have_content(
|
||||
format(
|
||||
_('Make sure you trust %{client_name} before authorizing.'),
|
||||
client_name: client_name
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when brand title has HTML' do
|
||||
let(:application) { create(:oauth_application, scopes: 'read_user') }
|
||||
let(:user) { create(:user) }
|
||||
let!(:appearance) { create(:appearance, title: '<img src=x onerror=alert(1)>') }
|
||||
|
||||
before do
|
||||
visit_oauth_authorization_path
|
||||
end
|
||||
|
||||
it 'sanitizes the HTML' do
|
||||
expect(page).to have_content(
|
||||
format(_('%{client_name} is requesting access to your account on %{title}.'),
|
||||
title: '<img src=x onerror=alert(1)>',
|
||||
client_name: application.name
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -696,7 +696,12 @@ RSpec.describe DiffHelper, feature_category: :code_review_workflow do
|
|||
.with(when_renamed: true)
|
||||
.and_return(:renamed_same_file)
|
||||
|
||||
allow_next_instance_of(MergeRequests::Conflicts::ListService, merge_request, allow_tree_conflicts: true) do |svc|
|
||||
allow_next_instance_of(
|
||||
MergeRequests::Conflicts::ListService,
|
||||
merge_request,
|
||||
allow_tree_conflicts: true,
|
||||
skip_content: true
|
||||
) do |svc|
|
||||
if exception.present?
|
||||
allow(svc).to receive_message_chain(:conflicts, :files).and_raise(exception)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -231,6 +231,58 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
|
|||
it { is_expected.to include({ is_admin: true }) }
|
||||
end
|
||||
|
||||
describe "what's new information" do
|
||||
context 'when display_whats_new? is true' do
|
||||
before do
|
||||
allow(helper).to receive(:display_whats_new?).and_return(true)
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to include({
|
||||
whats_new_most_recent_release_items_count: helper.whats_new_most_recent_release_items_count,
|
||||
whats_new_version_digest: helper.whats_new_version_digest
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'when display_whats_new? is false' do
|
||||
before do
|
||||
allow(helper).to receive(:display_whats_new?).and_return(false)
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.not_to have_key(:whats_new_most_recent_release_items_count)
|
||||
is_expected.not_to have_key(:whats_new_version_digest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'instance version information' do
|
||||
context 'when show_version_check? is true' do
|
||||
before do
|
||||
allow(helper).to receive(:show_version_check?).and_return(true)
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to include({
|
||||
gitlab_version: Gitlab.version_info,
|
||||
gitlab_version_check: helper.gitlab_version_check
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'when show_version_check? is false' do
|
||||
before do
|
||||
allow(helper).to receive(:show_version_check?).and_return(false)
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.not_to have_key(:gitlab_version)
|
||||
is_expected.not_to have_key(:gitlab_version_check)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "shortcut links" do
|
||||
describe "as the anonymous user" do
|
||||
let_it_be(:user) { nil }
|
||||
|
|
|
|||
|
|
@ -4,12 +4,78 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Gitlab::Conflict::FileCollection do
|
||||
let(:merge_request) { create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start') }
|
||||
let(:file_collection) { described_class.new(merge_request) }
|
||||
let(:allow_tree_conflicts) { false }
|
||||
let(:skip_content) { false }
|
||||
|
||||
let(:file_collection) do
|
||||
described_class.new(
|
||||
merge_request,
|
||||
allow_tree_conflicts: allow_tree_conflicts,
|
||||
skip_content: skip_content
|
||||
)
|
||||
end
|
||||
|
||||
describe '#files' do
|
||||
let(:conflict_files) { [instance_double(Gitlab::Conflict::File, path: 'file.md')] }
|
||||
let(:git_conflict_files) { [instance_double(Gitlab::Git::Conflict::File, path: 'file.md')] }
|
||||
let(:resolver) { instance_double(Gitlab::Git::Conflict::Resolver, conflicts: git_conflict_files) }
|
||||
|
||||
it 'returns an array of Conflict::Files' do
|
||||
expect(file_collection.files).to all(be_an_instance_of(Gitlab::Conflict::File))
|
||||
end
|
||||
|
||||
it 'returns conflict files' do
|
||||
expect(Gitlab::Git::Conflict::Resolver)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
merge_request.source_project.repository.raw,
|
||||
merge_request.source_branch_head.raw.id,
|
||||
merge_request.target_branch_head.raw.id,
|
||||
allow_tree_conflicts: false,
|
||||
skip_content: false
|
||||
)
|
||||
.and_return(resolver)
|
||||
|
||||
expect(file_collection.files.map(&:path)).to eq(conflict_files.map(&:path))
|
||||
end
|
||||
|
||||
context 'when allow_tree_conflicts is set to true' do
|
||||
let(:allow_tree_conflicts) { true }
|
||||
|
||||
it 'returns conflict files with allow_tree_conflicts as true' do
|
||||
expect(Gitlab::Git::Conflict::Resolver)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
merge_request.source_project.repository.raw,
|
||||
merge_request.source_branch_head.raw.id,
|
||||
merge_request.target_branch_head.raw.id,
|
||||
allow_tree_conflicts: true,
|
||||
skip_content: false
|
||||
)
|
||||
.and_return(resolver)
|
||||
|
||||
expect(file_collection.files.map(&:path)).to eq(conflict_files.map(&:path))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when skip_content is set to true' do
|
||||
let(:skip_content) { true }
|
||||
|
||||
it 'returns conflict files with skip_content as true' do
|
||||
expect(Gitlab::Git::Conflict::Resolver)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
merge_request.source_project.repository.raw,
|
||||
merge_request.source_branch_head.raw.id,
|
||||
merge_request.target_branch_head.raw.id,
|
||||
allow_tree_conflicts: false,
|
||||
skip_content: true
|
||||
)
|
||||
.and_return(resolver)
|
||||
|
||||
expect(file_collection.files.map(&:path)).to eq(conflict_files.map(&:path))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cache' do
|
||||
|
|
|
|||
|
|
@ -7,21 +7,61 @@ RSpec.describe Gitlab::Git::Conflict::Resolver do
|
|||
let(:our_commit_oid) { 'our-commit-oid' }
|
||||
let(:their_commit_oid) { 'their-commit-oid' }
|
||||
let(:gitaly_conflicts_client) { instance_double(Gitlab::GitalyClient::ConflictsService) }
|
||||
let(:allow_tree_conflicts) { false }
|
||||
let(:skip_content) { false }
|
||||
|
||||
subject(:resolver) { described_class.new(repository, our_commit_oid, their_commit_oid) }
|
||||
subject(:resolver) do
|
||||
described_class.new(
|
||||
repository,
|
||||
our_commit_oid,
|
||||
their_commit_oid,
|
||||
allow_tree_conflicts: allow_tree_conflicts,
|
||||
skip_content: skip_content
|
||||
)
|
||||
end
|
||||
|
||||
describe '#conflicts' do
|
||||
let(:conflicts) { [double] }
|
||||
|
||||
before do
|
||||
allow(repository).to receive(:gitaly_conflicts_client).and_return(gitaly_conflicts_client)
|
||||
end
|
||||
|
||||
it 'returns list of conflicts' do
|
||||
conflicts = [double]
|
||||
expect(gitaly_conflicts_client)
|
||||
.to receive(:list_conflict_files)
|
||||
.with(allow_tree_conflicts: false, skip_content: false)
|
||||
.and_return(conflicts)
|
||||
|
||||
expect(gitaly_conflicts_client).to receive(:list_conflict_files).and_return(conflicts)
|
||||
expect(resolver.conflicts).to eq(conflicts)
|
||||
end
|
||||
|
||||
context 'when allow_tree_conflicts is set to true' do
|
||||
let(:allow_tree_conflicts) { true }
|
||||
|
||||
it 'returns list of conflicts with allow_tree_conflicts as true' do
|
||||
expect(gitaly_conflicts_client)
|
||||
.to receive(:list_conflict_files)
|
||||
.with(allow_tree_conflicts: true, skip_content: false)
|
||||
.and_return(conflicts)
|
||||
|
||||
expect(resolver.conflicts).to eq(conflicts)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when skip_content is set to true' do
|
||||
let(:skip_content) { true }
|
||||
|
||||
it 'returns list of conflicts with skip_content as true' do
|
||||
expect(gitaly_conflicts_client)
|
||||
.to receive(:list_conflict_files)
|
||||
.with(allow_tree_conflicts: false, skip_content: true)
|
||||
.and_return(conflicts)
|
||||
|
||||
expect(resolver.conflicts).to eq(conflicts)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when GRPC::FailedPrecondition is raised' do
|
||||
it 'rescues and raises Gitlab::Git::Conflict::Resolver::ConflictSideMissing' do
|
||||
expect(gitaly_conflicts_client).to receive(:list_conflict_files).and_raise(GRPC::FailedPrecondition)
|
||||
|
|
|
|||
|
|
@ -1127,6 +1127,16 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :system
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the project is archived' do
|
||||
let(:project) { create(:project, :repository, :archived) }
|
||||
|
||||
it 'denies push access' do
|
||||
project.add_maintainer(user)
|
||||
|
||||
expect { push_access_check }.to raise_forbidden(described_class::ERROR_MESSAGES[:archived])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'deploy key permissions' do
|
||||
let(:key) { create(:deploy_key, user: user) }
|
||||
let(:actor) { key }
|
||||
|
|
@ -1138,6 +1148,14 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :system
|
|||
end
|
||||
|
||||
it { expect { push_access_check }.not_to raise_error }
|
||||
|
||||
context 'when project is archived' do
|
||||
before do
|
||||
project.update!(archived: true)
|
||||
end
|
||||
|
||||
it { expect { push_access_check }.to raise_forbidden(described_class::ERROR_MESSAGES[:archived]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when unauthorized' do
|
||||
|
|
|
|||
|
|
@ -110,6 +110,64 @@ RSpec.describe API::DeployKeys, :aggregate_failures, feature_category: :continuo
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST /deploy_keys' do
|
||||
let_it_be(:path) { '/deploy_keys' }
|
||||
|
||||
it_behaves_like 'POST request permissions for admin mode' do
|
||||
let(:params) { attributes_for :another_key }
|
||||
let(:failed_status_code) { :forbidden }
|
||||
end
|
||||
|
||||
context 'when unauthenticated' do
|
||||
it 'returns authentication error' do
|
||||
post api(path), params: attributes_for(:another_key)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when authenticated as admin' do
|
||||
let_it_be(:pat) { create(:personal_access_token, :admin_mode, user: admin) }
|
||||
|
||||
it 'creates a new deploy key' do
|
||||
expect do
|
||||
post api(path, personal_access_token: pat), params: attributes_for(:another_key)
|
||||
end.to change { DeployKey.count }.by(1)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
end
|
||||
|
||||
it 'does not create an invalid ssh key' do
|
||||
post api(path, personal_access_token: pat), params: { title: 'invalid key' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq('key is missing')
|
||||
end
|
||||
|
||||
it 'does not create a key without title' do
|
||||
post api(path, personal_access_token: pat), params: { key: 'some key' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq('title is missing')
|
||||
end
|
||||
|
||||
it 'returns Bad Request when deploy key is duplicated' do
|
||||
post api(path, personal_access_token: pat), params: { key: deploy_key.key, title: deploy_key.title }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['message']['fingerprint_sha256']).to eq(['has already been taken'])
|
||||
end
|
||||
|
||||
it 'accepts optional expires_at parameter' do
|
||||
attrs = attributes_for(:another_key).merge(expires_at: 2.days.since.iso8601)
|
||||
post api(path, personal_access_token: pat), params: attrs
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(Time.parse(json_response['expires_at'])).to be_like_time(2.days.since)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/deploy_keys' do
|
||||
let(:deploy_key) { create(:deploy_key, public: true, user: admin) }
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ require 'spec_helper'
|
|||
RSpec.describe API::ProjectTemplates, feature_category: :source_code_management do
|
||||
let_it_be(:public_project) { create(:project, :public, :repository, create_templates: :merge_request, path: 'path.with.dot') }
|
||||
let_it_be(:private_project) { create(:project, :private, :repository, create_templates: :issue) }
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:reporter) { create(:user) }
|
||||
let_it_be(:guest) { create(:user) }
|
||||
|
||||
let(:url_encoded_path) { "#{public_project.namespace.path}%2F#{public_project.path}" }
|
||||
|
||||
before do
|
||||
stub_feature_flags(remove_monitor_metrics: false)
|
||||
private_project.add_developer(developer)
|
||||
private_project.add_developer(reporter)
|
||||
private_project.add_guest(guest)
|
||||
end
|
||||
|
||||
shared_examples 'accepts project paths with dots' do
|
||||
|
|
@ -64,7 +66,7 @@ RSpec.describe API::ProjectTemplates, feature_category: :source_code_management
|
|||
end
|
||||
|
||||
it 'returns issue templates' do
|
||||
get api("/projects/#{private_project.id}/templates/issues", developer)
|
||||
get api("/projects/#{private_project.id}/templates/issues", reporter)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
|
|
@ -94,23 +96,58 @@ RSpec.describe API::ProjectTemplates, feature_category: :source_code_management
|
|||
end
|
||||
|
||||
it 'permits access to a developer on a private project' do
|
||||
get api("/projects/#{private_project.id}/templates/licenses", developer)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/template_list')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/templates/licenses' do
|
||||
it 'returns key and name for the listed licenses' do
|
||||
get api("/projects/#{public_project.id}/templates/licenses")
|
||||
get api("/projects/#{private_project.id}/templates/licenses", reporter)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/template_list')
|
||||
end
|
||||
|
||||
it_behaves_like 'accepts project paths with dots' do
|
||||
subject { get api("/projects/#{url_encoded_path}/templates/licenses") }
|
||||
context 'when a guest has no permission to a template' do
|
||||
it 'denies access to the dockerfile' do
|
||||
get api("/projects/#{private_project.id}/templates/dockerfiles", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the dockerfiles template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the gitignore' do
|
||||
get api("/projects/#{private_project.id}/templates/gitignores", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the gitignores template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the gitlab_ci_yml' do
|
||||
get api("/projects/#{private_project.id}/templates/gitlab_ci_ymls", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the gitlab_ci_ymls template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the license' do
|
||||
get api("/projects/#{private_project.id}/templates/licenses", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the licenses template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the merge request' do
|
||||
get api("/projects/#{private_project.id}/templates/merge_requests", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the merge_requests template. Contact your project administrator for assistance.")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a guest has permission to an issues template' do
|
||||
it 'returns an issue template' do
|
||||
get api("/projects/#{private_project.id}/templates/issues", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response).to match_response_schema('public_api/v4/template_list')
|
||||
expect(json_response.map { |t| t['key'] }).to match_array(%w[bug feature_proposal template_test (test)])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -163,7 +200,7 @@ RSpec.describe API::ProjectTemplates, feature_category: :source_code_management
|
|||
end
|
||||
|
||||
it 'returns a specific issue template' do
|
||||
get api("/projects/#{private_project.id}/templates/issues/bug", developer)
|
||||
get api("/projects/#{private_project.id}/templates/issues/bug", reporter)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/template')
|
||||
|
|
@ -173,7 +210,7 @@ RSpec.describe API::ProjectTemplates, feature_category: :source_code_management
|
|||
|
||||
context 'when issue template uses parentheses' do
|
||||
it 'returns a specific issue template' do
|
||||
get api("/projects/#{private_project.id}/templates/issues/(test)", developer)
|
||||
get api("/projects/#{private_project.id}/templates/issues/(test)", reporter)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/template')
|
||||
|
|
@ -216,7 +253,7 @@ RSpec.describe API::ProjectTemplates, feature_category: :source_code_management
|
|||
end
|
||||
|
||||
it 'permits access to a developer on a private project' do
|
||||
get api("/projects/#{private_project.id}/templates/licenses/mit", developer)
|
||||
get api("/projects/#{private_project.id}/templates/licenses/mit", reporter)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/license')
|
||||
|
|
@ -243,6 +280,54 @@ RSpec.describe API::ProjectTemplates, feature_category: :source_code_management
|
|||
TemplateFinder::VENDORED_TEMPLATES.each do |template_type, _|
|
||||
it_behaves_like 'path traversal attempt', template_type
|
||||
end
|
||||
|
||||
context 'when a guest has no permission to a template' do
|
||||
it 'denies access to the dockerfile' do
|
||||
get api("/projects/#{private_project.id}/templates/dockerfiles/Binary", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the dockerfiles template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the gitignore' do
|
||||
get api("/projects/#{private_project.id}/templates/gitignores/Actionscript", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the gitignores template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the gitlab_ci_yml' do
|
||||
get api("/projects/#{private_project.id}/templates/gitlab_ci_ymls/Android", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the gitlab_ci_ymls template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the license' do
|
||||
get api("/projects/#{private_project.id}/templates/licenses/mit", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the licenses template. Contact your project administrator for assistance.")
|
||||
end
|
||||
|
||||
it 'denies access to the merge request' do
|
||||
get api("/projects/#{private_project.id}/templates/merge_requests/feature_proposal", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(json_response['message']).to eq("403 Forbidden - Your current role does not have the required permissions to access the merge_requests template. Contact your project administrator for assistance.")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a guest has permission to an issues template' do
|
||||
it 'returns an issue template' do
|
||||
get api("/projects/#{private_project.id}/templates/issues/bug", guest)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/template')
|
||||
expect(json_response['name']).to eq('bug')
|
||||
expect(json_response['content']).to eq('something valid')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/templates/licenses/:key' do
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@ RSpec.describe MergeRequests::Conflicts::ListService, feature_category: :code_re
|
|||
end
|
||||
end
|
||||
|
||||
def conflicts_service(merge_request)
|
||||
described_class.new(merge_request)
|
||||
end
|
||||
|
||||
it 'returns a falsey value when the MR can be merged without conflicts' do
|
||||
merge_request = create_merge_request('master')
|
||||
merge_request.mark_as_mergeable
|
||||
|
|
@ -95,4 +91,58 @@ RSpec.describe MergeRequests::Conflicts::ListService, feature_category: :code_re
|
|||
expect(conflicts_service(merge_request).can_be_resolved_in_ui?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe '#conflicts' do
|
||||
let(:merge_request) { build_stubbed(:merge_request) }
|
||||
let(:file_collection) { [instance_double(Gitlab::Conflict::FileCollection)] }
|
||||
|
||||
it 'returns conflict file collection' do
|
||||
expect(Gitlab::Conflict::FileCollection)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
merge_request,
|
||||
allow_tree_conflicts: nil,
|
||||
skip_content: nil
|
||||
)
|
||||
.and_return(file_collection)
|
||||
|
||||
expect(conflicts_service(merge_request).conflicts).to eq(file_collection)
|
||||
end
|
||||
|
||||
context 'when allow_tree_conflicts is set to true' do
|
||||
it 'returns conflict file collection with allow_tree_conflicts as true' do
|
||||
expect(Gitlab::Conflict::FileCollection)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
merge_request,
|
||||
allow_tree_conflicts: true,
|
||||
skip_content: nil
|
||||
)
|
||||
.and_return(file_collection)
|
||||
|
||||
expect(conflicts_service(merge_request, allow_tree_conflicts: true).conflicts)
|
||||
.to eq(file_collection)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when skip_content is set to true' do
|
||||
it 'returns conflict file collection with skip_content as true' do
|
||||
expect(Gitlab::Conflict::FileCollection)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
merge_request,
|
||||
allow_tree_conflicts: nil,
|
||||
skip_content: true
|
||||
)
|
||||
.and_return(file_collection)
|
||||
|
||||
expect(conflicts_service(merge_request, skip_content: true).conflicts)
|
||||
.to eq(file_collection)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conflicts_service(merge_request, params = {})
|
||||
described_class.new(merge_request, params)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -246,6 +246,18 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor
|
|||
expect(@another_merge_request.has_commits?).to be_falsy
|
||||
end
|
||||
|
||||
context 'when push is a branch removal' do
|
||||
before do
|
||||
# If @newrev is a blank SHA, it means the ref has been removed
|
||||
@newrev = Gitlab::Git::SHA1_BLANK_SHA
|
||||
end
|
||||
|
||||
it 'does not create detached merge request pipeline' do
|
||||
expect { subject }
|
||||
.not_to change { @merge_request.pipelines_for_merge_request.count }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when "push_options: nil" is passed' do
|
||||
let(:service_instance) { service.new(project: project, current_user: @user, params: { push_options: nil }) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1909,7 +1909,6 @@
|
|||
- './ee/spec/requests/api/resource_label_events_spec.rb'
|
||||
- './ee/spec/requests/api/resource_weight_events_spec.rb'
|
||||
- './ee/spec/requests/api/saml_group_links_spec.rb'
|
||||
- './ee/spec/requests/api/search_spec.rb'
|
||||
- './ee/spec/requests/api/settings_spec.rb'
|
||||
- './ee/spec/requests/api/status_checks_spec.rb'
|
||||
- './ee/spec/requests/api/submodules_spec.rb'
|
||||
|
|
|
|||
|
|
@ -7,11 +7,7 @@ RSpec.shared_examples 'shared super sidebar context' do
|
|||
current_context_header: nil,
|
||||
support_path: helper.support_url,
|
||||
display_whats_new: helper.display_whats_new?,
|
||||
whats_new_most_recent_release_items_count: helper.whats_new_most_recent_release_items_count,
|
||||
whats_new_version_digest: helper.whats_new_version_digest,
|
||||
show_version_check: helper.show_version_check?,
|
||||
gitlab_version: Gitlab.version_info,
|
||||
gitlab_version_check: helper.gitlab_version_check,
|
||||
search: {
|
||||
search_path: search_path,
|
||||
issues_path: issues_dashboard_path,
|
||||
|
|
|
|||
Loading…
Reference in New Issue