Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-04-23 00:08:09 +00:00
parent 940dfdfee4
commit d7ad87b535
68 changed files with 1505 additions and 102 deletions

View File

@ -1203,6 +1203,12 @@ SidekiqLoadBalancing/WorkerDataConsistency:
- 'app/workers/**/*'
- 'ee/app/workers/**/*'
Sidekiq/EnforceDatabaseHealthSignalDeferral:
Enabled: true
Include:
- 'app/workers/**/*'
- 'ee/app/workers/**/*'
Graphql/ResourceNotAvailableError:
Exclude:
# Definition of `raise_resource_not_available_error!`

View File

@ -2469,7 +2469,6 @@ RSpec/NamedSubject:
- 'spec/models/packages/dependency_link_spec.rb'
- 'spec/models/packages/dependency_spec.rb'
- 'spec/models/packages/npm/metadata_cache_spec.rb'
- 'spec/models/packages/package_file_spec.rb'
- 'spec/models/packages/package_spec.rb'
- 'spec/models/packages/rpm/repository_file_spec.rb'
- 'spec/models/plan_limits_spec.rb'

View File

@ -0,0 +1,207 @@
---
Sidekiq/EnforceDatabaseHealthSignalDeferral:
Details: grace period
Exclude:
- 'app/workers/analytics/usage_trends/count_job_trigger_worker.rb'
- 'app/workers/analytics/usage_trends/counter_job_worker.rb'
- 'app/workers/anti_abuse/ban_duplicate_users_worker.rb'
- 'app/workers/anti_abuse/spam_abuse_events_worker.rb'
- 'app/workers/anti_abuse/trust_score_cleanup_worker.rb'
- 'app/workers/anti_abuse/trust_score_worker.rb'
- 'app/workers/authorized_project_update/enqueue_group_members_refresh_authorized_projects_worker.rb'
- 'app/workers/authorized_project_update/periodic_recalculate_worker.rb'
- 'app/workers/authorized_project_update/user_refresh_from_replica_worker.rb'
- 'app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb'
- 'app/workers/authorized_project_update/user_refresh_with_low_urgency_worker.rb'
- 'app/workers/chat_notification_worker.rb'
- 'app/workers/ci/cancel_redundant_pipelines_worker.rb'
- 'app/workers/ci/catalog/resources/aggregate_last30_day_usage_worker.rb'
- 'app/workers/ci/catalog/resources/cleanup_last_usages_worker.rb'
- 'app/workers/ci/destroy_old_pipelines_worker.rb'
- 'app/workers/ci/execute_build_hooks_worker.rb'
- 'app/workers/ci/job_token/log_authorization_worker.rb'
- 'app/workers/ci/low_urgency_cancel_redundant_pipelines_worker.rb'
- 'app/workers/ci/merge_requests/add_todo_when_build_fails_worker.rb'
- 'app/workers/ci/parse_secure_file_metadata_worker.rb'
- 'app/workers/ci/pipeline_cleanup_ref_worker.rb'
- 'app/workers/ci/pipeline_finished_worker.rb'
- 'app/workers/ci/runners/process_runner_version_update_worker.rb'
- 'app/workers/ci/runners/reconcile_existing_runner_versions_cron_worker.rb'
- 'app/workers/ci/runners/stale_machines_cleanup_cron_worker.rb'
- 'app/workers/ci/schedule_old_pipelines_removal_cron_worker.rb'
- 'app/workers/ci/track_failed_build_worker.rb'
- 'app/workers/cleanup_container_repository_worker.rb'
- 'app/workers/clusters/agents/notify_git_push_worker.rb'
- 'app/workers/clusters/migration/install_agent_worker.rb'
- 'app/workers/concurrency_limit/resume_worker.rb'
- 'app/workers/container_expiration_policies/cleanup_container_repository_worker.rb'
- 'app/workers/container_registry/delete_container_repository_worker.rb'
- 'app/workers/container_registry/record_data_repair_detail_worker.rb'
- 'app/workers/counters/cleanup_refresh_worker.rb'
- 'app/workers/dependency_proxy/cleanup_blob_worker.rb'
- 'app/workers/dependency_proxy/cleanup_manifest_worker.rb'
- 'app/workers/design_management/copy_design_collection_worker.rb'
- 'app/workers/emails_on_push_worker.rb'
- 'app/workers/file_hook_worker.rb'
- 'app/workers/flush_counter_increments_worker.rb'
- 'app/workers/gitlab/version/version_check_cron_worker.rb'
- 'app/workers/google_cloud/fetch_google_ip_list_worker.rb'
- 'app/workers/incident_management/close_incident_worker.rb'
- 'app/workers/integrations/create_external_cross_reference_worker.rb'
- 'app/workers/integrations/execute_worker.rb'
- 'app/workers/integrations/group_mention_worker.rb'
- 'app/workers/integrations/irker_worker.rb'
- 'app/workers/integrations/jira_connect/remove_branch_worker.rb'
- 'app/workers/integrations/propagate_integration_descendant_worker.rb'
- 'app/workers/integrations/slack_event_worker.rb'
- 'app/workers/issuables/clear_groups_issue_counter_worker.rb'
- 'app/workers/issues/rebalancing_worker.rb'
- 'app/workers/issues/reschedule_stuck_issue_rebalances_worker.rb'
- 'app/workers/jira_connect/forward_event_worker.rb'
- 'app/workers/jira_connect/jira_cloud_app_deactivation_worker.rb'
- 'app/workers/jira_connect/retry_request_worker.rb'
- 'app/workers/jira_connect/send_uninstalled_hook_worker.rb'
- 'app/workers/jira_connect/sync_branch_worker.rb'
- 'app/workers/jira_connect/sync_builds_worker.rb'
- 'app/workers/jira_connect/sync_deployments_worker.rb'
- 'app/workers/jira_connect/sync_feature_flags_worker.rb'
- 'app/workers/jira_connect/sync_merge_request_worker.rb'
- 'app/workers/jira_connect/sync_project_worker.rb'
- 'app/workers/member_invitation_reminder_emails_worker.rb'
- 'app/workers/members/expiring_email_notification_worker.rb'
- 'app/workers/members/expiring_worker.rb'
- 'app/workers/members/prune_deletions_worker.rb'
- 'app/workers/members/schedule_prune_deletions_worker.rb'
- 'app/workers/merge_requests/cleanup_ref_worker.rb'
- 'app/workers/merge_requests/close_issue_worker.rb'
- 'app/workers/merge_requests/create_approval_event_worker.rb'
- 'app/workers/merge_requests/create_approval_note_worker.rb'
- 'app/workers/merge_requests/execute_approval_hooks_worker.rb'
- 'app/workers/merge_requests/resolve_todos_after_approval_worker.rb'
- 'app/workers/metrics/patched_files_worker.rb'
- 'app/workers/ml/experiment_tracking/associate_ml_candidate_to_package_worker.rb'
- 'app/workers/packages/cleanup/delete_orphaned_dependencies_worker.rb'
- 'app/workers/packages/cleanup/execute_policy_worker.rb'
- 'app/workers/packages/cleanup_package_file_worker.rb'
- 'app/workers/packages/mark_package_files_for_destruction_worker.rb'
- 'app/workers/packages/npm/deprecate_package_worker.rb'
- 'app/workers/packages/terraform_module/process_package_file_worker.rb'
- 'app/workers/pages/deactivate_mr_deployments_worker.rb'
- 'app/workers/pause_control/resume_worker.rb'
- 'app/workers/pipeline_metrics_worker.rb'
- 'app/workers/project_export_worker.rb'
- 'app/workers/projects/after_import_worker.rb'
- 'app/workers/projects/finalize_project_statistics_refresh_worker.rb'
- 'app/workers/projects/import_export/after_import_merge_requests_worker.rb'
- 'app/workers/projects/import_export/import_completion_notification_worker.rb'
- 'app/workers/projects/import_export/parallel_project_export_worker.rb'
- 'app/workers/projects/import_export/relation_export_worker.rb'
- 'app/workers/projects/import_export/relation_import_worker.rb'
- 'app/workers/projects/inactive_projects_deletion_cron_worker.rb'
- 'app/workers/projects/record_target_platforms_worker.rb'
- 'app/workers/propagate_integration_group_worker.rb'
- 'app/workers/propagate_integration_inherit_descendant_worker.rb'
- 'app/workers/propagate_integration_inherit_worker.rb'
- 'app/workers/propagate_integration_project_worker.rb'
- 'app/workers/propagate_integration_worker.rb'
- 'app/workers/reactive_caching_worker.rb'
- 'app/workers/remove_unaccepted_member_invites_worker.rb'
- 'app/workers/terraform/states/destroy_worker.rb'
- 'app/workers/update_container_registry_info_worker.rb'
- 'app/workers/virtual_registries/packages/cache/destroy_orphan_entries_worker.rb'
- 'app/workers/web_hook_worker.rb'
- 'app/workers/web_hooks/log_destroy_worker.rb'
- 'app/workers/web_hooks/log_execution_worker.rb'
- 'app/workers/work_items/user_preferences/destroy_worker.rb'
- 'app/workers/x509_issuer_crl_check_worker.rb'
- 'ee/app/workers/ai/active_context/bulk_process_worker.rb'
- 'ee/app/workers/ai/active_context/migration_worker.rb'
- 'ee/app/workers/ai/repository_xray/scan_dependencies_worker.rb'
- 'ee/app/workers/analytics/code_suggestions_events_backfill_worker.rb'
- 'ee/app/workers/analytics/duo_chat_events_backfill_worker.rb'
- 'ee/app/workers/anti_abuse/new_abuse_report_worker.rb'
- 'ee/app/workers/app_config/cascade_duo_features_enabled_worker.rb'
- 'ee/app/workers/ci/minutes/update_project_and_namespace_usage_worker.rb'
- 'ee/app/workers/ci/runners/stale_group_runners_prune_cron_worker.rb'
- 'ee/app/workers/ci/update_approval_rules_for_related_mrs_worker.rb'
- 'ee/app/workers/compliance_management/chain_of_custody_report_worker.rb'
- 'ee/app/workers/compliance_management/compliance_framework/project_compliance_statuses_removal_worker.rb'
- 'ee/app/workers/compliance_management/compliance_framework/project_requirement_statuses_export_mailer_worker.rb'
- 'ee/app/workers/compliance_management/framework_export_mailer_worker.rb'
- 'ee/app/workers/compliance_management/merge_requests/compliance_violations_consistency_worker.rb'
- 'ee/app/workers/compliance_management/pipl/block_pipl_users_worker.rb'
- 'ee/app/workers/compliance_management/pipl/delete_pipl_users_worker.rb'
- 'ee/app/workers/compliance_management/pipl/send_recurring_notifications_worker.rb'
- 'ee/app/workers/compliance_management/pipl/update_user_country_access_logs_worker.rb'
- 'ee/app/workers/compliance_management/pipl/user_paid_status_check_worker.rb'
- 'ee/app/workers/compliance_management/project_compliance_evaluator_worker.rb'
- 'ee/app/workers/compliance_management/project_framework_export_mailer_worker.rb'
- 'ee/app/workers/compliance_management/standards/base_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/at_least_two_approvals_group_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/at_least_two_approvals_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/dast_group_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/dast_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/prevent_approval_by_author_group_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/prevent_approval_by_author_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/prevent_approval_by_committer_group_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/prevent_approval_by_committer_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb'
- 'ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb'
- 'ee/app/workers/compliance_management/standards/group_base_worker.rb'
- 'ee/app/workers/compliance_management/standards/refresh_worker.rb'
- 'ee/app/workers/compliance_management/standards/soc2/at_least_one_non_author_approval_group_worker.rb'
- 'ee/app/workers/compliance_management/standards/soc2/at_least_one_non_author_approval_worker.rb'
- 'ee/app/workers/compliance_management/standards_adherence_export_mailer_worker.rb'
- 'ee/app/workers/compliance_management/timeout_pending_external_controls_worker.rb'
- 'ee/app/workers/compliance_management/update_default_framework_worker.rb'
- 'ee/app/workers/compliance_management/violation_export_mailer_worker.rb'
- 'ee/app/workers/elastic/migration_worker.rb'
- 'ee/app/workers/elastic_index_bulk_cron_worker.rb'
- 'ee/app/workers/elastic_index_initial_bulk_cron_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/add_on_purchases/bulk_refresh_user_assignments_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/add_on_purchases/cleanup_user_add_on_assignment_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/add_on_purchases/refresh_user_assignments_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/add_on_purchases/schedule_bulk_refresh_user_assignments_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/member_management/apply_pending_member_approvals_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/members/added_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/members/destroyed_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/members/record_last_activity_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/refresh_seats_worker.rb'
- 'ee/app/workers/gitlab_subscriptions/schedule_refresh_seats_worker.rb'
- 'ee/app/workers/llm/completion_worker.rb'
- 'ee/app/workers/llm/namespace_access_cache_reset_worker.rb'
- 'ee/app/workers/members/delete_pending_members_worker.rb'
- 'ee/app/workers/merge_requests/approval_metrics_event_worker.rb'
- 'ee/app/workers/merge_requests/capture_suggested_reviewers_accepted_worker.rb'
- 'ee/app/workers/merge_requests/create_approvals_reset_note_worker.rb'
- 'ee/app/workers/merge_requests/duo_code_review_chat_worker.rb'
- 'ee/app/workers/merge_requests/fetch_suggested_reviewers_worker.rb'
- 'ee/app/workers/merge_requests/notify_approvers_worker.rb'
- 'ee/app/workers/merge_requests/process_merge_audit_event_worker.rb'
- 'ee/app/workers/merge_requests/stream_approval_audit_event_worker.rb'
- 'ee/app/workers/namespaces/cascade_duo_features_enabled_worker.rb'
- 'ee/app/workers/namespaces/remove_dormant_members_worker.rb'
- 'ee/app/workers/namespaces/schedule_dormant_member_removal_worker.rb'
- 'ee/app/workers/namespaces/storage_usage_export_worker.rb'
- 'ee/app/workers/onboarding/progress_tracking_worker.rb'
- 'ee/app/workers/package_metadata/advisories_sync_worker.rb'
- 'ee/app/workers/package_metadata/cve_enrichment_sync_worker.rb'
- 'ee/app/workers/package_metadata/global_advisory_scan_worker.rb'
- 'ee/app/workers/package_metadata/licenses_sync_worker.rb'
- 'ee/app/workers/projects/deregister_suggested_reviewers_project_worker.rb'
- 'ee/app/workers/projects/disable_legacy_open_source_license_for_inactive_projects_worker.rb'
- 'ee/app/workers/projects/register_suggested_reviewers_project_worker.rb'
- 'ee/app/workers/sbom/create_occurrences_vulnerabilities_worker.rb'
- 'ee/app/workers/sbom/process_vulnerabilities_worker.rb'
- 'ee/app/workers/search/elastic_default_branch_changed_worker.rb'
- 'ee/app/workers/search/elastic_index_embedding_bulk_cron_worker.rb'
- 'ee/app/workers/search/zoekt/default_branch_changed_worker.rb'
- 'ee/app/workers/security/policies/report_security_policies_metrics_worker.rb'
- 'ee/app/workers/security/scan_result_policies/sync_any_merge_request_approval_rules_worker.rb'
- 'ee/app/workers/security/scan_result_policies/sync_merge_request_approvals_worker.rb'
- 'ee/app/workers/security/scans/purge_by_job_id_worker.rb'
- 'ee/app/workers/system_access/group_saml_microsoft_group_sync_worker.rb'
- 'ee/app/workers/system_access/saml_microsoft_group_sync_worker.rb'
- 'ee/app/workers/vulnerabilities/orphaned_remediations_cleanup_worker.rb'
- 'ee/app/workers/vulnerabilities/remove_all_vulnerabilities_worker.rb'
- 'ee/app/workers/work_items/validate_epic_work_item_sync_worker.rb'

