diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-27 18:09:39 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-27 18:09:39 +0000 |
commit | 3e1f93c033ed7744696f7763716b51ab5acda17a (patch) | |
tree | 9208f71b8b7461a34560ac2b7f5d01f26b5cd80c | |
parent | ab421e159d39cf91a95f4a911821308d258e77d9 (diff) | |
download | gitlab-ce-3e1f93c033ed7744696f7763716b51ab5acda17a.tar.gz |
Add latest changes from gitlab-org/gitlab@master
20 files changed, 308 insertions, 104 deletions
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index af0c1e9619e..0ba5465411d 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -1,5 +1,5 @@ <script> -import { GlSprintf, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; +import { GlSprintf, GlSafeHtmlDirective as SafeHtml, GlAvatarLink, GlAvatar } from '@gitlab/ui'; import $ from 'jquery'; import { escape, isEmpty } from 'lodash'; import { mapGetters, mapActions } from 'vuex'; @@ -11,7 +11,6 @@ import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending'; import { truncateSha } from '~/lib/utils/text_utility'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; import { __, s__, sprintf } from '~/locale'; -import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import eventHub from '../event_hub'; import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; @@ -31,11 +30,12 @@ export default { name: 'NoteableNote', components: { GlSprintf, - userAvatarLink, noteHeader, noteActions, NoteBody, TimelineEntryItem, + GlAvatarLink, + GlAvatar, }, directives: { SafeHtml, @@ -196,13 +196,11 @@ export default { return fileResolvedFromAvailableSource || null; }, - avatarSize() { - // Use a different size if shown on a Merge Request Diff - if (this.line && !this.isOverviewTab) { - return 24; - } - - return 40; + isMRDiffView() { + return this.line && !this.isOverviewTab; + }, + authorAvatarAdaptiveSize() { + return { default: 24, md: 32 }; }, }, created() { @@ -428,19 +426,33 @@ export default { </template> </gl-sprintf> </div> - <div class="timeline-icon"> - <user-avatar-link - :link-href="author.path" - :img-src="author.avatar_url" - :img-alt="author.name" - :img-size="avatarSize" - lazy - > - <template #avatar-badge> - <slot name="avatar-badge"></slot> - </template> - </user-avatar-link> + + <div v-if="isMRDiffView" class="gl-float-left gl-mt-n1 gl-mr-3"> + <gl-avatar-link :href="author.path"> + <gl-avatar + :src="author.avatar_url" + :entity-name="author.username" + :alt="author.name" + :size="24" + /> + + <slot name="avatar-badge"></slot> + </gl-avatar-link> + </div> + + <div v-else class="gl-float-left gl-pl-3 gl-mr-3 gl-md-pl-2 gl-md-pr-2"> + <gl-avatar-link :href="author.path"> + <gl-avatar + :src="author.avatar_url" + :entity-name="author.username" + :alt="author.name" + :size="authorAvatarAdaptiveSize" + /> + + <slot name="avatar-badge"></slot> + </gl-avatar-link> </div> + <div class="timeline-content"> <div class="note-header"> <note-header diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 64f284af43c..c25ba6f9268 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -185,7 +185,7 @@ class Deployment < ApplicationRecord def self.last_deployment_group_for_environment(env) return self.none unless env.last_deployment_pipeline&.latest_successful_builds&.present? - BatchLoader.for(env).batch do |environments, loader| + BatchLoader.for(env).batch(default_value: self.none) do |environments, loader| latest_successful_build_ids = [] environments_hash = {} diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 7aba5e93139..872470023eb 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -59,7 +59,13 @@ class ProjectPolicy < BasePolicy desc "Container registry is disabled" condition(:container_registry_disabled, scope: :subject) do - !access_allowed_to?(:container_registry) + if user.is_a?(DeployToken) + (!user.read_registry? && !user.write_registry?) || + user.revoked? || + !project.container_registry_enabled? + else + !access_allowed_to?(:container_registry) + end end desc "Container registry is enabled for everyone with access to the project" @@ -88,6 +94,16 @@ class ProjectPolicy < BasePolicy user.is_a?(DeployKey) && user.can_push_to?(project) end + desc "Deploy token with read_container_image scope" + condition(:read_container_image_deploy_token) do + user.is_a?(DeployToken) && user.has_access_to?(project) && user.read_registry? + end + + desc "Deploy token with create_container_image scope" + condition(:create_container_image_deploy_token) do + user.is_a?(DeployToken) && user.has_access_to?(project) && user.write_registry? + end + desc "Deploy token with read_package_registry scope" condition(:read_package_registry_deploy_token) do user.is_a?(DeployToken) && user.has_access_to?(project) && user.read_package_registry @@ -698,6 +714,14 @@ class ProjectPolicy < BasePolicy enable :push_code end + rule { read_container_image_deploy_token }.policy do + enable :read_container_image + end + + rule { create_container_image_deploy_token }.policy do + enable :create_container_image + end + rule { read_package_registry_deploy_token }.policy do enable :read_package enable :read_project diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index 6d6d8641d9d..e806bef46fe 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -215,15 +215,13 @@ module Auth def deploy_token_can_pull?(requested_project) has_authentication_ability?(:read_container_image) && deploy_token.present? && - deploy_token.has_access_to?(requested_project) && - deploy_token.read_registry? + can?(deploy_token, :read_container_image, requested_project) end def deploy_token_can_push?(requested_project) has_authentication_ability?(:create_container_image) && deploy_token.present? && - deploy_token.has_access_to?(requested_project) && - deploy_token.write_registry? + can?(deploy_token, :create_container_image, requested_project) end ## diff --git a/app/views/admin/application_settings/_package_registry.html.haml b/app/views/admin/application_settings/_package_registry.html.haml index c0fabb1d42e..b31576b5c48 100644 --- a/app/views/admin/application_settings/_package_registry.html.haml +++ b/app/views/admin/application_settings/_package_registry.html.haml @@ -1,7 +1,7 @@ - if Gitlab.config.packages.enabled %section.settings.as-package.no-animate#js-package-settings{ class: ('expanded' if expanded_by_default?) } .settings-header - %h4 + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = _('Package Registry') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do = expanded_by_default? ? _('Collapse') : _('Expand') diff --git a/app/views/admin/application_settings/ci/_header.html.haml b/app/views/admin/application_settings/ci/_header.html.haml index 5e3f0d6f2aa..0adb6cbbcf0 100644 --- a/app/views/admin/application_settings/ci/_header.html.haml +++ b/app/views/admin/application_settings/ci/_header.html.haml @@ -1,6 +1,6 @@ - expanded = local_assigns.fetch(:expanded) -%h4 +%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = _('Variables') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do diff --git a/app/views/admin/application_settings/ci_cd.html.haml b/app/views/admin/application_settings/ci_cd.html.haml index b635e7198cb..f0f7e6868da 100644 --- a/app/views/admin/application_settings/ci_cd.html.haml +++ b/app/views/admin/application_settings/ci_cd.html.haml @@ -14,7 +14,7 @@ %section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded_by_default?) } .settings-header - %h4 + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = _('Continuous Integration and Deployment') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do = expanded_by_default? ? _('Collapse') : _('Expand') @@ -29,7 +29,7 @@ - if Gitlab.config.registry.enabled %section.settings.as-registry.no-animate#js-registry-settings{ class: ('expanded' if expanded_by_default?) } .settings-header - %h4 + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = _('Container Registry') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do = expanded_by_default? ? _('Collapse') : _('Expand') @@ -41,7 +41,7 @@ - if Feature.enabled?(:runner_registration_control) %section.settings.as-runner.no-animate#js-runner-settings{ class: ('expanded' if expanded_by_default?) } .settings-header - %h4 + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = s_('Runners|Runner registration') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do = expanded_by_default? ? 'Collapse' : 'Expand' diff --git a/config/feature_flags/development/container_registry_legacy_authentication_for_deploy_tokens.yml b/config/feature_flags/development/container_registry_legacy_authentication_for_deploy_tokens.yml new file mode 100644 index 00000000000..fefc84ed0a0 --- /dev/null +++ b/config/feature_flags/development/container_registry_legacy_authentication_for_deploy_tokens.yml @@ -0,0 +1,8 @@ +--- +name: container_registry_legacy_authentication_for_deploy_tokens +introduced_by_url: https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/2470 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365968 +milestone: '15.1' +type: development +group: group::package +default_enabled: false diff --git a/db/post_migrate/20220620151740_add_indexes_issues_on_project_id_and_closed_at.rb b/db/post_migrate/20220620151740_add_indexes_issues_on_project_id_and_closed_at.rb index 20db2f0c88e..066e72dce45 100644 --- a/db/post_migrate/20220620151740_add_indexes_issues_on_project_id_and_closed_at.rb +++ b/db/post_migrate/20220620151740_add_indexes_issues_on_project_id_and_closed_at.rb @@ -9,11 +9,16 @@ class AddIndexesIssuesOnProjectIdAndClosedAt < Gitlab::Database::Migration[2.0] def up # Index to improve performance when sorting issues by closed_at desc - add_concurrent_index :issues, 'project_id, closed_at DESC NULLS LAST, state_id, id', name: NEW_INDEX_NAME_1 + unless index_exists_by_name?(:issues, NEW_INDEX_NAME_1) + add_concurrent_index :issues, 'project_id, closed_at DESC NULLS LAST, state_id, id', name: NEW_INDEX_NAME_1 + end # Index to improve performance when sorting issues by closed_at asc # This replaces the old index which didn't account for state_id and id - add_concurrent_index :issues, [:project_id, :closed_at, :state_id, :id], name: NEW_INDEX_NAME_2 + unless index_exists_by_name?(:issues, NEW_INDEX_NAME_2) + add_concurrent_index :issues, [:project_id, :closed_at, :state_id, :id], name: NEW_INDEX_NAME_2 + end + remove_concurrent_index_by_name :issues, OLD_INDEX_NAME end diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md index 43548d21f70..d6cadbab6a6 100644 --- a/doc/administration/packages/container_registry.md +++ b/doc/administration/packages/container_registry.md @@ -938,7 +938,7 @@ Prerequisites: [cloud native chart](https://docs.gitlab.com/charts/charts/registry/#garbage-collection). - You must set the Registry to [read-only mode](#performing-garbage-collection-without-downtime). Running garbage collection causes downtime for the Container Registry. When you run this command - on an instance in an environment where another instances is still writing to the Registry storage, + on an instance in an environment where another instance is still writing to the Registry storage, referenced manifests are removed. ### Understanding the content-addressable layers diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md index 8d56effd9a4..50bb36a6a32 100644 --- a/doc/user/application_security/policies/scan-execution-policies.md +++ b/doc/user/application_security/policies/scan-execution-policies.md @@ -88,9 +88,8 @@ This rule enforces the defined actions and schedules a scan on the provided date |------------|------|-----------------|-------------| | `type` | `string` | `schedule` | The rule's type. | | `branches` | `array` of `string` | `*` or the branch's name | The branch the given policy applies to (supports wildcard). | -| `cadence` | `string` | CRON expression (for example, `0 0 * * *`) | A whitespace-separated string containing five fields that represents the scheduled time. | -| `agents` | `object` | | The name of the [GitLab agents](../../clusters/agent/index.md) where [cluster image scanning](../../clusters/agent/vulnerabilities.md) will run. The key of the object is the name of the Kubernetes cluster configured for your project in GitLab. In the optionally provided value of the object, you can precisely select Kubernetes resources that are scanned. <!--- start_remove The following content will be removed on remove_date: '2022-08-22' --> | -| `clusters` (removed) | `object` | | This field was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/356465) in 15.0. Use the `agents` field instead. The cluster where the given policy enforces running selected scans (only for `container_scanning`/`cluster_image_scanning` scans). The key of the object is the name of the Kubernetes cluster configured for your project in GitLab. In the optionally provided value of the object, you can precisely select Kubernetes resources that are scanned. <!--- end_remove --> | +| `cadence` | `string` | CRON expression (for example, `0 0 * * *`) | A whitespace-separated string containing five fields that represents the scheduled time. <!--- start_remove The following content will be removed on remove_date: '2022-08-22' --> | +| `clusters` (removed) | `object` | | This field was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/356465) in 15.0. The cluster where the given policy enforces running selected scans (only for `container_scanning`/`cluster_image_scanning` scans). The key of the object is the name of the Kubernetes cluster configured for your project in GitLab. In the optionally provided value of the object, you can precisely select Kubernetes resources that are scanned. <!--- end_remove --> | GitLab supports the following types of CRON syntax for the `cadence` field: @@ -99,20 +98,11 @@ GitLab supports the following types of CRON syntax for the `cadence` field: It is possible that other elements of the CRON syntax will work in the cadence field, however, GitLab does not officially test or support them. -### `agent` schema - -Use this schema to define `agents` objects in the [`schedule` rule type](#schedule-rule-type). - -| Field | Type | Possible values | Description | -|--------------|---------------------|--------------------------|-------------| -| `namespaces` | `array` of `string` | | The namespace that is scanned. If empty, all namespaces will be scanned. | - <!--- start_remove The following content will be removed on remove_date: '2022-08-22' --> ### `cluster` schema (removed) This schema was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/356465) in 15.0. -Use the [`agent` schema](#agent-schema) instead. Use this schema to define `clusters` objects in the [`schedule` rule type](#schedule-rule-type). @@ -203,18 +193,6 @@ scan_execution_policy: variables: SAST_EXCLUDED_ANALYZERS: brakeman - scan: container_scanning -- name: Enforce Cluster Image Scanning on production-cluster every 24h - description: This policy enforces Cluster Image Scanning scan to run every 24 hours - enabled: true - rules: - - type: schedule - cadence: "15 3 * * *" - agents: - production-agent: - namespaces: - - production-namespace - actions: - - scan: cluster_image_scanning ``` In this example: diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb index 2fed724f947..e2481dcb8c1 100644 --- a/lib/api/maven_packages.rb +++ b/lib/api/maven_packages.rb @@ -35,6 +35,8 @@ module API name, _, format = file_name.rpartition('.') if %w(md5 sha1).include?(format) + unprocessable_entity! if Gitlab::FIPS.enabled? && format == 'md5' + [name, format] else [file_name, format] @@ -109,6 +111,7 @@ module API route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true get 'packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do # return a similar failure to authorize_read_package!(project) + forbidden! unless path_exists?(params[:path]) file_name, format = extract_format(params[:file_name]) @@ -241,6 +244,7 @@ module API end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true put ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do + unprocessable_entity! if Gitlab::FIPS.enabled? && params['file.md5'] authorize_upload! bad_request!('File is too large') if user_project.actual_limits.exceeded?(:maven_max_file_size, params[:file].size) diff --git a/qa/Dockerfile b/qa/Dockerfile index 5d046636984..74df07aa609 100644 --- a/qa/Dockerfile +++ b/qa/Dockerfile @@ -54,4 +54,8 @@ COPY ./INSTALLATION_TYPE ./VERSION /home/gitlab/ COPY ./qa /home/gitlab/qa +# Add JH files when JH dir exist. +COPY ./j[h]/qa /home/gitlab/jh/qa +COPY ./j[h]/lib /home/gitlab/jh/lib + ENTRYPOINT ["bin/test"] diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js index 385edc59eb6..3350609bb90 100644 --- a/spec/frontend/notes/components/noteable_note_spec.js +++ b/spec/frontend/notes/components/noteable_note_spec.js @@ -1,20 +1,15 @@ import { mount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; - +import { GlAvatar } from '@gitlab/ui'; import waitForPromises from 'helpers/wait_for_promises'; - import DiffsModule from '~/diffs/store/modules'; - import NoteActions from '~/notes/components/note_actions.vue'; import NoteBody from '~/notes/components/note_body.vue'; import NoteHeader from '~/notes/components/note_header.vue'; import issueNote from '~/notes/components/noteable_note.vue'; import NotesModule from '~/notes/stores/modules'; import { NOTEABLE_TYPE_MAPPING } from '~/notes/constants'; - -import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; - import { noteableDataMock, notesDataMock, note } from '../mock_data'; Vue.use(Vuex); @@ -205,19 +200,21 @@ describe('issue_note', () => { await nextTick(); - expect(wrapper.findComponent(UserAvatarLink).props('imgSize')).toBe(24); + const avatar = wrapper.findComponent(GlAvatar); + const avatarProps = avatar.props(); + expect(avatarProps.size).toBe(24); }); }); - it('should render user information', () => { + it('should render user avatar', () => { const { author } = note; - const avatar = wrapper.findComponent(UserAvatarLink); + const avatar = wrapper.findComponent(GlAvatar); const avatarProps = avatar.props(); - expect(avatarProps.linkHref).toBe(author.path); - expect(avatarProps.imgSrc).toBe(author.avatar_url); - expect(avatarProps.imgAlt).toBe(author.name); - expect(avatarProps.imgSize).toBe(40); + expect(avatarProps.src).toBe(author.avatar_url); + expect(avatarProps.entityName).toBe(author.username); + expect(avatarProps.alt).toBe(author.name); + expect(avatarProps.size).toEqual({ default: 24, md: 32 }); }); it('should render note header content', () => { diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index a3a4f0a5d38..0a4ee73f3d3 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -692,6 +692,37 @@ RSpec.describe Deployment do .to contain_exactly(stop_env_b) end end + + context 'When last deployment for environment is a retried build' do + let(:pipeline) { create(:ci_pipeline, project: project) } + let(:environment_b) { create(:environment, project: project) } + + let(:build_a) do + create(:ci_build, :success, project: project, pipeline: pipeline, environment: environment.name) + end + + let(:build_b) do + create(:ci_build, :success, project: project, pipeline: pipeline, environment: environment_b.name) + end + + let!(:deployment_a) do + create(:deployment, :success, project: project, environment: environment, deployable: build_a) + end + + let!(:deployment_b) do + create(:deployment, :success, project: project, environment: environment_b, deployable: build_b) + end + + before do + # Retry build_b + build_b.update!(retried: true) + + # New successful build after retry. + create(:ci_build, :success, project: project, pipeline: pipeline, environment: environment_b.name) + end + + it { expect(subject_method(environment_b)).not_to be_nil } + end end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 6857865c7cf..eaace86025c 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -1098,25 +1098,117 @@ RSpec.describe ProjectPolicy do subject { described_class.new(deploy_token, project) } - context 'a deploy token with read_package_registry scope' do - let(:deploy_token) { create(:deploy_token, read_package_registry: true) } + context 'private project' do + let(:project) { private_project } - it { is_expected.to be_allowed(:read_package) } - it { is_expected.to be_allowed(:read_project) } - it { is_expected.to be_disallowed(:create_package) } + context 'a deploy token with read_registry scope' do + let(:deploy_token) { create(:deploy_token, read_registry: true, write_registry: false) } - it_behaves_like 'package access with repository disabled' + it { is_expected.to be_allowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + + context 'with registry disabled' do + include_context 'registry disabled via project features' + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end + end + + context 'a deploy token with write_registry scope' do + let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: true) } + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_allowed(:create_container_image) } + + context 'with registry disabled' do + include_context 'registry disabled via project features' + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end + end + + context 'a deploy token with no registry scope' do + let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: false) } + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end + + context 'a deploy token with read_package_registry scope' do + let(:deploy_token) { create(:deploy_token, read_repository: false, read_registry: false, read_package_registry: true) } + + it { is_expected.to be_allowed(:read_project) } + it { is_expected.to be_allowed(:read_package) } + it { is_expected.to be_disallowed(:create_package) } + + it_behaves_like 'package access with repository disabled' + end + + context 'a deploy token with write_package_registry scope' do + let(:deploy_token) { create(:deploy_token, read_repository: false, read_registry: false, write_package_registry: true) } + + it { is_expected.to be_allowed(:create_package) } + it { is_expected.to be_allowed(:read_package) } + it { is_expected.to be_allowed(:read_project) } + it { is_expected.to be_disallowed(:destroy_package) } + + it_behaves_like 'package access with repository disabled' + end end - context 'a deploy token with write_package_registry scope' do - let(:deploy_token) { create(:deploy_token, write_package_registry: true) } + context 'public project' do + let(:project) { public_project } + + context 'a deploy token with read_registry scope' do + let(:deploy_token) { create(:deploy_token, read_registry: true, write_registry: false) } - it { is_expected.to be_allowed(:create_package) } - it { is_expected.to be_allowed(:read_package) } - it { is_expected.to be_allowed(:read_project) } - it { is_expected.to be_disallowed(:destroy_package) } + it { is_expected.to be_allowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } - it_behaves_like 'package access with repository disabled' + context 'with registry disabled' do + include_context 'registry disabled via project features' + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end + + context 'with registry private' do + include_context 'registry set to private via project features' + + it { is_expected.to be_allowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end + end + + context 'a deploy token with write_registry scope' do + let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: true) } + + it { is_expected.to be_allowed(:read_container_image) } + it { is_expected.to be_allowed(:create_container_image) } + + context 'with registry disabled' do + include_context 'registry disabled via project features' + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end + + context 'with registry private' do + include_context 'registry set to private via project features' + + it { is_expected.to be_allowed(:read_container_image) } + it { is_expected.to be_allowed(:create_container_image) } + end + end + + context 'a deploy token with no registry scope' do + let(:deploy_token) { create(:deploy_token, read_registry: false, write_registry: false) } + + it { is_expected.to be_disallowed(:read_container_image) } + it { is_expected.to be_disallowed(:create_container_image) } + end end end diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb index bc325aad823..ba82d2facc6 100644 --- a/spec/requests/api/maven_packages_spec.rb +++ b/spec/requests/api/maven_packages_spec.rb @@ -226,14 +226,26 @@ RSpec.describe API::MavenPackages do end end + shared_examples 'file download in FIPS mode' do + context 'in FIPS mode', :fips_mode do + it_behaves_like 'successfully returning the file' + + it 'rejects the request for an md5 file' do + download_file(file_name: package_file.file_name + '.md5') + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + end + describe 'GET /api/v4/packages/maven/*path/:file_name' do context 'a public project' do subject { download_file(file_name: package_file.file_name) } shared_examples 'getting a file' do it_behaves_like 'tracking the file download event' - it_behaves_like 'successfully returning the file' + it_behaves_like 'file download in FIPS mode' it 'returns sha1 of the file' do download_file(file_name: package_file.file_name + '.sha1') @@ -402,8 +414,8 @@ RSpec.describe API::MavenPackages do shared_examples 'getting a file for a group' do it_behaves_like 'tracking the file download event' - it_behaves_like 'successfully returning the file' + it_behaves_like 'file download in FIPS mode' it 'returns sha1 of the file' do download_file(file_name: package_file.file_name + '.sha1') @@ -625,8 +637,8 @@ RSpec.describe API::MavenPackages do subject { download_file(file_name: package_file.file_name) } it_behaves_like 'tracking the file download event' - it_behaves_like 'successfully returning the file' + it_behaves_like 'file download in FIPS mode' it 'returns sha1 of the file' do download_file(file_name: package_file.file_name + '.sha1') @@ -833,6 +845,16 @@ RSpec.describe API::MavenPackages do subject { upload_file_with_token(params: params) } + context 'FIPS mode', :fips_mode do + it_behaves_like 'package workhorse uploads' + + it 'rejects the request for md5 file' do + upload_file_with_token(params: params, file_extension: 'jar.md5') + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + context 'file size is too large' do it 'rejects the request' do allow_next_instance_of(UploadedFile) do |uploaded_file| @@ -995,12 +1017,22 @@ RSpec.describe API::MavenPackages do end context 'for md5 file' do + subject { upload_file_with_token(params: params, file_extension: 'jar.md5') } + it 'returns an empty body' do - upload_file_with_token(params: params, file_extension: 'jar.md5') + subject expect(response.body).to eq('') expect(response).to have_gitlab_http_status(:ok) end + + context 'with FIPS mode enabled', :fips_mode do + it 'rejects the request' do + subject + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end end end diff --git a/spec/support/shared_contexts/project_features_shared_context.rb b/spec/support/shared_contexts/project_features_shared_context.rb new file mode 100644 index 00000000000..40d9cb29c14 --- /dev/null +++ b/spec/support/shared_contexts/project_features_shared_context.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.shared_context 'repository disabled via project features' do + before do + project.project_feature.update_columns( + # Disable merge_requests and builds as well, since merge_requests and + # builds cannot have higher visibility than repository. + merge_requests_access_level: ProjectFeature::DISABLED, + builds_access_level: ProjectFeature::DISABLED, + repository_access_level: ProjectFeature::DISABLED) + end +end + +RSpec.shared_context 'registry disabled via project features' do + before do + project.project_feature.update_columns( + container_registry_access_level: ProjectFeature::DISABLED + ) + end +end + +RSpec.shared_context 'registry set to private via project features' do + before do + project.project_feature.update_columns( + container_registry_access_level: ProjectFeature::PRIVATE + ) + end +end diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb index 63e4d458ad4..c4083df47e2 100644 --- a/spec/support/shared_examples/policies/project_policy_shared_examples.rb +++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb @@ -345,16 +345,7 @@ RSpec.shared_examples 'project policies as admin without admin mode' do end RSpec.shared_examples 'package access with repository disabled' do - context 'when repository is disabled' do - before do - project.project_feature.update!( - # Disable merge_requests and builds as well, since merge_requests and - # builds cannot have higher visibility than repository. - merge_requests_access_level: ProjectFeature::DISABLED, - builds_access_level: ProjectFeature::DISABLED, - repository_access_level: ProjectFeature::DISABLED) - end + include_context 'repository disabled via project features' - it { is_expected.to be_allowed(:read_package) } - end + it { is_expected.to be_allowed(:read_package) } end diff --git a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb index 7677e5d8cb2..f18869fb380 100644 --- a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb +++ b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb @@ -142,9 +142,9 @@ RSpec.shared_examples 'logs an auth warning' do |requested_actions| requested_project_path: project.full_path, requested_actions: requested_actions, authorized_actions: [], - user_id: current_user.id, - username: current_user.username - } + user_id: current_user&.id, + username: current_user&.username + }.compact end it do |