diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index e808a0297a6..d02299c48f6 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -73,6 +73,9 @@ .if-merge-request-labels-skip-undercoverage: &if-merge-request-labels-skip-undercoverage if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:skip-undercoverage/' +.if-merge-request-labels-jh-contribution: &if-merge-request-labels-jh-contribution + if: '$CI_MERGE_REQUEST_LABELS =~ /JiHu contribution/' + .if-security-merge-request: &if-security-merge-request if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID' @@ -1682,6 +1685,13 @@ - <<: *if-default-refs changes: *code-backstage-patterns +.setup:rules:jh-contribution: + rules: + - <<: *if-jh + when: never + - <<: *if-merge-request-labels-jh-contribution + + .setup:rules:generate-frontend-fixtures-mapping: rules: - <<: *if-not-ee diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml index ad500fe0ddc..4339251897c 100644 --- a/.gitlab/ci/setup.gitlab-ci.yml +++ b/.gitlab/ci/setup.gitlab-ci.yml @@ -68,6 +68,15 @@ verify-tests-yml: - install_tff_gem - scripts/verify-tff-mapping +verify-approvals: + extends: + - .setup:rules:jh-contribution + needs: [] + script: + - source scripts/utils.sh + - install_gitlab_gem + - tooling/bin/find_app_sec_approval + generate-frontend-fixtures-mapping: extends: - .setup:rules:generate-frontend-fixtures-mapping diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index cc4992020ae..502534e5010 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -18,11 +18,6 @@ Gitlab/PolicyRuleBoolean: Layout/MultilineOperationIndentation: Enabled: false -# Offense count: 53 -# Cop supports --auto-correct. -Layout/SpaceAroundMethodCallOperator: - Enabled: false - # Offense count: 754 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. @@ -73,11 +68,6 @@ Lint/EmptyFile: - 'db/seeds.rb' - 'ee/db/geo/seeds.rb' -# Offense count: 208 -# Configuration parameters: MaximumRangeSize. -Lint/MissingCopEnableDirective: - Enabled: false - # Offense count: 13 Lint/MixedRegexpCaptureTypes: Exclude: diff --git a/.rubocop_todo/layout/space_around_method_call_operator.yml b/.rubocop_todo/layout/space_around_method_call_operator.yml new file mode 100644 index 00000000000..bc174a43d77 --- /dev/null +++ b/.rubocop_todo/layout/space_around_method_call_operator.yml @@ -0,0 +1,32 @@ +--- +# Cop supports --auto-correct. +Layout/SpaceAroundMethodCallOperator: + # Offense count: 35 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/helpers/badges_helper.rb' + - 'app/services/google_cloud/create_service_accounts_service.rb' + - 'app/services/google_cloud/enable_cloud_run_service.rb' + - 'app/services/google_cloud/generate_pipeline_service.rb' + - 'ee/spec/lib/gitlab/ci/config/entry/dast_configuration_spec.rb' + - 'ee/spec/migrations/geo/set_resync_flag_for_retried_projects_spec.rb' + - 'ee/spec/models/approval_project_rule_spec.rb' + - 'ee/spec/models/integrations/github/status_message_spec.rb' + - 'ee/spec/services/ee/boards/issues/move_service_spec.rb' + - 'ee/spec/services/ee/issues/create_service_spec.rb' + - 'ee/spec/services/geo/repository_base_sync_service_spec.rb' + - 'ee/spec/services/requirements_management/create_requirement_service_spec.rb' + - 'ee/spec/services/requirements_management/update_requirement_service_spec.rb' + - 'spec/graphql/types/base_field_spec.rb' + - 'spec/lib/gitlab/ci/pipeline/chain/command_spec.rb' + - 'spec/lib/gitlab/database/shared_model_spec.rb' + - 'spec/lib/gitlab/diff/highlight_spec.rb' + - 'spec/lib/gitlab/spamcheck/client_spec.rb' + - 'spec/migrations/20220128155251_remove_dangling_running_builds_spec.rb' + - 'spec/models/integrations/chat_message/issue_message_spec.rb' + - 'spec/models/milestone_spec.rb' + - 'spec/presenters/alert_management/alert_presenter_spec.rb' + - 'spec/requests/api/graphql/custom_emoji_query_spec.rb' + - 'spec/tasks/gitlab/db_rake_spec.rb' + - 'spec/workers/concerns/limited_capacity/job_tracker_spec.rb' diff --git a/.rubocop_todo/lint/missing_cop_enable_directive.yml b/.rubocop_todo/lint/missing_cop_enable_directive.yml new file mode 100644 index 00000000000..a8edf6c85dc --- /dev/null +++ b/.rubocop_todo/lint/missing_cop_enable_directive.yml @@ -0,0 +1,196 @@ +--- +Lint/MissingCopEnableDirective: + # Offense count: 199 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/controllers/admin/users_controller.rb' + - 'app/controllers/projects/forks_controller.rb' + - 'app/finders/projects/serverless/functions_finder.rb' + - 'app/graphql/resolvers/group_issues_resolver.rb' + - 'app/graphql/resolvers/issues_resolver.rb' + - 'app/graphql/resolvers/project_members_resolver.rb' + - 'app/graphql/resolvers/project_milestones_resolver.rb' + - 'app/graphql/resolvers/projects/snippets_resolver.rb' + - 'app/graphql/resolvers/snippets_resolver.rb' + - 'app/graphql/resolvers/users/snippets_resolver.rb' + - 'app/graphql/types/access_level_type.rb' + - 'app/graphql/types/base_enum.rb' + - 'app/graphql/types/boards/board_issue_input_base_type.rb' + - 'app/graphql/types/ci/analytics_type.rb' + - 'app/graphql/types/ci/build_need_type.rb' + - 'app/graphql/types/ci/config/config_type.rb' + - 'app/graphql/types/ci/config/group_type.rb' + - 'app/graphql/types/ci/config/job_restriction_type.rb' + - 'app/graphql/types/ci/config/job_type.rb' + - 'app/graphql/types/ci/config/need_type.rb' + - 'app/graphql/types/ci/config/stage_type.rb' + - 'app/graphql/types/ci/group_type.rb' + - 'app/graphql/types/ci/job_artifact_type.rb' + - 'app/graphql/types/ci/job_type.rb' + - 'app/graphql/types/ci/pipeline_message_type.rb' + - 'app/graphql/types/ci/runner_architecture_type.rb' + - 'app/graphql/types/ci/runner_platform_type.rb' + - 'app/graphql/types/ci/runner_setup_type.rb' + - 'app/graphql/types/ci/runner_web_url_edge.rb' + - 'app/graphql/types/ci/status_action_type.rb' + - 'app/graphql/types/ci/template_type.rb' + - 'app/graphql/types/ci_configuration/sast/analyzers_entity_type.rb' + - 'app/graphql/types/ci_configuration/sast/entity_type.rb' + - 'app/graphql/types/ci_configuration/sast/options_entity_type.rb' + - 'app/graphql/types/ci_configuration/sast/type.rb' + - 'app/graphql/types/countable_connection_type.rb' + - 'app/graphql/types/design_management_type.rb' + - 'app/graphql/types/issue_connection_type.rb' + - 'app/graphql/types/merge_request_connection_type.rb' + - 'app/graphql/types/packages/composer/json_type.rb' + - 'app/graphql/types/packages/helm/dependency_type.rb' + - 'app/graphql/types/packages/helm/maintainer_type.rb' + - 'app/graphql/types/packages/helm/metadata_type.rb' + - 'app/graphql/types/packages/package_dependency_type.rb' + - 'app/graphql/types/repository/blob_type.rb' + - 'app/graphql/types/snippets/blob_connection_type.rb' + - 'app/graphql/types/user_preferences_type.rb' + - 'app/graphql/types/user_status_type.rb' + - 'app/models/commit_collection.rb' + - 'app/models/concerns/batch_destroy_dependent_associations.rb' + - 'app/models/concerns/deployment_platform.rb' + - 'app/models/token_with_iv.rb' + - 'app/models/wiki_page.rb' + - 'app/services/ci/queue/build_queue_service.rb' + - 'app/services/commits/change_service.rb' + - 'app/services/labels/promote_service.rb' + - 'app/services/notification_service.rb' + - 'app/services/projects/container_repository/third_party/delete_tags_service.rb' + - 'app/services/search/global_service.rb' + - 'config/initializers_before_autoloader/003_gc_compact.rb' + - 'danger/feature_flag/Dangerfile' + - 'danger/pajamas/Dangerfile' + - 'danger/z_metadata/Dangerfile' + - 'db/migrate/20210807101621_add_timezone_to_dast_profile_schedules.rb' + - 'db/migrate/20210816095826_add_unique_index_on_dast_profile_to_dast_profile_schedules.rb' + - 'db/migrate/20210818061156_remove_project_profile_compound_index_from_dast_profile_schedules.rb' + - 'db/migrate/20210818115613_add_index_project_id_on_dast_profile_schedule.rb' + - 'db/migrate/20211013014228_add_content_validation_endpoint_to_application_settings.rb' + - 'db/post_migrate/20210825182303_remove_duplicate_dast_site_tokens_with_same_token.rb' + - 'ee/app/controllers/ee/admin/dashboard_controller.rb' + - 'ee/app/controllers/ee/admin/groups_controller.rb' + - 'ee/app/controllers/ee/admin/users_controller.rb' + - 'ee/app/controllers/ee/projects/settings/ci_cd_controller.rb' + - 'ee/app/graphql/resolvers/vulnerabilities_base_resolver.rb' + - 'ee/app/graphql/types/admin/cloud_licenses/current_license_type.rb' + - 'ee/app/graphql/types/admin/cloud_licenses/license_history_entry_type.rb' + - 'ee/app/graphql/types/admin/cloud_licenses/subscription_future_entry_type.rb' + - 'ee/app/graphql/types/analytics/devops_adoption/enabled_namespace_type.rb' + - 'ee/app/graphql/types/analytics/devops_adoption/snapshot_type.rb' + - 'ee/app/graphql/types/burnup_chart_daily_totals_type.rb' + - 'ee/app/graphql/types/ci/code_coverage_activity_type.rb' + - 'ee/app/graphql/types/ci/code_coverage_summary_type.rb' + - 'ee/app/graphql/types/ci/code_quality_degradation_type.rb' + - 'ee/app/graphql/types/ci/minutes/namespace_monthly_usage_type.rb' + - 'ee/app/graphql/types/ci/minutes/project_monthly_usage_type.rb' + - 'ee/app/graphql/types/compliance_management/compliance_framework_type.rb' + - 'ee/app/graphql/types/dast/profile_cadence_type.rb' + - 'ee/app/graphql/types/geo/group_wiki_repository_registry_type.rb' + - 'ee/app/graphql/types/geo/job_artifact_registry_type.rb' + - 'ee/app/graphql/types/geo/lfs_object_registry_type.rb' + - 'ee/app/graphql/types/geo/merge_request_diff_registry_type.rb' + - 'ee/app/graphql/types/geo/package_file_registry_type.rb' + - 'ee/app/graphql/types/geo/pages_deployment_registry_type.rb' + - 'ee/app/graphql/types/geo/pipeline_artifact_registry_type.rb' + - 'ee/app/graphql/types/geo/snippet_repository_registry_type.rb' + - 'ee/app/graphql/types/geo/terraform_state_version_registry_type.rb' + - 'ee/app/graphql/types/geo/upload_registry_type.rb' + - 'ee/app/graphql/types/network_policy_type.rb' + - 'ee/app/graphql/types/scan_type.rb' + - 'ee/app/graphql/types/scanned_resource_type.rb' + - 'ee/app/graphql/types/security_report_summary_section_type.rb' + - 'ee/app/graphql/types/security_report_summary_type.rb' + - 'ee/app/graphql/types/security_scanners.rb' + - 'ee/app/graphql/types/time_report_stats_type.rb' + - 'ee/app/graphql/types/timebox_metrics_type.rb' + - 'ee/app/graphql/types/timebox_report_type.rb' + - 'ee/app/graphql/types/vulnerabilities_count_by_day_type.rb' + - 'ee/app/graphql/types/vulnerability_details/base_type.rb' + - 'ee/app/graphql/types/vulnerability_details/boolean_type.rb' + - 'ee/app/graphql/types/vulnerability_details/code_type.rb' + - 'ee/app/graphql/types/vulnerability_details/commit_type.rb' + - 'ee/app/graphql/types/vulnerability_details/diff_type.rb' + - 'ee/app/graphql/types/vulnerability_details/file_location_type.rb' + - 'ee/app/graphql/types/vulnerability_details/int_type.rb' + - 'ee/app/graphql/types/vulnerability_details/list_type.rb' + - 'ee/app/graphql/types/vulnerability_details/markdown_type.rb' + - 'ee/app/graphql/types/vulnerability_details/module_location_type.rb' + - 'ee/app/graphql/types/vulnerability_details/table_type.rb' + - 'ee/app/graphql/types/vulnerability_details/text_type.rb' + - 'ee/app/graphql/types/vulnerability_details/url_type.rb' + - 'ee/app/graphql/types/vulnerability_location/cluster_image_scanning_type.rb' + - 'ee/app/graphql/types/vulnerability_location/container_scanning_type.rb' + - 'ee/app/graphql/types/vulnerability_location/coverage_fuzzing_type.rb' + - 'ee/app/graphql/types/vulnerability_location/dast_type.rb' + - 'ee/app/graphql/types/vulnerability_location/dependency_scanning_type.rb' + - 'ee/app/graphql/types/vulnerability_location/generic_type.rb' + - 'ee/app/graphql/types/vulnerability_location/sast_type.rb' + - 'ee/app/graphql/types/vulnerability_location/secret_detection_type.rb' + - 'ee/app/graphql/types/vulnerability_severities_count_type.rb' + - 'ee/app/graphql/types/vulnerable_dependency_type.rb' + - 'ee/app/graphql/types/vulnerable_kubernetes_resource_type.rb' + - 'ee/app/graphql/types/vulnerable_package_type.rb' + - 'ee/app/workers/groups/export_memberships_worker.rb' + - 'ee/app/workers/update_max_seats_used_for_gitlab_com_subscriptions_worker.rb' + - 'ee/lib/api/ldap_group_links.rb' + - 'ee/lib/api/scim.rb' + - 'ee/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules.rb' + - 'ee/lib/ee/gitlab/usage_data.rb' + - 'ee/lib/elastic/latest/git_class_proxy.rb' + - 'ee/lib/gitlab/spdx/license.rb' + - 'lib/gitlab/auth/ldap/dn.rb' + - 'lib/gitlab/background_migration/backfill_issue_search_data.rb' + - 'lib/gitlab/background_migration/backfill_iteration_cadence_id_for_boards.rb' + - 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_children.rb' + - 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots.rb' + - 'lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans.rb' + - 'lib/gitlab/background_migration/drop_invalid_vulnerabilities.rb' + - 'lib/gitlab/background_migration/fix_incorrect_max_seats_used.rb' + - 'lib/gitlab/background_migration/mailers/unconfirm_mailer.rb' + - 'lib/gitlab/background_migration/migrate_approver_to_approval_rules.rb' + - 'lib/gitlab/background_migration/migrate_approver_to_approval_rules_check_progress.rb' + - 'lib/gitlab/background_migration/migrate_approver_to_approval_rules_in_batch.rb' + - 'lib/gitlab/background_migration/migrate_job_artifact_registry_to_ssf.rb' + - 'lib/gitlab/background_migration/migrate_stage_status.rb' + - 'lib/gitlab/background_migration/migrate_u2f_webauthn.rb' + - 'lib/gitlab/background_migration/populate_latest_pipeline_ids.rb' + - 'lib/gitlab/background_migration/populate_resolved_on_default_branch_column.rb' + - 'lib/gitlab/background_migration/populate_test_reports_issue_id.rb' + - 'lib/gitlab/background_migration/populate_uuids_for_security_findings.rb' + - 'lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid.rb' + - 'lib/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings.rb' + - 'lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings.rb' + - 'lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url.rb' + - 'lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb' + - 'lib/gitlab/ci/reports/test_suite_summary.rb' + - 'lib/gitlab/data_builder/push.rb' + - 'lib/gitlab/database/load_balancing/connection_proxy.rb' + - 'lib/gitlab/database/migration_helpers.rb' + - 'lib/gitlab/database/postgresql_adapter/type_map_cache.rb' + - 'lib/gitlab/github_import/client.rb' + - 'lib/gitlab/github_import/importer/diff_note_importer.rb' + - 'lib/gitlab/gon_helper.rb' + - 'lib/gitlab/graphql/pagination/keyset/generic_keyset_pagination.rb' + - 'lib/gitlab/graphql/pagination/keyset/last_items.rb' + - 'lib/gitlab/graphql/standard_graphql_error.rb' + - 'lib/gitlab/metrics/methods.rb' + - 'lib/gitlab/patch/action_cable_redis_listener.rb' + - 'lib/gitlab/patch/prependable.rb' + - 'lib/gitlab/project_search_results.rb' + - 'lib/gitlab/task_helpers.rb' + - 'lib/gitlab/testing/request_blocker_middleware.rb' + - 'lib/gitlab/testing/request_inspector_middleware.rb' + - 'lib/gitlab/testing/robots_blocker_middleware.rb' + - 'qa/qa/scenario/test/integration/registry_with_cdn.rb' + - 'spec/benchmarks/banzai_benchmark.rb' + - 'spec/lib/gitlab/sidekiq_middleware/size_limiter/server_spec.rb' + - 'spec/support/capybara.rb' + - 'spec/support/cycle_analytics_helpers/test_generation.rb' + - 'spec/support/google_api/cloud_platform_helpers.rb' + - 'tooling/danger/product_intelligence.rb' diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index af3deaab686..c80e5e56f93 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -13.24.2 +13.25.0 diff --git a/app/models/packages/package_file.rb b/app/models/packages/package_file.rb index ad8140ac684..b49e04f481c 100644 --- a/app/models/packages/package_file.rb +++ b/app/models/packages/package_file.rb @@ -34,7 +34,7 @@ class Packages::PackageFile < ApplicationRecord validates :file, presence: true validates :file_name, presence: true - validates :file_name, uniqueness: { scope: :package }, if: -> { package&.pypi? } + validates :file_name, uniqueness: { scope: :package }, if: -> { !pending_destruction? && package&.pypi? } scope :recent, -> { order(id: :desc) } scope :limit_recent, ->(limit) { recent.limit(limit) } diff --git a/app/views/notify/issue_due_email.html.haml b/app/views/notify/issue_due_email.html.haml index e512d7732e2..3208d061928 100644 --- a/app/views/notify/issue_due_email.html.haml +++ b/app/views/notify/issue_due_email.html.haml @@ -1,11 +1,11 @@ %p.details - #{link_to @issue.author_name, user_url(@issue.author)}'s issue #{issue_reference_link(@issue)} is due soon. + = sprintf(s_("Notify|%{author_link}'s issue %{issue_reference_link} is due soon."), { author_link: link_to(@issue.author_name, user_url(@issue.author)), issue_reference_link: issue_reference_link(@issue) }) - if @issue.assignees.any? %p = assignees_label(@issue) %p - This issue is due on: #{@issue.due_date.to_s(:medium)} + = sprintf(s_('Notify|This issue is due on: %{issue_due_date}'), { issue_due_date: @issue.due_date.to_s(:medium) }).html_safe - if @issue.description .md diff --git a/app/views/notify/issue_moved_email.html.haml b/app/views/notify/issue_moved_email.html.haml index b766cb1a523..c77a863d1a4 100644 --- a/app/views/notify/issue_moved_email.html.haml +++ b/app/views/notify/issue_moved_email.html.haml @@ -1,9 +1,7 @@ %p - Issue was moved to another project. + = s_('Notify|Issue was moved to another project.') - if @can_access_project %p - New issue: - = link_to project_issue_url(@new_project, @new_issue) do - = @new_issue.title + = sprintf(s_('Notify|New issue: %{project_issue_url}'), { project_issue_url: link_to(@new_issue.title, project_issue_url(@new_project, @new_issue)) } ).html_safe - else - You don't have access to the project. + = s_("Notify|You don't have access to the project.") diff --git a/app/views/notify/issue_status_changed_email.html.haml b/app/views/notify/issue_status_changed_email.html.haml index 66e73a9b03f..545f9c006af 100644 --- a/app/views/notify/issue_status_changed_email.html.haml +++ b/app/views/notify/issue_status_changed_email.html.haml @@ -1,2 +1,2 @@ %p - Issue was #{@issue_status} by #{sanitize_name(@updated_by.name)} + = sprintf(s_('Notify|Issue was %{issue_status} by %{updated_by}'), { issue_status: @issue_status, updated_by: sanitize_name(@updated_by.name) }).html_safe diff --git a/app/views/notify/merge_request_status_email.html.haml b/app/views/notify/merge_request_status_email.html.haml index 49f2366c594..8e8d27b3cec 100644 --- a/app/views/notify/merge_request_status_email.html.haml +++ b/app/views/notify/merge_request_status_email.html.haml @@ -1,3 +1,3 @@ %p - Merge request #{merge_request_reference_link(@merge_request)} - was #{@mr_status} by #{sanitize_name(@updated_by.name)} + = sprintf(s_('Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}'), + { merge_request: merge_request_reference_link(@merge_request), mr_status: @mr_status, updated_by: sanitize_name(@updated_by.name) }).html_safe diff --git a/app/views/notify/merge_request_status_email.text.haml b/app/views/notify/merge_request_status_email.text.haml index 1a8f848218c..f3845b2b910 100644 --- a/app/views/notify/merge_request_status_email.text.haml +++ b/app/views/notify/merge_request_status_email.text.haml @@ -1,9 +1,9 @@ -Merge request #{@merge_request.to_reference} was #{@mr_status} by #{sanitize_name(@updated_by.name)} += sprintf(s_('Notify|Merge request %{merge_request} was %{mr_status}'), { merge_request: @merge_request.to_reference, mr_status: sanitize_name(@updated_by.name) }) -Merge request URL: #{project_merge_request_url(@merge_request.target_project, @merge_request)} += sprintf(s_('Notify|Merge request URL: %{merge_request_url}'), { merge_request_url: project_merge_request_url(@merge_request.target_project, @merge_request) }) = merge_path_description(@merge_request, 'to') -Author: #{sanitize_name(@merge_request.author_name)} += sprintf(s_('Notify|Author: %{author_name}'), { author_name: sanitize_name(@merge_request.author_name) }) = assignees_label(@merge_request) = reviewers_label(@merge_request) diff --git a/app/views/notify/merge_request_unmergeable_email.html.haml b/app/views/notify/merge_request_unmergeable_email.html.haml index fddf9eaf95a..6bcff28985c 100644 --- a/app/views/notify/merge_request_unmergeable_email.html.haml +++ b/app/views/notify/merge_request_unmergeable_email.html.haml @@ -1,2 +1,2 @@ %p - Merge request #{merge_request_reference_link(@merge_request)} can no longer be merged due to conflict. + = sprintf(s_('Notify|Merge request %{merge_request} can no longer be merged due to conflict.'), { merge_request: merge_request_reference_link(@merge_request) }).html_safe diff --git a/app/views/notify/merge_request_unmergeable_email.text.haml b/app/views/notify/merge_request_unmergeable_email.text.haml index 3db5f21e6c2..22d56e73ca8 100644 --- a/app/views/notify/merge_request_unmergeable_email.text.haml +++ b/app/views/notify/merge_request_unmergeable_email.text.haml @@ -1,9 +1,9 @@ -Merge request #{@merge_request.to_reference} can no longer be merged due to conflict. += sprintf(s_('Notify|Merge request %{merge_request} can no longer be merged due to conflict.'), { merge_request: @merge_request.to_reference }) -Merge request URL: #{project_merge_request_url(@merge_request.target_project, @merge_request)} += sprintf(s_('Notify|Merge request URL: %{merge_request_url}'), { merge_request_url: project_merge_request_url(@merge_request.target_project, @merge_request) }) = merge_path_description(@merge_request, 'to') -Author: #{sanitize_name(@merge_request.author_name)} += sprintf(s_('Author: %{author_name}'), { author_name: sanitize_name(@merge_request.author_name) }) = assignees_label(@merge_request) = reviewers_label(@merge_request) diff --git a/app/views/notify/merged_merge_request_email.html.haml b/app/views/notify/merged_merge_request_email.html.haml index f0dadd9ce91..0622e2f6ffb 100644 --- a/app/views/notify/merged_merge_request_email.html.haml +++ b/app/views/notify/merged_merge_request_email.html.haml @@ -1,2 +1,2 @@ %p - Merge request #{merge_request_reference_link(@merge_request)} was merged + = sprintf(s_('Notify|Merge request %{merge_request} was merged'), { merge_request: merge_request_reference_link(@merge_request) }).html_safe diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml index 91f920dec21..3c22954952d 100644 --- a/app/views/notify/merged_merge_request_email.text.haml +++ b/app/views/notify/merged_merge_request_email.text.haml @@ -1,9 +1,9 @@ -Merge request #{@merge_request.to_reference} was merged += sprintf(s_('Notify|Merge request %{merge_request} was merged'), { merge_request: @merge_request.to_reference }) -Merge request URL: #{project_merge_request_url(@merge_request.target_project, @merge_request)} += sprintf(s_('Notify|Merge request URL: %{merge_request_url}'), { merge_request_url: project_merge_request_url(@merge_request.target_project, @merge_request) }) = merge_path_description(@merge_request, 'to') -Author: #{sanitize_name(@merge_request.author_name)} +sprintf(s_('Notify|Author: %{author_name}'), { author_name: sanitize_name(@merge_request.author_name) }) = assignees_label(@merge_request) = reviewers_label(@merge_request) diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index 4a44ad2337f..a654d0a8863 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -29,9 +29,12 @@ - else .nothing-here-block - = s_('TagsPage|Repository has no tags yet.') - %br - %small - = s_('TagsPage|Use git tag command to add a new one:') + - if @search.present? + = s_('TagsPage|Sorry, your filter produced no results.') + - else + = s_('TagsPage|Repository has no tags yet.') %br - %span.monospace git tag -a v1.4 -m 'version 1.4' + %small + = s_('TagsPage|Use git tag command to add a new one:') + %br + %span.monospace git tag -a v1.4 -m 'version 1.4' diff --git a/app/views/shared/_outdated_browser.html.haml b/app/views/shared/_outdated_browser.html.haml index f5a32050a79..76fb34985c0 100644 --- a/app/views/shared/_outdated_browser.html.haml +++ b/app/views/shared/_outdated_browser.html.haml @@ -1,6 +1,5 @@ - if outdated_browser? - .gl-alert.gl-alert-danger.outdated-browser{ :role => "alert" } - = sprite_icon('error', css_class: "gl-alert-icon gl-alert-icon-no-title gl-icon") + = render Pajamas::AlertComponent.new(variant: :danger, dismissible: false) do .gl-alert-body = s_('OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser.') %br diff --git a/app/workers/concerns/packages/cleanup_artifact_worker.rb b/app/workers/concerns/packages/cleanup_artifact_worker.rb index d4ad023b4a8..bee9587cb35 100644 --- a/app/workers/concerns/packages/cleanup_artifact_worker.rb +++ b/app/workers/concerns/packages/cleanup_artifact_worker.rb @@ -14,7 +14,7 @@ module Packages artifact.destroy! rescue StandardError - artifact&.error! + artifact&.update_column(:status, :error) end after_destroy @@ -48,7 +48,7 @@ module Packages to_delete = next_item if to_delete - to_delete.processing! + to_delete.update_column(:status, :processing) log_cleanup_item(to_delete) end diff --git a/db/post_migrate/20220325000001_finalize_index_for_ci_job_artifacts_unlocked_with_expire_at.rb b/db/post_migrate/20220325000001_finalize_index_for_ci_job_artifacts_unlocked_with_expire_at.rb new file mode 100644 index 00000000000..d0fe7ceb34f --- /dev/null +++ b/db/post_migrate/20220325000001_finalize_index_for_ci_job_artifacts_unlocked_with_expire_at.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class FinalizeIndexForCiJobArtifactsUnlockedWithExpireAt < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + + TABLE_NAME = 'ci_job_artifacts' + INDEX_NAME = 'index_ci_job_artifacts_on_expire_at_for_removal' + CONDITIONS = 'locked = 0 AND expire_at IS NOT NULL' + + def up + add_concurrent_index TABLE_NAME, [:expire_at], where: CONDITIONS, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME + end +end diff --git a/db/schema_migrations/20220325000001 b/db/schema_migrations/20220325000001 new file mode 100644 index 00000000000..aa258196cb3 --- /dev/null +++ b/db/schema_migrations/20220325000001 @@ -0,0 +1 @@ +d9ad9c043faf278e33707baeccb5b7733aec408446b3dacf685e126309c4808c \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 95611ceb31d..fff5312ea72 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -27004,6 +27004,8 @@ CREATE INDEX index_ci_job_artifacts_id_for_terraform_reports ON ci_job_artifacts CREATE INDEX index_ci_job_artifacts_on_expire_at_and_job_id ON ci_job_artifacts USING btree (expire_at, job_id); +CREATE INDEX index_ci_job_artifacts_on_expire_at_for_removal ON ci_job_artifacts USING btree (expire_at) WHERE ((locked = 0) AND (expire_at IS NOT NULL)); + CREATE INDEX index_ci_job_artifacts_on_file_store ON ci_job_artifacts USING btree (file_store); CREATE INDEX index_ci_job_artifacts_on_file_type_for_devops_adoption ON ci_job_artifacts USING btree (file_type, project_id, created_at) WHERE (file_type = ANY (ARRAY[5, 6, 8, 23])); diff --git a/doc/administration/index.md b/doc/administration/index.md index fa473332717..73ea4a8e1d0 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -218,6 +218,7 @@ Learn how to install, configure, update, and maintain your GitLab instance. - [Troubleshooting Elasticsearch](troubleshooting/elasticsearch.md) - [Navigating GitLab via Rails console](troubleshooting/navigating_gitlab_via_rails_console.md) - [GitLab application limits](instance_limits.md) +- [Responding to security incidents](../security/responding_to_security_incidents.md) ### Support Team Docs diff --git a/doc/api/discussions.md b/doc/api/discussions.md index c775d761d4d..c30c00cef67 100644 --- a/doc/api/discussions.md +++ b/doc/api/discussions.md @@ -994,7 +994,11 @@ curl --request POST --header "PRIVATE-TOKEN: [ACCESS_TOKEN]"\ ### Resolve a merge request thread -Resolve/unresolve whole thread of a merge request. +Resolve or unresolve a thread of discussion in a merge request. + +Prerequisite: + +- You must have at least the Developer role, or be the author of the change being reviewed. ```plaintext PUT /projects/:id/merge_requests/:merge_request_iid/discussions/:discussion_id diff --git a/doc/development/cicd/schema.md b/doc/development/cicd/schema.md index 71a1450ccfe..55d3634d136 100644 --- a/doc/development/cicd/schema.md +++ b/doc/development/cicd/schema.md @@ -138,9 +138,71 @@ under the topmost **properties** key. ## Test the schema -For now, the CI/CD schema can only be tested manually. To verify the behavior is correct: +### Verifying changes manually 1. Enable the `schema_linting` feature flag. 1. Go to **CI/CD** > **Editor**. 1. Write your CI/CD configuration in the editor and verify that the schema validates it correctly. + +### Writing specs + +All of our schema specs live in the `spec/frontend/editor/schema/ci` directory. +Legacy tests are written in JSON, but we recommend writing all new tests in YAML. +You can write them as if you're adding to a `.gitlab-ci.yml` configuration file. + +Tests are separated into **positive** tests and **negative** tests. Positive tests +are snippets of CI configuration code that use the schema keywords as intended. +Conversely, negative tests give examples of how to use the schema keywords incorrectly. +This allows us the check that our CI schema validates different examples of input. + +`ci_schema_spec.js` is responsible for running all of our tests against the CI schema. + +A detailed explanation of how the tests are set up can be found in this +[merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83047). + +#### How to update schema specs + +1. If a YAML test does not exist for the specified keyword, create new files in +`yaml_tests/positive_tests` and `yaml_tests/negative_tests`. Otherwise, you can update +the existing tests. +1. Write both positive and negative tests to validaste different kinds of input. +1. If you created new files, import them in `ci_schema_spec.js` and add each file to their +corresponding object entries. + +```javascript +import CacheYaml from './yaml_tests/positive_tests/cache.yml'; +import CacheNegativeYaml from './yaml_tests/negative_tests/cache.yml'; + +// import your new test files +import NewKeywordTestYaml from './yaml_tests/positive_tests/cache.yml'; +import NewKeywordTestNegativeYaml from './yaml_tests/negative_tests/cache.yml'; + +describe('positive tests', () => { + it.each( + Object.entries({ + CacheYaml, + NewKeywordTestYaml, // add positive test here + }), + )('schema validates %s', (_, input) => { + expect(input).toValidateJsonSchema(schema); + }); +}); + +describe('negative tests', () => { + it.each( + Object.entries({ + CacheNegativeYaml, + NewKeywordTestYaml, // add negative test here + }), + )('schema validates %s', (_, input) => { + expect(input).not.toValidateJsonSchema(schema); + }); +}); +``` + +1. Run the command `yarn jest spec/frontend/editor/schema/ci/ci_schema_spec.js`. +1. Make sure that: + +- All tests successfully pass. +- If the spec covers a change to an existing keyword and it affects the legacy JSON tests, make sure to also update them. diff --git a/doc/development/service_ping/metrics_instrumentation.md b/doc/development/service_ping/metrics_instrumentation.md index c684d9d12ef..3d56f3e777f 100644 --- a/doc/development/service_ping/metrics_instrumentation.md +++ b/doc/development/service_ping/metrics_instrumentation.md @@ -24,7 +24,9 @@ This guide describes how to develop Service Ping metrics using metrics instrumen A metric definition has the [`instrumentation_class`](metrics_dictionary.md) field, which can be set to a class. -The defined instrumentation class should have one of the existing metric classes: `DatabaseMetric`, `RedisMetric`, `RedisHLLMetric`, or `GenericMetric`. +The defined instrumentation class should inherit one of the existing metric classes: `DatabaseMetric`, `RedisMetric`, `RedisHLLMetric`, or `GenericMetric`. + +The current convention is that a single instrumentation class corresponds to a single metric. On a rare occasions, there are exceptions to that convention like [Redis metrics](#redis-metrics). To use a single instrumentation class for more than one metric, please reach out to one of the `@gitlab-org/growth/product-intelligence/engineers` members to consult about your case. Using the instrumentation classes ensures that metrics can fail safe individually, without breaking the entire process of Service Ping generation. @@ -186,3 +188,30 @@ rails generate gitlab:usage_metric CountIssues --type database create lib/gitlab/usage/metrics/instrumentations/count_issues_metric.rb create spec/lib/gitlab/usage/metrics/instrumentations/count_issues_metric_spec.rb ``` + +## Migrate Service Ping metrics to instrumentation classes + +This guide describes how to migrate a Service Ping metric from [`lib/gitlab/usage_data.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb) or [`ee/lib/ee/gitlab/usage_data.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/ee/gitlab/usage_data.rb) to instrumentation classes. + +1. Choose the metric type: + +- [Database metric](#database-metrics) +- [Redis HyperLogLog metrics](#redis-hyperloglog-metrics) +- [Redis metric](#redis-metrics) +- [Generic metric](#generic-metrics) + +1. Determine the location of instrumentation class: either under `ee` or outside `ee`. + +1. [Generate the instrumentation class file](#create-a-new-metric-instrumentation-class). + +1. Fill the instrumentation class body: + + - Add code logic for the metric. This might be similar to the metric implementation in `usage_data.rb`. + - Add tests for the individual metric [`spec/lib/gitlab/usage/metrics/instrumentations/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/usage/metrics/instrumentations). + - Add tests for Service Ping. + +1. [Generate the metric definition file](metrics_dictionary.md#create-a-new-metric-definition). + +1. Remove the code from [`lib/gitlab/usage_data.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb) or [`ee/lib/ee/gitlab/usage_data.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/ee/gitlab/usage_data.rb). + +1. Remove the tests from [`spec/lib/gitlab/usage_data.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/lib/gitlab/usage_data_spec.rb) or [`ee/spec/lib/ee/gitlab/usage_data.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/lib/ee/gitlab/usage_data_spec.rb). diff --git a/doc/security/index.md b/doc/security/index.md index da3fa761f3f..73ac5028db5 100644 --- a/doc/security/index.md +++ b/doc/security/index.md @@ -26,6 +26,7 @@ type: index - [CI/CD variables](../ci/variables/index.md#cicd-variable-security) - [Token overview](token_overview.md) - [Project Import decompressed archive size limits](project_import_decompressed_archive_size_limits.md) +- [Responding to security incidents](responding_to_security_incidents.md) ## Securing your GitLab installation diff --git a/doc/security/responding_to_security_incidents.md b/doc/security/responding_to_security_incidents.md new file mode 100644 index 00000000000..b3bce785695 --- /dev/null +++ b/doc/security/responding_to_security_incidents.md @@ -0,0 +1,65 @@ +--- +stage: Manage +group: Authentication and Authorization +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +type: reference, howto +--- + +# Responding to security incidents **(FREE SELF)** + +When a security incident occurs, you should follow the processes defined by your organization. However, you might consider some +additional steps. These suggestions are intended to supplement existing security incident response processes within your organization. + +## Suspected compromised user account + +If you suspect that a user account or bot account has been compromised, consider taking the following steps: + +- [Block the user](../user/admin_area/moderate_users.md#block-a-user) to mitigate any current risk. +- [Review the audit events](../administration/audit_events.md) available to you to identify any suspicious account behavior. For + example: + - Suspicious sign-in events. + - Creation or deletion of personal access tokens, project access tokens, and group access tokens. + - Creation or deletion of SSH or GPG keys. + - Creation, modification, or deletion of two-factor authentication. + - Changes to repositories. + - Changes to group or project configurations. + - Addition or modification of runners. + - Addition or modification of webhooks or Git hooks. +- Reset any credentials the user might have had access to. For example, users with at least the Maintainer role can view protected + [CI/CD variables](../ci/variables/index.md) and [runner registration tokens](token_overview.md#runner-registration-tokens). +- [Reset the user's password](reset_user_password.md). +- Get the user to [enable two factor authentication](../user/profile/account/two_factor_authentication.md) (2FA), and consider [enforcing 2FA at the instance or group level](two_factor_authentication.md) +- After completing an investigation and mitigating impacts, unblock the user. + +## Suspected compromised instance **(FREE SELF)** + +Self-managed GitLab customers and administrators are responsible for: + +- The security of their underlying hosts. +- Keeping GitLab itself up to date. + +It is important to [regularly update GitLab](../policy/maintenance.md), update your operating system and its software, and harden your +hosts in accordance with vendor guidance. + +If you suspect that your GitLab instance has been compromised, consider taking the following steps: + +- [Review the audit events](../administration/audit_events.md) available to you for suspicious account behavior. +- [Review all users](../user/admin_area/moderate_users.md) (including the Administrative root user), and follow the steps in [Suspected compromised user account](#suspected-compromised-user-account) if necessary. +- Review the [Credentials Inventory](../user/admin_area/credentials_inventory.md), if available to you. +- Change any sensitive credentials, variables, tokens, and secrets. For example, those located in instance configuration, database, + CI/CD pipelines, or elsewhere. +- Upgrade to the latest version of GitLab and adopt a plan to upgrade after every security patch release. + +In addition, the suggestions below are common steps taken in incident response plans when servers are compromised by malicious actors. + +WARNING: +Use these suggestions at your own risk. + +- Save any server state and logs to a write-once location, for later investigation. +- Look for unrecognized background processes. +- Check for open ports on the system. +- Rebuild the host from a known-good backup or from scratch, and apply all the latest security patches. +- Review network logs for uncommon traffic. +- Establish network monitoring and network-level controls. +- Restrict inbound and outbound network access to authorized users and servers only. +- Ensure all logs are routed to an independent write-only datastore. diff --git a/doc/topics/git/lfs/index.md b/doc/topics/git/lfs/index.md index e1c21e1b06a..db63cee3523 100644 --- a/doc/topics/git/lfs/index.md +++ b/doc/topics/git/lfs/index.md @@ -62,7 +62,7 @@ Git as usual without redoing the command to track a file with the same extension cp ~/tmp/debian.iso ./ # copy a large file into the current directory git add . # add the large file to the project git commit -am "Added Debian iso" # commit the file meta data -git push origin master # sync the git repo and large file to the GitLab server +git push origin main # sync the git repo and large file to the GitLab server ``` **Make sure** that `.gitattributes` is tracked by Git. Otherwise Git @@ -85,7 +85,7 @@ If you already cloned the repository and you want to get the latest LFS object that are on the remote repository, such as for a branch from origin: ```shell -git lfs fetch origin master +git lfs fetch origin main ``` Make sure your files aren't listed in `.gitignore`, otherwise, they are ignored by Git diff --git a/doc/user/application_security/dast/checks/829.1.md b/doc/user/application_security/dast/checks/829.1.md new file mode 100644 index 00000000000..ca3d99c2bc9 --- /dev/null +++ b/doc/user/application_security/dast/checks/829.1.md @@ -0,0 +1,48 @@ +--- +stage: Secure +group: Dynamic Analysis +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Inclusion of Functionality from Untrusted Control Sphere + +## Description + +JavaScript or CSS source files are included from third party domains without +[Sub-Resource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). +If an attacker were to compromise the sites hosting these third party resources, they could inject malicious +script or CSS data in an attempt to compromise users of your application. However, if SRI was applied and an +attacker attempted to modify the contents of the script, the browser would not load the script and your +applications users would be protected from the malicious alterations. + +## Remediation + +All identified resources should be sourced from the same domain as the target application. If this is not +possible, it is strongly recommended that all `script` tags that implement `src` values, or `link` tags +that implement the `href` values include Sub-Resource Integrity. To generate SRI integrity values the +[srihash](https://www.srihash.org/) tool can be used, or by running one of the following commands: + +- `cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A` +- `shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64` + +The output of these tools must be added as additional attributes, in particular: `integrity` and either +`crossorigin=anonymous` or `crossorigin=use-credentials`. +An example of a valid SRI protected script tag can be found below: + +```html + +``` + +## Details + +| ID | Aggregated | CWE | Type | Risk | +|:---|:--------|:--------|:--------|:--------| +| 829.1 | true | 829 | Passive | Low | + +## Links + +- [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html#subresource-integrity) +- [CWE](https://cwe.mitre.org/data/definitions/829.html) +- [MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) diff --git a/doc/user/application_security/dast/checks/829.2.md b/doc/user/application_security/dast/checks/829.2.md new file mode 100644 index 00000000000..e6fada117f8 --- /dev/null +++ b/doc/user/application_security/dast/checks/829.2.md @@ -0,0 +1,47 @@ +--- +stage: Secure +group: Dynamic Analysis +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Invalid Sub-Resource Integrity values detected + +## Description + +JavaScript or CSS source files were found to contain invalid +[Sub-Resource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) +`integrity` values or a missing `crossorigin` value. These scripts or links should be investigated to +ensure they have not been maliciously altered. If in doubt, contact the owner of the scripts or replace +them with known good versions. + +## Remediation + +All identified resources should be sourced from the same domain as the target application. If this is not +possible, it is strongly recommended that all `script` tags that implement `src` values, or `link` tags +that implement the `href` values include Sub-Resource Integrity. To generate SRI integrity values the +[srihash](https://www.srihash.org/) tool can be used, or by running one of the following commands: + +- `cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A` +- `shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64` + +The output of these tools must be added as additional attributes, in particular: `integrity` and either +`crossorigin=anonymous` or `crossorigin=use-credentials`. +An example of a valid SRI protected script tag can be found below: + +```html + +``` + +## Details + +| ID | Aggregated | CWE | Type | Risk | +|:---|:--------|:--------|:--------|:--------| +| 829.2 | true | 829 | Passive | Medium | + +## Links + +- [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html#subresource-integrity) +- [CWE](https://cwe.mitre.org/data/definitions/829.html) +- [MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) diff --git a/doc/user/application_security/dast/checks/index.md b/doc/user/application_security/dast/checks/index.md index a1070792091..764e3c4a839 100644 --- a/doc/user/application_security/dast/checks/index.md +++ b/doc/user/application_security/dast/checks/index.md @@ -24,3 +24,5 @@ The [DAST browser-based crawler](../browser_based.md) provides a number of vulne | [598.3](598.3.md) | Use of GET request method with sensitive query strings (Authorization header details) | Medium | Passive | | [614.1](614.1.md) | Sensitive cookie without Secure attribute | Low | Passive | | [693.1](693.1.md) | Missing X-Content-Type-Options: nosniff | Low | Passive | +| [829.1](829.1.md) | Inclusion of Functionality from Untrusted Control Sphere | Low | Passive | +| [829.2](829.2.md) | Invalid Sub-Resource Integrity values detected | Medium | Passive | diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 28b3987605b..4810fb92345 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -120,6 +120,7 @@ The following table lists project permissions available for each role: | [Merge requests](project/merge_requests/index.md):
Add labels | | | ✓ | ✓ | ✓ | | [Merge requests](project/merge_requests/index.md):
Lock threads | | | ✓ | ✓ | ✓ | | [Merge requests](project/merge_requests/index.md):
Manage or accept | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):
[Resolve a thread](discussions/#resolve-a-thread) | | | ✓ | ✓ | ✓ | | [Merge requests](project/merge_requests/index.md):
Manage merge approval rules (project settings) | | | | ✓ | ✓ | | [Merge requests](project/merge_requests/index.md):
Delete | | | | | ✓ | | [Metrics dashboards](../operations/metrics/dashboards/index.md):
Manage user-starred metrics dashboards (*6*) | ✓ | ✓ | ✓ | ✓ | ✓ | diff --git a/lib/gitlab/insecure_key_fingerprint.rb b/lib/gitlab/insecure_key_fingerprint.rb index ef342f3819f..43ad64603a6 100644 --- a/lib/gitlab/insecure_key_fingerprint.rb +++ b/lib/gitlab/insecure_key_fingerprint.rb @@ -11,19 +11,12 @@ module Gitlab class InsecureKeyFingerprint attr_accessor :key - alias_attribute :fingerprint_md5, :fingerprint - - # # Gets the base64 encoded string representing a rsa or dsa key # def initialize(key_base64) @key = key_base64 end - def fingerprint - OpenSSL::Digest::MD5.hexdigest(Base64.decode64(@key)).scan(/../).join(':') - end - def fingerprint_sha256 Digest::SHA256.base64digest(Base64.decode64(@key)).scan(/../).join('').delete("=") end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 417871f6484..ed6931385af 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7029,6 +7029,9 @@ msgstr "" msgid "Changed assignee(s)." msgstr "" +msgid "Changed merge method to %{merge_method}" +msgstr "" + msgid "Changed reviewer(s)." msgstr "" @@ -25836,6 +25839,42 @@ msgstr "" msgid "Notify users by email when sign-in location is not recognized." msgstr "" +msgid "Notify|%{author_link}'s issue %{issue_reference_link} is due soon." +msgstr "" + +msgid "Notify|Author: %{author_name}" +msgstr "" + +msgid "Notify|Issue was %{issue_status} by %{updated_by}" +msgstr "" + +msgid "Notify|Issue was moved to another project." +msgstr "" + +msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict." +msgstr "" + +msgid "Notify|Merge request %{merge_request} was %{mr_status}" +msgstr "" + +msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}" +msgstr "" + +msgid "Notify|Merge request %{merge_request} was merged" +msgstr "" + +msgid "Notify|Merge request URL: %{merge_request_url}" +msgstr "" + +msgid "Notify|New issue: %{project_issue_url}" +msgstr "" + +msgid "Notify|This issue is due on: %{issue_due_date}" +msgstr "" + +msgid "Notify|You don't have access to the project." +msgstr "" + msgid "Nov" msgstr "" @@ -36884,6 +36923,9 @@ msgstr "" msgid "TagsPage|Repository has no tags yet." msgstr "" +msgid "TagsPage|Sorry, your filter produced no results." +msgstr "" + msgid "TagsPage|Tags" msgstr "" diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 08d7105a57e..0837664dcc3 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -364,6 +364,17 @@ RSpec.describe "Admin Runners" do create(:ci_runner, :instance, description: 'runner-red', tag_list: ['red']) end + it 'shows tags suggestions' do + visit admin_runners_path + + open_filtered_search_suggestions('Tags') + + page.within(search_bar_selector) do + expect(page).to have_content 'blue' + expect(page).to have_content 'red' + end + end + it 'shows correct runner when tag matches' do visit admin_runners_path @@ -709,6 +720,16 @@ RSpec.describe "Admin Runners" do wait_for_requests end + def open_filtered_search_suggestions(filter) + focus_filtered_search + + page.within(search_bar_selector) do + click_on filter + end + + wait_for_requests + end + def input_filtered_search_filter_is_only(filter, value) focus_filtered_search diff --git a/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb b/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb index d5151dd6beb..b430da376dd 100644 --- a/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb +++ b/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb @@ -17,7 +17,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do end context 'with available_runner_releases configured up to 14.1.1' do - let(:available_runner_releases) { %w[13.9.0 13.9.1 13.9.2 13.10.0 13.10.1 14.0.0 14.0.1 14.0.2 14.1.0 14.1.1] } + let(:available_runner_releases) { %w[13.9.0 13.9.1 13.9.2 13.10.0 13.10.1 14.0.0 14.0.1 14.0.2 14.1.0 14.1.1 14.1.1-rc3] } context 'with nil runner_version' do let(:runner_version) { nil } @@ -60,15 +60,20 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do context 'with valid params' do where(:runner_version, :expected_result) do - 'v14.1.0' | :not_available # not available since the GitLab instance is still on 14.0.x - 'v14.0.1' | :recommended # recommended upgrade since 14.0.2 is available - 'v14.0.2' | :not_available # not available since 14.0.2 is the latest 14.0.x release available - 'v13.10.1' | :available # available upgrade: 14.1.1 - 'v13.10.0' | :recommended # recommended upgrade since 13.10.1 is available - 'v13.9.2' | :recommended # recommended upgrade since backports are no longer released for this version - 'v13.9.0' | :recommended # recommended upgrade since backports are no longer released for this version - 'v13.8.1' | :recommended # recommended upgrade since build is too old (missing in records) - 'v11.4.1' | :recommended # recommended upgrade since build is too old (missing in records) + 'v14.1.0-rc3' | :not_available # not available since the GitLab instance is still on 14.0.x + 'v14.1.0~beta.1574.gf6ea9389' | :not_available # suffixes are correctly handled + 'v14.1.0/1.1.0' | :not_available # suffixes are correctly handled + 'v14.1.0' | :not_available # not available since the GitLab instance is still on 14.0.x + 'v14.0.1' | :recommended # recommended upgrade since 14.0.2 is available + 'v14.0.2' | :not_available # not available since 14.0.2 is the latest 14.0.x release available + 'v13.10.1' | :available # available upgrade: 14.1.1 + 'v13.10.1~beta.1574.gf6ea9389' | :available # suffixes are correctly handled + 'v13.10.1/1.1.0' | :available # suffixes are correctly handled + 'v13.10.0' | :recommended # recommended upgrade since 13.10.1 is available + 'v13.9.2' | :recommended # recommended upgrade since backports are no longer released for this version + 'v13.9.0' | :recommended # recommended upgrade since backports are no longer released for this version + 'v13.8.1' | :recommended # recommended upgrade since build is too old (missing in records) + 'v11.4.1' | :recommended # recommended upgrade since build is too old (missing in records) end with_them do diff --git a/spec/lib/gitlab/insecure_key_fingerprint_spec.rb b/spec/lib/gitlab/insecure_key_fingerprint_spec.rb index 2f3489edcd8..3a281574563 100644 --- a/spec/lib/gitlab/insecure_key_fingerprint_spec.rb +++ b/spec/lib/gitlab/insecure_key_fingerprint_spec.rb @@ -10,16 +10,9 @@ RSpec.describe Gitlab::InsecureKeyFingerprint do 'Jw0=' end - let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" } let(:fingerprint_sha256) { "MQHWhS9nhzUezUdD42ytxubZoBKrZLbyBZzxCkmnxXc" } - describe "#fingerprint" do - it "generates the key's fingerprint" do - expect(described_class.new(key.split[1]).fingerprint_md5).to eq(fingerprint) - end - end - - describe "#fingerprint" do + describe '#fingerprint_sha256' do it "generates the key's fingerprint" do expect(described_class.new(key.split[1]).fingerprint_sha256).to eq(fingerprint_sha256) end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 42187c3ef99..05b7bc39a74 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -134,28 +134,28 @@ RSpec.describe Ci::Runner do end context 'cost factors validations' do - it 'dissalows :private_projects_minutes_cost_factor being nil' do + it 'disallows :private_projects_minutes_cost_factor being nil' do runner = build(:ci_runner, private_projects_minutes_cost_factor: nil) expect(runner).to be_invalid expect(runner.errors.full_messages).to include('Private projects minutes cost factor needs to be non-negative') end - it 'dissalows :public_projects_minutes_cost_factor being nil' do + it 'disallows :public_projects_minutes_cost_factor being nil' do runner = build(:ci_runner, public_projects_minutes_cost_factor: nil) expect(runner).to be_invalid expect(runner.errors.full_messages).to include('Public projects minutes cost factor needs to be non-negative') end - it 'dissalows :private_projects_minutes_cost_factor being negative' do + it 'disallows :private_projects_minutes_cost_factor being negative' do runner = build(:ci_runner, private_projects_minutes_cost_factor: -1.1) expect(runner).to be_invalid expect(runner.errors.full_messages).to include('Private projects minutes cost factor needs to be non-negative') end - it 'dissalows :public_projects_minutes_cost_factor being negative' do + it 'disallows :public_projects_minutes_cost_factor being negative' do runner = build(:ci_runner, public_projects_minutes_cost_factor: -2.2) expect(runner).to be_invalid diff --git a/spec/models/packages/package_file_spec.rb b/spec/models/packages/package_file_spec.rb index fd453d8e5a9..f6af8f6a951 100644 --- a/spec/models/packages/package_file_spec.rb +++ b/spec/models/packages/package_file_spec.rb @@ -23,6 +23,28 @@ RSpec.describe Packages::PackageFile, type: :model do describe 'validations' do it { is_expected.to validate_presence_of(:package) } + + context 'with pypi package' do + let_it_be(:package) { create(:pypi_package) } + + let(:package_file) { package.package_files.first } + let(:status) { :default } + let(:file) { fixture_file_upload('spec/fixtures/dk.png') } + + subject { package.package_files.create!(file: file, file_name: package_file.file_name, status: status) } + + it 'can not save a duplicated file' do + expect { subject }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: File name has already been taken") + end + + context 'with a pending destruction package duplicated file' do + let(:status) { :pending_destruction } + + it 'can save it' do + expect { subject }.to change { package.package_files.count }.from(1).to(2) + end + end + end end context 'with package filenames' do diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb index b99a3d14fb9..6102e15012b 100644 --- a/spec/requests/api/graphql/ci/runner_spec.rb +++ b/spec/requests/api/graphql/ci/runner_spec.rb @@ -27,27 +27,14 @@ RSpec.describe 'Query.runner(id)' do let_it_be(:active_project_runner) { create(:ci_runner, :project) } - def get_runner(id) - case id - when :active_instance_runner - active_instance_runner - when :inactive_instance_runner - inactive_instance_runner - when :active_group_runner - active_group_runner - when :active_project_runner - active_project_runner - end - end - - shared_examples 'runner details fetch' do |runner_id| + shared_examples 'runner details fetch' do let(:query) do wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner'))) end let(:query_path) do [ - [:runner, { id: get_runner(runner_id).to_global_id.to_s }] + [:runner, { id: runner.to_global_id.to_s }] ] end @@ -57,7 +44,6 @@ RSpec.describe 'Query.runner(id)' do runner_data = graphql_data_at(:runner) expect(runner_data).not_to be_nil - runner = get_runner(runner_id) expect(runner_data).to match a_hash_including( 'id' => runner.to_global_id.to_s, 'description' => runner.description, @@ -90,14 +76,14 @@ RSpec.describe 'Query.runner(id)' do end end - shared_examples 'retrieval with no admin url' do |runner_id| + shared_examples 'retrieval with no admin url' do let(:query) do wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner'))) end let(:query_path) do [ - [:runner, { id: get_runner(runner_id).to_global_id.to_s }] + [:runner, { id: runner.to_global_id.to_s }] ] end @@ -107,7 +93,6 @@ RSpec.describe 'Query.runner(id)' do runner_data = graphql_data_at(:runner) expect(runner_data).not_to be_nil - runner = get_runner(runner_id) expect(runner_data).to match a_hash_including( 'id' => runner.to_global_id.to_s, 'adminUrl' => nil @@ -116,14 +101,14 @@ RSpec.describe 'Query.runner(id)' do end end - shared_examples 'retrieval by unauthorized user' do |runner_id| + shared_examples 'retrieval by unauthorized user' do let(:query) do wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner'))) end let(:query_path) do [ - [:runner, { id: get_runner(runner_id).to_global_id.to_s }] + [:runner, { id: runner.to_global_id.to_s }] ] end @@ -135,7 +120,9 @@ RSpec.describe 'Query.runner(id)' do end describe 'for active runner' do - it_behaves_like 'runner details fetch', :active_instance_runner + let(:runner) { active_instance_runner } + + it_behaves_like 'runner details fetch' context 'when tagList is not requested' do let(:query) do @@ -144,7 +131,7 @@ RSpec.describe 'Query.runner(id)' do let(:query_path) do [ - [:runner, { id: active_instance_runner.to_global_id.to_s }] + [:runner, { id: runner.to_global_id.to_s }] ] end @@ -193,7 +180,9 @@ RSpec.describe 'Query.runner(id)' do end describe 'for inactive runner' do - it_behaves_like 'runner details fetch', :inactive_instance_runner + let(:runner) { inactive_instance_runner } + + it_behaves_like 'runner details fetch' end describe 'for group runner request' do @@ -369,15 +358,21 @@ RSpec.describe 'Query.runner(id)' do let(:user) { create(:user) } context 'on instance runner' do - it_behaves_like 'retrieval by unauthorized user', :active_instance_runner + let(:runner) { active_instance_runner } + + it_behaves_like 'retrieval by unauthorized user' end context 'on group runner' do - it_behaves_like 'retrieval by unauthorized user', :active_group_runner + let(:runner) { active_group_runner } + + it_behaves_like 'retrieval by unauthorized user' end context 'on project runner' do - it_behaves_like 'retrieval by unauthorized user', :active_project_runner + let(:runner) { active_project_runner } + + it_behaves_like 'retrieval by unauthorized user' end end @@ -388,13 +383,17 @@ RSpec.describe 'Query.runner(id)' do group.add_user(user, Gitlab::Access::OWNER) end - it_behaves_like 'retrieval with no admin url', :active_group_runner + it_behaves_like 'retrieval with no admin url' do + let(:runner) { active_group_runner } + end end describe 'by unauthenticated user' do let(:user) { nil } - it_behaves_like 'retrieval by unauthorized user', :active_instance_runner + it_behaves_like 'retrieval by unauthorized user' do + let(:runner) { active_instance_runner } + end end describe 'Query limits' do diff --git a/spec/workers/packages/cleanup_package_file_worker_spec.rb b/spec/workers/packages/cleanup_package_file_worker_spec.rb index 33f89826312..23553ba472e 100644 --- a/spec/workers/packages/cleanup_package_file_worker_spec.rb +++ b/spec/workers/packages/cleanup_package_file_worker_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Packages::CleanupPackageFileWorker do - let_it_be(:package) { create(:package) } + let_it_be_with_reload(:package) { create(:package) } let(:worker) { described_class.new } @@ -23,7 +23,23 @@ RSpec.describe Packages::CleanupPackageFileWorker do expect(worker).to receive(:log_extra_metadata_on_done).twice expect { subject }.to change { Packages::PackageFile.count }.by(-1) - .and not_change { Packages::Package.count } + .and not_change { Packages::Package.count } + expect { package_file2.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + context 'with a duplicated PyPI package file' do + let_it_be_with_reload(:duplicated_package_file) { create(:package_file, package: package) } + + before do + package.update!(package_type: :pypi, version: '1.2.3') + duplicated_package_file.update_column(:file_name, package_file2.file_name) + end + + it 'deletes one of the duplicates' do + expect { subject }.to change { Packages::PackageFile.count }.by(-1) + .and not_change { Packages::Package.count } + expect { package_file2.reload }.to raise_error(ActiveRecord::RecordNotFound) + end end end diff --git a/tooling/bin/find_app_sec_approval b/tooling/bin/find_app_sec_approval new file mode 100755 index 00000000000..ea85617eb43 --- /dev/null +++ b/tooling/bin/find_app_sec_approval @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'gitlab' + +# This script is used to confirm that AppSec has approved upstream JiHu contributions +# +# It will error if the approval is missing from the MR when it is run. + +gitlab_token = ENV.fetch('PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE') +gitlab_endpoint = ENV.fetch('CI_API_V4_URL') +mr_project_path = ENV['CI_MERGE_REQUEST_PROJECT_PATH'] +mr_iid = ENV['CI_MERGE_REQUEST_IID'] +approval_label = "sec-planning::complete" + +warn "WARNING: CI_MERGE_REQUEST_PROJECT_PATH is missing." if mr_project_path.to_s.empty? +warn "WARNING: CI_MERGE_REQUEST_IID is missing." if mr_iid.to_s.empty? + +unless mr_project_path && mr_iid + warn "ERROR: Exiting as this does not appear to be a merge request pipeline." + exit +end + +Gitlab.configure do |config| + config.endpoint = gitlab_endpoint + config.private_token = gitlab_token +end + +if Gitlab.merge_request(mr_project_path, mr_iid).labels.include?(approval_label) + puts 'INFO: No action required.' +else + abort('ERROR: This merge request has not been approved by application security and is required prior to merge.') +end