View File

@ -653,7 +653,7 @@ gem 'spamcheck', '~> 1.3.0', feature_category: :insider_threat
gem 'gitaly', '~> 17.8.0', feature_category: :gitaly
# KAS GRPC protocol definitions
gem 'gitlab-kas-grpc', '~> 17.9.0.pre.rc2', feature_category: :deployment_management
gem 'gitlab-kas-grpc', '~> 17.10.4', feature_category: :deployment_management
# Lock the version before issues below are resolved:
# https://gitlab.com/gitlab-org/gitlab/-/issues/473169#note_2028352939

View File

@ -204,7 +204,7 @@
{"name":"fog-google","version":"1.24.1","platform":"ruby","checksum":"dcd64ec5d12ed53f269afd7a88738b453e5150ef72b451900bb7abf3678358e0"},
{"name":"fog-json","version":"1.2.0","platform":"ruby","checksum":"dd4f5ab362dbc72b687240bba9d2dd841d5dfe888a285797533f85c03ea548fe"},
{"name":"fog-local","version":"0.8.0","platform":"ruby","checksum":"263b2d09e54c69d1b87ad7f235a1a1e53c8a674edcedf7512c1715765ad7ef79"},
{"name":"fog-xml","version":"0.1.3","platform":"ruby","checksum":"5604c42649ebb0d8a31bd973aa000c2dd0127f1c1c4c174b69266a2e78e37410"},
{"name":"fog-xml","version":"0.1.5","platform":"ruby","checksum":"52b9fea10701461dd3eaf9d9839702169b418dbbf50426786b9b74fade373bd6"},
{"name":"formatador","version":"0.2.5","platform":"ruby","checksum":"80821869ddacb79e72870ff4bb1531efacd278c04f2df26bc6b4529ee13582bd"},
{"name":"forwardable","version":"1.3.3","platform":"ruby","checksum":"f17df4bd6afa6f46a003217023fe5716ef88ce261f5c4cf0edbdeed6470cafac"},
{"name":"fugit","version":"1.11.1","platform":"ruby","checksum":"e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868"},
@ -230,7 +230,7 @@
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-darwin","checksum":"1e322c51ec338a6958010a062005285f335318c2a4b2dee71c2848468498c08d"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-gnu","checksum":"e8086a21a4e3187d76fa89eecac88aa57a89627de2a3b789d70d4844efe881db"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-musl","checksum":"f934efe5efc53d36ea00a030cc0d530bad81901ef782b7774dd0bfaef73f1c37"},
{"name":"gitlab-kas-grpc","version":"17.9.1","platform":"ruby","checksum":"fd480c1669c741ceab8d5f86b7e5e32b71f4f25af8b523725382dae425aaa958"},
{"name":"gitlab-kas-grpc","version":"17.10.4","platform":"ruby","checksum":"eef69a52b39ea69f7c79ba1785b37f985187a8609744d2b17336b738402858b1"},
{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},
{"name":"gitlab-mail_room","version":"0.0.27","platform":"ruby","checksum":"05c07db892094cf5747ea00afb0a95c5a5406e05f34ae779f4388f2ddf962316"},
@ -282,7 +282,7 @@
{"name":"google-protobuf","version":"3.25.6","platform":"x86_64-darwin","checksum":"0ddac5fcfa104531891fc15d26706e168397e0cc4ab4f9f8e1869035ab4768da"},
{"name":"google-protobuf","version":"3.25.6","platform":"x86_64-linux","checksum":"5334ae993505fb1e409563f95afd720a868d0f2182865d05280943f9be6c22df"},
{"name":"googleapis-common-protos","version":"1.4.0","platform":"ruby","checksum":"da2380fb5ab1563580816c74e8d684ac17512c3654c829a3ee84f6d6139de382"},
{"name":"googleapis-common-protos-types","version":"1.18.0","platform":"ruby","checksum":"280d19dcf431f86b9ff7ed8b23994915c5f4f7a0282ad3e870a2d3595976559f"},
{"name":"googleapis-common-protos-types","version":"1.19.0","platform":"ruby","checksum":"aecb76ca5326f8bcc47ab083259bbc4971d07e87f56808af7e210669d9765694"},
{"name":"googleauth","version":"1.8.1","platform":"ruby","checksum":"814adadaaa1221dce72a67131e3ecbd6d23491a161ec84fb15fd353b87d8c9e7"},
{"name":"gpgme","version":"2.0.24","platform":"ruby","checksum":"53eccd7042abb4fd5c78f30bc9ed075b1325e6450eab207f2f6a1e7e28ae3b64"},
{"name":"grape","version":"2.0.0","platform":"ruby","checksum":"3aeff94c17e84ccead4ff98833df691e7da0c108878cc128ca31f80c1047494a"},

View File

@ -700,7 +700,7 @@ GEM
multi_json (~> 1.10)
fog-local (0.8.0)
fog-core (>= 1.27, < 3.0)
fog-xml (0.1.3)
fog-xml (0.1.5)
fog-core
nokogiri (>= 1.5.11, < 2.0.0)
formatador (0.2.5)
@ -762,7 +762,7 @@ GEM
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.29)
rb_sys (~> 0.9.109)
gitlab-kas-grpc (17.9.1)
gitlab-kas-grpc (17.10.4)
grpc (~> 1.0)
gitlab-labkit (0.37.0)
actionpack (>= 5.0.0, < 8.1.0)
@ -913,7 +913,7 @@ GEM
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27)
googleapis-common-protos-types (1.18.0)
googleapis-common-protos-types (1.19.0)
google-protobuf (>= 3.18, < 5.a)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
@ -2135,7 +2135,7 @@ DEPENDENCIES
gitlab-glfm-markdown (~> 0.0.29)
gitlab-housekeeper!
gitlab-http!
gitlab-kas-grpc (~> 17.9.0.pre.rc2)
gitlab-kas-grpc (~> 17.10.4)
gitlab-labkit (~> 0.37.0)
gitlab-license (~> 2.6)
gitlab-mail_room (~> 0.0.24)

