diff --git a/.rubocop_todo/gitlab/delegate_predicate_methods.yml b/.rubocop_todo/gitlab/delegate_predicate_methods.yml index 854cd3e0a83..543b0059fe1 100644 --- a/.rubocop_todo/gitlab/delegate_predicate_methods.yml +++ b/.rubocop_todo/gitlab/delegate_predicate_methods.yml @@ -2,5 +2,4 @@ Gitlab/DelegatePredicateMethods: Exclude: - app/models/clusters/cluster.rb - - app/models/project.rb - ee/app/models/concerns/ee/ci/metadatable.rb diff --git a/app/assets/javascripts/init_confirm_danger.js b/app/assets/javascripts/init_confirm_danger.js index 98bfa48740c..6c6cadedf00 100644 --- a/app/assets/javascripts/init_confirm_danger.js +++ b/app/assets/javascripts/init_confirm_danger.js @@ -12,11 +12,11 @@ export default () => { phrase, buttonText, buttonClass = '', - buttonTestid = null, - buttonVariant = null, + buttonTestid, + buttonVariant, confirmDangerMessage, confirmButtonText = null, - disabled = false, + disabled, additionalInformation, htmlConfirmationMessage, } = el.dataset; diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js index bf4fb5f3b7e..595a285032c 100644 --- a/app/assets/javascripts/pages/projects/project_members/index.js +++ b/app/assets/javascripts/pages/projects/project_members/index.js @@ -38,7 +38,7 @@ initMembersApp(document.querySelector('.js-project-members-list-app'), { }, }, [MEMBER_TYPES.group]: { - tableFields: SHARED_FIELDS.concat('granted'), + tableFields: SHARED_FIELDS.concat(['source', 'granted']), tableAttrs: { table: { 'data-qa-selector': 'groups_list' }, tr: { 'data-qa-selector': 'group_row' }, @@ -46,7 +46,7 @@ initMembersApp(document.querySelector('.js-project-members-list-app'), { requestFormatter: groupLinkRequestFormatter, filteredSearchBar: { show: true, - tokens: [], + tokens: ['groups_with_inherited_permissions'], searchParam: 'search_groups', placeholder: s__('Members|Search groups'), recentSearchesStorageKey: 'project_group_links', diff --git a/app/assets/javascripts/projects/compare/components/app.vue b/app/assets/javascripts/projects/compare/components/app.vue index 3945bed9649..bda58091b97 100644 --- a/app/assets/javascripts/projects/compare/components/app.vue +++ b/app/assets/javascripts/projects/compare/components/app.vue @@ -121,27 +121,21 @@ export default { @selectRevision="onSelectRevision" /> -
+
{{ s__('CompareRevisions|Compare') }} - + {{ s__('CompareRevisions|Swap revisions') }} {{ s__('CompareRevisions|View open merge request') }} - + {{ s__('CompareRevisions|Create merge request') }}
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 2c2f957a75d..186946a83ad 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -276,28 +276,33 @@ const bindEvents = () => { ); let isProjectImportUrlDirty = false; - $projectImportUrl.addEventListener('blur', () => { - isProjectImportUrlDirty = true; - debouncedUpdateUrlPathWarningVisibility(); - }); - $projectImportUrl.addEventListener('keyup', () => { - deriveProjectPathFromUrl($projectImportUrl); - }); + + if ($projectImportUrl) { + $projectImportUrl.addEventListener('blur', () => { + isProjectImportUrlDirty = true; + debouncedUpdateUrlPathWarningVisibility(); + }); + $projectImportUrl.addEventListener('keyup', () => { + deriveProjectPathFromUrl($projectImportUrl); + }); + } [$projectImportUrl, $projectImportUrlUser, $projectImportUrlPassword].forEach(($f) => { - if ($f?.on) { - $f.on('input', () => { - if (isProjectImportUrlDirty) { - debouncedUpdateUrlPathWarningVisibility(); - } - }); - } else { - $f.addEventListener('input', () => { + if (!$f) return false; + + if ($f.on) { + return $f.on('input', () => { if (isProjectImportUrlDirty) { debouncedUpdateUrlPathWarningVisibility(); } }); } + + return $f.addEventListener('input', () => { + if (isProjectImportUrlDirty) { + debouncedUpdateUrlPathWarningVisibility(); + } + }); }); $projectImportForm.on('submit', async (e) => { diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 168e703c87d..cd9c6efb106 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -13,9 +13,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @sort = params[:sort].presence || sort_value_name - - @group_links = @project.project_group_links - @group_links = @group_links.search(params[:search_groups]) if params[:search_groups].present? + @include_relations ||= requested_relations(:groups_with_inherited_permissions) if can?(current_user, :admin_project_member, @project) @invited_members = present_members(invited_members) diff --git a/app/helpers/projects/project_members_helper.rb b/app/helpers/projects/project_members_helper.rb index d5cc2b72ae9..51a7d3e35d0 100644 --- a/app/helpers/projects/project_members_helper.rb +++ b/app/helpers/projects/project_members_helper.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true module Projects::ProjectMembersHelper - def project_members_app_data_json(project, members:, group_links:, invited:, access_requests:) + def project_members_app_data_json(project, members:, invited:, access_requests:, include_relations:, search:) { user: project_members_list_data(project, members, { param_name: :page, params: { search_groups: nil } }), - group: project_group_links_list_data(project, group_links), + group: project_group_links_list_data(project, include_relations, search), invite: project_members_list_data(project, invited.nil? ? [] : invited), access_request: project_members_list_data(project, access_requests.nil? ? [] : access_requests), source_id: project.id, @@ -57,10 +57,29 @@ module Projects::ProjectMembersHelper } end - def project_group_links_list_data(project, group_links) + def project_group_links_list_data(project, include_relations, search) + members = [] + + if include_relations.include?(:direct) + project_group_links = project.project_group_links + project_group_links = project_group_links.search(search) if search + members += project_group_links_serialized(project, project_group_links) + end + + if include_relations.include?(:inherited) + group_group_links = project.group_group_links.distinct_on_shared_with_group_id_with_group_access + group_group_links = group_group_links.search(search) if search + members += group_group_links_serialized(project, group_group_links) + end + + if project_group_links.present? && group_group_links.present? + members = members.sort_by { |m| -m.dig(:access_level, :integer_value).to_i } + .uniq { |m| m.dig(:shared_with_group, :id) } + end + { - members: project_group_links_serialized(project, group_links), - pagination: members_pagination_data(group_links), + members: members, + pagination: members_pagination_data(members), member_path: project_group_link_path(project, ':id') } end diff --git a/app/models/project.rb b/app/models/project.rb index 110f400d3ec..9ca969e0c53 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -441,33 +441,29 @@ class Project < ApplicationRecord accepts_nested_attributes_for :prometheus_integration, update_only: true accepts_nested_attributes_for :alerting_setting, update_only: true - delegate :feature_available?, :builds_enabled?, :wiki_enabled?, - :merge_requests_enabled?, :forking_enabled?, :issues_enabled?, - :pages_enabled?, :analytics_enabled?, :snippets_enabled?, :public_pages?, :private_pages?, - :merge_requests_access_level, :forking_access_level, :issues_access_level, - :wiki_access_level, :snippets_access_level, :builds_access_level, - :repository_access_level, :package_registry_access_level, :pages_access_level, :metrics_dashboard_access_level, :analytics_access_level, - :operations_enabled?, :operations_access_level, :security_and_compliance_access_level, - :container_registry_access_level, :container_registry_enabled?, - to: :project_feature, allow_nil: true - alias_method :container_registry_enabled, :container_registry_enabled? - delegate :show_default_award_emojis, :show_default_award_emojis=, :show_default_award_emojis?, - :enforce_auth_checks_on_uploads, :enforce_auth_checks_on_uploads=, :enforce_auth_checks_on_uploads?, - :warn_about_potentially_unwanted_characters, :warn_about_potentially_unwanted_characters=, :warn_about_potentially_unwanted_characters?, - to: :project_setting, allow_nil: true - delegate :scheduled?, :started?, :in_progress?, :failed?, :finished?, - prefix: :import, to: :import_state, allow_nil: true + delegate :merge_requests_access_level, :forking_access_level, :issues_access_level, + :wiki_access_level, :snippets_access_level, :builds_access_level, + :repository_access_level, :package_registry_access_level, :pages_access_level, + :metrics_dashboard_access_level, :analytics_access_level, + :operations_access_level, :security_and_compliance_access_level, + :container_registry_access_level, + to: :project_feature, allow_nil: true + + delegate :show_default_award_emojis, :show_default_award_emojis=, + :enforce_auth_checks_on_uploads, :enforce_auth_checks_on_uploads=, + :warn_about_potentially_unwanted_characters, :warn_about_potentially_unwanted_characters=, + to: :project_setting, allow_nil: true + delegate :squash_always?, :squash_never?, :squash_enabled_by_default?, :squash_readonly?, to: :project_setting delegate :squash_option, :squash_option=, to: :project_setting delegate :mr_default_target_self, :mr_default_target_self=, to: :project_setting delegate :previous_default_branch, :previous_default_branch=, to: :project_setting - delegate :no_import?, to: :import_state, allow_nil: true delegate :name, to: :owner, allow_nil: true, prefix: true delegate :members, to: :team, prefix: true delegate :add_user, :add_users, to: :team delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_owner, :add_role, to: :team delegate :group_runners_enabled, :group_runners_enabled=, to: :ci_cd_settings, allow_nil: true - delegate :root_ancestor, :certificate_based_clusters_enabled?, to: :namespace, allow_nil: true + delegate :root_ancestor, to: :namespace, allow_nil: true delegate :last_pipeline, to: :commit, allow_nil: true delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true @@ -483,7 +479,6 @@ class Project < ApplicationRecord delegate :allow_merge_on_skipped_pipeline, :allow_merge_on_skipped_pipeline?, :allow_merge_on_skipped_pipeline=, :has_confluence?, :has_shimo?, to: :project_setting - delegate :active?, to: :prometheus_integration, allow_nil: true, prefix: true delegate :merge_commit_template, :merge_commit_template=, to: :project_setting, allow_nil: true delegate :squash_commit_template, :squash_commit_template=, to: :project_setting, allow_nil: true @@ -916,6 +911,14 @@ class Project < ApplicationRecord association(:namespace).loaded? end + def certificate_based_clusters_enabled? + !!namespace&.certificate_based_clusters_enabled? + end + + def prometheus_integration_active? + !!prometheus_integration&.active? + end + def personal_namespace_holder?(user) return false unless personal? return false unless user @@ -932,6 +935,42 @@ class Project < ApplicationRecord super.presence || build_project_setting end + def show_default_award_emojis? + !!project_setting&.show_default_award_emojis? + end + + def enforce_auth_checks_on_uploads? + !!project_setting&.enforce_auth_checks_on_uploads? + end + + def warn_about_potentially_unwanted_characters? + !!project_setting&.warn_about_potentially_unwanted_characters? + end + + def no_import? + !!import_state&.no_import? + end + + def import_scheduled? + !!import_state&.scheduled? + end + + def import_started? + !!import_state&.started? + end + + def import_in_progress? + !!import_state&.in_progress? + end + + def import_failed? + !!import_state&.failed? + end + + def import_finished? + !!import_state&.finished? + end + def all_pipelines if builds_enabled? super @@ -1839,6 +1878,59 @@ class Project < ApplicationRecord end end + def feature_available?(feature, user = nil) + !!project_feature&.feature_available?(feature, user) + end + + def builds_enabled? + !!project_feature&.builds_enabled? + end + + def wiki_enabled? + !!project_feature&.wiki_enabled? + end + + def merge_requests_enabled? + !!project_feature&.merge_requests_enabled? + end + + def forking_enabled? + !!project_feature&.forking_enabled? + end + + def issues_enabled? + !!project_feature&.issues_enabled? + end + + def pages_enabled? + !!project_feature&.pages_enabled? + end + + def analytics_enabled? + !!project_feature&.analytics_enabled? + end + + def snippets_enabled? + !!project_feature&.snippets_enabled? + end + + def public_pages? + !!project_feature&.public_pages? + end + + def private_pages? + !!project_feature&.private_pages? + end + + def operations_enabled? + !!project_feature&.operations_enabled? + end + + def container_registry_enabled? + !!project_feature&.container_registry_enabled? + end + alias_method :container_registry_enabled, :container_registry_enabled? + def enable_ci project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED) end @@ -2902,6 +2994,10 @@ class Project < ApplicationRecord build_artifacts_size_refresh&.started? end + def group_group_links + group&.shared_with_group_links&.of_ancestors_and_self || GroupGroupLink.none + end + def security_training_available? licensed_feature_available?(:security_training) end diff --git a/app/services/packages/pypi/create_package_service.rb b/app/services/packages/pypi/create_package_service.rb index 5d7e967ceb0..b464ce4504a 100644 --- a/app/services/packages/pypi/create_package_service.rb +++ b/app/services/packages/pypi/create_package_service.rb @@ -16,6 +16,8 @@ module Packages raise ActiveRecord::RecordInvalid, meta end + params.delete(:md5_digest) if Gitlab::FIPS.enabled? + Packages::Pypi::Metadatum.upsert(meta.attributes) ::Packages::CreatePackageFileService.new(created_package, file_params).execute diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 1a5a7ae94d3..fd91786e9f9 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -39,7 +39,8 @@ .js-project-members-list-app{ data: { members_data: project_members_app_data_json(@project, members: @project_members, - group_links: @group_links, invited: @invited_members, - access_requests: @requesters) } } + access_requests: @requesters, + include_relations: @include_relations, + search: params[:search_groups]) } } = gl_loading_icon(css_class: 'gl-my-5', size: 'md') diff --git a/config/application.rb b/config/application.rb index ad76a6d8e7e..5e18d5fdd96 100644 --- a/config/application.rb +++ b/config/application.rb @@ -20,6 +20,8 @@ module Gitlab config.view_component.preview_route = "/-/view_component/previews" + config.active_support.hash_digest_class = ::OpenSSL::Digest::SHA256 + # This section contains configuration from Rails upgrades to override the new defaults so that we # keep existing behavior. # @@ -38,7 +40,6 @@ module Gitlab # Rails 5.2 config.action_dispatch.use_authenticated_cookie_encryption = false config.active_support.use_authenticated_message_encryption = false - config.active_support.hash_digest_class = ::Digest::MD5 # New default is ::Digest::SHA1 config.action_controller.default_protect_from_forgery = false config.action_view.form_with_generates_ids = false diff --git a/config/feature_flags/development/active_support_hash_digest_sha256.yml b/config/feature_flags/development/active_support_hash_digest_sha256.yml deleted file mode 100644 index 147b84bf112..00000000000 --- a/config/feature_flags/development/active_support_hash_digest_sha256.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: active_support_hash_digest_sha256 -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90098 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365314 -milestone: '15.1' -type: development -group: group::sharding -default_enabled: false diff --git a/config/initializers/rack_timeout.rb b/config/initializers/rack_timeout.rb index c2f2f3e093c..c9dc9fa209a 100644 --- a/config/initializers/rack_timeout.rb +++ b/config/initializers/rack_timeout.rb @@ -8,7 +8,8 @@ # and it's used only as the last resort. In such case this termination is # logged and we should fix the potential timeout issue in the code itself. -if Gitlab::Runtime.puma? && !Rails.env.test? +if Gitlab::Runtime.puma? && !Rails.env.test? && + Gitlab::Utils.to_boolean(ENV['GITLAB_RAILS_RACK_TIMEOUT_ENABLE'], default: true) Rack::Timeout::Logger.level = Logger::ERROR Gitlab::Application.configure do |config| diff --git a/config/initializers/set_active_support_hash_digest_class.rb b/config/initializers/set_active_support_hash_digest_class.rb deleted file mode 100644 index 743b45eed34..00000000000 --- a/config/initializers/set_active_support_hash_digest_class.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -Rails.application.configure do - # We set ActiveSupport::Digest.hash_digest_class directly copying - # See https://github.com/rails/rails/blob/6-1-stable/activesupport/lib/active_support/railtie.rb#L96-L98 - # - # Note that is the only usage of config.active_support.hash_digest_class - config.after_initialize do - ActiveSupport::Digest.hash_digest_class = Gitlab::HashDigest::Facade - end -end diff --git a/doc/administration/audit_event_streaming.md b/doc/administration/audit_event_streaming.md index 5fc92c5fb6c..4e44a3a3e79 100644 --- a/doc/administration/audit_event_streaming.md +++ b/doc/administration/audit_event_streaming.md @@ -169,6 +169,20 @@ mutation { The header is created if the returned `errors` object is empty. +### Update with the API + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/361964) in GitLab 15.2. + +Group owners can update a HTTP header using the GraphQL `auditEventsStreamingHeadersCreate` mutation. + +```graphql +mutation { + auditEventsStreamingHeadersUpdate(input: { headerId: "gid://gitlab/AuditEvents::Streaming::Header/24255", key: "new-foo", value: "new-bar" }) { + errors + } +} +``` + ### Delete with the API Group owners can remove a HTTP header using the GraphQL `auditEventsStreamingHeadersDestroy` mutation. You can retrieve the header ID diff --git a/doc/administration/auth/ldap/ldap_synchronization.md b/doc/administration/auth/ldap/ldap_synchronization.md index 0f0d301bfa9..b0ada1c11dd 100644 --- a/doc/administration/auth/ldap/ldap_synchronization.md +++ b/doc/administration/auth/ldap/ldap_synchronization.md @@ -42,11 +42,6 @@ The process also updates the following user information: - SSH public keys (if `sync_ssh_keys` is set) - Kerberos identity (if Kerberos is enabled) -The LDAP sync process: - -- Updates existing users. -- Creates new users on first sign in. - ### Adjust LDAP user sync schedule By default, GitLab runs a worker once per day at 01:30 a.m. server time to diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index b3cdaeea85c..5c179e18a4b 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -778,6 +778,27 @@ Input type: `AuditEventsStreamingHeadersDestroyInput` | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | +### `Mutation.auditEventsStreamingHeadersUpdate` + +Input type: `AuditEventsStreamingHeadersUpdateInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| `headerId` | [`AuditEventsStreamingHeaderID!`](#auditeventsstreamingheaderid) | Header to update. | +| `key` | [`String!`](#string) | Header key. | +| `value` | [`String!`](#string) | Header value. | + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | +| `header` | [`AuditEventStreamingHeader`](#auditeventstreamingheader) | Updates header. | + ### `Mutation.awardEmojiAdd` Input type: `AwardEmojiAddInput` diff --git a/doc/api/jobs.md b/doc/api/jobs.md index 85cdf7d892a..b23c33ddc0d 100644 --- a/doc/api/jobs.md +++ b/doc/api/jobs.md @@ -692,7 +692,7 @@ Example of response "finished_at": null, "duration": 8, "queued_duration": 0.010, - "id": 42, + "id": 1, "name": "rubocop", "ref": "main", "artifacts": [], @@ -742,7 +742,7 @@ Example of response "finished_at": null, "duration": null, "queued_duration": 0.010, - "id": 42, + "id": 1, "name": "rubocop", "ref": "main", "artifacts": [], @@ -792,7 +792,7 @@ Example of response "coverage": null, "allow_failure": false, "download_url": null, - "id": 42, + "id": 1, "name": "rubocop", "ref": "main", "artifacts": [], @@ -873,7 +873,7 @@ Example response: "finished_at": null, "duration": null, "queued_duration": 0.010, - "id": 42, + "id": 1, "name": "rubocop", "ref": "main", "artifacts": [], diff --git a/doc/api/packages/pypi.md b/doc/api/packages/pypi.md index 3e23ded61f4..e6204d87e1f 100644 --- a/doc/api/packages/pypi.md +++ b/doc/api/packages/pypi.md @@ -20,6 +20,10 @@ These endpoints do not adhere to the standard API authentication methods. See the [PyPI package registry documentation](../../user/packages/pypi_repository/index.md) for details on which headers and token types are supported. +NOTE: +[Twine 3.4.2](https://twine.readthedocs.io/en/stable/changelog.html?highlight=FIPS#id28) or greater +is recommended when [FIPS mode](../../development/fips_compliance.md) is enabled. + ## Download a package file from a group > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225545) in GitLab 13.12. diff --git a/doc/development/cicd/templates.md b/doc/development/cicd/templates.md index 8d88e7155a2..eafb1817a0a 100644 --- a/doc/development/cicd/templates.md +++ b/doc/development/cicd/templates.md @@ -393,7 +393,7 @@ is updated in a major version GitLab release. ### Add metrics -Every CI/CD template must also have metrics defined to track their use. +Every CI/CD template must also have metrics defined to track their use. The CI/CD template monthly usage report can be found in [Sisense (GitLab team members only)](https://app.periscopedata.com/app/gitlab/785953/Pipeline-Authoring-Dashboard?widget=14910475&udv=0). To add a metric definition for a new template: diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb index 5bf3c3b8aac..ae53f08fb1d 100644 --- a/lib/api/pypi_packages.rb +++ b/lib/api/pypi_packages.rb @@ -217,6 +217,8 @@ module API track_package_event('push_package', :pypi, project: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace) + unprocessable_entity! if Gitlab::FIPS.enabled? && declared_params[:md5_digest].present? + ::Packages::Pypi::CreatePackageService .new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job)) .execute diff --git a/lib/gitlab/content_security_policy/config_loader.rb b/lib/gitlab/content_security_policy/config_loader.rb index 574a7dceaa4..f57050e5a1f 100644 --- a/lib/gitlab/content_security_policy/config_loader.rb +++ b/lib/gitlab/content_security_policy/config_loader.rb @@ -7,6 +7,8 @@ module Gitlab form_action frame_ancestors frame_src img_src manifest_src media_src object_src report_uri script_src style_src worker_src).freeze + DEFAULT_FALLBACK_VALUE = '' + def self.default_enabled Rails.env.development? || Rails.env.test? end @@ -62,8 +64,10 @@ module Gitlab end def initialize(csp_directives) + # Using falls back to the default values. + directives = csp_directives.reject { |_, value| value == DEFAULT_FALLBACK_VALUE } @merged_csp_directives = - HashWithIndifferentAccess.new(csp_directives) + HashWithIndifferentAccess.new(directives) .reverse_merge(::Gitlab::ContentSecurityPolicy::ConfigLoader.default_directives) end diff --git a/lib/gitlab/hash_digest/facade.rb b/lib/gitlab/hash_digest/facade.rb deleted file mode 100644 index d8efef02893..00000000000 --- a/lib/gitlab/hash_digest/facade.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module HashDigest - # Used for rolling out to use OpenSSL::Digest::SHA256 - # for ActiveSupport::Digest - class Facade - class << self - def hexdigest(...) - hash_digest_class.hexdigest(...) - end - - def hash_digest_class - if use_sha256? - ::OpenSSL::Digest::SHA256 - else - ::Digest::MD5 # rubocop:disable Fips/MD5 - end - end - - def use_sha256? - return false unless Feature.feature_flags_available? - - Feature.enabled?(:active_support_hash_digest_sha256) - end - end - end - end -end diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index fe468de60cd..b331e1724db 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -79,7 +79,10 @@ module QA def delete_issue click_element(:issue_actions_ellipsis_dropdown) - click_element(:delete_issue_button, Page::Modal::DeleteIssue) + + click_element(:delete_issue_button, + Page::Modal::DeleteIssue, + wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME) Page::Modal::DeleteIssue.perform(&:confirm_delete_issue) diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/personal_project_permissions_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/personal_project_permissions_spec.rb deleted file mode 100644 index fb486ab1532..00000000000 --- a/qa/qa/specs/features/browser_ui/1_manage/project/personal_project_permissions_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -module QA - RSpec.describe 'Manage' do - describe 'Personal project permissions', :reliable do - let!(:owner) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } - - let!(:owner_api_client) { Runtime::API::Client.new(:gitlab, user: owner) } - - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.api_client = owner_api_client - project.name = 'qa-owner-personal-project' - project.personal_namespace = owner.username - end - end - - after do - project&.remove_via_api! - end - - context 'when user is added as Owner' do - let(:issue) do - Resource::Issue.fabricate_via_api! do |issue| - issue.api_client = owner_api_client - issue.project = project - issue.title = 'Test Owner deletes issue' - end - end - - before do - Flow::Login.sign_in(as: owner) - end - - it "has Owner role with Owner permissions", testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352542' do - Page::Dashboard::Projects.perform do |projects| - projects.filter_by_name(project.name) - - expect(projects).to have_project_with_access_role(project.name, 'Owner') - end - - expect_owner_permissions_allow_delete_issue - end - end - - context 'when user is added as Maintainer' do - let(:maintainer) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) } - - let(:issue) do - Resource::Issue.fabricate_via_api! do |issue| - issue.api_client = owner_api_client - issue.project = project - issue.title = 'Test Maintainer deletes issue' - end - end - - before do - project.add_member(maintainer, Resource::Members::AccessLevel::MAINTAINER) - Flow::Login.sign_in(as: maintainer) - end - - it "has Maintainer role without Owner permissions", testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352607' do - Page::Dashboard::Projects.perform do |projects| - projects.filter_by_name(project.name) - - expect(projects).to have_project_with_access_role(project.name, 'Maintainer') - end - - expect_maintainer_permissions_do_not_allow_delete_issue - end - end - - private - - def expect_owner_permissions_allow_delete_issue - issue.visit! - - Page::Project::Issue::Show.perform(&:delete_issue) - - Page::Project::Issue::Index.perform do |index| - expect(index).not_to have_issue(issue) - end - end - - def expect_maintainer_permissions_do_not_allow_delete_issue - issue.visit! - - Page::Project::Issue::Show.perform do |issue| - expect(issue).not_to have_delete_issue_button - end - end - end - end -end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb new file mode 100644 index 00000000000..2f148c4051c --- /dev/null +++ b/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Manage' do + describe 'Project owner permissions' do + let!(:owner) do + Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) + end + + let!(:owner_api_client) { Runtime::API::Client.new(:gitlab, user: owner) } + + let!(:maintainer) do + Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) + end + + shared_examples 'when user is added as owner' do |project_type, testcase| + let!(:issue) do + Resource::Issue.fabricate_via_api! do |issue| + issue.api_client = owner_api_client + issue.project = project + issue.title = 'Test Owner Deletes Issue' + end + end + + before do + project.add_member(owner, Resource::Members::AccessLevel::OWNER) if project_type == :group_project + Flow::Login.sign_in(as: owner) + end + + it "has owner role with owner permissions", testcase: testcase do + Page::Dashboard::Projects.perform do |projects| + projects.filter_by_name(project.name) + + expect(projects).to have_project_with_access_role(project.name, 'Owner') + end + + issue.visit! + + Page::Project::Issue::Show.perform(&:delete_issue) + + Page::Project::Issue::Index.perform do |index| + expect(index).not_to have_issue(issue) + end + end + end + + shared_examples 'when user is added as maintainer' do |testcase| + let!(:issue) do + Resource::Issue.fabricate_via_api! do |issue| + issue.api_client = owner_api_client + issue.project = project + issue.title = 'Test Maintainer Deletes Issue' + end + end + + before do + project.add_member(maintainer, Resource::Members::AccessLevel::MAINTAINER) + Flow::Login.sign_in(as: maintainer) + end + + it "has maintainer role without owner permissions", testcase: testcase do + Page::Dashboard::Projects.perform do |projects| + projects.filter_by_name(project.name) + + expect(projects).to have_project_with_access_role(project.name, 'Maintainer') + end + + issue.visit! + + Page::Project::Issue::Show.perform do |issue| + expect(issue).not_to have_delete_issue_button + end + end + end + + context 'for personal projects' do + let!(:project) do + Resource::Project.fabricate_via_api! do |project| + project.api_client = owner_api_client + project.name = 'qa-owner-personal-project' + project.personal_namespace = owner.username + end + end + + it_behaves_like 'when user is added as owner', :personal_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352542' + it_behaves_like 'when user is added as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352607' + end + + context 'for group projects' do + let!(:group) { Resource::Group.fabricate_via_api! } + + let!(:project) do + Resource::Project.fabricate_via_api! do |project| + project.group = group + project.name = 'qa-owner-group-project' + end + end + + it_behaves_like 'when user is added as owner', :group_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366436' + it_behaves_like 'when user is added as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366435' + end + end + end +end diff --git a/scripts/lib/glfm/parse_examples.rb b/scripts/lib/glfm/parse_examples.rb index 051cbdc7941..14634bcfb3e 100644 --- a/scripts/lib/glfm/parse_examples.rb +++ b/scripts/lib/glfm/parse_examples.rb @@ -41,7 +41,6 @@ module Glfm h1_regex = /\A# / # new logic compared to original Python code h2_regex = /\A## / # new logic compared to original Python code - h3_regex = /\A### / # new logic compared to original Python code header_regex = /\A#+ / # Added beginning of line anchor to original Python code spec_txt_lines.each do |line| @@ -103,19 +102,12 @@ module Glfm # reset the headers array if we found a new H1 headers = [] if line =~ h1_regex - if headers.length == 2 && line =~ h2_regex - # pop the last entry from the headers array if we are in an H2 and found a new H2 - headers.pop - elsif headers.length == 3 && line =~ h3_regex - # pop the last entry from the headers array if we are in an H3 and found a new H3 - headers.pop - elsif headers.length == 3 && line =~ h2_regex - # pop the last two entries from the headers array if we are in an H3 and found a new H2 - headers.pop(2) - end + # headers should be size 2 or less [, ] + # pop the last entry from the headers array if we are in an H2 and found a new H2 + headers.pop if headers.length == 2 && line =~ h2_regex # push the new header text to the headers array - headers << headertext # New logic compared to original Python code + headers << headertext if line =~ h1_regex || line =~ h2_regex else # Else if we are in regular text... diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 9bb34a38005..46eb340cbba 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -68,27 +68,6 @@ RSpec.describe Projects::ProjectMembersController do end end - context 'group links' do - let_it_be(:project_group_link) { create(:project_group_link, project: project, group: group) } - - it 'lists group links' do - get :index, params: { namespace_id: project.namespace, project_id: project } - - expect(assigns(:group_links).map(&:id)).to contain_exactly(project_group_link.id) - end - - context 'when `search_groups` param is present' do - let(:group_2) { create(:group, :public, name: 'group_2') } - let!(:project_group_link_2) { create(:project_group_link, project: project, group: group_2) } - - it 'lists group links that match search' do - get :index, params: { namespace_id: project.namespace, project_id: project, search_groups: 'group_2' } - - expect(assigns(:group_links).map(&:id)).to contain_exactly(project_group_link_2.id) - end - end - end - context 'invited members' do let_it_be(:invited_member) { create(:project_member, :invited, project: project) } diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index c323e60bb71..a1e92a79516 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -298,6 +298,20 @@ RSpec.describe 'New project', :js do end end + context 'Import project options without any sources', :js do + before do + stub_application_setting(import_sources: []) + + visit new_project_path + click_link 'Import project' + end + + it 'displays the no import options message' do + expect(page).to have_text s_('ProjectsNew|No import options available') + expect(page).to have_text s_('ProjectsNew|Contact an administrator to enable options for importing your project.') + end + end + context 'Import project options', :js do before do visit new_project_path diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb index 2414a1782c5..844c33de635 100644 --- a/spec/helpers/projects/project_members_helper_spec.rb +++ b/spec/helpers/projects/project_members_helper_spec.rb @@ -14,7 +14,6 @@ RSpec.describe Projects::ProjectMembersHelper do describe 'project members' do let_it_be(:members) { create_list(:project_member, 2, project: project) } - let_it_be(:group_links) { create_list(:project_group_link, 1, project: project) } let_it_be(:invited) { create_list(:project_member, 2, :invited, project: project) } let_it_be(:access_requests) { create_list(:project_member, 2, :access_request, project: project) } @@ -26,9 +25,10 @@ RSpec.describe Projects::ProjectMembersHelper do helper.project_members_app_data_json( project, members: present_members(members_collection), - group_links: group_links, invited: present_members(invited), - access_requests: present_members(access_requests) + access_requests: present_members(access_requests), + include_relations: [:inherited, :direct], + search: nil ) ) end @@ -84,6 +84,70 @@ RSpec.describe Projects::ProjectMembersHelper do expect(subject['user']['pagination']).to match(expected) end end + + context 'group links' do + let_it_be(:shared_with_group) { create(:group) } + let_it_be(:group_link) { create(:project_group_link, project: project, group: shared_with_group) } + + before do + allow(helper).to receive(:project_group_link_path).with(project, ':id').and_return('/foo-group/foo-project/-/group_links/:id') + end + + it 'sets `group.members` property that matches json schema' do + expect(subject['group']['members'].to_json).to match_schema('group_link/project_group_links') + end + + it 'sets `member_path` property' do + expect(subject['group']['member_path']).to eq('/foo-group/foo-project/-/group_links/:id') + end + + context 'inherited' do + let_it_be(:shared_with_group_1) { create(:group) } + let_it_be(:shared_with_group_2) { create(:group) } + let_it_be(:shared_with_group_3) { create(:group) } + let_it_be(:shared_with_group_4) { create(:group) } + let_it_be(:shared_with_group_5) { create(:group) } + let_it_be(:top_group) { create(:group) } + let_it_be(:sub_group) { create(:group, parent: top_group) } + let_it_be(:project) { create(:project, group: sub_group) } + let_it_be(:group_link_1) { create(:group_group_link, shared_group: top_group, shared_with_group: shared_with_group_1, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_2) { create(:group_group_link, shared_group: top_group, shared_with_group: shared_with_group_4, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_3) { create(:group_group_link, shared_group: top_group, shared_with_group: shared_with_group_5, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_4) { create(:group_group_link, shared_group: sub_group, shared_with_group: shared_with_group_2, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_5) { create(:group_group_link, shared_group: sub_group, shared_with_group: shared_with_group_4, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_6) { create(:group_group_link, shared_group: sub_group, shared_with_group: shared_with_group_5, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_7) { create(:project_group_link, project: project, group: shared_with_group_1, group_access: Gitlab::Access::DEVELOPER) } + let_it_be(:group_link_8) { create(:project_group_link, project: project, group: shared_with_group_2, group_access: Gitlab::Access::GUEST) } + let_it_be(:group_link_9) { create(:project_group_link, project: project, group: shared_with_group_3, group_access: Gitlab::Access::REPORTER) } + + subject do + Gitlab::Json.parse( + helper.project_members_app_data_json( + project, + members: present_members(members_collection), + invited: present_members(invited), + access_requests: present_members(access_requests), + include_relations: include_relations, + search: nil + ) + ) + end + + using RSpec::Parameterized::TableSyntax + + where(:include_relations, :result) do + [:inherited, :direct] | lazy { [group_link_7, group_link_4, group_link_9, group_link_5, group_link_3].map(&:id) } + [:inherited] | lazy { [group_link_1, group_link_4, group_link_5, group_link_3].map(&:id) } + [:direct] | lazy { [group_link_7, group_link_8, group_link_9].map(&:id) } + end + + with_them do + it 'returns correct group links' do + expect(subject['group']['members'].map { |link| link['id'] }).to match_array(result) + end + end + end + end end end diff --git a/spec/initializers/set_active_support_hash_digest_class_spec.rb b/spec/initializers/set_active_support_hash_digest_class_spec.rb deleted file mode 100644 index 256e8a1f218..00000000000 --- a/spec/initializers/set_active_support_hash_digest_class_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'setting ActiveSupport::Digest.hash_digest_class' do - it 'sets overrides config.active_support.hash_digest_class' do - expect(ActiveSupport::Digest.hash_digest_class).to eq(Gitlab::HashDigest::Facade) - end -end diff --git a/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb b/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb index 72574d50176..5ab859241c6 100644 --- a/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb +++ b/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb @@ -71,6 +71,13 @@ RSpec.describe Gitlab::Ci::Tags::BulkInsert do expect(Ci::Build.tagged_with('tag3')).to include(other_job) end + it 'strips tags' do + job.tag_list = [' taga', 'tagb ', ' tagc '] + + service.insert! + expect(job.tags.map(&:name)).to match_array(%w[taga tagb tagc]) + end + context 'when batching inserts for tags' do before do stub_const("#{described_class}::TAGS_BATCH_SIZE", 2) diff --git a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb index 109e83be294..7ab60af31e5 100644 --- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb +++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb @@ -220,10 +220,11 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do expect(policy.directives['base-uri']).to be_nil end - it 'returns default values for directives not defined by the user' do + it 'returns default values for directives not defined by the user or with and disables directives set to false' do # Explicitly disabling script_src and setting report_uri csp_config[:directives] = { script_src: false, + style_src: '', report_uri: 'https://example.org' } diff --git a/spec/lib/gitlab/hash_digest/facade_spec.rb b/spec/lib/gitlab/hash_digest/facade_spec.rb deleted file mode 100644 index b352744513e..00000000000 --- a/spec/lib/gitlab/hash_digest/facade_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::HashDigest::Facade do - describe '.hexdigest' do - let(:plaintext) { 'something that is plaintext' } - - let(:sha256_hash) { OpenSSL::Digest::SHA256.hexdigest(plaintext) } - let(:md5_hash) { Digest::MD5.hexdigest(plaintext) } # rubocop:disable Fips/MD5 - - it 'uses SHA256' do - expect(described_class.hexdigest(plaintext)).to eq(sha256_hash) - end - - context 'when feature flags is not available' do - before do - allow(Feature).to receive(:feature_flags_available?).and_return(false) - end - - it 'uses MD5' do - expect(described_class.hexdigest(plaintext)).to eq(md5_hash) - end - end - - context 'when active_support_hash_digest_sha256 FF is disabled' do - before do - stub_feature_flags(active_support_hash_digest_sha256: false) - end - - it 'uses MD5' do - expect(described_class.hexdigest(plaintext)).to eq(md5_hash) - end - end - end -end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 587c7332ad3..dea1c5c57e1 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -2073,6 +2073,13 @@ RSpec.describe Ci::Build do expect(build.tags.first.name).to eq('tag') end + it 'strips tags' do + build.tag_list = [' taga', 'tagb ', ' tagc '] + + build.save! + expect(build.tags.map(&:name)).to match_array(%w[taga tagb tagc]) + end + context 'with BulkInsertableTags.with_bulk_insert_tags' do it 'does not save_tags' do Ci::BulkInsertableTags.with_bulk_insert_tags do diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 06baad38768..b1f5cca647b 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -1190,6 +1190,13 @@ RSpec.describe Ci::Runner do expect(runner.tags.first.name).to eq('tag') end + it 'strips tags' do + runner.tag_list = [' taga', 'tagb ', ' tagc '] + + runner.save! + expect(runner.tags.map(&:name)).to match_array(%w[taga tagb tagc]) + end + context 'with BulkInsertableTags.with_bulk_insert_tags' do it 'does not save_tags' do Ci::BulkInsertableTags.with_bulk_insert_tags do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 421e9ec47c3..b7ed7b20833 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -8390,6 +8390,27 @@ RSpec.describe Project, factory_default: :keep do end end + describe '#group_group_links' do + context 'with group project' do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + it 'returns group links of group' do + expect(group).to receive_message_chain(:shared_with_group_links, :of_ancestors_and_self) + + project.group_group_links + end + end + + context 'with personal project' do + let_it_be(:project) { create(:project) } + + it 'returns none' do + expect(project.group_group_links).to eq(GroupGroupLink.none) + end + end + end + describe '#security_training_available?' do subject { build(:project) } diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb index a24b852cdac..9e0d3780fd8 100644 --- a/spec/requests/api/pypi_packages_spec.rb +++ b/spec/requests/api/pypi_packages_spec.rb @@ -197,7 +197,7 @@ RSpec.describe API::PypiPackages do let(:url) { "/projects/#{project.id}/packages/pypi" } let(:headers) { {} } let(:requires_python) { '>=3.7' } - let(:base_params) { { requires_python: requires_python, version: '1.0.0', name: 'sample-project', sha256_digest: '1' * 64 } } + let(:base_params) { { requires_python: requires_python, version: '1.0.0', name: 'sample-project', sha256_digest: '1' * 64, md5_digest: '1' * 32 } } let(:params) { base_params.merge(content: temp_file(file_name)) } let(:send_rewritten_field) { true } let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } } @@ -254,6 +254,19 @@ RSpec.describe API::PypiPackages do it_behaves_like 'PyPI package creation', :developer, :created, true end + + context 'without md5_digest' do + let(:token) { personal_access_token.token } + let(:user_headers) { basic_auth_header(user.username, token) } + let(:headers) { user_headers.merge(workhorse_headers) } + let(:params) { base_params.merge(content: temp_file(file_name)) } + + before do + params.delete(:md5_digest) + end + + it_behaves_like 'PyPI package creation', :developer, :created, true, false + end end context 'with required_python too big' do diff --git a/spec/services/packages/pypi/create_package_service_spec.rb b/spec/services/packages/pypi/create_package_service_spec.rb index 354ac92b99a..6794ab4d9d6 100644 --- a/spec/services/packages/pypi/create_package_service_spec.rb +++ b/spec/services/packages/pypi/create_package_service_spec.rb @@ -42,6 +42,21 @@ RSpec.describe Packages::Pypi::CreatePackageService, :aggregate_failures do end end + context 'with FIPS mode', :fips_mode do + it 'does not generate file_md5' do + expect { subject }.to change { Packages::Package.pypi.count }.by(1) + + expect(created_package.name).to eq 'foo' + expect(created_package.version).to eq '1.0' + + expect(created_package.pypi_metadatum.required_python).to eq '>=2.7' + expect(created_package.package_files.size).to eq 1 + expect(created_package.package_files.first.file_name).to eq 'foo.tgz' + expect(created_package.package_files.first.file_sha256).to eq sha256 + expect(created_package.package_files.first.file_md5).to be_nil + end + end + context 'without required_python' do before do params.delete(:requires_python) diff --git a/spec/services/projects/create_from_template_service_spec.rb b/spec/services/projects/create_from_template_service_spec.rb index 7e23daabcd3..fba6225b87a 100644 --- a/spec/services/projects/create_from_template_service_spec.rb +++ b/spec/services/projects/create_from_template_service_spec.rb @@ -49,7 +49,7 @@ RSpec.describe Projects::CreateFromTemplateService do end it 'is not scheduled' do - expect(project.import_scheduled?).to be_nil + expect(project.import_scheduled?).to be(false) end it 'repository is empty' do diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb index 795545e4ad1..1a248bb04e7 100644 --- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_examples 'PyPI package creation' do |user_type, status, add_member = true| +RSpec.shared_examples 'PyPI package creation' do |user_type, status, add_member = true, md5_digest = true| RSpec.shared_examples 'creating pypi package files' do it 'creates package files' do expect { subject } @@ -14,6 +14,17 @@ RSpec.shared_examples 'PyPI package creation' do |user_type, status, add_member expect(package.name).to eq params[:name] expect(package.version).to eq params[:version] expect(package.pypi_metadatum.required_python).to eq params[:requires_python] + + if md5_digest + expect(package.package_files.first.file_md5).not_to be_nil + else + expect(package.package_files.first.file_md5).to be_nil + end + end + + context 'with FIPS mode', :fips_mode do + it_behaves_like 'returning response status', :unprocessable_entity if md5_digest + it_behaves_like 'returning response status', status unless md5_digest end end