From fc0d8fd420d54aeffe4cbb55ef604fb9aa41ba32 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 22 Apr 2024 21:09:46 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/workhorse.gitlab-ci.yml | 4 +- ...e_end_string_concatenation_indentation.yml | 2 - .rubocop_todo/rspec/context_wording.yml | 1 - GITALY_SERVER_VERSION | 2 +- .../environments/graphql/resolvers/flux.js | 2 +- .../empty_state_without_any_issues.vue | 2 +- .../page_bundles/design_management.scss | 2 - .../types/ci/runner_membership_filter_enum.rb | 3 +- app/graphql/types/ci/runner_type.rb | 21 --- app/models/ci/runner_manager.rb | 1 + app/models/repository.rb | 5 - app/presenters/ci/runner_presenter.rb | 4 - .../json_schemas/member_role_permissions.json | 3 + .../devise/shared/_signup_box_form.html.haml | 12 +- app/views/groups/edit.html.haml | 4 + app/views/projects/edit.html.haml | 2 + .../15-6-deprecate-post-api-v4-runner.yml | 1 - ...eprecate-runner-setup-instructions-api.yml | 3 +- ...rt_type_severity_traversal_ids_archived.rb | 17 ++ db/schema_migrations/20240410104838 | 1 + db/structure.sql | 2 + doc/api/graphql/reference/index.md | 10 +- doc/api/graphql/removed_items.md | 15 ++ doc/api/rest/deprecations.md | 8 + doc/api/runners.md | 92 ++++++++-- doc/ci/yaml/index.md | 3 + .../sec/analyzer_development_guide.md | 1 - doc/topics/autodevops/cicd_variables.md | 2 +- doc/update/deprecations.md | 32 ++-- doc/user/ai_features.md | 4 +- doc/user/analytics/analytics_dashboards.md | 41 +++++ .../container_scanning/index.md | 22 +-- doc/user/compliance/license_list.md | 6 - .../index.md | 17 +- doc/user/custom_roles/abilities.md | 6 + doc/user/group/saml_sso/index.md | 8 +- doc/user/packages/generic_packages/index.md | 26 ++- doc/user/project/issues/index.md | 1 + .../service_desk/external_participants.md | 159 ++++++++++++++++++ ...ticipants_comment_editor_warning_v17_0.png | Bin 0 -> 32285 bytes ...sk_external_participants_comment_v17_0.png | Bin 0 -> 19911 bytes ...l_participants_email_obfuscation_v17_0.png | Bin 0 -> 27676 bytes doc/user/project/service_desk/index.md | 4 + .../service_desk/using_service_desk.md | 4 +- lib/api/entities/ci/runner.rb | 4 +- lib/api/entities/ci/runner_details.rb | 14 +- lib/api/generic_packages.rb | 2 +- .../packages/maven/basic_auth_helpers.rb | 2 +- lib/gitlab/auth/auth_finders.rb | 60 ++++--- lib/gitlab/auth/request_authenticator.rb | 2 +- .../ci/templates/Auto-DevOps.gitlab-ci.yml | 5 - .../Jobs/Container-Scanning.gitlab-ci.yml | 2 +- .../Container-Scanning.latest.gitlab-ci.yml | 2 +- .../Jobs/License-Scanning.gitlab-ci.yml | 38 ----- .../License-Scanning.latest.gitlab-ci.yml | 48 ------ .../Security/License-Scanning.gitlab-ci.yml | 5 - lib/gitlab/graphql/type_name_deprecations.rb | 6 +- lib/tasks/gitlab/graphql.rake | 17 +- lib/unnested_in_filters/rewriter.rb | 94 ++++++++++- .../auto_devops/auto_devops_templates_spec.rb | 1 - .../create_project_with_auto_devops_spec.rb | 2 +- .../kubernetes/kubernetes_status_bar_spec.js | 4 +- ...environment_flux_resource_selector_spec.js | 2 +- .../environments/graphql/mock_data.js | 2 +- .../graphql/resolvers/flux_spec.js | 4 +- .../empty_state_without_any_issues_spec.js | 2 +- spec/graphql/types/ci/runner_type_spec.rb | 6 +- spec/lib/gitlab/auth/auth_finders_spec.rb | 58 ++++++- spec/lib/unnested_in_filters/rewriter_spec.rb | 38 +++++ spec/models/ci/runner_manager_spec.rb | 10 ++ spec/models/repository_spec.rb | 20 --- spec/requests/api/commits_spec.rb | 23 +++ spec/requests/api/generic_packages_spec.rb | 10 ++ spec/requests/api/graphql/ci/runner_spec.rb | 6 - .../shared/_signup_box.html.haml_spec.rb | 20 ++- workhorse/go.mod | 4 +- workhorse/go.sum | 43 +++++ 77 files changed, 791 insertions(+), 320 deletions(-) create mode 100644 db/post_migrate/20240410104838_index_vulnerability_reads_on_state_report_type_severity_traversal_ids_archived.rb create mode 100644 db/schema_migrations/20240410104838 create mode 100644 doc/user/project/service_desk/external_participants.md create mode 100644 doc/user/project/service_desk/img/service_desk_external_participants_comment_editor_warning_v17_0.png create mode 100644 doc/user/project/service_desk/img/service_desk_external_participants_comment_v17_0.png create mode 100644 doc/user/project/service_desk/img/service_desk_external_participants_email_obfuscation_v17_0.png delete mode 100644 lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml delete mode 100644 lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml delete mode 100644 lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml diff --git a/.gitlab/ci/workhorse.gitlab-ci.yml b/.gitlab/ci/workhorse.gitlab-ci.yml index 21b4cfba137..411cdcf65a1 100644 --- a/.gitlab/ci/workhorse.gitlab-ci.yml +++ b/.gitlab/ci/workhorse.gitlab-ci.yml @@ -33,7 +33,7 @@ workhorse:test go: extends: .workhorse:test parallel: matrix: - - GO_VERSION: ["1.20", "1.21", "1.22"] + - GO_VERSION: ["1.21", "1.22"] REDIS_VERSION: ["7.0", "6.2"] script: - make -C workhorse test-coverage @@ -49,7 +49,7 @@ workhorse:test fips: - setup-test-env-fips parallel: matrix: - - GO_VERSION: ["1.20", "1.21", "1.22"] + - GO_VERSION: ["1.21", "1.22"] REDIS_VERSION: ["7.0", "6.2"] image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/${BUILD_OS}-${OS_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}-rust-${RUST_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-exiftool-12.60 variables: diff --git a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml index f00e4c23398..34875f252e0 100644 --- a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml +++ b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml @@ -105,8 +105,6 @@ Layout/LineEndStringConcatenationIndentation: - 'ee/spec/lib/gitlab/ci/templates/dast_latest_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/dependency_scanning_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/dependency_scanning_latest_gitlab_ci_yaml_spec.rb' - - 'ee/spec/lib/gitlab/ci/templates/license_scanning_gitlab_ci_yaml_spec.rb' - - 'ee/spec/lib/gitlab/ci/templates/license_scanning_latest_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/sast_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/sast_iac_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/sast_latest_gitlab_ci_yaml_spec.rb' diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml index 76f2b23d6af..8f9eba3cdaf 100644 --- a/.rubocop_todo/rspec/context_wording.yml +++ b/.rubocop_todo/rspec/context_wording.yml @@ -334,7 +334,6 @@ RSpec/ContextWording: - 'ee/spec/lib/gitlab/ci/templates/dast_api_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/dast_latest_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/dependency_scanning_gitlab_ci_yaml_spec.rb' - - 'ee/spec/lib/gitlab/ci/templates/license_scanning_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/sast_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/sast_iac_gitlab_ci_yaml_spec.rb' - 'ee/spec/lib/gitlab/ci/templates/sast_latest_gitlab_ci_yaml_spec.rb' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 36f61c2a24a..f7f0261106b 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -faac94442a49a42427236f28d5190c6d721c172b +84074347b5ad5ff09fd4d6068c8bcdf356f7798c diff --git a/app/assets/javascripts/environments/graphql/resolvers/flux.js b/app/assets/javascripts/environments/graphql/resolvers/flux.js index 5cb5db5d752..fa2c3adeb63 100644 --- a/app/assets/javascripts/environments/graphql/resolvers/flux.js +++ b/app/assets/javascripts/environments/graphql/resolvers/flux.js @@ -8,7 +8,7 @@ import fluxKustomizationStatusQuery from '../queries/flux_kustomization_status.q import fluxHelmReleaseStatusQuery from '../queries/flux_helm_release_status.query.graphql'; const helmReleasesApiVersion = 'helm.toolkit.fluxcd.io/v2beta1'; -const kustomizationsApiVersion = 'kustomize.toolkit.fluxcd.io/v1beta1'; +const kustomizationsApiVersion = 'kustomize.toolkit.fluxcd.io/v1'; const helmReleaseField = 'fluxHelmReleaseStatus'; const kustomizationField = 'fluxKustomizationStatus'; diff --git a/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue b/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue index 48d6545b21e..0b3c43f2ffa 100644 --- a/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue +++ b/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue @@ -69,7 +69,7 @@ export default {
diff --git a/app/assets/stylesheets/page_bundles/design_management.scss b/app/assets/stylesheets/page_bundles/design_management.scss index b5a797725dc..59dc2c1233b 100644 --- a/app/assets/stylesheets/page_bundles/design_management.scss +++ b/app/assets/stylesheets/page_bundles/design_management.scss @@ -3,7 +3,6 @@ $design-pin-diameter: 28px; $design-pin-diameter-sm: 24px; $t-gray-a-16-design-pin: rgba($black, 0.16); -$zindex-design-detail: 1061; .design-card-header { background: transparent; @@ -15,7 +14,6 @@ $zindex-design-detail: 1061; .design-detail { bottom: $calc-application-footer-height; - z-index: $zindex-design-detail; .comment-indicator { border-radius: 50%; diff --git a/app/graphql/types/ci/runner_membership_filter_enum.rb b/app/graphql/types/ci/runner_membership_filter_enum.rb index eb691166944..439e2b984cc 100644 --- a/app/graphql/types/ci/runner_membership_filter_enum.rb +++ b/app/graphql/types/ci/runner_membership_filter_enum.rb @@ -4,8 +4,7 @@ module Types module Ci class RunnerMembershipFilterEnum < BaseEnum graphql_name 'CiRunnerMembershipFilter' - description 'Values for filtering runners in namespaces. ' \ - 'The previous type name `RunnerMembershipFilter` was deprecated in 15.4.' + description 'Values for filtering runners in namespaces.' value 'DIRECT', description: "Include runners that have a direct relationship.", diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index dcacfb48997..ebdc7f1d9de 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -23,10 +23,6 @@ module Types deprecated: { reason: 'Use paused', milestone: '14.8' } field :admin_url, GraphQL::Types::String, null: true, description: 'Admin URL of the runner. Only available for administrators.' - field :architecture_name, GraphQL::Types::String, null: true, - deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, - description: 'Architecture provided by the the runner.', - method: :architecture field :contacted_at, Types::TimeType, null: true, description: 'Timestamp of last contact from this runner.', method: :contacted_at @@ -46,17 +42,10 @@ module Types field :ephemeral_register_url, GraphQL::Types::String, null: true, description: 'URL of the registration page of the runner manager. Only available for the creator of the runner for a limited time during registration.', alpha: { milestone: '15.11' } - field :executor_name, GraphQL::Types::String, null: true, - deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, - description: 'Executor last advertised by the runner.', - method: :executor_name field :groups, null: true, resolver: ::Resolvers::Ci::RunnerGroupsResolver, description: 'Groups the runner is associated with. For group runners only.' field :id, ::Types::GlobalIDType[::Ci::Runner], null: false, description: 'ID of the runner.' - field :ip_address, GraphQL::Types::String, null: true, - deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, - description: 'IP address of the runner.' field :job_count, GraphQL::Types::Int, null: true, description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to " \ "indicate that more items exist).\n`jobCount` is an optimized version of `jobs { count }`, " \ @@ -86,10 +75,6 @@ module Types resolver: ::Resolvers::Ci::RunnerOwnerProjectResolver field :paused, GraphQL::Types::Boolean, null: false, description: 'Indicates the runner is paused and not available to run jobs.' - field :platform_name, GraphQL::Types::String, null: true, - deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, - description: 'Platform provided by the runner.', - method: :platform field :project_count, GraphQL::Types::Int, null: true, description: 'Number of projects that the runner is associated with.' field :projects, @@ -99,9 +84,6 @@ module Types description: 'Find projects the runner is associated with. For project runners only.' field :register_admin_url, GraphQL::Types::String, null: true, description: 'URL of the temporary registration page of the runner. Only available before the runner is registered. Only available for administrators.' - field :revision, GraphQL::Types::String, null: true, - deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, - description: 'Revision of the runner.' field :run_untagged, GraphQL::Types::Boolean, null: false, description: 'Indicates the runner is able to run untagged jobs.' field :runner_type, ::Types::Ci::RunnerTypeEnum, null: false, @@ -118,9 +100,6 @@ module Types field :token_expires_at, Types::TimeType, null: true, description: 'Runner token expiration time.', method: :token_expires_at - field :version, GraphQL::Types::String, null: true, - deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, - description: 'Version of the runner.' markdown_field :maintenance_note_html, null: true diff --git a/app/models/ci/runner_manager.rb b/app/models/ci/runner_manager.rb index 69b8bd1cbef..e4810d83ab5 100644 --- a/app/models/ci/runner_manager.rb +++ b/app/models/ci/runner_manager.rb @@ -76,6 +76,7 @@ module Ci end scope :order_id_desc, -> { order(id: :desc) } + scope :order_contacted_at_desc, -> { order(contacted_at: :desc) } scope :with_version_prefix, ->(value) do regex = version_regex_expression_for_version(value) diff --git a/app/models/repository.rb b/app/models/repository.rb index ceed9929d26..32e26474db6 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -170,11 +170,6 @@ class Repository commits = Commit.decorate(commits, container) if commits.present? CommitCollection.new(container, commits, ref) - rescue Gitlab::Git::CommandError => e - # Temporary fix to address a new Gitaly internal error: https://gitlab.com/gitlab-org/gitlab/-/issues/452488 - return CommitCollection.new(container, [], ref) if e.message.include?('listing commits failed') - - raise end def commits_between(from, to, limit: nil) diff --git a/app/presenters/ci/runner_presenter.rb b/app/presenters/ci/runner_presenter.rb index 482534f27b9..cd268140c50 100644 --- a/app/presenters/ci/runner_presenter.rb +++ b/app/presenters/ci/runner_presenter.rb @@ -12,10 +12,6 @@ module Ci delegator_override :locked alias_method :locked, :locked? - def executor_name - Ci::Runner::EXECUTOR_TYPE_TO_NAMES[executor_type&.to_sym] - end - def paused !active end diff --git a/app/validators/json_schemas/member_role_permissions.json b/app/validators/json_schemas/member_role_permissions.json index b2c50bb9ad4..2257ec48934 100644 --- a/app/validators/json_schemas/member_role_permissions.json +++ b/app/validators/json_schemas/member_role_permissions.json @@ -22,6 +22,9 @@ "admin_terraform_state": { "type": "boolean" }, + "admin_compliance_framework": { + "type": "boolean" + }, "admin_vulnerability": { "type": "boolean" }, diff --git a/app/views/devise/shared/_signup_box_form.html.haml b/app/views/devise/shared/_signup_box_form.html.haml index 33b364965db..af5ec456872 100644 --- a/app/views/devise/shared/_signup_box_form.html.haml +++ b/app/views/devise/shared/_signup_box_form.html.haml @@ -20,10 +20,14 @@ .form-group = label_tag :signup_intent, s_('SignUp|I want to...') = select_tag :signup_intent, - options_for_select([[s_('SignUp|Set up a new team'), :new_team], - [s_('SignUp|Set up a new personal account'), :new_personal_account], - [s_('SignUp|Join an existing team'), :join_existing_team], - [s_('SignUp|Contribute to a public project on GitLab'), :contribute_public_project]]), + options_for_select([[s_('SignUp|Set up a new team'), + :select_signup_intent_dropdown_new_team_registration_step_one], + [s_('SignUp|Set up a new personal account'), + :select_signup_intent_dropdown_new_personal_account_registration_step_one], + [s_('SignUp|Join an existing team'), + :select_signup_intent_dropdown_join_existing_team_registration_step_one], + [s_('SignUp|Contribute to a public project on GitLab'), + :select_signup_intent_dropdown_contribute_public_project_registration_step_one]]), prompt: s_('SignUp|Please select an option...'), class: 'gl-form-select custom-select', required: true diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 1c1388013af..afdb4cc1c55 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -45,7 +45,10 @@ .settings-content = render 'shared/badges/badge_settings' +- if can?(current_user, :admin_compliance_framework, @group) = render_if_exists 'groups/compliance_frameworks', expanded: expanded + +- if can?(current_user, :admin_group, @group) = render_if_exists 'groups/custom_project_templates_setting' = render_if_exists 'groups/templates_setting', expanded: expanded = render_if_exists 'shared/groups/max_pages_size_setting' @@ -60,6 +63,7 @@ = _('Perform advanced options such as changing path, transferring, exporting, or removing the group.') .settings-content = render 'groups/settings/advanced' + - elsif can?(current_user, :remove_group, @group) = render 'groups/settings/remove', group: @group, remove_form_id: 'js-remove-group-form' = render_if_exists 'groups/settings/restore', group: @group diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 90837a1a291..d185ef2f130 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -51,8 +51,10 @@ .settings-content = render 'shared/badges/badge_settings' +- if can?(current_user, :admin_compliance_framework, @project) = render_if_exists 'compliance_management/compliance_framework/project_settings', expanded: expanded +- if can?(current_user, :admin_project, @project) = render_if_exists 'projects/settings/default_issue_template' = render 'projects/service_desk_settings' diff --git a/data/deprecations/15-6-deprecate-post-api-v4-runner.yml b/data/deprecations/15-6-deprecate-post-api-v4-runner.yml index 9e8b1f81832..e8b49c5427d 100644 --- a/data/deprecations/15-6-deprecate-post-api-v4-runner.yml +++ b/data/deprecations/15-6-deprecate-post-api-v4-runner.yml @@ -1,7 +1,6 @@ - title: 'Registration tokens and server-side runner arguments in `POST /api/v4/runners` endpoint' # (required) The name of the feature to be deprecated announcement_milestone: '15.6' # (required) The milestone when this feature was first announced as deprecated. removal_milestone: '18.0' # (required) The milestone when this feature is planned to be removed - removal_date: '2024-04-22' breaking_change: true # (required) If this deprecation is a breaking change, set this value to true reporter: pedropombeiro # (required) GitLab username of the person reporting the deprecation stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth diff --git a/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml b/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml index 4f5c301b7c2..1339225ef20 100644 --- a/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml +++ b/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml @@ -1,8 +1,7 @@ - title: 'GitLab Runner platforms and setup instructions in GraphQL API' announcement_milestone: '15.9' announcement_date: '2023-02-22' - removal_milestone: '17.0' - removal_date: '2024-05-22' + removal_milestone: '18.0' breaking_change: true reporter: mrincon body: | diff --git a/db/post_migrate/20240410104838_index_vulnerability_reads_on_state_report_type_severity_traversal_ids_archived.rb b/db/post_migrate/20240410104838_index_vulnerability_reads_on_state_report_type_severity_traversal_ids_archived.rb new file mode 100644 index 00000000000..6b750eb3fe0 --- /dev/null +++ b/db/post_migrate/20240410104838_index_vulnerability_reads_on_state_report_type_severity_traversal_ids_archived.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class IndexVulnerabilityReadsOnStateReportTypeSeverityTraversalIdsArchived < Gitlab::Database::Migration[2.2] + disable_ddl_transaction! + milestone '16.11' + + INDEX_NAME = 'index_vulnerability_reads_common_attrs_and_detection_for_groups' + COLUMNS = %i[resolved_on_default_branch state report_type severity traversal_ids vulnerability_id].freeze + + def up + add_concurrent_index :vulnerability_reads, COLUMNS, name: INDEX_NAME, where: 'archived = false' + end + + def down + remove_concurrent_index_by_name :vulnerability_reads, INDEX_NAME + end +end diff --git a/db/schema_migrations/20240410104838 b/db/schema_migrations/20240410104838 new file mode 100644 index 00000000000..f10968480cb --- /dev/null +++ b/db/schema_migrations/20240410104838 @@ -0,0 +1 @@ +09626f964c06c02dff8c779f4e7bcfe56cb5ba6a256af43ce8a7d57dff4509c7 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index f11da557671..ae2e565ae94 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -27698,6 +27698,8 @@ CREATE UNIQUE INDEX index_vulnerability_occurrences_on_uuid_1 ON vulnerability_o CREATE INDEX index_vulnerability_occurrences_on_vulnerability_id ON vulnerability_occurrences USING btree (vulnerability_id); +CREATE INDEX index_vulnerability_reads_common_attrs_and_detection_for_groups ON vulnerability_reads USING btree (resolved_on_default_branch, state, report_type, severity, traversal_ids, vulnerability_id) WHERE (archived = false); + CREATE INDEX index_vulnerability_reads_common_finder_query_2 ON vulnerability_reads USING btree (project_id, state, report_type, severity, vulnerability_id DESC, dismissal_reason); CREATE INDEX index_vulnerability_reads_common_finder_query_w_namespace_id ON vulnerability_reads USING btree (namespace_id, state, report_type, severity, vulnerability_id DESC, dismissal_reason); diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index ad42824bec2..69bb258d130 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -17269,7 +17269,6 @@ CI/CD variables for a project. | `accessLevel` | [`CiRunnerAccessLevel!`](#cirunneraccesslevel) | Access level of the runner. | | `active` **{warning-solid}** | [`Boolean!`](#boolean) | **Deprecated** in GitLab 14.8. Use paused. | | `adminUrl` | [`String`](#string) | Admin URL of the runner. Only available for administrators. | -| `architectureName` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 16.2. Use field in `manager` object instead. | | `contactedAt` | [`Time`](#time) | Timestamp of last contact from this runner. | | `createdAt` | [`Time`](#time) | Timestamp of creation of this runner. | | `createdBy` | [`UserCore`](#usercore) | User that created this runner. | @@ -17277,10 +17276,8 @@ CI/CD variables for a project. | `editAdminUrl` | [`String`](#string) | Admin form URL of the runner. Only available for administrators. | | `ephemeralAuthenticationToken` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 15.9. **Status**: Experiment. Ephemeral authentication token used for runner manager registration. Only available for the creator of the runner for a limited time during registration. | | `ephemeralRegisterUrl` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 15.11. **Status**: Experiment. URL of the registration page of the runner manager. Only available for the creator of the runner for a limited time during registration. | -| `executorName` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 16.2. Use field in `manager` object instead. | | `groups` | [`GroupConnection`](#groupconnection) | Groups the runner is associated with. For group runners only. (see [Connections](#connections)) | | `id` | [`CiRunnerID!`](#cirunnerid) | ID of the runner. | -| `ipAddress` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 16.2. Use field in `manager` object instead. | | `jobExecutionStatus` **{warning-solid}** | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | **Introduced** in GitLab 15.7. **Status**: Experiment. Job execution status of the runner. | | `locked` | [`Boolean`](#boolean) | Indicates the runner is locked. | | `maintenanceNote` | [`String`](#string) | Runner's maintenance notes. | @@ -17288,12 +17285,10 @@ CI/CD variables for a project. | `maximumTimeout` | [`Int`](#int) | Maximum timeout (in seconds) for jobs processed by the runner. | | `ownerProject` | [`Project`](#project) | Project that owns the runner. For project runners only. | | `paused` | [`Boolean!`](#boolean) | Indicates the runner is paused and not available to run jobs. | -| `platformName` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 16.2. Use field in `manager` object instead. | | `privateProjectsMinutesCostFactor` | [`Float`](#float) | Private projects' "compute cost factor" associated with the runner (GitLab.com only). | | `projectCount` | [`Int`](#int) | Number of projects that the runner is associated with. | | `publicProjectsMinutesCostFactor` | [`Float`](#float) | Public projects' "compute cost factor" associated with the runner (GitLab.com only). | | `registerAdminUrl` | [`String`](#string) | URL of the temporary registration page of the runner. Only available before the runner is registered. Only available for administrators. | -| `revision` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 16.2. Use field in `manager` object instead. | | `runUntagged` | [`Boolean!`](#boolean) | Indicates the runner is able to run untagged jobs. | | `runnerType` | [`CiRunnerType!`](#cirunnertype) | Type of the runner. | | `shortSha` | [`String`](#string) | First eight characters of the runner's token used to authenticate new job requests. Used as the runner's unique ID. | @@ -17301,7 +17296,6 @@ CI/CD variables for a project. | `tokenExpiresAt` | [`Time`](#time) | Runner token expiration time. | | `upgradeStatus` **{warning-solid}** | [`CiRunnerUpgradeStatus`](#cirunnerupgradestatus) | **Introduced** in GitLab 14.10. **Status**: Experiment. Availability of upgrades for the runner. | | `userPermissions` | [`RunnerPermissions!`](#runnerpermissions) | Permissions for the current user on the resource. | -| `version` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 16.2. Use field in `manager` object instead. | #### Fields with arguments @@ -26133,6 +26127,7 @@ Represents vulnerability finding of a security report on the pipeline. | `scanner` | [`VulnerabilityScanner`](#vulnerabilityscanner) | Scanner metadata for the vulnerability. | | `severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability finding. | | `solution` | [`String`](#string) | Solution for resolving the security report finding. | +| `solutionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `solution`. | | `state` | [`VulnerabilityState`](#vulnerabilitystate) | Finding status. | | `stateComment` | [`String`](#string) | Comment for the state of the security report finding. | | `title` | [`String`](#string) | Title of the vulnerability finding. | @@ -32010,7 +32005,7 @@ Runner cloud provider. ### `CiRunnerMembershipFilter` -Values for filtering runners in namespaces. The previous type name `RunnerMembershipFilter` was deprecated in 15.4. +Values for filtering runners in namespaces. | Value | Description | | ----- | ----------- | @@ -33156,6 +33151,7 @@ Member role permission. | Value | Description | | ----- | ----------- | | `ADMIN_CICD_VARIABLES` | Create, read, update, and delete CI/CD variables. | +| `ADMIN_COMPLIANCE_FRAMEWORK` | Enables administrator access to the compliance framework. | | `ADMIN_GROUP_MEMBER` | Add or remove users in a group, and assign roles to users. When assigning a role, users with this custom permission must select a role that has the same or fewer permissions as the default role used as the base for their custom role. | | `ADMIN_MERGE_REQUEST` | Allows approval of merge requests. | | `ADMIN_PUSH_RULES` | Configure push rules for repositories at the group or project level. | diff --git a/doc/api/graphql/removed_items.md b/doc/api/graphql/removed_items.md index 57c8458ca20..3f1c464bce7 100644 --- a/doc/api/graphql/removed_items.md +++ b/doc/api/graphql/removed_items.md @@ -14,6 +14,21 @@ GraphQL is a versionless API, unlike the REST API. Occasionally, items have to be updated or removed from the GraphQL API. According to our [process for removing items](index.md#deprecation-and-removal-process), here are the items that have been removed. +## GitLab 17.0 + +Fields removed in GitLab 17.0. + +### GraphQL Fields + +| Field name | GraphQL type | Deprecated in | Removal MR | Use instead | +|---|---|---|---|---| +| `architectureName` | `CiRunner` | 16.2 | [!124751](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124751) | Use this field in `manager` object instead. | +| `executorName` | `CiRunner` | 16.2 | [!124751](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124751) | Use this field in `manager` object instead. | +| `ipAddress` | `CiRunner` | 16.2 | [!124751](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124751) | Use this field in `manager` object instead. | +| `platformName` | `CiRunner` | 16.2 | [!124751](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124751) | Use this field in `manager` object instead. | +| `revision` | `CiRunner` | 16.2 | [!124751](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124751) | Use this field in `manager` object instead. | +| `version` | `CiRunner` | 16.2 | [!124751](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124751) | Use this field in `manager` object instead. | + ## GitLab 16.0 Fields removed in GitLab 16.0. diff --git a/doc/api/rest/deprecations.md b/doc/api/rest/deprecations.md index f192f3d4592..ba54ba46ddd 100644 --- a/doc/api/rest/deprecations.md +++ b/doc/api/rest/deprecations.md @@ -116,3 +116,11 @@ Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/4 In GitLab 17.0, the [Runners API](../runners.md) will return `""` in place of `ip_address` for runners. In v5 of the REST API, the field will be removed. + +## Runner will not return `version`, `revision`, `platform`, or `architecture` + +Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/457128). + +In GitLab 18.0, the [Runners API](../runners.md) will return `""` in place of `version`, `revision`, `platform`, +and `architecture` for runners. +In v5 of the REST API, the fields will be removed. diff --git a/doc/api/runners.md b/doc/api/runners.md index 48f1b67b33d..4f6ec49d756 100644 --- a/doc/api/runners.md +++ b/doc/api/runners.md @@ -80,6 +80,14 @@ NOTE: The `active` attribute in the response was deprecated [in GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/347211) and will be removed in [a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). It is replaced by the `paused` attribute. +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -89,7 +97,7 @@ Example response: "paused": false, "description": "test-1-20150125", "id": 6, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "project_type", "name": null, @@ -101,7 +109,7 @@ Example response: "paused": false, "description": "test-2-20150125", "id": 8, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "group_type", "name": null, @@ -150,6 +158,14 @@ NOTE: The `active` attribute in the response was deprecated [in GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/347211) and will be removed in [a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). It is replaced by the `paused` attribute. +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -159,7 +175,7 @@ Example response: "paused": false, "description": "shared-runner-1", "id": 1, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": true, "runner_type": "instance_type", "name": null, @@ -171,7 +187,7 @@ Example response: "paused": false, "description": "shared-runner-2", "id": 3, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": true, "runner_type": "instance_type", "name": null, @@ -183,7 +199,7 @@ Example response: "paused": false, "description": "test-1-20150125", "id": 6, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "project_type", "name": null, @@ -195,7 +211,7 @@ Example response: "paused": false, "description": "test-2-20150125", "id": 8, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "group_type", "name": null, @@ -236,6 +252,22 @@ NOTE: The `active` attribute in the response was deprecated [in GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/347211) and will be removed in [a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). It is replaced by the `paused` attribute. +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + +NOTE: +The `version`, `revision`, `platform`, and `architecture` attributes in the response were deprecated +[in GitLab 17.0](https://gitlab.com/gitlab-org/gitlab/-/issues/457128) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +These attributes will start returning an empty string in GitLab 18.0. +The same attributes can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -245,7 +277,7 @@ Example response: "architecture": null, "description": "test-1-20150125", "id": 6, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "project_type", "contacted_at": "2016-01-25T16:39:48.066Z", @@ -308,6 +340,14 @@ NOTE: The `active` query parameter was deprecated [in GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/347211) and will be removed in [a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). It is replaced by the `paused` attribute. +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -316,7 +356,7 @@ Example response: "architecture": null, "description": "test-1-20150125-test", "id": 6, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "group_type", "contacted_at": "2016-01-25T16:39:48.066Z", @@ -507,6 +547,14 @@ NOTE: The `active` attribute in the response was deprecated [in GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/347211) and will be removed in [a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). It is replaced by the `paused` attribute. +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -516,7 +564,7 @@ Example response: "paused": false, "description": "test-2-20150125", "id": 8, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "project_type", "name": null, @@ -528,7 +576,7 @@ Example response: "paused": false, "description": "development_runner", "id": 5, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": true, "runner_type": "instance_type", "name": null, @@ -556,6 +604,14 @@ curl --request POST --header "PRIVATE-TOKEN: " "https://gitla --form "runner_id=9" ``` +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -563,7 +619,7 @@ Example response: "active": true, "description": "test-2016-02-01", "id": 9, - "ip_address": "127.0.0.1", + "ip_address": "", "is_shared": false, "runner_type": "project_type", "name": null, @@ -624,6 +680,14 @@ NOTE: The `active` attribute in the response was deprecated [in GitLab 14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/347211) and will be removed in [a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). It is replaced by the `paused` attribute. +NOTE: +The `ip_address` attribute in the response was deprecated +[in GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/415159) and will be removed in +[a future version of the REST API](https://gitlab.com/gitlab-org/gitlab/-/issues/351109). +This attribute will start returning an empty string in GitLab 17.0. +The `ipAddress` attribute can be found inside the respective runner manager, currently only available through the GraphQL +[`CiRunnerManager` type](graphql/reference/index.md#cirunnermanager). + Example response: ```json @@ -631,7 +695,7 @@ Example response: { "id": 3, "description": "Shared", - "ip_address": "127.0.0.1", + "ip_address": "", "active": true, "paused": false, "is_shared": true, @@ -643,7 +707,7 @@ Example response: { "id": 6, "description": "Test", - "ip_address": "127.0.0.1", + "ip_address": "", "active": true, "paused": false, "is_shared": true, @@ -655,7 +719,7 @@ Example response: { "id": 8, "description": "Test 2", - "ip_address": "127.0.0.1", + "ip_address": "", "active": true, "paused": false, "is_shared": false, diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 834b825d001..d429cf8b829 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -997,6 +997,7 @@ in a header section. **Possible inputs**: Can be one of: +- `array`, to accept an [array](../yaml/inputs.md#array-type) of inputs. - `string`, to accept string inputs (default when not defined). - `number`, to only accept numeric inputs. - `boolean`, to only accept `true` or `false` inputs. @@ -1013,6 +1014,8 @@ spec: type: number available: type: boolean + array_input: + type: array --- # The pipeline configuration would follow... diff --git a/doc/development/sec/analyzer_development_guide.md b/doc/development/sec/analyzer_development_guide.md index 990e6c7aa5c..ed3012db241 100644 --- a/doc/development/sec/analyzer_development_guide.md +++ b/doc/development/sec/analyzer_development_guide.md @@ -396,7 +396,6 @@ This issue will guide you through the whole release process. In general, you hav - [SAST vendored CI/CD template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) - [Dependency Scanning vendored CI/CD template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml) - - [License Scanning vendored CI/CD template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml) - [Container Scanning CI/CD template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml) If needed, go to the pipeline corresponding to the last Git tag, diff --git a/doc/topics/autodevops/cicd_variables.md b/doc/topics/autodevops/cicd_variables.md index 4e4c8cf2588..476d7fcd62c 100644 --- a/doc/topics/autodevops/cicd_variables.md +++ b/doc/topics/autodevops/cicd_variables.md @@ -111,7 +111,7 @@ Use these variables to disable CI/CD jobs. | `gemnasium-python-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | The job isn't created if the value is `"true"`. | | `kubesec-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. | | `license_management` | `LICENSE_MANAGEMENT_DISABLED` | GitLab 12.7 and earlier | If the variable is present, the job isn't created. Job deprecated [from GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22773) | -| `license_scanning` | `LICENSE_MANAGEMENT_DISABLED` | | The job isn't created if the value is `"true"`.| +| `license_scanning` | `LICENSE_MANAGEMENT_DISABLED` | | The job isn't created if the value is `"true"`. Job deprecated [from GitLab 15.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111071) | | `load_performance` | `LOAD_PERFORMANCE_DISABLED` | | If the variable is present, the job isn't created. | | `nodejs-scan-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. | | `performance` | `PERFORMANCE_DISABLED` | GitLab 13.12 and earlier | Browser performance. If the variable is present, the job isn't created. Replaced by `browser_performance`. | diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index eba45fbf0b9..41fb0347497 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -192,6 +192,22 @@ upgrade to GitLab 16.3 or above, and remove the feature flag configuration.
+### GitLab Runner platforms and setup instructions in GraphQL API + +
+- Announced in GitLab 15.9 +- Removal in GitLab 18.0 ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change)) +- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387937). +
+ +The `runnerPlatforms` and `runnerSetup` queries to get GitLab Runner platforms and installation instructions +are deprecated and will be removed from the GraphQL API. For installation instructions, you should use the +[GitLab Runner documentation](https://docs.gitlab.com/runner/) + +
+ +
+ ### GitLab Runner registration token in Runner Operator
@@ -1140,22 +1156,6 @@ Because the new values provide a streamlined, comprehensive method to enable TLS
-### GitLab Runner platforms and setup instructions in GraphQL API - -
-- Announced in GitLab 15.9 -- Removal in GitLab 17.0 ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change)) -- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387937). -
- -The `runnerPlatforms` and `runnerSetup` queries to get GitLab Runner platforms and installation instructions -are deprecated and will be removed from the GraphQL API. For installation instructions, you should use the -[GitLab Runner documentation](https://docs.gitlab.com/runner/) - -
- -
- ### GitLab Runner provenance metadata SLSA v0.2 statement
diff --git a/doc/user/ai_features.md b/doc/user/ai_features.md index 2606416dc46..37c7ec4b5ca 100644 --- a/doc/user/ai_features.md +++ b/doc/user/ai_features.md @@ -33,6 +33,7 @@ GitLab is [transparent](https://handbook.gitlab.com/handbook/values/#transparenc | Helps you understand code by explaining it in English language.

[Watch overview](https://www.youtube.com/watch?v=1izKaLmmaCA) | [Code explanation](#explain-code-in-the-web-ui-with-code-explanation) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | | Assists you in determining the root cause for a pipeline failure and failed CI/CD build. | [Root cause analysis](#root-cause-analysis) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | | Assists you with predicting productivity metrics and identifying anomalies across your software development lifecycle. | [Value stream forecasting](#forecast-deployment-frequency-with-value-stream-forecasting) | **Tier:** Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Status:** Experiment | +| Processes and responds to your questions about your application's usage data. | [Product Analytics](analytics/analytics_dashboards.md#generate-a-custom-visualization-with-gitlab-duo) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | ## Controlling GitLab Duo features @@ -317,7 +318,7 @@ language model referenced above. | [Git suggestions](https://gitlab.com/gitlab-org/gitlab/-/issues/409636) | Vertex AI Codey [`codechat-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-chat) | | [Discussion summary](#summarize-issue-discussions-with-discussion-summary) |Anthropic [`Claude-2`](https://docs.anthropic.com/claude/reference/selecting-a-model) | | [Issue description generation](#summarize-an-issue-with-issue-description-generation) | Anthropic [`Claude-2`](https://docs.anthropic.com/claude/reference/selecting-a-model) | -| [Code Suggestions](project/repository/code_suggestions/index.md) | For Code Completion: Vertex AI Codey [`code-gecko`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-completion) For Code Generation: Anthropic [`Claude-2`](https://docs.anthropic.com/claude/reference/selecting-a-model) | +| [Code Suggestions](project/repository/code_suggestions/index.md) | For Code Completion: Vertex AI Codey [`code-gecko`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-completion) For Code Generation: Anthropic [`Claude-3-Sonnet`](https://docs.anthropic.com/claude/docs/models-overview) | | [Test generation](gitlab_duo_chat.md#write-tests-in-the-ide) | Anthropic [`Claude-2`](https://docs.anthropic.com/claude/reference/selecting-a-model) | | [Merge request template population](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates) | Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text) | | [Suggested Reviewers](project/merge_requests/reviews/index.md#gitlab-duo-suggested-reviewers) | GitLab creates a machine learning model for each project, which is used to generate reviewers [View the issue](https://gitlab.com/gitlab-org/modelops/applied-ml/applied-ml-updates/-/issues/10) | @@ -329,6 +330,7 @@ language model referenced above. | [GitLab Duo Chat](gitlab_duo_chat.md) | Anthropic [`Claude-2`](https://docs.anthropic.com/claude/reference/selecting-a-model) Vertex AI Codey [`textembedding-gecko`](https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-text-embeddings) | | [Root cause analysis](#root-cause-analysis) | Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text) | | [Value stream forecasting](#forecast-deployment-frequency-with-value-stream-forecasting) | Statistical forecasting | +| [Product analytics](analytics/analytics_dashboards.md#generate-a-custom-visualization-with-gitlab-duo) | Vertex AI Codey [`codechat-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/code-chat) | ## Data usage diff --git a/doc/user/analytics/analytics_dashboards.md b/doc/user/analytics/analytics_dashboards.md index 4173c73b262..049abe9cc08 100644 --- a/doc/user/analytics/analytics_dashboards.md +++ b/doc/user/analytics/analytics_dashboards.md @@ -88,6 +88,7 @@ This feature is only compatible with the [product analytics](../product_analytic You can use the dashboard designer to: - [Create custom visualizations](#create-a-custom-visualization). +- [Generate custom visualizations with GitLab Duo](#generate-a-custom-visualization-with-gitlab-duo). - Explore available data. ## View project dashboards @@ -291,6 +292,38 @@ To create a custom visualization: After you saved a visualization, you can add it to a new or existing custom dashboard in the same project. +### Generate a custom visualization with GitLab Duo + +DETAILS: +**Tier:** Ultimate +**Offering:** GitLab.com +**Status:** Experiment + +> - Introduced in GitLab 16.11 as an [Experiment](../../policy/experiment-beta-support.md#experiment) feature [with a flag](../../administration/feature_flags.md) named `generate_cube_query`. Disabled by default. + +Prerequisites: + +- The parent group of the project must have [experiment and beta features enabled](../group/manage.md#enable-experiment-and-beta-features). + +To generate a custom visualization with GitLab Duo using a natural language query: + +1. On the left sidebar, select **Search or go to** and find your project. +1. Select **Analyze > Analytics dashboards**. +1. Select **Visualization designer**. +1. In the **Visualization title** field, enter the name of your visualization. +1. From the **Visualization type** dropdown list, select a visualization type. +1. In the **Generate with GitLab Duo** section, enter your prompt. For example: + + - _Daily sessions_ + - _Number of unique users, grouped weekly_ + - _Which are the most popular pages?_ + - _How many unique users does each browser have?_ + +1. Select **Generate with GitLab Duo**. +1. Select **Save**. + +After you saved a visualization, you can add it to a new or existing custom dashboard in the same project. + ## Troubleshooting ### `Something went wrong while loading the dashboard.` @@ -311,3 +344,11 @@ If a dashboard panel displays an error message: - Check your [Cube query](../product_analytics/index.md#product-analytics-dashboards) and [visualization](../analytics/analytics_dashboards.md#define-a-chart-visualization) configurations, and make sure they are set up correctly. - For [product analytics](../product_analytics/index.md), also check that your visualization's Cube query is valid. + +### Generate visualization with GitLab Duo returns unexpected results + +If GitLab Duo doesn't return the expected or a useful result, try editing your query to: + +- Specify a date range. For example: _number of unique users in 2023 to 2024, grouped monthly_. +- Use the same names for metrics and dimensions as shown in the visualization designer. +For example: _returning users_ instead of _existing customers_. diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index 6809cfbcfff..0304f7ba37c 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -266,7 +266,7 @@ including a large number of false positives. | `ADDITIONAL_CA_CERT_BUNDLE` | `""` | Bundle of CA certs that you want to trust. See [Using a custom SSL CA certificate authority](#using-a-custom-ssl-ca-certificate-authority) for more details. | All | | `CI_APPLICATION_REPOSITORY` | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` | Docker repository URL for the image to be scanned. | All | | `CI_APPLICATION_TAG` | `$CI_COMMIT_SHA` | Docker repository tag for the image to be scanned. | All | -| `CS_ANALYZER_IMAGE` | `registry.gitlab.com/security-products/container-scanning:6` | Docker image of the analyzer. | All | +| `CS_ANALYZER_IMAGE` | `registry.gitlab.com/security-products/container-scanning:7` | Docker image of the analyzer. | All | | `CS_DEFAULT_BRANCH_IMAGE` | `""` | The name of the `CS_IMAGE` on the default branch. See [Setting the default branch image](#setting-the-default-branch-image) for more details. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/338877) in GitLab 14.5. | All | | `CS_DISABLE_DEPENDENCY_LIST` | `"false"` | Disable Dependency Scanning for packages installed in the scanned image. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345434) in GitLab 14.6. | All | | `CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN` | `"true"` | Disable scanning for language-specific packages installed in the scanned image. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345434) in GitLab 14.6. | All | @@ -325,9 +325,9 @@ standard tag plus the `-fips` extension. | Scanner name | `CS_ANALYZER_IMAGE` | | --------------- | ------------------- | -| Default (Trivy) | `registry.gitlab.com/security-products/container-scanning:6-fips` | -| Grype | `registry.gitlab.com/security-products/container-scanning/grype:6-fips` | -| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:6-fips` | +| Default (Trivy) | `registry.gitlab.com/security-products/container-scanning:7-fips` | +| Grype | `registry.gitlab.com/security-products/container-scanning/grype:7-fips` | +| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:7-fips` | NOTE: Prior to GitLab 15.0, the `-ubi` image extension is also available. GitLab 15.0 and later only @@ -384,9 +384,9 @@ The following options are available: | Scanner name | `CS_ANALYZER_IMAGE` | |----------------------------------------------------------|--------------------------------------------------------------------| -| Default ([Trivy](https://github.com/aquasecurity/trivy)) | `registry.gitlab.com/security-products/container-scanning:6` | -| [Grype](https://github.com/anchore/grype) | `registry.gitlab.com/security-products/container-scanning/grype:6` | -| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:6` | +| Default ([Trivy](https://github.com/aquasecurity/trivy)) | `registry.gitlab.com/security-products/container-scanning:7` | +| [Grype](https://github.com/anchore/grype) | `registry.gitlab.com/security-products/container-scanning/grype:7` | +| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:7` | WARNING: Do not use the `:latest` tag when selecting the scanner image. @@ -584,9 +584,9 @@ For container scanning, import the following images from `registry.gitlab.com` i [local Docker container registry](../../packages/container_registry/index.md): ```plaintext -registry.gitlab.com/security-products/container-scanning:6 -registry.gitlab.com/security-products/container-scanning/grype:6 -registry.gitlab.com/security-products/container-scanning/trivy:6 +registry.gitlab.com/security-products/container-scanning:7 +registry.gitlab.com/security-products/container-scanning/grype:7 +registry.gitlab.com/security-products/container-scanning/trivy:7 ``` The process for importing Docker images into a local offline Docker registry depends on @@ -626,7 +626,7 @@ following `.gitlab-ci.yml` example as a template. ```yaml variables: - SOURCE_IMAGE: registry.gitlab.com/security-products/container-scanning:6 + SOURCE_IMAGE: registry.gitlab.com/security-products/container-scanning:7 TARGET_IMAGE: $CI_REGISTRY/namespace/container-scanning image: docker:latest diff --git a/doc/user/compliance/license_list.md b/doc/user/compliance/license_list.md index 3465ed48fca..5ddb3c78939 100644 --- a/doc/user/compliance/license_list.md +++ b/doc/user/compliance/license_list.md @@ -25,12 +25,6 @@ requirements must be met: 1. You must be generating an SBOM file with components from one of our [one of our supported languages](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers). 1. If using our [`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml) to generate the SBOM file, then your project must use at least one of the [supported languages and package managers](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers). -Alternatively, licenses will also appear under the license list when using our deprecated [`License-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml) as long as the following requirements are met: - -1. The Dependency Scanning CI/CD job must be [enabled](license_scanning_of_cyclonedx_files/index.md#configuration) for your project. -1. Your project must use at least one of the - [supported languages and package managers](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers). - When everything is configured, on the left sidebar, select **Secure > License compliance**. The licenses are displayed, where: diff --git a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md index 9e33054f5af..c2c50fcdef2 100644 --- a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md +++ b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md @@ -12,22 +12,7 @@ DETAILS: > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384932) in GitLab 15.9 for GitLab SaaS [with two flags](../../../administration/feature_flags.md) named `license_scanning_sbom_scanner` and `package_metadata_synchronization`. Both flags disabled by default. > - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/385176) in GitLab 16.4. Feature flags `license_scanning_sbom_scanner` and `package_metadata_synchronization` removed. - -NOTE: -The legacy License Compliance analyzer was deprecated in GitLab 15.9 and removed in GitLab 16.3. -To continue using GitLab for License Compliance, remove the License Compliance template from your -CI/CD pipeline and add the [Dependency Scanning template](../../application_security/dependency_scanning/index.md#configuration). -The Dependency Scanning template is now capable of gathering the required license information so it -is no longer necessary to run a separate License Compliance job. The License Compliance CI/CD -template should not be removed prior to verifying that the instance has been upgraded to a version -that supports the new method of license scanning. To begin using the Dependency Scanner quickly at -scale, you may set up a [scan execution policy](../../application_security/policies/scan-execution-policies.md) -at the group level to enforce the SBOM-based license scan for all projects in the group. -Then, you may remove the inclusion of the `Jobs/License-Scanning.gitlab-ci.yml` template from your -CI/CD configuration. If you wish to continue using the legacy License Compliance feature, you can do -so by setting the `LICENSE_MANAGEMENT_VERSION CI` variable to `4`. This variable can be set at the -[project](../../../ci/variables/index.md#for-a-project), [group](../../../ci/variables/index.md#for-a-group) -or [instance](../../../ci/variables/index.md#for-an-instance) level. +> - The legacy License Compliance analyzer (`License-Scanning.gitlab-ci.yml`) was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/439162) in GitLab 17.0. To detect the licenses in use, License Compliance relies on running the [Dependency Scanning CI Jobs](../../application_security/dependency_scanning/index.md), diff --git a/doc/user/custom_roles/abilities.md b/doc/user/custom_roles/abilities.md index e49f3ec807c..7dcede3beab 100644 --- a/doc/user/custom_roles/abilities.md +++ b/doc/user/custom_roles/abilities.md @@ -30,6 +30,12 @@ These requirements are documented in the `Required permission` column in the fol | [`admin_merge_request`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128302) | | Allows approval of merge requests. | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/412708) | | | | [`read_code`](https://gitlab.com/gitlab-org/gitlab/-/issues/376180) | | Allows read-only access to the source code. | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/20277) | `customizable_roles` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110810) | +## Compliance management + +| Name | Required permission | Description | Introduced in | Feature flag | Enabled in | +|:-----|:------------|:------------------|:---------|:--------------|:---------| +| [`admin_compliance_framework`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144183) | | Enables administrator access to the compliance framework. | GitLab [17.0](https://gitlab.com/gitlab-org/gitlab/-/issues/411502) | | | + ## Group and projects | Name | Required permission | Description | Introduced in | Feature flag | Enabled in | diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md index 616aa2d4d80..4b812e25c52 100644 --- a/doc/user/group/saml_sso/index.md +++ b/doc/user/group/saml_sso/index.md @@ -249,7 +249,13 @@ After you set up your identity provider to work with GitLab, you must configure 1. Complete the fields: - In the **Identity provider single sign-on URL** field, enter the SSO URL from your identity provider. - In the **Certificate fingerprint** field, enter the fingerprint for the SAML token signing certificate. -1. In the **Default membership role** field, select the role to assign to new users. +1. For groups on GitLab.com: in the **Default membership role** field, select: + 1. The role to assign to new users. + 1. The role to assign to + [users who are not members of a mapped SAML group](../saml_sso/group_sync.md#automatic-member-removal) + when SAML Group Links is configured for the group. +1. For groups on self-managed instances: in the **Default membership role** field, + select the role to assign to new users. The default role is **Guest**. That role becomes the starting role of all users added to the group: - In [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/214523) and diff --git a/doc/user/packages/generic_packages/index.md b/doc/user/packages/generic_packages/index.md index 2081a979ab5..9b53828f9ec 100644 --- a/doc/user/packages/generic_packages/index.md +++ b/doc/user/packages/generic_packages/index.md @@ -163,20 +163,38 @@ GET /projects/:id/packages/generic/:package_name/:package_version/:file_name The file context is served in the response body. The response content type is `application/octet-stream`. +::Tabs + +:::TabTitle Personal access token + Example request that uses a personal access token: ```shell +# Header authentication curl --header "PRIVATE-TOKEN: " \ "https://gitlab.example.com/api/v4/projects/24/packages/generic/my_package/0.0.1/file.txt" -``` -Example request that uses HTTP Basic authentication: - -```shell +# Basic authentication curl --user "user:" \ "https://gitlab.example.com/api/v4/projects/24/packages/generic/my_package/0.0.1/file.txt" ``` +:::TabTitle CI_JOB_TOKEN + +Example request that uses a `CI_JOB_TOKEN`: + +```shell +# Header authentication +curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" \ + "https://gitlab.example.com/api/v4/projects/24/packages/generic/my_package/0.0.1/file.txt" + +# Basic authentication +curl --user "gitlab-ci-token:${CI_JOB_TOKEN}" \ + "https://gitlab.example.com/api/v4/projects/24/packages/generic/my_package/0.0.1/file.txt" +``` + +::EndTabs + ## Publish a generic package by using CI/CD To work with generic packages in [GitLab CI/CD](../../../ci/index.md), you can use diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index 5f13e419332..fd74988e668 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -62,3 +62,4 @@ To learn how the GitLab Strategic Marketing department uses GitLab issues with [ - [Issues API](../../../api/issues.md) - [Configure an external issue tracker](../../../integration/external-issue-tracker.md) - [Tasks](../../tasks.md) +- [External participants](../service_desk/external_participants.md) diff --git a/doc/user/project/service_desk/external_participants.md b/doc/user/project/service_desk/external_participants.md new file mode 100644 index 00000000000..82da367cee7 --- /dev/null +++ b/doc/user/project/service_desk/external_participants.md @@ -0,0 +1,159 @@ +--- +stage: Service Management +group: Respond +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + +# External participants + +DETAILS: +**Tier:** Free, Premium, Ultimate +**Offering:** GitLab.com, Self-managed + +> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3758) in GitLab 17.0 [with a flag](../../../administration/feature_flags.md) named `issue_email_participants`. Disabled by default. + +FLAG: +The availability of this feature is controlled by a feature flag. +For more information, see the history. +This feature is available for testing, but not ready for production use. + +External participants are users without a GitLab account that can interact with an issue or Service Desk ticket only by email. +They get notified of public comments on an issue or ticket by [Service Desk emails](configure.md#customize-emails-sent-to-the-requester). + +The maximum number of external participants on an issue or ticket is 10. + +## Service Desk tickets + +GitLab adds the external author of a Service Desk ticket as an external participant. +That usually is the email address from the `From` header of the initial email that created the ticket. + +### Add external participants from the `Cc` header + +By default GitLab only adds the sender of the email that creates the Service Desk ticket as an external participant. + +You can configure GitLab to also add all email addresses from the `Cc` header to the Service Desk ticket. +This works for the initial email and all replies to the [`thank_you` email](configure.md#customize-emails-sent-to-the-requester). + +Prerequisites: + +- You must have at least the Maintainer role for the project. + +To enable the setting for the project: + +1. On the left sidebar, select **Search or go to** and find your project. +1. Select **Settings > General**. +1. Expand **Service Desk**. +1. Select **Add external participants from the `Cc` header**. +1. Select **Save changes**. + +## As an external participant + +An external participant receives a notification for each public comment on the issue or ticket +using [Service Desk emails](configure.md#customize-emails-sent-to-the-requester). + +### Replying to notification emails + +An external participant can [reply to the received notification email](../../../administration/reply_by_email.md#you-reply-to-the-notification-email). +It creates a new comment on the issue or ticket and displays the email address of the external participant +instead of a GitLab username. The email address is followed by `(external participant)`. + +![Comment from an external participant on an issue or ticket](img/service_desk_external_participants_comment_v17_0.png) + +### Unsubscribing from notification emails + +External participants can use the unsubscribe link in the default Service Desk email template to +unsubscribe from the issue or ticket. + +If you [customize your `thank_you` and `new_note` email templates](configure.md#customize-emails-sent-to-the-requester), +you can use the `%{UNSUBSCRIBE_URL}` placeholder to add the unsubscribe link to the templates. + +Your GitLab instance must be reachable (for example, from the public internet) for the external participant to successfully unsubscribe. +If that's not the case, consider removing the unsubscribe link from your template. + +## As a GitLab user + +To see the email address of an external participant you must have at least the Reporter role for the project. + +The external participant's email address is obfuscated if both these conditions are true: + +- You are not a member of the project or have the Guest role. +- The issue or ticket is public ([non-confidential](../issues/confidential_issues.md#confidential-issues)). + +The external participant's email address is then obfuscated in: + +- The author field of a Service Desk ticket. +- All [system notes](../system_notes.md) that mention an external participant. +- The [REST](../../../api/notes.md) and [GraphQL](../../../api/graphql/index.md) APIs. +- The warning message below the comment editor. + +For example: + +![Obfuscated email addresses of external participants in system notes](img/service_desk_external_participants_email_obfuscation_v17_0.png) + +### Notifications sent to external participants + +External participants get notifications for all public comments on an issue. +For private communication, use [internal notes](../../discussions/index.md#add-an-internal-note). + +External participants don't receive notifications for any other issue or ticket event. + +### View all external participants + +Get an overview of all external participants that receive a Service Desk email for a new comment. + +Prerequisites: + +- You must have at least the Reporter role for the project. + +To see a list of all external participants: + +1. Go to the issue or ticket. +1. Scroll down to the comment editor. +1. If the issue or ticket has external participants, you can see a warning under the comment editor + that lists all external participants. + +![Warning below the comment editor listing external participants](img/service_desk_external_participants_comment_editor_warning_v17_0.png) + +### Add an external participant + +Add an external participant using the `/invite_email` [quick action](../quick_actions.md) when you want +to include them in the conversation at any time. + +When added, the external participant starts receiving notifications using Service Desk emails. +GitLab doesn't send a `thank_you` email for manually added external participants. + +You should add external participants in a dedicated comment because they don't receive a notification +email for the comment that contains the `/invite_email` quick action. + +Prerequisites: + +- You must have at least the Reporter role for the project. + +To add an external participant to an issue or ticket: + +1. Go to the issue or ticket. +1. Add a comment that contains only the quick action `/invite_email user@example.com`. + You can chain up to 6 email addresses. For example `/invite_email user@example.com user2@example.com` + +You should see a success message and a new system note with the email address. + +### Remove an external participant + +Remove an external participant from an issue or Service Desk ticket using the `/remove_email` +[quick action](../quick_actions.md) when they should stop receiving notifications. + +After removing them from the issue or ticket they don't receive new notifications. +But they can still reply to emails they received before and create a new comment on the issue or ticket. + +Prerequisites: + +- You must have at least the Reporter role for the project. +- There must be at least one external participant on the issue or ticket. + +To remove an existing external participant from an issue or ticket: + +1. Go to the issue or ticket. +1. Add a comment that contains only the quick action `/remove_email user@example.com`. + You can chain up to 6 email addresses. For example `/remove_email user@example.com user2@example.com` + +You should see a success message and a new system note with the email address. diff --git a/doc/user/project/service_desk/img/service_desk_external_participants_comment_editor_warning_v17_0.png b/doc/user/project/service_desk/img/service_desk_external_participants_comment_editor_warning_v17_0.png new file mode 100644 index 0000000000000000000000000000000000000000..c956f085c277c6d32f5fb4f3f980d7244a0d2d5d GIT binary patch literal 32285 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 BuZREu literal 0 HcmV?d00001 diff --git a/doc/user/project/service_desk/img/service_desk_external_participants_comment_v17_0.png b/doc/user/project/service_desk/img/service_desk_external_participants_comment_v17_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9033a960fe64abb9a9bb5796abe35cc610772e7f GIT binary patch literal 19911 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 literal 0 HcmV?d00001 diff --git a/doc/user/project/service_desk/img/service_desk_external_participants_email_obfuscation_v17_0.png b/doc/user/project/service_desk/img/service_desk_external_participants_email_obfuscation_v17_0.png new file mode 100644 index 0000000000000000000000000000000000000000..a39f6b662e393c2e6b14684643248e983fd7757f GIT binary patch literal 27676 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 literal 0 HcmV?d00001 diff --git a/doc/user/project/service_desk/index.md b/doc/user/project/service_desk/index.md index 27e3817ba5a..6dc1a67aabc 100644 --- a/doc/user/project/service_desk/index.md +++ b/doc/user/project/service_desk/index.md @@ -64,6 +64,10 @@ Meanwhile: - [Email contents and formatting](using_service_desk.md#email-contents-and-formatting) - [Convert a regular issue to a Service Desk ticket](using_service_desk.md#convert-a-regular-issue-to-a-service-desk-ticket) - [Privacy considerations](using_service_desk.md#privacy-considerations) +- [External Participants](external_participants.md) + - [Service Desk tickets](external_participants.md#service-desk-tickets) + - [As an external participant](external_participants.md#as-an-external-participant) + - [As a GitLab user](external_participants.md#as-a-gitlab-user) ## Troubleshooting Service Desk diff --git a/doc/user/project/service_desk/using_service_desk.md b/doc/user/project/service_desk/using_service_desk.md index 054918343cc..5271e442707 100644 --- a/doc/user/project/service_desk/using_service_desk.md +++ b/doc/user/project/service_desk/using_service_desk.md @@ -39,8 +39,8 @@ are sent as emails: Any responses they send via email are displayed in the issue itself. -For information about headers used for treating email, see -[the incoming email documentation](../../../administration/incoming_email.md#accepted-headers). +For additional information see [External participants](external_participants.md) and the +[headers used for treating email](../../../administration/incoming_email.md#accepted-headers). ### Create a Service Desk ticket in GitLab UI diff --git a/lib/api/entities/ci/runner.rb b/lib/api/entities/ci/runner.rb index 441e1dc1117..821c7dc1256 100644 --- a/lib/api/entities/ci/runner.rb +++ b/lib/api/entities/ci/runner.rb @@ -6,8 +6,8 @@ module API class Runner < Grape::Entity expose :id, documentation: { type: 'integer', example: 8 } expose :description, documentation: { type: 'string', example: 'test-1-20150125' } - # TODO: return null in 17.0 and remove in v5 https://gitlab.com/gitlab-org/gitlab/-/issues/415159 - expose :ip_address, documentation: { type: 'string', example: '127.0.0.1' } + # TODO: remove in v5 https://gitlab.com/gitlab-org/gitlab/-/issues/415159 + expose(:ip_address, documentation: { type: 'string', example: '127.0.0.1' }) { |_runner, _options| nil } # TODO Remove in v5 in favor of `paused` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709 expose :active, documentation: { type: 'boolean', example: true } expose :paused, documentation: { type: 'boolean', example: false } do |runner| diff --git a/lib/api/entities/ci/runner_details.rb b/lib/api/entities/ci/runner_details.rb index a26e3afb4c7..40b4d3fa1a0 100644 --- a/lib/api/entities/ci/runner_details.rb +++ b/lib/api/entities/ci/runner_details.rb @@ -4,12 +4,18 @@ module API module Entities module Ci class RunnerDetails < Runner + include Gitlab::Utils::StrongMemoize + expose :tag_list expose :run_untagged expose :locked expose :maximum_timeout expose :access_level - expose :version, :revision, :platform, :architecture + # TODO: return nil in 18.0 and remove in v5 https://gitlab.com/gitlab-org/gitlab/-/issues/457128 + expose(:version) { |runner, _options| latest_runner_manager(runner)&.version } + expose(:revision) { |runner, _options| latest_runner_manager(runner)&.revision } + expose(:platform) { |runner, _options| latest_runner_manager(runner)&.platform } + expose(:architecture) { |runner, _options| latest_runner_manager(runner)&.architecture } expose :contacted_at expose :maintenance_note @@ -31,6 +37,12 @@ module API end end # rubocop: enable CodeReuse/ActiveRecord + + def latest_runner_manager(runner) + strong_memoize_with(:latest_runner_manager, runner) do + runner.runner_managers.order_contacted_at_desc.first + end + end end end end diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb index 8d1e9e55f24..56188392288 100644 --- a/lib/api/generic_packages.rb +++ b/lib/api/generic_packages.rb @@ -119,7 +119,7 @@ module API requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.generic_package_file_name_regex, file_path: true end - route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true + route_setting :authentication, job_token_allowed: %i[request basic_auth], basic_auth_personal_access_token: true, deploy_token_allowed: true get do project = authorized_user_project(action: :read_package) diff --git a/lib/api/helpers/packages/maven/basic_auth_helpers.rb b/lib/api/helpers/packages/maven/basic_auth_helpers.rb index c9ef95adc33..0b0082dc7af 100644 --- a/lib/api/helpers/packages/maven/basic_auth_helpers.rb +++ b/lib/api/helpers/packages/maven/basic_auth_helpers.rb @@ -12,7 +12,7 @@ module API # basic auth. override :find_user_from_job_token def find_user_from_job_token - super || find_user_from_basic_auth_job + super || find_user_from_job_token_basic_auth end end end diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb index 319d1121ec8..f753db5076b 100644 --- a/lib/gitlab/auth/auth_finders.rb +++ b/lib/gitlab/auth/auth_finders.rb @@ -76,30 +76,11 @@ module Gitlab def find_user_from_job_token return unless route_authentication_setting[:job_token_allowed] - return find_user_from_basic_auth_job if route_authentication_setting[:job_token_allowed] == :basic_auth - token = current_request.params[JOB_TOKEN_PARAM].presence || - current_request.params[RUNNER_JOB_TOKEN_PARAM].presence || - current_request.env[JOB_TOKEN_HEADER].presence - return unless token + user = find_user_from_job_token_basic_auth if can_authenticate_job_token_basic_auth? + return user if user - job = find_valid_running_job_by_token!(token.to_s) - @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables - - job.user - end - - def find_user_from_basic_auth_job - return unless has_basic_credentials?(current_request) - - login, password = user_name_and_password(current_request) - return unless login.present? && password.present? - return unless ::Gitlab::Auth::CI_JOB_USER == login - - job = find_valid_running_job_by_token!(password.to_s) - @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables - - job.user + find_user_from_job_token_query_params_or_header if can_authenticate_job_token_request? end def find_user_from_basic_auth_password @@ -322,6 +303,41 @@ module Gitlab user end + def can_authenticate_job_token_basic_auth? + setting = route_authentication_setting[:job_token_allowed] + Array.wrap(setting).include?(:basic_auth) + end + + def can_authenticate_job_token_request? + setting = route_authentication_setting[:job_token_allowed] + setting == true || Array.wrap(setting).include?(:request) + end + + def find_user_from_job_token_query_params_or_header + token = current_request.params[JOB_TOKEN_PARAM].presence || + current_request.params[RUNNER_JOB_TOKEN_PARAM].presence || + current_request.env[JOB_TOKEN_HEADER].presence + return unless token + + job = find_valid_running_job_by_token!(token.to_s) + @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables + + job.user + end + + def find_user_from_job_token_basic_auth + return unless has_basic_credentials?(current_request) + + login, password = user_name_and_password(current_request) + return unless login.present? && password.present? + return unless ::Gitlab::Auth::CI_JOB_USER == login + + job = find_valid_running_job_by_token!(password.to_s) + @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables + + job.user + end + def parsed_oauth_token Doorkeeper::OAuth::Token.from_request(current_request, *Doorkeeper.configuration.access_token_methods) end diff --git a/lib/gitlab/auth/request_authenticator.rb b/lib/gitlab/auth/request_authenticator.rb index c33ae1ce901..da13d8e382f 100644 --- a/lib/gitlab/auth/request_authenticator.rb +++ b/lib/gitlab/auth/request_authenticator.rb @@ -38,7 +38,7 @@ module Gitlab find_user_from_web_access_token(request_format, scopes: [:api, :read_api]) || find_user_from_feed_token(request_format) || find_user_from_static_object_token(request_format) || - find_user_from_basic_auth_job || + find_user_from_job_token_basic_auth || find_user_from_job_token || find_user_from_personal_access_token_for_api_or_git || find_user_for_git_or_lfs_request diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml index fa1d8bec7e6..2a07530c00d 100644 --- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @@ -65,10 +65,6 @@ variables: DOCKER_TLS_CERTDIR: "" # https://gitlab.com/gitlab-org/gitlab-runner/issues/4501 - # License-Scanning job is removed from GitLab 16.3 - # This is the fix for https://gitlab.com/gitlab-org/gitlab/-/issues/422791 - LICENSE_MANAGEMENT_DISABLED: "true" - stages: - build - test @@ -182,7 +178,6 @@ include: - template: Jobs/Container-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml - template: Jobs/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml - template: Jobs/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml - - template: Jobs/License-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml - template: Jobs/Secret-Detection.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Secret-Detection.gitlab-ci.yml # The latest build job generates a dotenv report artifact with a CI_APPLICATION_TAG diff --git a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml index 5cee19a746c..fe8f3be11b4 100644 --- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml @@ -22,7 +22,7 @@ # List of available variables: https://docs.gitlab.com/ee/user/application_security/container_scanning/#available-variables variables: - CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:6" + CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:7" CS_SCHEMA_MODEL: 15 container_scanning: diff --git a/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml index ade4be99f18..30c6a30f2fb 100644 --- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml @@ -22,7 +22,7 @@ # List of available variables: https://docs.gitlab.com/ee/user/application_security/container_scanning/#available-variables variables: - CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:6" + CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:7" CS_SCHEMA_MODEL: 15 container_scanning: diff --git a/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml deleted file mode 100644 index 58846d31e2f..00000000000 --- a/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml +++ /dev/null @@ -1,38 +0,0 @@ -# To contribute improvements to CI/CD templates, please follow the Development guide at: -# https://docs.gitlab.com/ee/development/cicd/templates.html -# This specific template is located at: -# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml - -# Read more about this feature here: https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html -# -# Configure license scanning with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html). -# List of available variables: https://docs.gitlab.com/ee/user/compliance/license_compliance/#available-variables - -variables: - # Setting this variable will affect all Security templates - # (SAST, Dependency Scanning, ...) - SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products" - - LICENSE_MANAGEMENT_SETUP_CMD: '' # If needed, specify a command to setup your environment with a custom package manager. - LICENSE_MANAGEMENT_VERSION: 'removed' - -license_scanning: - stage: test - image: - name: "$SECURE_ANALYZERS_PREFIX/license-finder:$LICENSE_MANAGEMENT_VERSION" - entrypoint: [""] - variables: - LM_REPORT_VERSION: '2.1' - SETUP_CMD: $LICENSE_MANAGEMENT_SETUP_CMD - allow_failure: true - script: - - /run.sh analyze . - artifacts: - reports: - license_scanning: gl-license-scanning-report.json - dependencies: [] - rules: - - if: $LICENSE_MANAGEMENT_DISABLED == 'true' || $LICENSE_MANAGEMENT_DISABLED == '1' - when: never - - if: $CI_COMMIT_BRANCH && - $GITLAB_FEATURES =~ /\blicense_scanning\b/ diff --git a/lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml deleted file mode 100644 index 8e1b0159cb0..00000000000 --- a/lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml +++ /dev/null @@ -1,48 +0,0 @@ -# To contribute improvements to CI/CD templates, please follow the Development guide at: -# https://docs.gitlab.com/ee/development/cicd/templates.html -# This specific template is located at: -# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml - -# Read more about this feature here: https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html -# -# Configure license scanning with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html). -# List of available variables: https://docs.gitlab.com/ee/user/compliance/license_compliance/#available-variables - -variables: - # Setting this variable will affect all Security templates - # (SAST, Dependency Scanning, ...) - SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products" - - LICENSE_MANAGEMENT_SETUP_CMD: '' # If needed, specify a command to setup your environment with a custom package manager. - LICENSE_MANAGEMENT_VERSION: 4 - -license_scanning: - stage: test - image: - name: "$SECURE_ANALYZERS_PREFIX/license-finder:$LICENSE_MANAGEMENT_VERSION" - entrypoint: [""] - variables: - LM_REPORT_VERSION: '2.1' - SETUP_CMD: $LICENSE_MANAGEMENT_SETUP_CMD - allow_failure: true - script: - - /run.sh analyze . - artifacts: - reports: - license_scanning: gl-license-scanning-report.json - dependencies: [] - rules: - - if: $LICENSE_MANAGEMENT_DISABLED == 'true' || $LICENSE_MANAGEMENT_DISABLED == '1' - when: never - - # Add the job to merge request pipelines if there's an open merge request. - - if: $CI_PIPELINE_SOURCE == "merge_request_event" && - $GITLAB_FEATURES =~ /\blicense_scanning\b/ - - # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. - - if: $CI_OPEN_MERGE_REQUESTS - when: never - - # Add the job to branch pipelines. - - if: $CI_COMMIT_BRANCH && - $GITLAB_FEATURES =~ /\blicense_scanning\b/ diff --git a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml deleted file mode 100644 index 0fe544b2c84..00000000000 --- a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml +++ /dev/null @@ -1,5 +0,0 @@ -# This template moved to Jobs/License-Scanning.gitlab-ci.yml in GitLab 14.8 -# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/292977 - -include: - - template: Jobs/License-Scanning.gitlab-ci.yml diff --git a/lib/gitlab/graphql/type_name_deprecations.rb b/lib/gitlab/graphql/type_name_deprecations.rb index b06749df269..34f7e16e515 100644 --- a/lib/gitlab/graphql/type_name_deprecations.rb +++ b/lib/gitlab/graphql/type_name_deprecations.rb @@ -11,11 +11,7 @@ module Gitlab # old_name: 'RunnerMembershipFilter', new_name: 'CiRunnerMembershipFilter', milestone: '15.4' # ) # ].freeze - DEPRECATIONS = [ - Gitlab::Graphql::DeprecationsBase::NameDeprecation.new( - old_name: 'RunnerMembershipFilter', new_name: 'CiRunnerMembershipFilter', milestone: '15.4' - ) - ].freeze + DEPRECATIONS = [].freeze def self.map_graphql_name(name) name diff --git a/lib/tasks/gitlab/graphql.rake b/lib/tasks/gitlab/graphql.rake index 8a677ff4677..686abe0900b 100644 --- a/lib/tasks/gitlab/graphql.rake +++ b/lib/tasks/gitlab/graphql.rake @@ -20,13 +20,18 @@ namespace :gitlab do end end + task generous_gitlab_schema: :environment do + GitlabSchema.validate_timeout 1.second + puts "Validation timeout set to #{GitlabSchema.validate_timeout} second(s)" + end + # Defines tasks for dumping the GraphQL schema: # - gitlab:graphql:schema:dump # - gitlab:graphql:schema:idl # - gitlab:graphql:schema:json GraphQL::RakeTask.new( schema_name: 'GitlabSchema', - dependencies: [:environment, :enable_feature_flags], + dependencies: [:environment, :enable_feature_flags, :generous_gitlab_schema], directory: TEMP_SCHEMA_DIR, idl_outfile: "gitlab_schema.graphql", json_outfile: "gitlab_schema.json" @@ -70,13 +75,7 @@ namespace :gitlab do end desc 'GitLab | GraphQL | Validate queries' - task validate: [:environment, :enable_feature_flags] do |t, args| - class GenerousTimeoutSchema < GitlabSchema # rubocop:disable Gitlab/NamespacedClass - validate_timeout 1.second - end - - puts "Validating GraphQL queries. Validation timeout set to #{GenerousTimeoutSchema.validate_timeout} second(s)" - + task validate: [:environment, :enable_feature_flags, :generous_gitlab_schema] do |t, args| queries = if args.to_a.present? args.to_a.flat_map { |path| Gitlab::Graphql::Queries.find(path) } else @@ -84,7 +83,7 @@ namespace :gitlab do end failed = queries.flat_map do |defn| - summary, errs = defn.validate(GenerousTimeoutSchema) + summary, errs = defn.validate(GitlabSchema) case summary when :client_query diff --git a/lib/unnested_in_filters/rewriter.rb b/lib/unnested_in_filters/rewriter.rb index 2e334eb147b..386dd548127 100644 --- a/lib/unnested_in_filters/rewriter.rb +++ b/lib/unnested_in_filters/rewriter.rb @@ -69,6 +69,90 @@ module UnnestedInFilters end end + # A naive query planner implementation. + # Checks if a database-level index can be utilized by given filtering and ordering predicates. + # + # Partial index support: + # - Supports partial indices if the partial index predicate contains only one column. + # - Supports only the `=` operator in partial index predicate. + class IndexCoverage + PARTIAL_INDEX_REGEX = /(?\(*(?\b\w+)\s*=\s*(?\w+)\)*)(?!\s)/ + + def initialize(index, where_hash, order_attributes) + @index = index + @where_hash = where_hash + @order_attributes = order_attributes + end + + def covers? + filter_attributes_covered? && + can_be_used_for_sorting? && + does_not_contain_any_other_column? + end + + private + + attr_reader :index, :where_hash, :order_attributes + + def filter_attributes_covered? + partial? ? partial_index_coverage? : full_index_coverage? + end + + def can_be_used_for_sorting? + index.columns.last(order_attributes.length) == order_attributes + end + + def does_not_contain_any_other_column? + (index.columns - combined_attributes).empty? + end + + def partial? + index.where.present? + end + + def full_index_coverage? + (filter_attributes - Array(index.columns)).empty? + end + + def partial_index_coverage? + return false unless partial_column + + full_index_coverage_with_partial_column? && partial_filter_matches? + end + + def full_index_coverage_with_partial_column? + (filter_attributes - Array(index.columns) - Array(partial_column)).empty? + end + + def combined_attributes + filter_attributes + order_attributes + end + + def filter_attributes + @filter_attributes ||= where_hash.keys + end + + def partial_filter_matches? + partial_filter == partial_value + end + + def partial_filter + where_hash[partial_column].to_s + end + + def partial_column + index_filter['column_name'] + end + + def partial_value + index_filter['column_value'] + end + + def index_filter + @index_filter ||= index.where.match(PARTIAL_INDEX_REGEX)&.named_captures.to_h + end + end + def initialize(relation) @relation = relation end @@ -252,11 +336,7 @@ module UnnestedInFilters end def has_index_coverage? - indices.any? do |index| - (filter_attributes - Array(index.columns)).empty? && # all the filter attributes are indexed - index.columns.last(order_attributes.length) == order_attributes && # index can be used in sorting - (index.columns - combined_attributes).empty? # there is no other columns in the index - end + indices.any?(&:covers?) end def primary_key_present? @@ -285,7 +365,9 @@ module UnnestedInFilters end def indices - model.connection.schema_cache.indexes(model.table_name) + model.connection.schema_cache.indexes(model.table_name).map do |index| + IndexCoverage.new(index, where_clause.to_h, order_attributes) + end end def value_tables diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb index 2e64987f605..88e1487df34 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb @@ -15,7 +15,6 @@ module QA # during the production run let(:optional_jobs) do %w[ - LICENSE_MANAGEMENT_DISABLED SAST_DISABLED DAST_DISABLED DEPENDENCY_SCANNING_DISABLED CONTAINER_SCANNING_DISABLED diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index b0eea1e5553..12e37f2742d 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -80,7 +80,7 @@ module QA def disable_optional_jobs(project) %w[ - TEST_DISABLED CODE_QUALITY_DISABLED LICENSE_MANAGEMENT_DISABLED + TEST_DISABLED CODE_QUALITY_DISABLED BROWSER_PERFORMANCE_DISABLED LOAD_PERFORMANCE_DISABLED SAST_DISABLED SECRET_DETECTION_DISABLED DEPENDENCY_SCANNING_DISABLED CONTAINER_SCANNING_DISABLED DAST_DISABLED REVIEW_DISABLED diff --git a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_status_bar_spec.js b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_status_bar_spec.js index 0bed741a21e..df6f5cfd725 100644 --- a/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_status_bar_spec.js +++ b/spec/frontend/environments/environment_details/components/kubernetes/kubernetes_status_bar_spec.js @@ -28,7 +28,7 @@ const configuration = { }; const environmentName = 'environment_name'; const kustomizationResourcePath = - 'kustomize.toolkit.fluxcd.io/v1beta1/namespaces/my-namespace/kustomizations/app'; + 'kustomize.toolkit.fluxcd.io/v1/namespaces/my-namespace/kustomizations/app'; describe('~/environments/environment_details/components/kubernetes/kubernetes_status_bar.vue', () => { let wrapper; @@ -280,7 +280,7 @@ describe('~/environments/environment_details/components/kubernetes/kubernetes_st createWrapper({ apolloProvider: createApolloProviderWithErrors(), fluxResourcePath: - 'kustomize.toolkit.fluxcd.io/v1beta1/namespaces/my-namespace/kustomizations/app', + 'kustomize.toolkit.fluxcd.io/v1/namespaces/my-namespace/kustomizations/app', }); await waitForPromises(); }); diff --git a/spec/frontend/environments/environment_flux_resource_selector_spec.js b/spec/frontend/environments/environment_flux_resource_selector_spec.js index 8dab8fdd96a..a05deb52463 100644 --- a/spec/frontend/environments/environment_flux_resource_selector_spec.js +++ b/spec/frontend/environments/environment_flux_resource_selector_spec.js @@ -29,7 +29,7 @@ describe('~/environments/components/flux_resource_selector.vue', () => { let wrapper; const kustomizationItem = { - apiVersion: 'kustomize.toolkit.fluxcd.io/v1beta1', + apiVersion: 'kustomize.toolkit.fluxcd.io/v1', metadata: { name: 'kustomization', namespace }, }; const helmReleaseItem = { diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js index 4754d1c15a8..9501887b10c 100644 --- a/spec/frontend/environments/graphql/mock_data.js +++ b/spec/frontend/environments/graphql/mock_data.js @@ -822,7 +822,7 @@ export const fluxKustomizationsMock = [ }, ]; -export const fluxResourcePathMock = 'path/to/flux/resource'; +export const fluxResourcePathMock = 'kustomize.toolkit.fluxcd.io/v1/path/to/flux/resource'; export const resolvedEnvironmentToDelete = { __typename: 'LocalEnvironment', diff --git a/spec/frontend/environments/graphql/resolvers/flux_spec.js b/spec/frontend/environments/graphql/resolvers/flux_spec.js index 526c98b55b3..ff808032205 100644 --- a/spec/frontend/environments/graphql/resolvers/flux_spec.js +++ b/spec/frontend/environments/graphql/resolvers/flux_spec.js @@ -28,7 +28,7 @@ describe('~/frontend/environments/graphql/resolvers', () => { describe('fluxKustomizationStatus', () => { const client = { writeQuery: jest.fn() }; const fluxResourcePath = - 'kustomize.toolkit.fluxcd.io/v1beta1/namespaces/my-namespace/kustomizations/app'; + 'kustomize.toolkit.fluxcd.io/v1/namespaces/my-namespace/kustomizations/app'; const endpoint = `${configuration.basePath}/apis/${fluxResourcePath}`; describe('when k8sWatchApi feature is disabled', () => { @@ -84,7 +84,7 @@ describe('~/frontend/environments/graphql/resolvers', () => { }); const resourceName = 'custom-resource'; const resourceNamespace = 'custom-namespace'; - const apiVersion = 'kustomize.toolkit.fluxcd.io/v1beta1'; + const apiVersion = 'kustomize.toolkit.fluxcd.io/v1'; beforeEach(() => { gon.features = { k8sWatchApi: true }; diff --git a/spec/frontend/issues/list/components/empty_state_without_any_issues_spec.js b/spec/frontend/issues/list/components/empty_state_without_any_issues_spec.js index 004e5fd9356..ab3e90e40ab 100644 --- a/spec/frontend/issues/list/components/empty_state_without_any_issues_spec.js +++ b/spec/frontend/issues/list/components/empty_state_without_any_issues_spec.js @@ -184,7 +184,7 @@ describe('EmptyStateWithoutAnyIssues component', () => { const experimentTracking = { 'data-track-experiment': 'issues_mrs_empty_state' }; const emptyStateBlockTracking = { - 'data-track-action': 'render_project_issues_empty_list_page', + 'data-track-action': 'render', 'data-track-label': 'project_issues_empty_list', }; diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb index dc664f281b7..cbfea04e71d 100644 --- a/spec/graphql/types/ci/runner_type_spec.rb +++ b/spec/graphql/types/ci/runner_type_spec.rb @@ -10,9 +10,9 @@ RSpec.describe GitlabSchema.types['CiRunner'], feature_category: :runner do it 'contains attributes related to a runner' do expected_fields = %w[ id description created_by created_at contacted_at managers maximum_timeout access_level active paused status - version short_sha revision locked run_untagged ip_address runner_type tag_list - project_count job_count admin_url edit_admin_url register_admin_url user_permissions executor_name - architecture_name platform_name maintenance_note maintenance_note_html groups projects jobs token_expires_at + short_sha locked run_untagged runner_type tag_list + project_count job_count admin_url edit_admin_url register_admin_url user_permissions + maintenance_note maintenance_note_html groups projects jobs token_expires_at owner_project job_execution_status ephemeral_authentication_token ephemeral_register_url ] diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb index 26e6cd36615..914d675452c 100644 --- a/spec/lib/gitlab/auth/auth_finders_spec.rb +++ b/spec/lib/gitlab/auth/auth_finders_spec.rb @@ -786,8 +786,8 @@ RSpec.describe Gitlab::Auth::AuthFinders, feature_category: :system_access do end end - describe '#find_user_from_basic_auth_job' do - subject { find_user_from_basic_auth_job } + describe '#find_user_from_job_token_basic_auth' do + subject { find_user_from_job_token_basic_auth } context 'when the request does not have AUTHORIZATION header' do it { is_expected.to be_nil } @@ -1037,6 +1037,60 @@ RSpec.describe Gitlab::Auth::AuthFinders, feature_category: :system_access do end end + context 'for route_authentication_setting[job_token_allowed]' do + using RSpec::Parameterized::TableSyntax + + where(:route_setting, :expect_user_via_request, :expect_user_via_basic_auth) do + true | true | false + :request | true | false + [:request] | true | false + :basic_auth | false | true + [:basic_auth] | false | true + [:request, :basic_auth] | true | true + + # unexpected values + :foo | false | false + [:foo] | false | false + [:foo, :bar] | false | false + end + + with_them do + let(:route_authentication_setting) { { job_token_allowed: route_setting } } + + context 'when the token is in the headers' do + before do + set_header(described_class::JOB_TOKEN_HEADER, token) + end + + it { is_expected.to eq(expect_user_via_request ? user : nil) } + end + + context 'when the token is in the job_token param' do + before do + set_param(described_class::JOB_TOKEN_PARAM, token) + end + + it { is_expected.to eq(expect_user_via_request ? user : nil) } + end + + context 'when the token is in the token param' do + before do + set_param(described_class::RUNNER_JOB_TOKEN_PARAM, token) + end + + it { is_expected.to eq(expect_user_via_request ? user : nil) } + end + + context 'when the token is in basic auth header' do + before do + set_basic_auth_header(::Gitlab::Auth::CI_JOB_USER, token) + end + + it { is_expected.to eq(expect_user_via_basic_auth ? user : nil) } + end + end + end + context 'when route setting allows job_token' do let(:route_authentication_setting) { { job_token_allowed: true } } diff --git a/spec/lib/unnested_in_filters/rewriter_spec.rb b/spec/lib/unnested_in_filters/rewriter_spec.rb index 945a50ce2e8..24ee4c16b52 100644 --- a/spec/lib/unnested_in_filters/rewriter_spec.rb +++ b/spec/lib/unnested_in_filters/rewriter_spec.rb @@ -62,6 +62,44 @@ RSpec.describe UnnestedInFilters::Rewriter do end end end + + context 'with partial indices' do + let(:relation) { Vulnerability.where(state: [:detected, :confirmed], resolved_on_default_branch: false) } + + before do + Vulnerability.reset_column_information + end + + context 'when there is a partial index coverage for the used columns' do + before do + ApplicationRecord.connection.execute(<<~SQL) + CREATE INDEX on vulnerabilities USING btree(state) WHERE (resolved_on_default_branch = false) + SQL + end + + it { is_expected.to be_truthy } + end + + context 'when there is no partial index coverage for the used columns' do + before do + ApplicationRecord.connection.execute(<<~SQL) + CREATE INDEX on vulnerabilities USING btree(state) WHERE (id = 100) + SQL + end + + it { is_expected.to be_falsey } + end + + context 'when the partial index definition has more columns' do + before do + ApplicationRecord.connection.execute(<<~SQL) + CREATE INDEX on vulnerabilities USING btree(state) WHERE (resolved_on_default_branch = false AND id = 100) + SQL + end + + it { is_expected.to be_falsey } + end + end end end diff --git a/spec/models/ci/runner_manager_spec.rb b/spec/models/ci/runner_manager_spec.rb index bc479036b00..eca02c01796 100644 --- a/spec/models/ci/runner_manager_spec.rb +++ b/spec/models/ci/runner_manager_spec.rb @@ -226,6 +226,16 @@ RSpec.describe Ci::RunnerManager, feature_category: :fleet_visibility, type: :mo it { is_expected.to eq([runner_manager2, runner_manager1]) } end + describe '.order_contacted_at_desc', :freeze_time do + subject(:scope) { described_class.order_contacted_at_desc } + + let_it_be(:runner_manager1) { create(:ci_runner_machine, contacted_at: 1.second.ago) } + let_it_be(:runner_manager2) { create(:ci_runner_machine, contacted_at: 3.seconds.ago) } + let_it_be(:runner_manager3) { create(:ci_runner_machine, contacted_at: 2.seconds.ago) } + + it { is_expected.to eq([runner_manager1, runner_manager3, runner_manager2]) } + end + describe '.with_upgrade_status' do subject(:scope) { described_class.with_upgrade_status(upgrade_status) } diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index dd9ecdf993c..485e400eb26 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -386,26 +386,6 @@ RSpec.describe Repository, feature_category: :source_code_management do end end - context 'when Gitaly raises a CommandError error' do - let(:error_message) { 'Boom' } - - before do - expect(Gitlab::Git::Commit).to receive(:where).and_raise(Gitlab::Git::CommandError, error_message) - end - - it 're-raises an error' do - expect { repository.commits('master', limit: 60) }.to raise_error(Gitlab::Git::CommandError, error_message) - end - - context 'when error contains "listing commits failed" message' do - let(:error_message) { 'listing commits failed' } - - it 'returns an empty collection' do - expect(repository.commits('master', limit: 60).to_a).to eq([]) - end - end - end - context 'when ref is passed' do it 'returns every commit from the specified ref' do expect(repository.commits('master', limit: 60).size).to eq(37) diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 85a07d85174..db76b03090a 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -277,6 +277,29 @@ RSpec.describe API::Commits, feature_category: :source_code_management do end end + context 'with ref_name + path params' do + let(:params) { { ref_name: ref_name, path: 'files/ruby/popen.rb' } } + let(:ref_name) { 'master' } + + it 'returns project commits matching provided path parameter' do + get api("/projects/#{project_id}/repository/commits", user), params: params + + expect(json_response.size).to eq(3) + expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") + expect(response).to include_limited_pagination_headers + end + + context 'when ref_name does not exist' do + let(:ref_name) { 'does-not-exist' } + + it 'returns an empty response' do + get api("/projects/#{project_id}/repository/commits", user), params: params + + expect(json_response).to eq([]) + end + end + end + context 'with pagination params' do let(:page) { 1 } let(:per_page) { 5 } diff --git a/spec/requests/api/generic_packages_spec.rb b/spec/requests/api/generic_packages_spec.rb index cf9912ba906..eadd0817fb6 100644 --- a/spec/requests/api/generic_packages_spec.rb +++ b/spec/requests/api/generic_packages_spec.rb @@ -29,6 +29,8 @@ RSpec.describe API::GenericPackages, feature_category: :package_registry do personal_access_token_header when :job_token job_token_header + when :job_basic_auth + job_basic_auth_header when :invalid_personal_access_token personal_access_token_header('wrong token') when :invalid_job_token @@ -61,6 +63,10 @@ RSpec.describe API::GenericPackages, feature_category: :package_registry do { Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER => value || ci_build.token } end + def job_basic_auth_header(value = nil) + basic_auth_header(Gitlab::Auth::CI_JOB_USER, value || ci_build.token) + end + def deploy_token_header(value) { Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => value } end @@ -564,12 +570,16 @@ RSpec.describe API::GenericPackages, feature_category: :package_registry do 'PRIVATE' | :guest | false | :invalid_user_basic_auth | :unauthorized 'PRIVATE' | :anonymous | false | :none | :unauthorized 'PUBLIC' | :developer | true | :job_token | :success + 'PUBLIC' | :developer | true | :job_basic_auth | :success 'PUBLIC' | :developer | true | :invalid_job_token | :unauthorized 'PUBLIC' | :developer | false | :job_token | :success + 'PUBLIC' | :developer | false | :job_basic_auth | :success 'PUBLIC' | :developer | false | :invalid_job_token | :unauthorized 'PRIVATE' | :developer | true | :job_token | :success + 'PRIVATE' | :developer | true | :job_basic_auth | :success 'PRIVATE' | :developer | true | :invalid_job_token | :unauthorized 'PRIVATE' | :developer | false | :job_token | :not_found + 'PRIVATE' | :developer | false | :job_basic_auth | :not_found 'PRIVATE' | :developer | false | :invalid_job_token | :unauthorized end diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb index a2fb646769b..ec30c6fb71c 100644 --- a/spec/requests/api/graphql/ci/runner_spec.rb +++ b/spec/requests/api/graphql/ci/runner_spec.rb @@ -89,9 +89,7 @@ RSpec.describe 'Query.runner(id)', :freeze_time, feature_category: :fleet_visibi created_by: runner.creator ? a_graphql_entity_for(runner.creator) : nil, created_at: runner.created_at&.iso8601, contacted_at: runner.contacted_at&.iso8601, - version: runner.version, short_sha: runner.short_sha, - revision: runner.revision, locked: false, active: runner.active, paused: !runner.active, @@ -100,12 +98,8 @@ RSpec.describe 'Query.runner(id)', :freeze_time, feature_category: :fleet_visibi maximum_timeout: runner.maximum_timeout, access_level: runner.access_level.to_s.upcase, run_untagged: runner.run_untagged, - ip_address: runner.ip_address, runner_type: runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE', ephemeral_authentication_token: nil, - executor_name: runner.executor_type&.dasherize, - architecture_name: runner.architecture, - platform_name: runner.platform, maintenance_note: runner.maintenance_note, maintenance_note_html: runner.maintainer_note.present? ? a_string_including('Test maintenance note') : '', diff --git a/spec/views/devise/shared/_signup_box.html.haml_spec.rb b/spec/views/devise/shared/_signup_box.html.haml_spec.rb index e4ca48f1623..d620449672d 100644 --- a/spec/views/devise/shared/_signup_box.html.haml_spec.rb +++ b/spec/views/devise/shared/_signup_box.html.haml_spec.rb @@ -110,10 +110,22 @@ RSpec.describe 'devise/shared/_signup_box', feature_category: :system_access do expect(rendered).to include(s_('SignUp|Contribute to a public project on GitLab')) expect(rendered).to have_css('select[name="signup_intent"]') - expect(rendered).to have_css('option[value="new_team"]') - expect(rendered).to have_css('option[value="new_personal_account"]') - expect(rendered).to have_css('option[value="join_existing_team"]') - expect(rendered).to have_css('option[value="contribute_public_project"]') + + expect(rendered).to have_css( + 'option[value="select_signup_intent_dropdown_new_team_registration_step_one"]' + ) + + expect(rendered).to have_css( + 'option[value="select_signup_intent_dropdown_new_personal_account_registration_step_one"]' + ) + + expect(rendered).to have_css( + 'option[value="select_signup_intent_dropdown_join_existing_team_registration_step_one"]' + ) + + expect(rendered).to have_css( + 'option[value="select_signup_intent_dropdown_contribute_public_project_registration_step_one"]' + ) end end diff --git a/workhorse/go.mod b/workhorse/go.mod index 833670fdd90..93174b7b34e 100644 --- a/workhorse/go.mod +++ b/workhorse/go.mod @@ -1,6 +1,8 @@ module gitlab.com/gitlab-org/gitlab/workhorse -go 1.20 +go 1.21 + +toolchain go1.21.9 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 diff --git a/workhorse/go.sum b/workhorse/go.sum index 7d31ec736c7..b2b44637324 100644 --- a/workhorse/go.sum +++ b/workhorse/go.sum @@ -67,6 +67,7 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMiv github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 h1:fXPMAmuh0gDuRDey0atC8cXBuKIlqCzCkL8sm1n9Ov0= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -85,36 +86,58 @@ github.com/DataDog/gostackparse v0.5.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZ github.com/DataDog/sketches-go v1.0.0 h1:chm5KSXO7kO+ywGWJ0Zs6tdmWU8PBXSbywFVciL6BG4= github.com/DataDog/sketches-go v1.0.0/go.mod h1:O+XkJHWk9w4hDwY2ZUDU31ZC9sNYlYo8DiFsxjYeo1k= github.com/HdrHistogram/hdrhistogram-go v1.1.1 h1:cJXY5VLMHgejurPjZH6Fo9rIwRGLefBGdiaENZALqrg= +github.com/HdrHistogram/hdrhistogram-go v1.1.1/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= +github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI= github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go v1.51.14 h1:qedX6zZEO1a+5kra+D4ythOYR3TgaROC0hTPxhTFh8I= github.com/aws/aws-sdk-go v1.51.14/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.25.3 h1:xYiLpZTQs1mzvz5PaI6uR0Wh57ippuEthxS4iK5v0n0= +github.com/aws/aws-sdk-go-v2 v1.25.3/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo= github.com/aws/aws-sdk-go-v2/config v1.27.7 h1:JSfb5nOQF01iOgxFI5OIKWwDiEXWTyTgg1Mm1mHi0A4= +github.com/aws/aws-sdk-go-v2/config v1.27.7/go.mod h1:PH0/cNpoMO+B04qET699o5W92Ca79fVtbUnvMIZro4I= github.com/aws/aws-sdk-go-v2/credentials v1.17.7 h1:WJd+ubWKoBeRh7A5iNMnxEOs982SyVKOJD+K8HIezu4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.7/go.mod h1:UQi7LMR0Vhvs+44w5ec8Q+VS+cd10cjwgHwiVkE0YGU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 h1:p+y7FvkK2dxS+FEwRIDHDe//ZX+jDhP8HHE50ppj4iI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3/go.mod h1:/fYB+FZbDlwlAiynK9KDXlzZl3ANI9JkD0Uhz5FjNT4= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9 h1:vXY/Hq1XdxHBIYgBUmug/AbMyIe1AKulPYS2/VE1X70= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9/go.mod h1:GyJJTZoHVuENM4TeJEl5Ffs4W9m19u+4wKJcDi/GZ4A= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 h1:ifbIbHZyGl1alsAhPIYsHOg5MuApgqOvVeI8wIugXfs= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3/go.mod h1:oQZXg3c6SNeY6OZrDY+xHcF4VGIEoNotX2B4PrDeoJI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 h1:Qvodo9gHG9F3E8SfYOspPeBt0bjSbsevK8WhRAUHcoY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3/go.mod h1:vCKrdLXtybdf/uQd/YfVR2r5pcbNuEYKzMQpcxmeSJw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3 h1:mDnFOE2sVkyphMWtTH+stv0eW3k0OTx94K63xpxHty4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3/go.mod h1:V8MuRVcCRt5h1S+Fwu8KbC7l/gBGo3yBAyUbJM2IJOk= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5 h1:mbWNpfRUTT6bnacmvOTKXZjR/HycibdWzNpfbrbLDIs= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5/go.mod h1:FCOPWGjsshkkICJIn9hq9xr6dLKtyaWpuUojiN3W1/8= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 h1:K/NXvIftOlX+oGgWGIa3jDyYLDNsdVhsjHmsBH2GLAQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5/go.mod h1:cl9HGLV66EnCmMNzq4sYOti+/xo8w34CsgzVtm2GgsY= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3 h1:4t+QEX7BsXz98W8W1lNvMAG+NX8qHz2CjLBxQKku40g= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3/go.mod h1:oFcjjUq5Hm09N9rpxTdeMeLeQcxS7mIkBkL8qUKng+A= github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4 h1:lW5xUzOPGAMY7HPuNF4FdyBwRc3UJ/e8KsapbesVeNU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4/go.mod h1:MGTaf3x/+z7ZGugCGvepnx2DS6+caCYYqKhzVoLNYPk= github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 h1:XOPfar83RIRPEzfihnp+U6udOveKZJvPQ76SKWrLRHc= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.2/go.mod h1:Vv9Xyk1KMHXrR3vNQe8W5LMFdTjSeWk0gBZBzvf3Qa0= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 h1:pi0Skl6mNl2w8qWZXcdOyg197Zsf4G97U7Sso9JXGZE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2/go.mod h1:JYzLoEVeLXk+L4tn1+rrkfhkxl6mLDEVaDSvGq9og90= github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 h1:Ppup1nVNAOWbBOrcoOxaxPeEnSFB2RnnQdguhXpmeQk= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.4/go.mod h1:+K1rNPVyGxkRuv9NNiaZ4YhBFuyw2MMA9SlIJ1Zlpz8= github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= +github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -122,7 +145,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= @@ -137,6 +162,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/client9/reopen v1.0.0 h1:8tpLVR74DLpLObrn2KvsyxJY++2iORGR17WLUdSzUws= github.com/client9/reopen v1.0.0/go.mod h1:caXVCEr+lUtoN1FlsRiOWdfQtdRHIYfcb0ai8qKWtkQ= github.com/cloudflare/tableflip v1.2.3 h1:8I+B99QnnEWPHOY3fWipwVKxS70LGgUsslG7CSfmHMw= +github.com/cloudflare/tableflip v1.2.3/go.mod h1:P4gRehmV6Z2bY5ao5ml9Pd8u6kuEnlB37pUFMmv7j2E= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -152,6 +178,7 @@ github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44am github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -243,8 +270,11 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= +github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= @@ -253,6 +283,7 @@ github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIG github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -305,6 +336,7 @@ github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh github.com/hashicorp/yamux v0.1.2-0.20220728231024-8f49b6f63f18 h1:IVujPV6DRIu1fYF4zUHrfhkngJzmYjelXa+iSUiFZSI= github.com/hashicorp/yamux v0.1.2-0.20220728231024-8f49b6f63f18/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -328,6 +360,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -343,6 +376,7 @@ github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1: github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -353,8 +387,10 @@ github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOE github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -389,6 +425,7 @@ github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM= @@ -416,6 +453,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -471,6 +509,7 @@ go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= @@ -479,6 +518,7 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= @@ -505,6 +545,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE= golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -935,6 +976,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -946,6 +988,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=