View File

@ -204,7 +204,7 @@
{"name":"fog-google","version":"1.24.1","platform":"ruby","checksum":"dcd64ec5d12ed53f269afd7a88738b453e5150ef72b451900bb7abf3678358e0"},
{"name":"fog-json","version":"1.2.0","platform":"ruby","checksum":"dd4f5ab362dbc72b687240bba9d2dd841d5dfe888a285797533f85c03ea548fe"},
{"name":"fog-local","version":"0.8.0","platform":"ruby","checksum":"263b2d09e54c69d1b87ad7f235a1a1e53c8a674edcedf7512c1715765ad7ef79"},
{"name":"fog-xml","version":"0.1.3","platform":"ruby","checksum":"5604c42649ebb0d8a31bd973aa000c2dd0127f1c1c4c174b69266a2e78e37410"},
{"name":"fog-xml","version":"0.1.5","platform":"ruby","checksum":"52b9fea10701461dd3eaf9d9839702169b418dbbf50426786b9b74fade373bd6"},
{"name":"formatador","version":"0.2.5","platform":"ruby","checksum":"80821869ddacb79e72870ff4bb1531efacd278c04f2df26bc6b4529ee13582bd"},
{"name":"forwardable","version":"1.3.3","platform":"ruby","checksum":"f17df4bd6afa6f46a003217023fe5716ef88ce261f5c4cf0edbdeed6470cafac"},
{"name":"fugit","version":"1.11.1","platform":"ruby","checksum":"e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868"},
@ -230,7 +230,7 @@
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-darwin","checksum":"1e322c51ec338a6958010a062005285f335318c2a4b2dee71c2848468498c08d"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-gnu","checksum":"e8086a21a4e3187d76fa89eecac88aa57a89627de2a3b789d70d4844efe881db"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-musl","checksum":"f934efe5efc53d36ea00a030cc0d530bad81901ef782b7774dd0bfaef73f1c37"},
{"name":"gitlab-kas-grpc","version":"17.9.1","platform":"ruby","checksum":"fd480c1669c741ceab8d5f86b7e5e32b71f4f25af8b523725382dae425aaa958"},
{"name":"gitlab-kas-grpc","version":"17.10.4","platform":"ruby","checksum":"eef69a52b39ea69f7c79ba1785b37f985187a8609744d2b17336b738402858b1"},
{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},
{"name":"gitlab-mail_room","version":"0.0.27","platform":"ruby","checksum":"05c07db892094cf5747ea00afb0a95c5a5406e05f34ae779f4388f2ddf962316"},
@ -282,7 +282,7 @@
{"name":"google-protobuf","version":"3.25.6","platform":"x86_64-darwin","checksum":"0ddac5fcfa104531891fc15d26706e168397e0cc4ab4f9f8e1869035ab4768da"},
{"name":"google-protobuf","version":"3.25.6","platform":"x86_64-linux","checksum":"5334ae993505fb1e409563f95afd720a868d0f2182865d05280943f9be6c22df"},
{"name":"googleapis-common-protos","version":"1.4.0","platform":"ruby","checksum":"da2380fb5ab1563580816c74e8d684ac17512c3654c829a3ee84f6d6139de382"},
{"name":"googleapis-common-protos-types","version":"1.18.0","platform":"ruby","checksum":"280d19dcf431f86b9ff7ed8b23994915c5f4f7a0282ad3e870a2d3595976559f"},
{"name":"googleapis-common-protos-types","version":"1.19.0","platform":"ruby","checksum":"aecb76ca5326f8bcc47ab083259bbc4971d07e87f56808af7e210669d9765694"},
{"name":"googleauth","version":"1.8.1","platform":"ruby","checksum":"814adadaaa1221dce72a67131e3ecbd6d23491a161ec84fb15fd353b87d8c9e7"},
{"name":"gpgme","version":"2.0.24","platform":"ruby","checksum":"53eccd7042abb4fd5c78f30bc9ed075b1325e6450eab207f2f6a1e7e28ae3b64"},
{"name":"grape","version":"2.0.0","platform":"ruby","checksum":"3aeff94c17e84ccead4ff98833df691e7da0c108878cc128ca31f80c1047494a"},

View File

@ -712,7 +712,7 @@ GEM
multi_json (~> 1.10)
fog-local (0.8.0)
fog-core (>= 1.27, < 3.0)
fog-xml (0.1.3)
fog-xml (0.1.5)
fog-core
nokogiri (>= 1.5.11, < 2.0.0)
formatador (0.2.5)
@ -774,7 +774,7 @@ GEM
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.29)
rb_sys (~> 0.9.109)
gitlab-kas-grpc (17.9.1)
gitlab-kas-grpc (17.10.4)
grpc (~> 1.0)
gitlab-labkit (0.37.0)
actionpack (>= 5.0.0, < 8.1.0)
@ -925,7 +925,7 @@ GEM
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27)
googleapis-common-protos-types (1.18.0)
googleapis-common-protos-types (1.19.0)
google-protobuf (>= 3.18, < 5.a)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
@ -2169,7 +2169,7 @@ DEPENDENCIES
gitlab-glfm-markdown (~> 0.0.29)
gitlab-housekeeper!
gitlab-http!
gitlab-kas-grpc (~> 17.9.0.pre.rc2)
gitlab-kas-grpc (~> 17.10.4)
gitlab-labkit (~> 0.37.0)
gitlab-license (~> 2.6)
gitlab-mail_room (~> 0.0.24)

View File

@ -8,6 +8,7 @@ module Packages
def package_files
files = by_conan_file_type(super)
files = by_recipe_revision(files)
files = by_package_revision(files)
by_conan_package_reference(files)
end
@ -32,6 +33,16 @@ module Packages
files.with_conan_recipe_revision(params[:recipe_revision])
end
end
def by_package_revision(files)
return files unless params[:package_revision]
if params[:package_revision] == Packages::Conan::FileMetadatum::DEFAULT_REVISION
files.without_conan_package_revision.with_conan_file_type(:package_file)
else
files.with_conan_package_revision(params[:package_revision])
end
end
end
end
end

View File

@ -13,17 +13,22 @@ module Clusters
validates :template_name, length: { maximum: 1024 }
validates :tracked_objects, json_schema: { filename: 'clusters_agents_managed_resource_tracked_objects' }
scope :order_id_desc, -> { order(id: :desc) }
enum :status, {
processing: 0,
completed: 1,
failed: 2
failed: 2,
deleting: 3,
deleted: 4,
delete_failed: 5
}
enum :deletion_strategy, {
never: 0,
on_stop: 1,
on_delete: 2
}
}, prefix: true
end
end
end

View File

@ -30,6 +30,7 @@ class Environment < ApplicationRecord
has_many :successful_deployments, -> { success }, class_name: 'Deployment'
has_many :active_deployments, -> { active }, class_name: 'Deployment'
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :environment
has_many :managed_resources, class_name: 'Clusters::Agents::ManagedResource', inverse_of: :environment
# NOTE: If you preload multiple last deployments of environments, use Preloaders::Environments::DeploymentPreloader.
has_one :last_deployment, -> { success.ordered }, class_name: 'Deployment', inverse_of: :environment

View File

@ -113,6 +113,16 @@ class Packages::PackageFile < ApplicationRecord
.where(packages_conan_file_metadata: { recipe_revision_id: nil })
end
scope :with_conan_package_revision, ->(package_revision) do
joins(conan_file_metadatum: :package_revision)
.where(packages_conan_package_revisions: { revision: package_revision })
end
scope :without_conan_package_revision, -> do
joins(:conan_file_metadatum)
.where(packages_conan_file_metadata: { package_revision_id: nil })
end
def self.most_recent!
recent.first!
end

View File

@ -0,0 +1,65 @@
# frozen_string_literal: true
module Clusters
module Agents
module ManagedResources
class DeleteService
POLLING_SCHEDULE = [
10.seconds,
30.seconds,
5.minutes,
30.minutes,
1.hour
].freeze
def initialize(managed_resource, attempt_count: nil)
@managed_resource = managed_resource
@attempt_count = attempt_count || 0
end
def execute
return unless managed_resource.deleting?
response = kas_client.delete_environment(managed_resource:)
if response.errors.any?
requeue!
return
end
managed_resource.update!(tracked_objects: response.in_progress.map(&:to_h))
if managed_resource.tracked_objects.any?
requeue!
else
update_status!(:deleted)
end
end
private
attr_reader :managed_resource, :attempt_count
def requeue!
if attempt_count >= POLLING_SCHEDULE.length
update_status!(:delete_failed)
else
next_attempt_in = POLLING_SCHEDULE[attempt_count]
Clusters::Agents::ManagedResources::DeleteWorker.perform_in(next_attempt_in, managed_resource.id,
attempt_count + 1)
end
end
def update_status!(status)
managed_resource.update!(status: status)
end
def kas_client
@kas_client ||= Gitlab::Kas::Client.new
end
end
end
end
end

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
module Environments
class DeleteManagedResourcesService
include Gitlab::Utils::StrongMemoize
def initialize(environment)
@environment = environment
end
def execute
return unless can_delete_resources?
managed_resource.update!(status: :deleting)
Clusters::Agents::ManagedResources::DeleteWorker.perform_async(managed_resource.id)
ServiceResponse.success
end
private
attr_reader :environment
def can_delete_resources?
environment.stopped? &&
managed_resource.present? &&
managed_resource.cluster_agent.resource_management_enabled? &&
managed_resource.deletion_strategy_on_stop?
end
def managed_resource
environment.managed_resources.completed.order_id_desc.first
end
strong_memoize_attr :managed_resource
end
end

View File

