summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-07 15:09:57 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-07 15:09:57 +0000
commitfe4751154c331e35c0e6575a3aedc02b210a1c63 (patch)
tree737b3a67b895d0bda4be915e593f86ca089f65ec
parent630c555b11c0fc64d3f0c1ec13b314e2efe3f7ee (diff)
downloadgitlab-ce-fe4751154c331e35c0e6575a3aedc02b210a1c63.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml10
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml9
-rw-r--r--.rubocop_todo.yml10
-rw-r--r--.rubocop_todo/layout/space_around_method_call_operator.yml32
-rw-r--r--.rubocop_todo/lint/missing_cop_enable_directive.yml196
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--app/models/packages/package_file.rb2
-rw-r--r--app/views/notify/issue_due_email.html.haml4
-rw-r--r--app/views/notify/issue_moved_email.html.haml8
-rw-r--r--app/views/notify/issue_status_changed_email.html.haml2
-rw-r--r--app/views/notify/merge_request_status_email.html.haml4
-rw-r--r--app/views/notify/merge_request_status_email.text.haml6
-rw-r--r--app/views/notify/merge_request_unmergeable_email.html.haml2
-rw-r--r--app/views/notify/merge_request_unmergeable_email.text.haml6
-rw-r--r--app/views/notify/merged_merge_request_email.html.haml2
-rw-r--r--app/views/notify/merged_merge_request_email.text.haml6
-rw-r--r--app/views/projects/tags/index.html.haml13
-rw-r--r--app/views/shared/_outdated_browser.html.haml3
-rw-r--r--app/workers/concerns/packages/cleanup_artifact_worker.rb4
-rw-r--r--db/post_migrate/20220325000001_finalize_index_for_ci_job_artifacts_unlocked_with_expire_at.rb17
-rw-r--r--db/schema_migrations/202203250000011
-rw-r--r--db/structure.sql2
-rw-r--r--doc/administration/index.md1
-rw-r--r--doc/api/discussions.md6
-rw-r--r--doc/development/cicd/schema.md64
-rw-r--r--doc/development/service_ping/metrics_instrumentation.md31
-rw-r--r--doc/security/index.md1
-rw-r--r--doc/security/responding_to_security_incidents.md65
-rw-r--r--doc/topics/git/lfs/index.md4
-rw-r--r--doc/user/application_security/dast/checks/829.1.md48
-rw-r--r--doc/user/application_security/dast/checks/829.2.md47
-rw-r--r--doc/user/application_security/dast/checks/index.md2
-rw-r--r--doc/user/permissions.md1
-rw-r--r--lib/gitlab/insecure_key_fingerprint.rb7
-rw-r--r--locale/gitlab.pot42
-rw-r--r--spec/features/admin/admin_runners_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/runner_upgrade_check_spec.rb25
-rw-r--r--spec/lib/gitlab/insecure_key_fingerprint_spec.rb9
-rw-r--r--spec/models/ci/runner_spec.rb8
-rw-r--r--spec/models/packages/package_file_spec.rb22
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb57
-rw-r--r--spec/workers/packages/cleanup_package_file_worker_spec.rb20
-rwxr-xr-xtooling/bin/find_app_sec_approval33
43 files changed, 748 insertions, 107 deletions
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
+<script src="https://example.com/example-framework.js"
+ integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
+ crossorigin="anonymous"></script>
+```
+
+## 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
+<script src="https://example.com/example-framework.js"
+ integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
+ crossorigin="anonymous"></script>
+```
+
+## 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):<br>Add labels | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Lock threads | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Manage or accept | | | ✓ | ✓ | ✓ |
+| [Merge requests](project/merge_requests/index.md):<br>[Resolve a thread](discussions/#resolve-a-thread) | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Manage merge approval rules (project settings) | | | | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Delete | | | | | ✓ |
| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>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