@ -29,6 +29,8 @@ module Environments
end
if environment.stopped? || environment.stopping?
delete_managed_resources(environment)
ServiceResponse.success(payload: { environment: environment, actions: actions })
else
ServiceResponse.error(
@ -74,5 +76,9 @@ module Environments
.new(project, current_user, ref: @ref, recently_updated: true)
.execute
end
def delete_managed_resources(environment)
Environments::DeleteManagedResourcesService.new(environment).execute
end
end
end

View File

@ -1,6 +1,6 @@
- project_link = link_to(_("%{project_name}") % { project_name: @project.name }, @project.http_url_to_repo)
- projects_api_link = link_to(_("Projects API"), help_page_url('api/projects.md'))
- events_api_link = link_to(_("Events API"), help_page_url('api/events.md', anchor: 'list-a-projects-visible-events'))
- events_api_link = link_to(_("Events API"), help_page_url('api/events.md', anchor: 'list-all-visible-events-for-a-project'))
%p
= _('Hi %{username},') % { username: sanitize_name(@user.name) }

View File

@ -12,6 +12,6 @@
<%= _("- Go to the Activity page for %{project_name}.") % { project_name: @project.name } %>
<%= _("- View the last_activity_at attribute for %{project_name} using the Project API %{projects_api_link}.") % { project_name: @project.name, projects_api_link: help_page_url('api/projects.md') } %>
<%= _("- List the visible events for %{project_name} using the Events API %{events_api_link}.") % { project_name: @project.name, events_api_link: help_page_url('api/events.md', anchor: 'list-a-projects-visible-events') } %>
<%= _("- List the visible events for %{project_name} using the Events API %{events_api_link}.") % { project_name: @project.name, events_api_link: help_page_url('api/events.md', anchor: 'list-all-visible-events-for-a-project') } %>
<%= _("This email supersedes any previous emails about scheduled deletion you may have received for %{project_name}.") % { project_name: @project.name } %>

View File

@ -173,6 +173,16 @@
:idempotent: true
:tags: []
:queue_namespace: :cluster_agent
- :name: cluster_agent:clusters_agents_managed_resources_delete
:worker_name: Clusters::Agents::ManagedResources::DeleteWorker
:feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
:queue_namespace: :cluster_agent
- :name: cluster_agent:clusters_agents_notify_git_push
:worker_name: Clusters::Agents::NotifyGitPushWorker
:feature_category: :deployment_management

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
module Clusters
module Agents
module ManagedResources
class DeleteWorker
include ApplicationWorker
include ClusterAgentQueue
deduplicate :until_executed, including_scheduled: true
idempotent!
urgency :low
data_consistency :delayed
def perform(managed_resource_id, attempt = nil)
managed_resource = Clusters::Agents::ManagedResource.find_by_id(managed_resource_id)
return unless managed_resource.present?
Clusters::Agents::ManagedResources::DeleteService.new(managed_resource, attempt_count: attempt).execute
end
end
end
end
end

View File

@ -279,6 +279,9 @@ dast_site_profiles_builds:
- table: p_ci_builds
column: ci_build_id
on_delete: async_delete
- table: projects
column: project_id
on_delete: async_delete
dast_site_tokens:
- table: projects
column: project_id

View File

@ -8,14 +8,6 @@ description: Join table between DAST Site Profiles and CI Builds
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63362
milestone: '14.1'
gitlab_schema: gitlab_sec
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: dast_site_profile_id
table: dast_site_profiles
sharding_key: project_id
belongs_to: dast_site_profile
desired_sharding_key_migration_job_name: BackfillDastSiteProfilesBuildsProjectId
sharding_key:
project_id: projects
table_size: small

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
class AddDastSiteProfilesBuildsProjectIdNotNull < Gitlab::Database::Migration[2.2]
milestone '17.11'
disable_ddl_transaction!
def up
add_not_null_constraint :dast_site_profiles_builds, :project_id
end
def down
remove_not_null_constraint :dast_site_profiles_builds, :project_id
end
end

View File

@ -0,0 +1 @@
ec3e3399c4c66133b4323b6432f9fc21061625ce883e0ef6c54e0f20d605c097

View File

@ -13421,7 +13421,8 @@ CREATE TABLE dast_site_profiles (
CREATE TABLE dast_site_profiles_builds (
dast_site_profile_id bigint NOT NULL,
ci_build_id bigint NOT NULL,
project_id bigint
project_id bigint,
CONSTRAINT check_581c9bb699 CHECK ((project_id IS NOT NULL))
);
COMMENT ON TABLE dast_site_profiles_builds IS '{"owner":"group::dynamic analysis","description":"Join table between DAST Site Profiles and CI Builds"}';

View File

@ -85,5 +85,5 @@ You can view a project's activities and determine when the project was last acti
- Go to the [activity page](../user/project/working_with_projects.md#view-project-activity) for the project and view
the date of the latest event.
- View the `last_activity_at` attribute for the project using the [Projects API](../api/projects.md).
- List the visible events for the project using the [Events API](../api/events.md#list-a-projects-visible-events).
- List the visible events for the project using the [Events API](../api/events.md#list-all-visible-events-for-a-project).
View the `created_at` attribute of the latest event.

View File

@ -257,7 +257,7 @@ Example response:
]
```
## List a project's visible events
## List all visible events for a project
Lists all visible events for a specified project.

View File

@ -15278,7 +15278,87 @@ paths:
- conan_packages
operationId: getApiV4ProjectsIdPackagesConanV2ConansPackageNamePackageVersionPackageUsernamePackageChannelRevisionsRecipeRevisionPackagesConanPackageReferenceLatest
? "/api/v4/projects/{id}/packages/conan/v2/conans/{package_name}/{package_version}/{package_username}/{package_channel}/revisions/{recipe_revision}/packages/{conan_package_reference}/revisions/{package_revision}/files/{file_name}"
: put:
: get:
summary: Download package files
description: This feature was introduced in GitLab 17.11
produces:
- application/json
parameters:
- in: path
name: id
description: The ID or URL-encoded path of the project
type: string
required: true
- in: path
name: package_name
description: Package name
type: string
required: true
example: my-package
- in: path
name: package_version
description: Package version
type: string
required: true
example: '1.0'
- in: path
name: package_username
description: Package username
type: string
required: true
example: my-group+my-project
- in: path
name: package_channel
description: Package channel
type: string
required: true
example: stable
- in: path
name: recipe_revision
description: Recipe revision
type: string
required: true
example: df28fd816be3a119de5ce4d374436b25
- in: path
name: conan_package_reference
description: Package reference
type: string
required: true
example: 5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9
- in: path
name: package_revision
description: Package revision
type: string
required: true
example: 3bdd2d8c8e76c876ebd1ac0469a4e72c
- in: path
name: file_name
description: Package file name
type: string
enum:
- conanfile.py
- conanmanifest.txt
- conan_sources.tgz
- conan_export.tgz
- conaninfo.txt
- conan_package.tgz
required: true
example: conaninfo.txt
responses:
'200':
description: Download package files
'400':
description: Bad Request
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
tags:
- conan_packages
operationId: getApiV4ProjectsIdPackagesConanV2ConansPackageNamePackageVersionPackageUsernamePackageChannelRevisionsRecipeRevisionPackagesConanPackageReferenceRevisionsPackageRevisionFilesFileName
put:
summary: Upload package files
description: This feature was introduced in GitLab 17.11
produces:

View File

@ -336,6 +336,43 @@ Example response:
}
```
## Get a package file
Gets a package file from the package registry.
```plaintext
GET /projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/:package_channel/revisions/:recipe_revision/packages/:conan_package_reference/revisions/:package_revision/files/:file_name
```
| Attribute | Type | Required | Description |
| ------------------------- | ---- | -------- | ----------- |
| `id` | string | yes | The project ID or full project path. |
| `package_name` | string | yes | Name of a package. |
| `package_version` | string | yes | Version of a package. |
| `package_username` | string | yes | Conan username of a package. This attribute is the `+`-separated full path of your project. |
| `package_channel` | string | yes | Channel of a package. |
| `recipe_revision` | string | yes | Revision of the recipe. Does not accept a value of `0`. |
| `conan_package_reference` | string | yes | Reference hash of a Conan package. Conan generates this value. |
| `package_revision` | string | yes | Revision of the package. Does not accept a value of `0`. |
| `file_name` | string | yes | The name and file extension of the requested file. |
```shell
curl --request GET \
--header "Authorization: Bearer <authenticate_token>" \
--url "https://gitlab.example.com/api/v4/projects/9/packages/conan/v2/conans/my-package/1.0/my-group+my-project/stable/revisions/75151329520e7685dcf5da49ded2fec0/packages/103f6067a947f366ef91fc1b7da351c588d1827f/revisions/3bdd2d8c8e76c876ebd1ac0469a4e72c/files/conaninfo.txt"
```
You can also write the output to a file by using:
```shell
curl --request GET \
--header "Authorization: Bearer <authenticate_token>" \
--url "https://gitlab.example.com/api/v4/projects/9/packages/conan/v2/conans/my-package/1.0/my-group+my-project/stable/revisions/75151329520e7685dcf5da49ded2fec0/packages/103f6067a947f366ef91fc1b7da351c588d1827f/revisions/3bdd2d8c8e76c876ebd1ac0469a4e72c/files/conaninfo.txt" \
>> conaninfo.txt
```
This example writes to `conaninfo.txt` in the current directory.
## Upload a package file
Uploads a package file to the package registry.

View File

@ -189,6 +189,7 @@ The following endpoints are available for CI/CD job tokens.
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/:package_channel/revisions/:recipe_revision/files/:file_name` | Download recipe files |
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/:package_channel/revisions/:recipe_revision/files` | List recipe files |
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/:package_channel/revisions/:recipe_revision/packages/:conan_package_reference/latest` | Get the latest package revision |
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/:package_channel/revisions/:recipe_revision/packages/:conan_package_reference/revisions/:package_revision/files/:file_name` | Download package files |
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/:package_channel/revisions` | Get the list of revisions |
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/generic/:package_name/*package_version/(*path/):file_name` | Download package file |
| Packages: Read | `READ_PACKAGES` | `GET /projects/:id/packages/go/*module_name/@v/:module_version.info` | Version metadata |

View File

@ -9,7 +9,8 @@ title: JetBrains troubleshooting
If the steps on this page don't solve your problem, check the
[list of open issues](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin/-/issues/?sort=created_date&state=opened&first_page_size=100)
in the JetBrains plugin's project. If an issue matches your problem, update the issue.
If no issues match your problem, [create a new issue](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin/-/issues/new).
If no issues match your problem, [create a new issue](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin/-/issues/new)
and provide the [required information for Support](#required-information-for-support).
For troubleshooting JetBrains IDEs for GitLab Duo Code Suggestions,
see [Troubleshooting Code Suggestions](../../user/project/repository/code_suggestions/troubleshooting.md#jetbrains-ides-troubleshooting).
@ -23,8 +24,6 @@ To enable debug logs in JetBrains:
1. Add this line: `com.gitlab.plugin`
1. Select **OK** or **Save**.
## Use an HTTP proxy
If you experience [certificate errors](#certificate-errors) or other connection errors, and
use a HTTP proxy to connect to your GitLab instance, you must
[configure the Language Server to use a proxy](../language_server/_index.md#configure-the-language-server-to-use-a-proxy)
@ -43,6 +42,8 @@ To enable GitLab Language Server debug logs:
1. Select **Apply**.
1. Below **Enable GitLab Language Server**, select **Restart Language Server**.
## Get debug logs
The debug logs are available in the `idea.log` log file. To view this file, either:
<!-- vale gitlab_base.SubstitutionWarning = NO -->
@ -74,7 +75,8 @@ To do this:
### Ignore certificate errors
If GitLab Duo still fails to connect, you might need to
ignore certificate errors. You might see errors in the GitLab Language Server logs after enabling [debug mode](jetbrains_troubleshooting.md#enable-debug-mode):
ignore certificate errors. You might see errors in the GitLab Language Server logs after enabling
[debug mode](jetbrains_troubleshooting.md#enable-debug-mode):
```plaintext
2024-10-31T10:32:54:165 [error]: fetch: request to https://gitlab.com/api/v4/personal_access_tokens/self failed with:
@ -124,3 +126,32 @@ If you experience issues with GitLab Duo Chat related to JCEF (Java Chromium Emb
1. Select the boot java runtime version that's the same as your current IDE version, but with JCEF bundled:
![JCEF supporting runtime example](img/jcef_supporting_runtime_example_v17_3.png)
1. Restart your IDE.
## Required information for support
Before contacting Support, make sure the latest GitLab Workflow extension is installed. All releases
are available in the [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/22325-gitlab-duo/versions),
on the **Versions** tab.
Gather this information from affected users, and provide it in your bug report:
1. The error message shown to the user.
1. Workflow and Language Server logs:
- [Debug logs](#enable-debug-mode).
- [Language Server debug logs](#enable-gitlab-language-server-debug-logs).
- [Logs output](#get-debug-logs)
1. Diagnostics output. In your IntelliJ product, go to **Help > Diagnostics Tools > Collect Troubleshooting Information**.
- In the **About** section, copy the **Build Version**.
- For plugin-specific versions: in the **Plugins** section, copy the output.
1. System details. In your IntelliJ product, go to **Help > Diagnostics Tools > Collect Troubleshooting Information**.
- For the operating system type and version: in the dialog, copy **Operating System**.
- For the machine specifications, copy the `System` section.
1. Describe the scope of impact. How many users are affected?
1. Describe how to reproduce the error. Include a screen recording, if possible.
1. Describe how other GitLab Duo features are affected:
- Is **GitLab Quick Chat** functional?
- Is **Code Suggestions** working?
- Does **Web IDE Duo Chat** return responses?
1. Perform extension isolation testing. Try disabling (or uninstalling) all other extensions to determine
if another extension is causing the issue. This helps determine if the problem is with our extension,
or from an external source.

View File

@ -42,14 +42,24 @@ When you view a GitLab project in VS Code, the extension shows you information a
## Switch GitLab accounts in VS Code
The GitLab Workflow extension uses one account for each [VS Code Workspace](https://code.visualstudio.com/docs/editor/workspaces) (window). The extension automatically selects the account when:
The GitLab Workflow extension uses one account for each
[VS Code Workspace](https://code.visualstudio.com/docs/editor/workspaces) (window). The extension
automatically selects the account when:
- You have added only one GitLab account to the extension.
- All workspaces in your VS Code window use the same GitLab account, based on the `git remote` configuration.
In other cases, you must select a GitLab account for the active VS Code window.
What the extension shows in the status bar depends on your account setup:
To change the account selection:
![Status bar for a user with multiple GitLab accounts, with one preselected.](img/preselected_account_v17_11.png)
- If only one GitLab account exists, the status bar shows no information.
- If multiple GitLab accounts exist, and the extension can determine which account to use,
the status bar shows the account name next to the tanuki ({{< icon name="tanuki">}}) icon.
- If multiple GitLab accounts exist, and the extension can't determine which account to use,
the status bar shows **Multiple GitLab Accounts** ({{< icon name="question-o">}}).
To select a GitLab account for the active VS Code window, select the status bar item, or:
1. Open the Command Palette:
- For macOS, press <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
@ -57,11 +67,10 @@ To change the account selection:
1. Run the command `GitLab: Select Account for this Workspace`.
1. Select your desired account from the list.
You can also change accounts by selecting the GitLab account status bar item.
## Select your GitLab project
When your Git repository can be associated with multiple GitLab projects, the extension cannot determine which account to use. This can happen when you have multiple remotes, for example:
When your Git repository can be associated with multiple GitLab projects, the extension cannot
determine which account to use. This can happen when you have multiple remotes, for example:
- `origin`: `git@gitlab.com:gitlab-org/gitlab-vscode-extension.git`
- `personal-fork`: `git@gitlab.com:myusername/gitlab-vscode-extension.git`

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -11,6 +11,7 @@ If you encounter any issues with the GitLab Workflow extension for VS Code, or h
for known issues and solutions.
1. Report bugs or request features in the
[`gitlab-vscode-extension` issue tracker](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues).
Provide the [required information for Support](#required-information-for-support).
For troubleshooting VS Code for GitLab Duo Code Suggestions,
see [Troubleshooting Code Suggestions for VS Code](../../user/project/repository/code_suggestions/troubleshooting.md#vs-code-troubleshooting).
@ -167,3 +168,33 @@ hosted on `https`.
To resolve this, manually enter an `http` URL for your instance when you run the
`GitLab: Authenticate` command.
## Required information for support
Before contacting Support, make sure the latest GitLab Workflow extension is installed. All releases
are available on the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow)
under the **Version History** tab.
Gather this information from affected users, and provide it in your bug report:
1. The error message shown to the user.
1. Workflow and Language Server logs:
1. [Enable debug logs](#enable-debug-logs).
1. [Retrieve log files](#view-log-files) for the extension, and the Language Server.
1. Diagnostics output.
1. Open the Command Palette with <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> or
<kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>
1. Run the command `GitLab: Diagnostics`, and note the extension version.
1. System details:
- In VS Code, go to **Code > About Visual Studio Code** and find **OS**.
- Machine specifications (CPU, RAM): Provide these from your machine. They are not accessible in the IDE.
1. Describe the scope of impact. How many users are affected?
1. Describe how to reproduce the error. Include a screen recording, if possible.
1. Describe how other GitLab Duo features are affected:
- Is **GitLab Quick Chat** functional?
- Is **Code Suggestions** working?
- Does **Web IDE Duo Chat** return responses?
1. Perform extension isolation testing as described in the
[GitLab Workflow Extension Isolation Guide](https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/issues/814#step-2-extension-isolation-testing).
Try disabling (or uninstalling) all other extensions to determine if another extension is causing
the issue. This helps determine if the problem is with our extension, or from an external source.

View File

@ -23,6 +23,7 @@ and crawls the site using an embedded browser.
- This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87183) to DAST_VERSION: 3 in GitLab 15.0.
- This template was updated to DAST_VERSION: 4 in GitLab 16.0.
- This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151910) to DAST_VERSION: 5 in GitLab 17.0.
- This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/188703) to DAST_VERSION: 6 in GitLab 18.0.
{{< /history >}}

View File

@ -145,6 +145,27 @@ The following variables are available:
All variables should be referenced using the double curly brace syntax, for example: `{{ .project.id }}`.
See [`text/template`](https://pkg.go.dev/text/template) documentation for more information on the templating system used.
### Resource lifecycle management
{{< history >}}
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/507486) in GitLab 18.0.
{{< /history >}}
Use the following settings to configure when Kubernetes resources should be removed:
```yaml
# Never delete resources
delete_resources: never
# Delete resources when environment is stopped
delete_resources: on_stop
```
The default value is `on_stop`, which is specified in the
[default environment template](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/internal/module/managed_resources/server/default_template.yaml).
### Managed resource labels and annotations
The resources created by GitLab use a series of labels and annotations for tracking and troubleshooting purposes.

View File

@ -230,6 +230,25 @@ module API
documentation: { example: 'conaninfo.txt' }
end
namespace ':file_name', requirements: FILE_NAME_REQUIREMENTS do
desc 'Download package files' do
detail 'This feature was introduced in GitLab 17.11'
success code: 200
failure [
{ code: 400, message: 'Bad Request' },
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not Found' }
]
tags %w[conan_packages]
end
route_setting :authentication, job_token_allowed: true,
basic_auth_personal_access_token: true
route_setting :authorization, job_token_policies: :read_packages,
allow_public_access_for_enabled_project_features: :package_registry
get urgency: :low do
download_package_file(:package_file)
end
desc 'Upload package files' do
detail 'This feature was introduced in GitLab 17.11'
success code: 200

View File

@ -170,7 +170,8 @@ module API
file_name: params[:file_name].to_s,
conan_file_type: file_type,
conan_package_reference: declared(params)[:conan_package_reference],
recipe_revision: params[:recipe_revision]
recipe_revision: params[:recipe_revision],
package_revision: declared(params)[:package_revision]
).execute!
track_package_event('pull_package', :conan, category: 'API::ConanPackages', project: project, namespace: project.namespace) if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY

View File

@ -26,7 +26,7 @@ variables:
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
#
FUZZAPI_VERSION: "5"
FUZZAPI_VERSION: "6"
FUZZAPI_IMAGE_SUFFIX: ""
FUZZAPI_IMAGE: api-security

View File

@ -28,7 +28,7 @@ variables:
AST_ENABLE_MR_PIPELINES: "true"
#
FUZZAPI_VERSION: "5"
FUZZAPI_VERSION: "6"
FUZZAPI_IMAGE_SUFFIX: ""
FUZZAPI_IMAGE: api-security

View File

@ -26,7 +26,7 @@ variables:
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
#
APISEC_VERSION: "5"
APISEC_VERSION: "6"
APISEC_IMAGE_SUFFIX: ""
APISEC_IMAGE: api-security

View File

@ -27,7 +27,7 @@ variables:
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
AST_ENABLE_MR_PIPELINES: "true"
#
APISEC_VERSION: "5"
APISEC_VERSION: "6"
APISEC_IMAGE_SUFFIX: ""
APISEC_IMAGE: api-security

View File

@ -26,7 +26,7 @@ variables:
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
#
DAST_API_VERSION: "5"
DAST_API_VERSION: "6"
DAST_API_IMAGE_SUFFIX: ""
DAST_API_IMAGE: api-security

View File

@ -27,7 +27,7 @@ variables:
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
AST_ENABLE_MR_PIPELINES: "true"
#
DAST_API_VERSION: "5"
DAST_API_VERSION: "6"
DAST_API_IMAGE_SUFFIX: ""
DAST_API_IMAGE: api-security

View File

@ -14,7 +14,7 @@ stages:
variables:
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
DAST_API_VERSION: "5"
DAST_API_VERSION: "6"
DAST_API_IMAGE_SUFFIX: ""
DAST_API_IMAGE: api-security

View File

@ -13,7 +13,7 @@ stages:
- dast
variables:
DAST_VERSION: 5
DAST_VERSION: 6
# Setting this variable will affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"

View File

@ -22,7 +22,7 @@
# List of available variables: https://docs.gitlab.com/ee/user/application_security/dast/#available-variables
variables:
DAST_VERSION: 5
DAST_VERSION: 6
# Setting this variable affects all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"

View File

@ -22,7 +22,7 @@
# List of available variables: https://docs.gitlab.com/user/application_security/dast/browser/configuration/variables/
variables:
DAST_VERSION: 5
DAST_VERSION: 6
# Setting these variables affect all Security templates
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"

View File

@ -219,7 +219,7 @@ license-finder:
dast:
extends: .download_images
variables:
SECURE_BINARIES_ANALYZER_VERSION: "5"
SECURE_BINARIES_ANALYZER_VERSION: "6"
rules:
- if: '$SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && $SECURE_BINARIES_ANALYZERS =~ /\bdast\b/'
@ -234,6 +234,6 @@ dast-runner-validation:
api-security:
extends: .download_images
variables:
SECURE_BINARIES_ANALYZER_VERSION: "5"
SECURE_BINARIES_ANALYZER_VERSION: "6"
rules:
- if: '$SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && $SECURE_BINARIES_ANALYZERS =~ /\bapi-security\b/'

View File

@ -146,6 +146,17 @@ module Gitlab
.ensure_environment(request, metadata: metadata)
end
def delete_environment(managed_resource:)
request = ::Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentRequest.new(
agent_id: managed_resource.cluster_agent_id,
project_id: managed_resource.project_id,
environment_slug: managed_resource.environment.slug,
objects: managed_resource.tracked_objects
)
stub_for(:managed_resources).delete_environment(request, metadata: metadata)
end
private
def stub_for(service)

View File

@ -59835,12 +59835,6 @@ msgstr ""
msgid "TargetedMessages|Failed to assign namespaces due to error processing CSV: %{error_message}"
msgstr ""
msgid "TargetedMessages|Failed to create targeted message: %{error_message}"
msgstr ""
msgid "TargetedMessages|Failed to update targeted message: %{error_message}"
msgstr ""
msgid "TargetedMessages|New targeted message"
msgstr ""
@ -59853,15 +59847,21 @@ msgstr ""
msgid "TargetedMessages|Targeted message was successfully created."
msgstr ""
msgid "TargetedMessages|Targeted message was successfully created. But %{invalid_namespace_ids_message}"
msgstr ""
msgid "TargetedMessages|Targeted message was successfully updated."
msgstr ""
msgid "TargetedMessages|The following namespace ids were invalid and have been ignored: %{invalid_ids_message}"
msgid "TargetedMessages|Targeted message was successfully updated. But %{invalid_namespace_ids_message}"
msgstr ""
msgid "TargetedMessages|Upload a csv file for targeted namespaces"
msgstr ""
msgid "TargetedMessages|the following namespace ids were invalid and have been ignored: %{invalid_ids_message}"
msgstr ""
msgid "Task"
msgstr ""

View File

@ -305,7 +305,7 @@
"swagger-cli": "^4.0.4",
"tailwindcss": "^3.4.1",
"timezone-mock": "^1.0.8",
"vite": "^6.3.0",
"vite": "^6.3.1",
"vite-plugin-ruby": "^5.1.1",
"vue-loader-vue3": "npm:vue-loader@17.4.2",
"vue-test-utils-compat": "0.0.14",

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Sidekiq
# This cop enforces the use of `defer_on_database_health_signal` for low urgency workers
#
# @example
#
# # bad
# module Workers
# class MyWorker
# include ApplicationWorker
#
# urgency :low
# end
# end
#
# # good
# module Workers
# class MyWorker
# include ApplicationWorker
#
# urgency :low
# defer_on_database_health_signal :gitlab_main, [:users], 2.minutes
# end
# end
class EnforceDatabaseHealthSignalDeferral < RuboCop::Cop::Base
URL = 'https://docs.gitlab.com/development/sidekiq/#deferring-sidekiq-workers'
MSG = "Low urgency workers should have the option to be deferred based on the database health condition. " \
"Consider using `defer_on_database_health_signal`, check #{URL} for more information.".freeze
# @!method low_urgency?(node)
def_node_matcher :low_urgency?, <<~PATTERN
`(send nil? :urgency (sym :low) ...)
PATTERN
# @!method defers_on_database_health_signal?(node)
def_node_matcher :defers_on_database_health_signal?, <<~PATTERN
`(send nil? :defer_on_database_health_signal ...)
PATTERN
def on_class(node)
return unless low_urgency?(node)
return if defers_on_database_health_signal?(node)
add_offense(node)
end
end
end
end
end

View File

@ -5,6 +5,30 @@ FactoryBot.define do
project
environment
association :cluster_agent
association :build
association :build, factory: :ci_build
deletion_strategy { :on_stop }
tracked_objects do
[
{
'kind' => 'Namespace',
'name' => 'production',
'group' => '',
'version' => 'v1',
'namespace' => ''
},
{
'kind' => 'RoleBinding',
'name' => 'bind-ci-job-production',
'group' => 'rbac.authorization.k8s.io',
'version' => 'v1',
'namespace' => 'production'
}
]
end
trait :completed do
status { :completed }
end
end
end

View File

@ -178,7 +178,7 @@ RSpec.describe 'Admin Mode Login', feature_category: :system_access do
end
def enable_admin_mode_using_saml!
gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response)
gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', saml_response: mock_saml_response)
end
end

View File

@ -0,0 +1,191 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Step-up authentication', :js, feature_category: :shared do
let_it_be(:extern_uid) { 'my-uid' }
let_it_be(:provider_oidc) { 'openid_connect' }
let(:provider_oidc_config_with_step_up_auth) do
GitlabSettings::Options.new(
name: provider_oidc,
step_up_auth: {
admin_mode: {
id_token: {
required: { acr: 'gold' }
}
}
}
)
end
let(:additional_info_rejected_step_up_auth) { { extra: { raw_info: { acr: 'bronze' } } } }
let(:additional_info_success_step_up_auth) { { extra: { raw_info: { acr: 'gold' } } } }
around do |example|
with_omniauth_full_host { example.run }
end
context 'for admin mode' do
let_it_be(:admin) do
create(:omniauth_user, :admin, password_automatically_set: false, extern_uid: extern_uid, provider: provider_oidc)
end
before do
stub_omniauth_setting(enabled: true, auto_link_user: true, providers: [provider_oidc_config_with_step_up_auth])
end
context 'when step-up auth conditions fulfilled' do
before do
sign_in(admin)
end
it 'user enters admin mode successfully' do
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_success_step_up_auth)
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).to have_content('Admin mode enabled')
end
it 'user enters admin mode, leaves admin mode and cannot re-enter admin mode without re-authentication' do
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_success_step_up_auth)
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).to have_content('Admin mode enabled')
# Leave admin mode
find_by_testid('user-menu-toggle').click
click_link('Leave Admin Mode', href: destroy_admin_session_path)
wait_for_requests
expect(page).to have_text 'Admin mode disabled'
# Attempt to access the admin area again
visit admin_root_path
# Ensure re-authentication is required
expect(page).to have_current_path new_admin_session_path
expect(page).to have_content('Re-authentication required')
end
it 'user enters admin mode and navigates successfully between non-admin and admin areas' do
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_success_step_up_auth)
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).to have_content('Admin mode enabled')
# Go to non-admin page
visit root_path
wait_for_requests
expect(page).to have_current_path root_path, ignore_query: true
# Return to admin area
visit admin_root_path
wait_for_requests
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).not_to have_content('Admin mode enabled')
end
context 'when feature flag :omniauth_step_up_auth_for_admin_mode is disabled' do
before do
stub_feature_flags(omniauth_step_up_auth_for_admin_mode: false)
end
it 'user enters admin mode' do
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_success_step_up_auth)
expect(page).to have_current_path admin_root_path, ignore_query: true
expect(page).to have_content('Admin mode enabled')
end
end
end
context 'when step-up auth conditions not fulfilled' do
before do
sign_in(admin)
end
it 'user cannot enter admin mode and shows correct info message' do
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_rejected_step_up_auth)
expect(page).to have_current_path new_admin_session_path
expect(page).to have_content('Step-up auth not successful')
end
context 'when feature flag :omniauth_step_up_auth_for_admin_mode is disabled' do
before do
stub_feature_flags(omniauth_step_up_auth_for_admin_mode: false)
end
it 'user enters admin mode successfully' do
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_rejected_step_up_auth)
expect(page).to have_current_path admin_root_path
expect(page).to have_content('Admin mode enabled')
end
end
end
context 'for different initial sign-in methods' do
shared_examples 'successful step-up auth process' do
it 'user enters admin mode with successful step-up auth process' do
wait_for_requests
expect(page).to have_current_path root_path, ignore_query: true
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_rejected_step_up_auth)
wait_for_requests
expect(page).to have_current_path new_admin_session_path
expect(page).to have_content('Step-up auth not successful')
gitlab_enable_admin_mode_sign_in_via(provider_oidc, admin, extern_uid,
additional_info: additional_info_success_step_up_auth)
expect(page).to have_current_path admin_root_path
expect(page).to have_content('Admin mode enabled')
end
end
context 'when user signed in initially with username and password' do
before do
gitlab_sign_in(admin)
end
it_behaves_like 'successful step-up auth process'
end
context 'when user signed in initially with same omniauth provider (openid_connect)' do
before do
gitlab_sign_in_via(provider_oidc, admin, extern_uid)
end
it_behaves_like 'successful step-up auth process'
end
context 'when user signed in initially with another omniauth provider (github)' do
let(:provider_github) { 'github' }
let(:provider_github_config) { GitlabSettings::Options.new(name: provider_github) }
before do
# Add github identity to admin user
admin.identities << create(:identity, provider: provider_github, extern_uid: extern_uid)
# Enable github provider
stub_omniauth_setting(enabled: true, auto_link_user: true,
providers: [provider_oidc_config_with_step_up_auth, provider_github_config])
gitlab_sign_in_via(provider_github, admin, extern_uid)
end
it_behaves_like 'successful step-up auth process'
end
end
end
end

View File

@ -5,15 +5,25 @@ require 'spec_helper'
RSpec.describe Packages::Conan::PackageFilesFinder, feature_category: :package_registry do
let_it_be(:package) { create(:conan_package) }
let_it_be(:aditional_recipe_revision) { create(:conan_recipe_revision, package: package) }
let_it_be(:aditional_package_revision) { create(:conan_package_revision, package: package) }
let_it_be(:recipe_file_without_revision) do
create(:conan_package_file, :conan_recipe_file,
package: package, conan_recipe_revision: nil, conan_package_revision: nil)
end
let_it_be(:package_file_without_revision) do
create(:conan_package_file, :conan_recipe_file,
package: package, conan_recipe_revision: nil)
create(:conan_package_file, :conan_package_manifest,
package: package, conan_recipe_revision: nil, conan_package_revision: nil)
end
let_it_be(:aditional_recipe_file) do
create(:conan_package_file, :conan_recipe_file, package: package,
conan_recipe_revision: aditional_recipe_revision)
end
let_it_be(:aditional_package_file) do
create(:conan_package_file, :conan_recipe_file, package: package,
conan_recipe_revision: aditional_recipe_revision)
create(:conan_package_file, :conan_package_manifest, package: package,
conan_recipe_revision: aditional_recipe_revision, conan_package_revision: aditional_package_revision)
end
let(:package_files) { package.package_files }
@ -84,7 +94,7 @@ RSpec.describe Packages::Conan::PackageFilesFinder, feature_category: :package_r
let(:recipe_revision_value) { Packages::Conan::FileMetadatum::DEFAULT_REVISION }
it 'returns package files without recipe revision' do
expect(found_package_files).to match_array([package_file_without_revision])
expect(found_package_files).to match_array([recipe_file_without_revision, package_file_without_revision])
end
end
@ -102,6 +112,31 @@ RSpec.describe Packages::Conan::PackageFilesFinder, feature_category: :package_r
end
end
context 'with package_revision' do
let(:params) { { package_revision: package_revision_value } }
context 'with default revision' do
let(:package_revision_value) { Packages::Conan::FileMetadatum::DEFAULT_REVISION }
it 'returns package files without package revision' do
expect(found_package_files).to match_array([package_file_without_revision])
end
end
context 'with specific revision' do
let(:package_revision_value) { package.conan_package_revisions.first.revision }
let(:expected_package_files) do
package_files.select do |file|
file.conan_file_metadatum.package_revision_value == package_revision_value
end
end
it 'returns package files with matching package revision' do
expect(found_package_files).to match_array(expected_package_files)
end
end
end
context 'when no files exist' do
let_it_be(:package) { create(:conan_package, without_package_files: true) }

View File

@ -384,5 +384,35 @@ RSpec.describe Gitlab::Kas::Client, feature_category: :deployment_management do
it { expect(subject).to eq(response) }
end
describe '#delete_environment' do
let_it_be(:managed_resource) { create(:managed_resource) }
let(:stub) { instance_double(Gitlab::Agent::ManagedResources::Rpc::Provisioner::Stub) }
let(:request) { instance_double(Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentRequest) }
let(:response) { double(Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentResponse) }
subject { client.delete_environment(managed_resource: managed_resource) }
before do
expect(Gitlab::Agent::ManagedResources::Rpc::Provisioner::Stub).to receive(:new)
.with('example.kas.internal', :this_channel_is_insecure, timeout: client.send(:timeout))
.and_return(stub)
expect(Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentRequest).to receive(:new)
.with(
agent_id: managed_resource.cluster_agent_id,
project_id: managed_resource.project_id,
environment_slug: managed_resource.environment.slug,
objects: managed_resource.tracked_objects
).and_return(request)
expect(stub).to receive(:delete_environment)
.with(request, metadata: { 'authorization' => 'bearer test-token' })
.and_return(response)
end
it { expect(subject).to eq(response) }
end
end
end

View File

@ -9,4 +9,32 @@ RSpec.describe Clusters::Agents::ManagedResource, feature_category: :deployment_
it { is_expected.to belong_to(:environment) }
it { is_expected.to validate_length_of(:template_name).is_at_most(1024) }
describe '.order_id_desc' do
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project:) }
let_it_be(:cluster_agent) { create(:cluster_agent, project:) }
let_it_be(:build1) { create(:ci_build, project:) }
let_it_be(:build2) { create(:ci_build, project:) }
let_it_be(:build3) { create(:ci_build, project:) }
let!(:record1) do
create(:managed_resource, id: 111, build: build1, project: project, environment: environment,
cluster_agent: cluster_agent)
end
let!(:record3) do
create(:managed_resource, id: 333, build: build3, project: project, environment: environment,
cluster_agent: cluster_agent)
end
let!(:record2) do
create(:managed_resource, id: 222, build: build2, project: project, environment: environment,
cluster_agent: cluster_agent)
end
subject { described_class.order_id_desc }
it { is_expected.to eq([record3, record2, record1]) }
end
end

View File

@ -25,6 +25,7 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching, feature_categ
it { is_expected.to have_many(:deployments) }
it { is_expected.to have_many(:alert_management_alerts) }
it { is_expected.to have_many(:managed_resources) }
it { is_expected.to have_one(:upcoming_deployment) }
it { is_expected.to have_one(:latest_opened_most_severe_alert) }

View File

@ -39,20 +39,20 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
let(:file) { fixture_file_upload('spec/fixtures/dk.png') }
let(:params) { { file: file, file_name: file_name, status: status } }
subject { package.package_files.create!(params) }
subject(:create_package_file) { package.package_files.create!(params) }
context 'file_name' do
let(:file_name) { package_file.file_name }
it 'can not save a duplicated file' do
expect { subject }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: File name has already been taken")
expect { create_package_file }.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)
expect { create_package_file }.to change { package.package_files.count }.from(1).to(2)
end
end
end
@ -72,9 +72,9 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
it 'does not allow invalid sha256 characters' do
if expected_success
expect { subject }.not_to raise_error
expect { create_package_file }.not_to raise_error
else
expect { subject }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: File sha256 is invalid")
expect { create_package_file }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: File sha256 is invalid")
end
end
end
@ -162,13 +162,13 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
conan_package_reference: other_package_reference)
end
subject { described_class.with_conan_package_reference(reference) }
subject(:result) { described_class.with_conan_package_reference(reference) }
context 'with existing reference' do
let(:reference) { matching_package_file.conan_file_metadatum.package_reference.reference }
it 'returns package files with matching reference' do
expect(subject).to contain_exactly(matching_package_file)
expect(result).to contain_exactly(matching_package_file)
end
end
@ -176,7 +176,7 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
let(:reference) { non_existing_record_id.to_s }
it 'returns empty relation' do
expect(subject).to be_empty
expect(result).to be_empty
end
end
end
@ -203,13 +203,13 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
end
describe '.with_conan_recipe_revision' do
subject { described_class.with_conan_recipe_revision(revision) }
subject(:result) { described_class.with_conan_recipe_revision(revision) }
context 'with existing revision' do
let(:revision) { recipe_revision.revision }
it 'returns package files with matching recipe revision' do
expect(subject).to contain_exactly(package_file_with_revision)
expect(result).to contain_exactly(package_file_with_revision)
end
end
@ -217,16 +217,66 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
let(:revision) { 'nonexistent' }
it 'returns empty relation' do
expect(subject).to be_empty
expect(result).to be_empty
end
end
end
describe '.without_conan_recipe_revision' do
subject { described_class.without_conan_recipe_revision }
subject(:result) { described_class.without_conan_recipe_revision }
it 'returns only package files without recipe revision' do
expect(subject).to contain_exactly(package_file_without_revision)
expect(result).to contain_exactly(package_file_without_revision)
end
end
end
context 'package revision scopes' do
let_it_be(:package_revision) { package.conan_package_revisions.first }
let_it_be(:other_package_revision) { create(:conan_package_revision, package_reference: package.conan_package_references.first) }
let_it_be(:package_file_with_revision) do
create(:conan_package_file, :conan_package,
package: package,
conan_package_revision: package_revision)
end
let_it_be(:package_file_with_other_revision) do
create(:conan_package_file, :conan_package,
package: package,
conan_package_revision: other_package_revision)
end
let_it_be(:package_file_without_revision) do
create(:conan_package_file, :conan_package,
package: package, conan_recipe_revision: nil, conan_package_revision: nil)
end
describe '.with_conan_package_revision' do
subject(:result) { described_class.with_conan_package_revision(revision) }
context 'with existing revision' do
let(:revision) { package_revision.revision }
it 'returns package files with matching package revision' do
expect(result).to contain_exactly(package_file_with_revision)
end
end
context 'when revision does not exist' do
let(:revision) { 'nonexistent' }
it 'returns empty relation' do
expect(result).to be_empty
end
end
end
describe '.without_conan_package_revision' do
subject(:result) { described_class.without_conan_package_revision }
it 'returns only package files without package revision' do
expect(result).to contain_exactly(package_file_without_revision)
end
end
end
@ -364,13 +414,13 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
end
with_them do
subject { described_class.where(package:).order_by(column_name, order) }
subject(:ordered_files) { described_class.where(package:).order_by(column_name, order) }
it 'returns the package files in the expected order' do
if expected_order
expect(subject.first(2)).to eq(expected_order.call(older_file, newer_file))
expect(ordered_files.first(2)).to eq(expected_order.call(older_file, newer_file))
else
expect(subject.order_values).to be_empty
expect(ordered_files.order_values).to be_empty
end
end
end
@ -386,17 +436,17 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
let(:extra_join) { :helm_file_metadatum }
let(:extra_where) { { packages_helm_file_metadata: { channel: 'alpha' } } }
subject { described_class.most_recent_for(Packages::Package.id_in(helm_package.id), extra_join: extra_join, extra_where: extra_where) }
subject(:joined_result) { described_class.most_recent_for(Packages::Package.id_in(helm_package.id), extra_join: extra_join, extra_where: extra_where) }
it 'returns the most recent package for the selected channel' do
expect(subject).to contain_exactly(helm_package_file2)
expect(joined_result).to contain_exactly(helm_package_file2)
end
context 'with package files pending destruction' do
let_it_be(:package_file_pending_destruction) { create(:helm_package_file, :pending_destruction, package: helm_package, channel: 'alpha') }
it 'does not return them' do
expect(subject).to contain_exactly(helm_package_file2)
expect(joined_result).to contain_exactly(helm_package_file2)
end
end
end
@ -427,26 +477,26 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
describe '#update_file_store callback' do
let_it_be(:package_file) { build(:package_file, :nuget, size: nil) }
subject { package_file.save! }
subject(:save_result) { package_file.save! }
it 'updates metadata columns' do
expect(package_file)
.to receive(:update_file_store)
.and_call_original
expect { subject }.to change { package_file.size }.from(nil).to(3513)
expect { save_result }.to change { package_file.size }.from(nil).to(3513)
end
end
context 'update callbacks' do
subject { package_file.save! }
subject(:save_result) { package_file.save! }
shared_examples 'executing the default callback' do
it 'executes the default callback' do
expect(package_file).to receive(:remove_previously_stored_file)
expect(package_file).not_to receive(:move_in_object_storage)
subject
save_result
end
end
@ -499,7 +549,7 @@ RSpec.describe Packages::PackageFile, type: :model, feature_category: :package_r
expect(package_file.file.file).to receive(:copy_to).and_call_original
expect(package_file.file.file).to receive(:delete).and_call_original
subject
save_result
end
end
end

View File

@ -145,6 +145,56 @@ RSpec.describe API::Conan::V2::ProjectPackages, feature_category: :package_regis
end
end
describe 'GET /api/v4/projects/:id/packages/conan/v2/conans/:package_name/:package_version/:package_username/' \
':package_channel/revisions/:recipe_revision/packages/:conan_package_reference/revisions/:package_revision/' \
'files/:file_name' do
include_context 'for conan file download endpoints'
let(:file_name) { package_file.file_name }
let(:recipe_revision) { package_file_metadata.recipe_revision_value }
let(:package_revision) { package_file_metadata.package_revision_value }
let(:conan_package_reference) { package_file_metadata.package_reference_value }
let(:url_suffix) do
"#{recipe_path}/revisions/#{recipe_revision}/packages/#{conan_package_reference}/revisions/#{package_revision}/" \
"files/#{file_name}"
end
subject(:request) { get api(url), headers: headers }
it_behaves_like 'conan package revisions feature flag check'
it_behaves_like 'packages feature check'
it_behaves_like 'package file download endpoint'
it_behaves_like 'accept get request on private project with access to package registry for everyone'
it_behaves_like 'project not found by project id'
it_behaves_like 'enforcing job token policies', :read_packages,
allow_public_access_for_enabled_project_features: :package_registry do
let(:headers) { job_basic_auth_header(target_job) }
end
describe 'parameter validation for package file endpoints' do
using RSpec::Parameterized::TableSyntax
let(:url_suffix) do
"#{recipe_path}/revisions/#{recipe_revision}/packages/#{url_package_reference}/revisions/" \
"#{url_package_revision}/files/#{url_file_name}"
end
# rubocop:disable Layout/LineLength -- Avoid formatting to keep one-line table syntax
where(:error, :url_package_reference, :url_package_revision, :url_file_name) do
/conan_package_reference/ | 'invalid_package_reference$' | ref(:package_revision) | ref(:file_name)
/package_revision/ | ref(:conan_package_reference) | 'invalid_package_revi$ion' | ref(:file_name)
/package_revision/ | ref(:conan_package_reference) | Packages::Conan::FileMetadatum::DEFAULT_REVISION | ref(:file_name)
/file_name/ | ref(:conan_package_reference) | ref(:package_revision) | 'invalid_file.txt'
end
# rubocop:enable Layout/LineLength
with_them do
it_behaves_like 'returning response status with error', status: :bad_request, error: params[:error]
end
end
end
context 'with file upload endpoints' do
include_context 'for conan file upload endpoints'
let(:file_name) { 'conanfile.py' }

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/sidekiq/enforce_database_health_signal_deferral'
RSpec.describe RuboCop::Cop::Sidekiq::EnforceDatabaseHealthSignalDeferral, feature_category: :database do
it 'adds an offense when worker has low urgency and does not defer to database health signal' do
expect_offense(<<~RUBY)
class SomeWorker
^^^^^^^^^^^^^^^^ Low urgency workers should have the option to be deferred based on the database health [...]
include ApplicationWorker
urgency :low
end
RUBY
end
it 'adds no offense when worker has low urgency and defer to database health signal' do
expect_no_offenses(<<~RUBY)
class SomeWorker
include ApplicationWorker
urgency :low
defer_on_database_health_signal :gitlab_main, [:my_table], 1.minute
end
RUBY
end
it 'adds no offense when worker urgency is other than low' do
expect_no_offenses(<<~RUBY)
class SomeWorker
include ApplicationWorker
urgency :high
end
RUBY
end
end

View File

@ -0,0 +1,127 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Clusters::Agents::ManagedResources::DeleteService, feature_category: :deployment_management do
let_it_be_with_reload(:managed_resource) { create(:managed_resource, status: :deleting) }
describe '#execute' do
let(:kas_client) { instance_double(Gitlab::Kas::Client) }
subject(:execute) { described_class.new(managed_resource).execute }
before do
allow(Gitlab::Kas::Client).to receive(:new).and_return(kas_client)
end
context 'when the managed resource is not in the correct initial state' do
before do
managed_resource.update!(status: :completed)
end
it 'does not delete resources' do
expect(kas_client).not_to receive(:delete_environment)
execute
expect(managed_resource.status).to eq('completed')
end
end
context 'when KAS returns an error' do
let(:attempt_count) { 1 }
let(:kas_response) do
Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentResponse.new(
errors: [Gitlab::Agent::ManagedResources::Rpc::ObjectError.new(error: 'error message', object: {})],
in_progress: []
)
end
before do
allow(kas_client).to receive(:delete_environment).with(managed_resource: managed_resource)
.and_return(kas_response)
end
it 'queues a worker for the next deletion attempt' do
expect(Clusters::Agents::ManagedResources::DeleteWorker).to receive(:perform_in)
.with(described_class::POLLING_SCHEDULE.first, managed_resource.id, attempt_count)
.and_call_original
execute
expect(managed_resource.status).to eq('deleting')
end
end
context 'when all resources are deleted' do
let(:kas_response) do
Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentResponse.new(
errors: [],
in_progress: []
)
end
it 'sets the status to deleted' do
expect(kas_client).to receive(:delete_environment).with(managed_resource: managed_resource)
.and_return(kas_response)
execute
expect(managed_resource.status).to eq('deleted')
expect(managed_resource.tracked_objects).to be_empty
end
end
context 'when deletion is still in progress' do
let(:attempt_count) { 1 }
let(:in_progress_object) do
{
kind: 'Namespace',
name: 'production',
group: '',
version: 'v1',
namespace: ''
}.stringify_keys
end
let(:kas_response) do
Gitlab::Agent::ManagedResources::Rpc::DeleteEnvironmentResponse.new(
errors: [],
in_progress: [Gitlab::Agent::ManagedResources::Rpc::Object.new(**in_progress_object)]
)
end
it 'queues a worker for the next deletion attempt' do
expect(kas_client).to receive(:delete_environment).with(managed_resource: managed_resource)
.and_return(kas_response)
expect(Clusters::Agents::ManagedResources::DeleteWorker).to receive(:perform_in)
.with(described_class::POLLING_SCHEDULE.first, managed_resource.id, attempt_count)
.and_call_original
execute
expect(managed_resource.status).to eq('deleting')
expect(managed_resource.tracked_objects).to contain_exactly(in_progress_object)
end
context 'when the attempt limit is reached' do
let(:attempt_count) { described_class::POLLING_SCHEDULE.length }
subject(:execute) { described_class.new(managed_resource, attempt_count: attempt_count).execute }
it 'sets the status to delete_failed' do
expect(kas_client).to receive(:delete_environment).with(managed_resource: managed_resource)
.and_return(kas_response)
expect(Clusters::Agents::ManagedResources::DeleteWorker).not_to receive(:perform_in)
execute
expect(managed_resource.status).to eq('delete_failed')
expect(managed_resource.tracked_objects).to contain_exactly(in_progress_object)
end
end
end
end
end

View File

@ -0,0 +1,82 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Environments::DeleteManagedResourcesService, feature_category: :deployment_management do
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, :stopped, project: project) }
let_it_be(:agent) { create(:cluster_agent, project: project) }
let_it_be(:build) { create(:ci_build, project: project) }
let!(:managed_resource) do
create(:managed_resource, :completed, project: project, environment: environment, cluster_agent: agent,
build: build)
end
before do
allow_next_found_instance_of(Clusters::Agent) do |agent|
allow(agent).to receive(:resource_management_enabled?).and_return(true)
end
end
describe '#execute' do
subject(:execute) { described_class.new(environment).execute }
it 'sets the status to :deleting and queues the deletion worker' do
expect(Clusters::Agents::ManagedResources::DeleteWorker).to receive(:perform_async)
.with(managed_resource.id).once.and_call_original
expect(execute.status).to eq(:success)
expect(managed_resource.reload.status).to eq('deleting')
end
shared_examples 'resources can not be deleted' do
it 'does not attempt to delete resources' do
expect(Clusters::Agents::ManagedResources::DeleteWorker).not_to receive(:perform_async)
expect(execute).to be_nil
end
end
context 'when the environment is not stopped' do
before do
environment.update!(state: :available)
end
it_behaves_like 'resources can not be deleted'
end
context 'when there is no associated managed resource' do
before do
managed_resource.destroy!
end
it_behaves_like 'resources can not be deleted'
end
context 'when the managed resource is not in the correct state' do
before do
managed_resource.update!(status: :failed)
end
it_behaves_like 'resources can not be deleted'
end
context 'when resource management is disabled' do
before do
allow_next_found_instance_of(Clusters::Agent) do |agent|
allow(agent).to receive(:resource_management_enabled?).and_return(false)
end
end
it_behaves_like 'resources can not be deleted'
end
context 'when the deletion strategy is not on_stop' do
before do
managed_resource.update!(deletion_strategy: :never)
end
it_behaves_like 'resources can not be deleted'
end
end
end

View File

@ -24,6 +24,14 @@ RSpec.describe Environments::StopService, feature_category: :continuous_delivery
review_job.success!
end
it 'calls the managed resource deletion service' do
expect_next_instance_of(Environments::DeleteManagedResourcesService, environment) do |service|
expect(service).to receive(:execute).and_call_original
end
subject
end
context 'without stop action' do
let!(:environment) { create(:environment, :available, project: project) }

View File

@ -55,8 +55,10 @@ module LoginHelpers
click_button Gitlab::Auth::OAuth::Provider.label_for(provider)
end
def gitlab_enable_admin_mode_sign_in_via(provider, user, uid, saml_response = nil)
mock_auth_hash_with_saml_xml(provider, uid, user.email, saml_response)
def gitlab_enable_admin_mode_sign_in_via(provider, user, uid, saml_response: nil, additional_info: {})
response_object = { document: saml_xml(saml_response) } if saml_response.present?
mock_auth_hash(provider, uid, user.email, response_object: response_object, additional_info: additional_info)
visit new_admin_session_path
click_button Gitlab::Auth::OAuth::Provider.label_for(provider)
end

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Clusters::Agents::ManagedResources::DeleteWorker, feature_category: :deployment_management do
let_it_be(:managed_resource) { create(:managed_resource) }
it_behaves_like 'an idempotent worker' do
let(:job_args) { managed_resource.id }
end
describe '#perform' do
let(:managed_resource_id) { managed_resource.id }
subject(:perform) { described_class.new.perform(managed_resource_id) }
it 'calls the deletion service' do
expect_next_instance_of(Clusters::Agents::ManagedResources::DeleteService, managed_resource,
attempt_count: nil) do |service|
expect(service).to receive(:execute).once
end
perform
end
context 'when an attempt number is provided' do
let(:attempt) { 123 }
subject(:perform) { described_class.new.perform(managed_resource_id, attempt) }
it 'calls the deletion service with the supplied attempt number' do
expect_next_instance_of(Clusters::Agents::ManagedResources::DeleteService, managed_resource,
attempt_count: attempt) do |service|
expect(service).to receive(:execute).once
end
perform
end
end
context 'when the managed resource record no longer exists' do
let(:managed_resource_id) { non_existing_record_id }
it 'completes without raising an error' do
expect { perform }.not_to raise_error
end
end
end
end

View File

@ -15035,10 +15035,10 @@ vite-plugin-ruby@^5.1.1:
debug "^4.3.4"
fast-glob "^3.3.2"
vite@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.0.tgz#17c86b3a0f4d20b210fe89f22f7b27d5926fcce5"
integrity sha512-9aC0n4pr6hIbvi1YOpFjwQ+QOTGssvbJKoeYkuHHGWwlXfdxQlI8L2qNMo9awEEcCPSiS+5mJZk5jH1PAqoDeQ==
vite@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.1.tgz#6b080ff907308ca691c5639c095ab6d938734c0d"
integrity sha512-kkzzkqtMESYklo96HKKPE5KKLkC1amlsqt+RjFMlX2AvbRB/0wghap19NdBxxwGZ+h/C6DLCrcEphPIItlGrRQ==
dependencies:
esbuild "^0.25.0"
fdir "^6.4.3"