diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-30 15:07:02 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-30 15:07:02 +0000 |
commit | 826cf5293fb78029f76c5e769696e3b37e681207 (patch) | |
tree | 703bc997b5fa36c42e2bd7486f000ad41b01d252 | |
parent | 7aa22e9a103b049dd2da70045a5822c51164f7db (diff) | |
download | gitlab-ce-826cf5293fb78029f76c5e769696e3b37e681207.tar.gz |
Add latest changes from gitlab-org/gitlab@master
54 files changed, 441 insertions, 280 deletions
diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml index df7e4b64ef0..1eeafaeedc3 100644 --- a/.rubocop_todo/gitlab/strong_memoize_attr.yml +++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml @@ -32,6 +32,7 @@ Gitlab/StrongMemoizeAttr: - 'app/controllers/projects/forks_controller.rb' - 'app/controllers/projects/import/jira_controller.rb' - 'app/controllers/projects/incidents_controller.rb' + - 'app/controllers/projects/merge_requests/drafts_controller.rb' - 'app/controllers/projects/merge_requests_controller.rb' - 'app/controllers/projects/metrics_dashboard_controller.rb' - 'app/controllers/projects/milestones_controller.rb' @@ -68,6 +69,8 @@ Gitlab/StrongMemoizeAttr: - 'app/graphql/resolvers/work_items_resolver.rb' - 'app/graphql/types/board_list_type.rb' - 'app/helpers/appearances_helper.rb' + - 'app/helpers/broadcast_messages_helper.rb' + - 'app/helpers/diff_helper.rb' - 'app/helpers/operations_helper.rb' - 'app/helpers/page_layout_helper.rb' - 'app/helpers/projects_helper.rb' @@ -99,10 +102,12 @@ Gitlab/StrongMemoizeAttr: - 'app/models/concerns/avatarable.rb' - 'app/models/concerns/cascading_namespace_setting_attribute.rb' - 'app/models/concerns/ci/contextable.rb' + - 'app/models/concerns/ci/partitionable.rb' - 'app/models/concerns/discussion_on_diff.rb' - 'app/models/concerns/has_repository.rb' - 'app/models/concerns/has_wiki.rb' - 'app/models/concerns/has_wiki_page_meta_attributes.rb' + - 'app/models/concerns/mentionable/reference_regexes.rb' - 'app/models/concerns/redis_cacheable.rb' - 'app/models/concerns/require_email_verification.rb' - 'app/models/concerns/resolvable_discussion.rb' @@ -131,6 +136,8 @@ Gitlab/StrongMemoizeAttr: - 'app/models/merge_request.rb' - 'app/models/merge_request_diff.rb' - 'app/models/namespace.rb' + - 'app/models/namespaces/traversal/linear.rb' + - 'app/models/namespaces/traversal/recursive.rb' - 'app/models/note.rb' - 'app/models/onboarding/completion.rb' - 'app/models/packages/go/module.rb' @@ -145,6 +152,7 @@ Gitlab/StrongMemoizeAttr: - 'app/models/snippet_input_action_collection.rb' - 'app/models/state_note.rb' - 'app/models/tree.rb' + - 'app/models/uploads/fog.rb' - 'app/models/user.rb' - 'app/models/wiki_page.rb' - 'app/models/work_item.rb' @@ -157,6 +165,7 @@ Gitlab/StrongMemoizeAttr: - 'app/presenters/ci/pipeline_presenter.rb' - 'app/presenters/clusters/cluster_presenter.rb' - 'app/presenters/merge_request_presenter.rb' + - 'app/presenters/packages/conan/package_presenter.rb' - 'app/presenters/packages/nuget/packages_metadata_presenter.rb' - 'app/presenters/packages/nuget/search_results_presenter.rb' - 'app/presenters/project_presenter.rb' @@ -215,6 +224,7 @@ Gitlab/StrongMemoizeAttr: - 'app/services/incident_management/issuable_escalation_statuses/prepare_update_service.rb' - 'app/services/incident_management/pager_duty/process_webhook_service.rb' - 'app/services/integrations/test/project_service.rb' + - 'app/services/issuable/discussions_list_service.rb' - 'app/services/issues/reorder_service.rb' - 'app/services/jira_connect_subscriptions/create_service.rb' - 'app/services/jira_import/users_mapper_service.rb' @@ -266,6 +276,7 @@ Gitlab/StrongMemoizeAttr: - 'app/services/projects/container_repository/third_party/cleanup_tags_service.rb' - 'app/services/projects/create_from_template_service.rb' - 'app/services/projects/gitlab_projects_import_service.rb' + - 'app/services/projects/lfs_pointers/lfs_object_download_list_service.rb' - 'app/services/projects/open_issues_count_service.rb' - 'app/services/projects/record_target_platforms_service.rb' - 'app/services/projects/update_remote_mirror_service.rb' @@ -337,6 +348,7 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/helpers/ee/welcome_helper.rb' - 'ee/app/helpers/license_monitoring_helper.rb' - 'ee/app/helpers/paid_feature_callout_helper.rb' + - 'ee/app/helpers/subscriptions_helper.rb' - 'ee/app/helpers/trial_status_widget_helper.rb' - 'ee/app/models/approval_merge_request_rule.rb' - 'ee/app/models/approval_state.rb' @@ -345,6 +357,7 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/models/approval_wrapped_rule.rb' - 'ee/app/models/approvals/scan_finding_wrapped_rule_set.rb' - 'ee/app/models/approvals/wrapped_rule_set.rb' + - 'ee/app/models/burndown.rb' - 'ee/app/models/ci/minutes/limit.rb' - 'ee/app/models/concerns/deprecated_approvals_before_merge.rb' - 'ee/app/models/concerns/ee/approvable.rb' @@ -357,6 +370,7 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/models/ee/ci/build.rb' - 'ee/app/models/ee/ci/build_dependencies.rb' - 'ee/app/models/ee/ci/job_artifact.rb' + - 'ee/app/models/ee/ci/pipeline.rb' - 'ee/app/models/ee/ci/runner.rb' - 'ee/app/models/ee/deployment.rb' - 'ee/app/models/ee/environment.rb' @@ -408,7 +422,9 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/services/ee/projects/gitlab_projects_import_service.rb' - 'ee/app/services/ee/protected_branches/create_service.rb' - 'ee/app/services/ee/search/global_service.rb' + - 'ee/app/services/ee/search/group_service.rb' - 'ee/app/services/ee/search_service.rb' + - 'ee/app/services/ee/users/authorized_build_service.rb' - 'ee/app/services/ee/users/build_service.rb' - 'ee/app/services/ee/users/update_service.rb' - 'ee/app/services/elastic/cluster_reindexing_service.rb' @@ -448,6 +464,7 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/services/vulnerability_feedback/destroy_service.rb' - 'ee/app/workers/auth/saml_group_sync_worker.rb' - 'ee/app/workers/geo/repository_cleanup_worker.rb' + - 'ee/app/workers/geo/scheduler/scheduler_worker.rb' - 'ee/app/workers/group_saml_group_sync_worker.rb' - 'ee/app/workers/status_page/publish_worker.rb' - 'ee/lib/api/analytics/project_deployment_frequency.rb' @@ -456,6 +473,7 @@ Gitlab/StrongMemoizeAttr: - 'ee/lib/api/vulnerability_exports.rb' - 'ee/lib/api/vulnerability_findings.rb' - 'ee/lib/ee/api/geo.rb' + - 'ee/lib/ee/api/helpers.rb' - 'ee/lib/ee/banzai/filter/references/reference_cache.rb' - 'ee/lib/ee/container_registry/client.rb' - 'ee/lib/ee/gitlab/alert_management/payload/generic.rb' @@ -499,10 +517,13 @@ Gitlab/StrongMemoizeAttr: - 'ee/lib/gitlab/code_owners/entry.rb' - 'ee/lib/gitlab/code_owners/loader.rb' - 'ee/lib/gitlab/custom_file_templates.rb' + - 'ee/lib/gitlab/elastic/client.rb' - 'ee/lib/gitlab/elastic/document_reference.rb' - 'ee/lib/gitlab/elastic/indexer.rb' + - 'ee/lib/gitlab/elastic/project_search_results.rb' - 'ee/lib/gitlab/elastic/search_results.rb' - 'ee/lib/gitlab/expiring_subscription_message.rb' + - 'ee/lib/gitlab/geo.rb' - 'ee/lib/gitlab/geo/health_check.rb' - 'ee/lib/gitlab/geo/jwt_request_decoder.rb' - 'ee/lib/gitlab/geo/oauth/logout_state.rb' @@ -528,6 +549,7 @@ Gitlab/StrongMemoizeAttr: - 'lib/api/composer_packages.rb' - 'lib/api/container_repositories.rb' - 'lib/api/entities/basic_project_details.rb' + - 'lib/api/helpers/authentication.rb' - 'lib/api/helpers/packages/basic_auth_helpers.rb' - 'lib/api/helpers/packages/conan/api_helpers.rb' - 'lib/api/helpers/packages/npm.rb' @@ -542,6 +564,7 @@ Gitlab/StrongMemoizeAttr: - 'lib/banzai/filter/issuable_reference_expansion_filter.rb' - 'lib/banzai/filter/references/reference_cache.rb' - 'lib/banzai/filter/repository_link_filter.rb' + - 'lib/banzai/reference_parser/merge_request_parser.rb' - 'lib/bulk_imports/clients/http.rb' - 'lib/bulk_imports/pipeline.rb' - 'lib/bulk_imports/users_mapper.rb' @@ -557,6 +580,7 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/analytics/cycle_analytics/average.rb' - 'lib/gitlab/analytics/cycle_analytics/data_collector.rb' - 'lib/gitlab/analytics/cycle_analytics/records_fetcher.rb' + - 'lib/gitlab/analytics/cycle_analytics/request_params.rb' - 'lib/gitlab/application_context.rb' - 'lib/gitlab/auth/atlassian/identity_linker.rb' - 'lib/gitlab/auth/auth_finders.rb' @@ -598,8 +622,10 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb' - 'lib/gitlab/ci/pipeline/chain/limit/rate_limit.rb' - 'lib/gitlab/ci/pipeline/chain/seed.rb' + - 'lib/gitlab/ci/pipeline/chain/skip.rb' - 'lib/gitlab/ci/pipeline/expression/lexer.rb' - 'lib/gitlab/ci/pipeline/logger.rb' + - 'lib/gitlab/ci/pipeline/metrics.rb' - 'lib/gitlab/ci/pipeline/quota/deployments.rb' - 'lib/gitlab/ci/pipeline/seed/build.rb' - 'lib/gitlab/ci/pipeline/seed/pipeline.rb' @@ -611,6 +637,7 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/ci/project_config/remote.rb' - 'lib/gitlab/ci/project_config/repository.rb' - 'lib/gitlab/ci/project_config/source.rb' + - 'lib/gitlab/ci/queue/metrics.rb' - 'lib/gitlab/ci/reports/accessibility_reports_comparer.rb' - 'lib/gitlab/ci/reports/codequality_reports_comparer.rb' - 'lib/gitlab/ci/reports/security/locations/base.rb' @@ -618,10 +645,13 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/ci/reports/test_reports_comparer.rb' - 'lib/gitlab/ci/reports/test_suite_comparer.rb' - 'lib/gitlab/ci/reports/test_suite_summary.rb' + - 'lib/gitlab/ci/runner/metrics.rb' + - 'lib/gitlab/ci/status/composite.rb' - 'lib/gitlab/ci/tags/bulk_insert.rb' - 'lib/gitlab/ci/trace.rb' - 'lib/gitlab/ci/trace/archive.rb' - 'lib/gitlab/ci/trace/checksum.rb' + - 'lib/gitlab/ci/trace/metrics.rb' - 'lib/gitlab/ci/trace/remote_checksum.rb' - 'lib/gitlab/ci/variables/builder.rb' - 'lib/gitlab/ci/variables/builder/group.rb' @@ -634,7 +664,9 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/config/entry/composable_array.rb' - 'lib/gitlab/config/loader/yaml.rb' - 'lib/gitlab/conflict/file.rb' + - 'lib/gitlab/database/as_with_materialized.rb' - 'lib/gitlab/database/background_migration/health_status/indicators/write_ahead_log.rb' + - 'lib/gitlab/database/background_migration/prometheus_metrics.rb' - 'lib/gitlab/database/bulk_update.rb' - 'lib/gitlab/database/load_balancing/srv_resolver.rb' - 'lib/gitlab/database/metrics.rb' @@ -650,12 +682,14 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/diff/suggestion.rb' - 'lib/gitlab/discussions_diff/file_collection.rb' - 'lib/gitlab/email/handler/service_desk_handler.rb' + - 'lib/gitlab/email/hook/delivery_metrics_observer.rb' - 'lib/gitlab/email/receiver.rb' - 'lib/gitlab/external_authorization/response.rb' - 'lib/gitlab/gfm/reference_rewriter.rb' - 'lib/gitlab/gfm/uploads_rewriter.rb' - 'lib/gitlab/git/commit.rb' - 'lib/gitlab/git/diff_stats_collection.rb' + - 'lib/gitlab/git/merge_base.rb' - 'lib/gitlab/git/push.rb' - 'lib/gitlab/git/repository.rb' - 'lib/gitlab/git/wiki_page_version.rb' @@ -689,10 +723,12 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/kubernetes/deployment.rb' - 'lib/gitlab/kubernetes/ingress.rb' - 'lib/gitlab/kubernetes/rollout_instances.rb' + - 'lib/gitlab/language_data.rb' - 'lib/gitlab/lets_encrypt/client.rb' - 'lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb' - 'lib/gitlab/metrics/dashboard/url.rb' - 'lib/gitlab/metrics/prometheus.rb' + - 'lib/gitlab/metrics/subscribers/active_record.rb' - 'lib/gitlab/pages/cache_control.rb' - 'lib/gitlab/prometheus_client.rb' - 'lib/gitlab/rack_attack/request.rb' @@ -702,7 +738,9 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/relative_positioning/starting_from.rb' - 'lib/gitlab/request_context.rb' - 'lib/gitlab/search/found_blob.rb' + - 'lib/gitlab/search/parsed_query.rb' - 'lib/gitlab/serverless/service.rb' + - 'lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb' - 'lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb' - 'lib/gitlab/sidekiq_queue.rb' - 'lib/gitlab/signed_commit.rb' @@ -715,7 +753,9 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/web_hooks/rate_limiter.rb' - 'lib/gitlab/web_ide/config/entry/terminal.rb' - 'lib/gitlab/webpack/graphql_known_operations.rb' + - 'lib/gitlab/webpack/manifest.rb' - 'lib/gitlab/wiki_pages/front_matter_parser.rb' + - 'lib/gitlab/x509/certificate.rb' - 'lib/gitlab/x509/signature.rb' - 'lib/gitlab/x509/tag.rb' - 'lib/grafana/time_window.rb' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index cabdb0c1288..74b94df5f28 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -ff3095c307c9223585ffe01d3e013929aa6279d8 +942f8800cc11d161785823fe8f65a77b5cb83718 @@ -19,7 +19,7 @@ gem 'bootsnap', '~> 1.15.0', require: false # Pin openssl to match the version bundled with our supported Rubies. # See https://stdgems.org/openssl/#gem-version. -gem 'openssl', '2.2.1' +gem 'openssl', '2.2.2' # This gem was originally bundled with Ruby 2.7, but is unbundled as of Ruby 3. # Since the latest version caused problems with GitLab, we pin this to an older # version for now. diff --git a/Gemfile.checksum b/Gemfile.checksum index 73608acb159..de417277434 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -403,7 +403,7 @@ {"name":"omniauth-twitter","version":"1.4.0","platform":"ruby","checksum":"c5cc6c77cd767745ffa9ebbd5fbd694a3fa99d1d2d82a4d7def0bf3b6131b264"}, {"name":"open4","version":"1.3.4","platform":"ruby","checksum":"a1df037310624ecc1ea1d81264b11c83e96d0c3c1c6043108d37d396dcd0f4b1"}, {"name":"openid_connect","version":"1.3.0","platform":"ruby","checksum":"a796855096850cc01140e37ea6ae9fd14f2be818b9b5bc698418063dfe228770"}, -{"name":"openssl","version":"2.2.1","platform":"ruby","checksum":"f6afbf4b66f3fcd3c08dc1da1ddd2245b76c19d0ea2dd7e2c8b55794ca1a7d72"}, +{"name":"openssl","version":"2.2.2","platform":"ruby","checksum":"53f72382bac046c36c37049c7ec9d5597d42628d140b5cfbcd61e0226c0ca077"}, {"name":"openssl-signature_algorithm","version":"0.4.0","platform":"ruby","checksum":"e53a225b773784935249cf4c61238c6cf0e1e464e78ae2f8ddaf995fb22ca991"}, {"name":"opentracing","version":"0.5.0","platform":"ruby","checksum":"deb5d7abe6b0e7631d866d8cb5ee7bb9352650a504a32f61591302bc510b9286"}, {"name":"optimist","version":"3.0.1","platform":"ruby","checksum":"336b753676d6117cad9301fac7e91dab4228f747d4e7179891ad3a163c64e2ed"}, diff --git a/Gemfile.lock b/Gemfile.lock index 94610975c23..beab0c53eac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1028,7 +1028,7 @@ GEM validate_email validate_url webfinger (>= 1.0.1) - openssl (2.2.1) + openssl (2.2.2) ipaddr openssl-signature_algorithm (0.4.0) opentracing (0.5.0) @@ -1763,7 +1763,7 @@ DEPENDENCIES omniauth-shibboleth (~> 1.3.0) omniauth-twitter (~> 1.4) omniauth_crowd (~> 2.4.0)! - openssl (= 2.2.1) + openssl (= 2.2.2) org-ruby (~> 0.9.12) pact (~> 1.63) parallel (~> 1.19) diff --git a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue index 1afc1c9a595..c9172fe0322 100644 --- a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue +++ b/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue @@ -2,9 +2,7 @@ import { GlButton, GlTableLite } from '@gitlab/ui'; import { __ } from '~/locale'; -const DEFAULT_TD_CLASSES = 'gl-w-half gl-font-sm! gl-border-gray-200!'; -const DEFAULT_TH_CLASSES = - 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-200! gl-border-b-1!'; +const DEFAULT_TD_CLASSES = 'gl-font-sm!'; export default { fields: [ @@ -13,14 +11,12 @@ export default { label: __('Key'), tdAttr: { 'data-testid': 'trigger-build-key' }, tdClass: DEFAULT_TD_CLASSES, - thClass: DEFAULT_TH_CLASSES, }, { key: 'value', label: __('Value'), tdAttr: { 'data-testid': 'trigger-build-value' }, tdClass: DEFAULT_TD_CLASSES, - thClass: DEFAULT_TH_CLASSES, }, ], components: { diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js index 3a6d7d2f779..e194bddcc56 100644 --- a/app/assets/javascripts/repository/constants.js +++ b/app/assets/javascripts/repository/constants.js @@ -99,5 +99,4 @@ export const LEGACY_FILE_TYPES = [ 'requirements_txt', 'cargo_toml', 'go_mod', - 'go_sum', ]; diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js index fca2616f069..cd15916851c 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js +++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js @@ -4,6 +4,7 @@ import godepsJsonLinker from './utils/godeps_json_linker'; import gemfileLinker from './utils/gemfile_linker'; import podspecJsonLinker from './utils/podspec_json_linker'; import composerJsonLinker from './utils/composer_json_linker'; +import goSumLinker from './utils/go_sum_linker'; const DEPENDENCY_LINKERS = { package_json: packageJsonLinker, @@ -12,6 +13,7 @@ const DEPENDENCY_LINKERS = { gemfile: gemfileLinker, podspec_json: podspecJsonLinker, composer_json: composerJsonLinker, + go_sum: goSumLinker, }; /** diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js new file mode 100644 index 00000000000..c0e3eadb3b3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js @@ -0,0 +1,33 @@ +import { createLink } from './dependency_linker_util'; + +const openTag = '<span class="">'; +const closeTag = '</span>'; +const TAG_URL = 'https://sum.golang.org/lookup/'; +const GO_PACKAGE_URL = 'https://pkg.go.dev/'; + +const DEPENDENCY_REGEX = new RegExp( + /* + * Detects dependencies inside of content that is highlighted by Highlight.js + * Example: '<span class="">cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=</span>' + * Group 1 (packageName): 'cloud.google.com/go/bigquery' + * Group 2 (version): 'v1.0.1/go.mod' + * Group 3 (base64url): 'i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=' + */ + `${openTag}(.*) (v.*) h1:(.*)${closeTag}`, + 'gm', +); + +const handleReplace = (packageName, version, tag) => { + const packageHref = `${GO_PACKAGE_URL}${packageName}`; + const packageLink = createLink(packageHref, packageName); + const tagHref = `${TAG_URL}${packageName}@${version.split('/go.mod')[0]}`; + const tagLink = createLink(tagHref, tag); + + return `${openTag}${packageLink} ${version} h1:${tagLink}${closeTag}`; +}; + +export default (result) => { + return result.value.replace(DEPENDENCY_REGEX, (_, packageName, version, tag) => + handleReplace(packageName, version, tag), + ); +}; diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb index 22dcc7c18a0..1da1e7dda53 100644 --- a/app/models/ci/bridge.rb +++ b/app/models/ci/bridge.rb @@ -18,6 +18,9 @@ module Ci belongs_to :project belongs_to :trigger_request + has_many :sourced_pipelines, class_name: "::Ci::Sources::Pipeline", + foreign_key: :source_job_id, + inverse_of: :source_bridge has_one :downstream_pipeline, through: :sourced_pipeline, source: :pipeline @@ -85,7 +88,7 @@ module Ci end def has_downstream_pipeline? - sourced_pipeline.present? + sourced_pipelines.exists? end def downstream_pipeline_params diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 40b46a3a342..3aa42db7b88 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -47,6 +47,7 @@ module Ci # Details: https://gitlab.com/gitlab-org/gitlab/-/issues/24644#note_689472685 has_many :job_artifacts, class_name: 'Ci::JobArtifact', foreign_key: :job_id, dependent: :destroy, inverse_of: :job # rubocop:disable Cop/ActiveRecordDependent has_many :job_variables, class_name: 'Ci::JobVariable', foreign_key: :job_id + has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_job_id has_many :pages_deployments, inverse_of: :ci_build diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 27119d3a95a..94ced96bbde 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -13,4 +13,9 @@ class ServiceHook < WebHook override :parent delegate :parent, to: :integration + + override :executable? + def executable? + true + end end diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb index fae3ae3bf02..d7065680053 100644 --- a/app/services/ci/pipeline_trigger_service.rb +++ b/app/services/ci/pipeline_trigger_service.rb @@ -62,7 +62,7 @@ module Ci response = Ci::CreatePipelineService .new(project, job.user, ref: params[:ref], variables_attributes: variables) .execute(:pipeline, ignore_skip_ci: true) do |pipeline| - source = job.build_sourced_pipeline( + source = job.sourced_pipelines.build( source_pipeline: job.pipeline, source_project: job.project, pipeline: pipeline, diff --git a/config/feature_flags/development/mirror_only_branches_match_regex.yml b/config/feature_flags/development/mirror_only_branches_match_regex.yml new file mode 100644 index 00000000000..6494569b364 --- /dev/null +++ b/config/feature_flags/development/mirror_only_branches_match_regex.yml @@ -0,0 +1,8 @@ +--- +name: mirror_only_branches_match_regex +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99201 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381667 +milestone: '15.6' +type: development +group: "group::source code" +default_enabled: false diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 6ee74cc73ce..c205ed625ff 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -971,6 +971,10 @@ Supported attributes: ## Get single merge request changes +WARNING: +This endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/322117) in GitLab 15.7 +and will be removed in API v5. Use the [List merge request diffs](#list-merge-request-diffs) endpoint instead. + Shows information about the merge request including its files and changes. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46190) in GitLab 13.6, @@ -1101,10 +1105,6 @@ Supported attributes: } ``` -WARNING: -This endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/322117) in GitLab 15.7 -and will be removed in API v5. Use the [List merge request diffs](#list-merge-request-diffs) endpoint instead. - ## List merge request diffs List diffs of the files changed in a merge request. diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md index 1106e306d4e..a14f385cdb5 100644 --- a/doc/api/project_import_export.md +++ b/doc/api/project_import_export.md @@ -30,6 +30,9 @@ project to a web server or to any S3-compatible platform. For exports, GitLab: The `upload[url]` parameter is required if the `upload` parameter is present. +For uploads to Amazon S3, refer to [Generating a pre-signed URL for uploading objects](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html) +documentation scripts to generate the `upload[url]`. + ```plaintext POST /projects/:id/export ``` diff --git a/doc/architecture/blueprints/pods/pods-feature-admin-area.md b/doc/architecture/blueprints/pods/pods-feature-admin-area.md index 6457f02f7cc..7efaa383510 100644 --- a/doc/architecture/blueprints/pods/pods-feature-admin-area.md +++ b/doc/architecture/blueprints/pods/pods-feature-admin-area.md @@ -14,14 +14,43 @@ we can document the reasons for not choosing this approach. # Pods: Admin Area -> TL;DR +In our Pods architecture proposal we plan to share all admin related tables in +GitLab. This allows simpler management of all Pods in one interface and reduces +the risk of settings diverging in different Pods. This introduces challenges +with admin pages that allow you to manage data that will be spread across all +Pods. ## 1. Definition +There are consequences for admin pages that contain data that spans "the whole +instance" as the Admin pages may be served by any Pod or possibly just 1 pod. +There are already many parts of the Admin interface that will have data that +spans many pods. For example lists of all Groups, Projects, Topics, Jobs, +Analytics, Applications and more. There are also administrative monitoring +capabilities in the Admin page that will span many pods such as the "Background +Jobs" and "Background Migrations" pages. + ## 2. Data flow ## 3. Proposal +We will need to decide how to handle these exceptions with a few possible +options: + +1. Move all these pages out into a dedicated per-pod Admin section. Probably + the URL will need to be routable to a single Pod like `/pods/<pod_id>/admin`, + then we can display this data per Pod. These pages will be distinct from + other Admin pages which control settings that are shared across all Pods. We + will also need to consider how this impacts self-managed customers and + whether, or not, this should be visible for single-pod instances of GitLab. +1. Build some aggregation interfaces for this data so that it can be fetched + from all Pods and presented in a single UI. This may be beneficial to an + administrator that needs to see and filter all data at a glance, especially + when they don't know which Pod the data is on. The downside, however, is + that building this kind of aggregation is very tricky when all the Pods are + designed to be totally independent, and it does also enforce more strict + requirements on compatibility between Pods. + ## 4. Evaluation ## 4.1. Pros diff --git a/doc/user/analytics/dora_metrics.md b/doc/user/analytics/dora_metrics.md index b5f37203817..a2b2762e6da 100644 --- a/doc/user/analytics/dora_metrics.md +++ b/doc/user/analytics/dora_metrics.md @@ -113,7 +113,7 @@ With this new visualization, software leaders can track metrics improvements, un Deployment frequency is calculated based on the deployments record, which is created for typical push-based deployments. These deployment records are not created for pull-based deployments, for example when Container Images are connected to GitLab with an agent. -To track DORA metrics in these cases, you can [create a deployment record](../../api/deployments.md#create-a-deployment) using the Deployments API. +To track DORA metrics in these cases, you can [create a deployment record](../../api/deployments.md#create-a-deployment) using the Deployments API. See also the documentation page for [Track deployments of an external deployment tool](../../ci/environments/external_deployment_tools.md). ### Supported DORA metrics in GitLab diff --git a/doc/user/project/integrations/webhook_events.md b/doc/user/project/integrations/webhook_events.md index 60187b9a682..65faf658bea 100644 --- a/doc/user/project/integrations/webhook_events.md +++ b/doc/user/project/integrations/webhook_events.md @@ -1475,6 +1475,8 @@ Payload example: "deployable_id": 796, "deployable_url": "http://10.126.0.2:3000/root/test-deployment-webhooks/-/jobs/796", "environment": "staging", + "environment_slug": "staging", + "environment_external_url": "https://staging.example.com", "project": { "id": 30, "name": "test-deployment-webhooks", diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md index 75a25678125..da00be361f3 100644 --- a/doc/user/project/releases/index.md +++ b/doc/user/project/releases/index.md @@ -209,11 +209,15 @@ Prerequisites: - You must have at least the Developer role. Read more about [Release permissions](#release-permissions). -To delete a release in the UI: +To delete a release, use either the +[Delete a release API](../../../api/releases/index.md#delete-a-release) or the UI. + +In the UI: 1. On the top bar, select **Main menu > Projects** and find your project. 1. On the left sidebar, select **Deployments > Releases**. -1. In the top-right corner of the release you want to delete, select **Edit this release** (**{pencil}**). +1. In the top-right corner of the release you want to delete, select **Edit this release** + (**{pencil}**). 1. On the **Edit Release** page, select **Delete**. 1. Select **Delete release**. diff --git a/doc/user/project/repository/ssh_signed_commits/index.md b/doc/user/project/repository/ssh_signed_commits/index.md index 4c7e07da7f1..81651058434 100644 --- a/doc/user/project/repository/ssh_signed_commits/index.md +++ b/doc/user/project/repository/ssh_signed_commits/index.md @@ -8,6 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343879) in GitLab 15.7 [with a flag](../../../../administration/feature_flags.md) named `ssh_commit_signatures`. Disabled by default. +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, +ask an administrator to [enable the feature flag](../../../../administration/feature_flags.md) named `ssh_commit_signatures`. +On GitLab.com, this feature is available. + Use SSH keys to sign Git commits in the same manner as [GPG signed commits](../gpg_signed_commits/index.md). When you sign commits with SSH keys, GitLab uses the SSH public keys associated with your @@ -15,16 +20,18 @@ GitLab account to cryptographically verify the commit signature. If successful, GitLab displays a **Verified** label on the commit. You may use the same SSH keys for `git+ssh` authentication to GitLab -and signing commit signatures. +and signing commit signatures as long as their usage type is **Authentication & Signing**. +It can be verified on the page for [adding an SSH key to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account). To learn more about managing the SSH keys associated with your GitLab account, read [use SSH keys to communicate with GitLab](../../../ssh.md). ## Configure Git to sign commits with your SSH key -After you have [created an SSH key](../../../ssh.md#generate-an-ssh-key-pair) and -[added it to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account), -you need to configure Git to begin using it. +After you [create an SSH key](../../../ssh.md#generate-an-ssh-key-pair) and +[add it to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account) +or [generate it using a password manager](../../../ssh.md#generate-an-ssh-key-pair-with-a-password-manager), +configure Git to begin using the key. Prerequisites: @@ -34,11 +41,12 @@ Prerequisites: NOTE: OpenSSH 8.7 has broken signing functionality. If you are on OpenSSH 8.7, upgrade to OpenSSH 8.8. -- A SSH key of one of these types: +- A SSH key with the usage type of either **Authentication & Signing** or **Signing**. + The SSH key must be one of these types: - [ED25519](../../../ssh.md#ed25519-ssh-keys) (recommended) - [RSA](../../../ssh.md#rsa-ssh-keys) -To configure Git: +To configure Git to use your key: 1. Configure Git to use SSH for commit signing: @@ -79,7 +87,9 @@ To sign a commit: 1. If your SSH key is protected, Git prompts you to enter your passphrase. 1. Push to GitLab. -1. Check that your commits [are verified](../gpg_signed_commits/index.md#verify-commits). +1. Check that your commits [are verified](#verify-commits). + Signature verification uses the `allowed_signers` file to associate emails and SSH keys. + For help configuring this file, read [Verify commits locally](#verify-commits-locally). ## Verify commits @@ -96,10 +106,62 @@ they are signed: 1. Identify the commit you want to review. Signed commits show either a **Verified** or **Unverified** badge, depending on the verification status of the signature. Unsigned commits do not display a badge. - 1. To display the signature details for a commit, select **Verified**. GitLab shows the SSH key's fingerprint. +## Verify commits locally + +To verify commits locally, create an +[allowed signers file](https://man7.org/linux/man-pages/man1/ssh-keygen.1.html#ALLOWED_SIGNERS) +for Git to associate SSH public keys with users: + +1. Create an allowed signers file: + + ```shell + touch allowed_signers + ``` + +1. Configure the `allowed_signers` file in Git: + + ```shell + git config gpg.ssh.allowedSignersFile "$(pwd)/allowed_signers" + ``` + +1. Add your entry to the allowed signers file. Use this command to add your + email address and public SSH key to the `allowed_signers` file. Replace `<MY_KEY>` + with the name of your key, and `~/.ssh/allowed_signers` + with the location of your project's `allowed_signers` file: + + ```shell + # Modify this line to meet your needs. + # Declaring the `git` namespace helps prevent cross-protocol attacks. + echo "$(git config --get user.email) namespaces=\"git\" $(cat ~/.ssh/<MY_KEY>.pub)" >> ~/.ssh/allowed_signers + ``` + + The resulting entry in the `allowed_signers` file contains your email address, key type, + and key contents, like this: + + ```plaintext + example@gitlab.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmaTS47vRmsKyLyK1jlIFJn/i8wdGQ3J49LYyIYJ2hv + ``` + +1. Repeat the previous step for each user who you want to verify signatures for. + Consider checking this file in to your Git repository if you want to locally + verify signatures for many different contributors. + +1. Use `git log --show-signature` to view the signature status for the commits: + + ```shell + $ git log --show-signature + + commit e2406b6cd8ebe146835ceab67ff4a5a116e09154 (HEAD -> main, origin/main, origin/HEAD) + Good "git" signature for johndoe@example.com with ED25519 key SHA256:Ar44iySGgxic+U6Dph4Z9Rp+KDaix5SFGFawovZLAcc + Author: John Doe <johndoe@example.com> + Date: Tue Nov 29 06:54:15 2022 -0600 + + SSH signed commit + ``` + ## Revoke an SSH key for signing commits You can't revoke an SSH key used for signing commits. To learn more, read diff --git a/doc/user/ssh.md b/doc/user/ssh.md index 85332446334..1d82d301e9a 100644 --- a/doc/user/ssh.md +++ b/doc/user/ssh.md @@ -270,6 +270,7 @@ You can use [1Password](https://1password.com/) and the [1Password browser exten 1. You can then select **Create SSH Key** or select an existing SSH key to fill in the public key. 1. In the **Title** box, type a description, like `Work Laptop` or `Home Workstation`. +1. Optional. Select the **Usage type** of the key. It can be used either for `Authentication` or `Signing` or both. `Authentication & Signing` is the default value. 1. Optional. Update **Expiration date** to modify the default expiration date. 1. Select **Add key**. @@ -314,6 +315,7 @@ To use SSH with GitLab, copy your public key to your GitLab account: `ssh-ed25519`, `sk-ecdsa-sha2-nistp256@openssh.com`, or `sk-ssh-ed25519@openssh.com`, and may end with a comment. 1. In the **Title** box, type a description, like `Work Laptop` or `Home Workstation`. +1. Optional. Select the **Usage type** of the key. It can be used either for `Authentication` or `Signing` or both. `Authentication & Signing` is the default value. 1. Optional. Update **Expiration date** to modify the default expiration date. In: - GitLab 13.12 and earlier, the expiration date is informational only. It doesn't prevent diff --git a/lib/gitlab/data_builder/deployment.rb b/lib/gitlab/data_builder/deployment.rb index a9c69e3f997..7055f64937d 100644 --- a/lib/gitlab/data_builder/deployment.rb +++ b/lib/gitlab/data_builder/deployment.rb @@ -35,6 +35,8 @@ module Gitlab deployable_id: deployment.deployable_id, deployable_url: deployable_url, environment: deployment.environment.name, + environment_slug: deployment.environment.slug, + environment_external_url: deployment.environment.external_url, project: deployment.project.hook_attrs, short_sha: deployment.short_sha, user: deployment.deployed_by&.hook_attrs, diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index fb3fbc80d24..02418c45e73 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -33,7 +33,7 @@ module Gitlab GitalyServer: { address: Gitlab::GitalyClient.address(repository.storage), token: Gitlab::GitalyClient.token(repository.storage), - features: Feature::Gitaly.server_feature_flags( + call_metadata: Feature::Gitaly.server_feature_flags( user: ::Feature::Gitaly.user_actor(user), repository: repository, project: ::Feature::Gitaly.project_actor(repository.container), @@ -48,14 +48,11 @@ module Gitlab attrs[:GitConfigOptions] << "receive.maxInputSize=#{receive_max_input_size.megabytes}" end - remote_ip = Gitlab::ApplicationContext.current_context_attribute(:remote_ip) - attrs[:RemoteIP] = remote_ip if remote_ip.present? - - attrs[:GitalyServer][:call_metadata] = attrs[:GitalyServer][:features].merge( + attrs[:GitalyServer][:call_metadata].merge!( 'user_id' => attrs[:GL_ID].presence, 'username' => attrs[:GL_USERNAME].presence, - 'remote_ip' => attrs[:RemoteIP] - ).compact + 'remote_ip' => Gitlab::ApplicationContext.current_context_attribute(:remote_ip).presence + ).compact! attrs end @@ -263,18 +260,15 @@ module Gitlab end def gitaly_server_hash(repository) - features = Feature::Gitaly.server_feature_flags( - user: ::Feature::Gitaly.user_actor, - repository: repository, - project: ::Feature::Gitaly.project_actor(repository.container), - group: ::Feature::Gitaly.group_actor(repository.container) - ) - { address: Gitlab::GitalyClient.address(repository.shard), token: Gitlab::GitalyClient.token(repository.shard), - features: features, - call_metadata: features + call_metadata: Feature::Gitaly.server_feature_flags( + user: ::Feature::Gitaly.user_actor, + repository: repository, + project: ::Feature::Gitaly.project_actor(repository.container), + group: ::Feature::Gitaly.group_actor(repository.container) + ) } end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 31afdb16aba..9a37d9d0ef0 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -720,6 +720,12 @@ msgstr "" msgid "%{host} sign-in from new location" msgstr "" +msgid "%{human_readable_key} exceeds %{max_value_length} characters" +msgstr "" + +msgid "%{human_readable_key} is less than %{min_value_length} characters" +msgstr "" + msgid "%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}." msgstr "" @@ -24006,6 +24012,9 @@ msgstr "" msgid "Last event" msgstr "" +msgid "Last login" +msgstr "" + msgid "Last modified" msgstr "" @@ -34769,6 +34778,9 @@ msgstr "" msgid "Request Access" msgstr "" +msgid "Request Headers" +msgstr "" + msgid "Request a new one" msgstr "" @@ -48689,9 +48701,6 @@ msgstr "" msgid "exceeds maximum length (100 usernames)" msgstr "" -msgid "exceeds the %{max_value_length} character limit" -msgstr "" - msgid "exceeds the limit of %{bytes} bytes" msgstr "" diff --git a/rubocop/cop/gitlab/strong_memoize_attr.rb b/rubocop/cop/gitlab/strong_memoize_attr.rb index 2da7f71b920..c98aa4765fa 100644 --- a/rubocop/cop/gitlab/strong_memoize_attr.rb +++ b/rubocop/cop/gitlab/strong_memoize_attr.rb @@ -3,34 +3,68 @@ module RuboCop module Cop module Gitlab - # Cop that disallows functions that contain only a call to `strong_memoize()`, in favor - # of `strong_memoize_attr()`. + # Prefer using `.strong_memoize_attr()` over `#strong_memoize()`. See + # https://docs.gitlab.com/ee/development/utilities.html/#strongmemoize. + # + # Good: + # + # def memoized_method + # 'This is a memoized method' + # end + # strong_memoize_attr :memoized_method + # + # Bad, can be autocorrected: + # + # def memoized_method + # strong_memoize(:memoized_method) do + # 'This is a memoized method' + # end + # end + # + # Very bad, can't be autocorrected: + # + # def memoized_method + # return unless enabled? + # + # strong_memoize(:memoized_method) do + # 'This is a memoized method' + # end + # end + # class StrongMemoizeAttr < RuboCop::Cop::Base extend RuboCop::Cop::AutoCorrector MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly' def_node_matcher :strong_memoize?, <<~PATTERN - (def $_ _ - (block - $(send nil? :strong_memoize - (sym $_) - ) - (args) - $_ + (block + $(send nil? :strong_memoize + (sym $_) ) + (args) + $_ ) PATTERN - def on_def(node) - method_name, send_node, attr_name, body = strong_memoize?(node) - return unless method_name + def on_block(node) + send_node, attr_name, body = strong_memoize?(node) + return unless send_node - add_offense(send_node) do |corrector| + corrector = autocorrect_pure_definitions(node.parent, attr_name, body) if node.parent.def_type? + + add_offense(send_node, &corrector) + end + + private + + def autocorrect_pure_definitions(def_node, attr_name, body) + proc do |corrector| + method_name = def_node.method_name attr_suffix = ", :#{attr_name}" if attr_name != method_name + replacement = "\n#{indent(def_node)}strong_memoize_attr :#{method_name}#{attr_suffix}" - corrector.insert_after(node, "\n#{indent(node)}strong_memoize_attr :#{method_name}#{attr_suffix}") - corrector.replace(node.body, body.source) + corrector.insert_after(def_node, replacement) + corrector.replace(def_node.body, body.source) end end end diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js index a7b55d7332f..4d38e8ef25d 100644 --- a/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js @@ -4,15 +4,16 @@ import gemspecLinker from '~/vue_shared/components/source_viewer/plugins/utils/g import gemfileLinker from '~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker'; import podspecJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker'; import composerJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker'; +import goSumLinker from '~/vue_shared/components/source_viewer/plugins/utils/go_sum_linker'; import linkDependencies from '~/vue_shared/components/source_viewer/plugins/link_dependencies'; import { PACKAGE_JSON_FILE_TYPE, - PACKAGE_JSON_CONTENT, GEMSPEC_FILE_TYPE, GODEPS_JSON_FILE_TYPE, GEMFILE_FILE_TYPE, PODSPEC_JSON_FILE_TYPE, COMPOSER_JSON_FILE_TYPE, + GO_SUM_FILE_TYPE, } from './mock_data'; jest.mock('~/vue_shared/components/source_viewer/plugins/utils/package_json_linker'); @@ -21,37 +22,31 @@ jest.mock('~/vue_shared/components/source_viewer/plugins/utils/godeps_json_linke jest.mock('~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker'); jest.mock('~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker'); jest.mock('~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker'); +jest.mock('~/vue_shared/components/source_viewer/plugins/utils/go_sum_linker'); describe('Highlight.js plugin for linking dependencies', () => { const hljsResultMock = { value: 'test' }; - it('calls packageJsonLinker for package_json file types', () => { - linkDependencies(hljsResultMock, PACKAGE_JSON_FILE_TYPE, PACKAGE_JSON_CONTENT); - expect(packageJsonLinker).toHaveBeenCalled(); - }); - - it('calls gemspecLinker for gemspec file types', () => { - linkDependencies(hljsResultMock, GEMSPEC_FILE_TYPE); - expect(gemspecLinker).toHaveBeenCalled(); - }); - - it('calls godepsJsonLinker for godeps_json file types', () => { - linkDependencies(hljsResultMock, GODEPS_JSON_FILE_TYPE); - expect(godepsJsonLinker).toHaveBeenCalled(); - }); - - it('calls gemfileLinker for gemfile file types', () => { - linkDependencies(hljsResultMock, GEMFILE_FILE_TYPE); - expect(gemfileLinker).toHaveBeenCalled(); - }); - - it('calls podspecJsonLinker for podspec_json file types', () => { - linkDependencies(hljsResultMock, PODSPEC_JSON_FILE_TYPE); - expect(podspecJsonLinker).toHaveBeenCalled(); - }); - - it('calls composerJsonLinker for composer_json file types', () => { - linkDependencies(hljsResultMock, COMPOSER_JSON_FILE_TYPE); - expect(composerJsonLinker).toHaveBeenCalled(); + describe.each` + fileType | linker + ${PACKAGE_JSON_FILE_TYPE} | ${packageJsonLinker} + ${GEMSPEC_FILE_TYPE} | ${gemspecLinker} + ${GODEPS_JSON_FILE_TYPE} | ${godepsJsonLinker} + ${GEMFILE_FILE_TYPE} | ${gemfileLinker} + ${PODSPEC_JSON_FILE_TYPE} | ${podspecJsonLinker} + ${COMPOSER_JSON_FILE_TYPE} | ${composerJsonLinker} + ${GO_SUM_FILE_TYPE} | ${goSumLinker} + `('$fileType file type', ({ fileType, linker }) => { + it('calls the correct linker', () => { + linkDependencies(hljsResultMock, fileType); + expect(linker).toHaveBeenCalled(); + }); + + it('does not call the linker for non-matching file types', () => { + const unknownFileType = 'unknown'; + + linkDependencies(hljsResultMock, unknownFileType); + expect(linker).not.toHaveBeenCalled(); + }); }); }); diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js b/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js index 5455479ec71..631baf19a2d 100644 --- a/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js +++ b/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js @@ -32,3 +32,5 @@ export const PODSPEC_JSON_CONTENT = `{ }`; export const COMPOSER_JSON_FILE_TYPE = 'composer_json'; + +export const GO_SUM_FILE_TYPE = 'go_sum'; diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js new file mode 100644 index 00000000000..293396c9de7 --- /dev/null +++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js @@ -0,0 +1,14 @@ +import goSumLinker from '~/vue_shared/components/source_viewer/plugins/utils/go_sum_linker'; + +describe('Highlight.js plugin for linking go.sum dependencies', () => { + it('mutates the input value by wrapping dependencies and tags in anchors', () => { + const inputValue = + '<span class="">cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=</span>'; + const outputValue = + '<span class=""><a href="https://pkg.go.dev/cloud.google.com/go/bigquery" target="_blank" rel="nofollow noreferrer noopener">cloud.google.com/go/bigquery</a> v1.0.1/go.mod h1:<a href="https://sum.golang.org/lookup/cloud.google.com/go/bigquery@v1.0.1" target="_blank" rel="nofollow noreferrer noopener">i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=</a></span>'; + const hljsResultMock = { value: inputValue }; + + const output = goSumLinker(hljsResultMock); + expect(output).toBe(outputValue); + }); +}); diff --git a/spec/lib/gitlab/data_builder/deployment_spec.rb b/spec/lib/gitlab/data_builder/deployment_spec.rb index 8ee57542d43..bf08e782035 100644 --- a/spec/lib/gitlab/data_builder/deployment_spec.rb +++ b/spec/lib/gitlab/data_builder/deployment_spec.rb @@ -12,8 +12,8 @@ RSpec.describe Gitlab::DataBuilder::Deployment do expect(data[:object_kind]).to eq('deployment') end - it 'returns data for the given build' do - environment = create(:environment, name: "somewhere") + it 'returns data for the given build', :aggregate_failures do + environment = create(:environment, name: 'somewhere/1', external_url: 'https://test.com') project = create(:project, :repository, name: 'myproj') commit = project.commit('HEAD') deployment = create(:deployment, status: :failed, environment: environment, sha: commit.sha, project: project) @@ -30,7 +30,9 @@ RSpec.describe Gitlab::DataBuilder::Deployment do expect(data[:deployment_id]).to eq(deployment.id) expect(data[:deployable_id]).to eq(deployable.id) expect(data[:deployable_url]).to eq(expected_deployable_url) - expect(data[:environment]).to eq("somewhere") + expect(data[:environment]).to eq('somewhere/1') + expect(data[:environment_slug]).to eq('somewhere-1-78avk6') + expect(data[:environment_external_url]).to eq('https://test.com') expect(data[:project]).to eq(project.hook_attrs) expect(data[:short_sha]).to eq(deployment.short_sha) expect(data[:user]).to eq(deployment.deployed_by.hook_attrs) diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 7a9b8f3ccc1..918b091eef2 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -44,7 +44,6 @@ RSpec.describe Gitlab::Workhorse do expect(params).to eq({ 'GitalyServer' => { 'call_metadata' => features, - 'features' => features, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -95,7 +94,6 @@ RSpec.describe Gitlab::Workhorse do expect(params).to eq({ 'GitalyServer' => { 'call_metadata' => features, - 'features' => features, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -159,7 +157,6 @@ RSpec.describe Gitlab::Workhorse do expect(params).to eq({ 'GitalyServer' => { 'call_metadata' => features, - 'features' => features, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -254,7 +251,6 @@ RSpec.describe Gitlab::Workhorse do { GitalyServer: { call_metadata: call_metadata, - features: features, address: Gitlab::GitalyClient.address('default'), token: Gitlab::GitalyClient.token('default') } @@ -299,24 +295,24 @@ RSpec.describe Gitlab::Workhorse do it 'sets the flag to true for that project' do response = described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action) - expect(response.dig(:GitalyServer, :features)).to eq('gitaly-feature-enforce-requests-limits' => 'true', - 'gitaly-feature-mep-mep' => 'true') + expect(response.dig(:GitalyServer, :call_metadata)).to include('gitaly-feature-enforce-requests-limits' => 'true', + 'gitaly-feature-mep-mep' => 'true') end it 'sets the flag to false for other projects' do other_project = create(:project, :public, :repository) response = described_class.git_http_ok(other_project.repository, Gitlab::GlRepository::PROJECT, user, action) - expect(response.dig(:GitalyServer, :features)).to eq('gitaly-feature-enforce-requests-limits' => 'true', - 'gitaly-feature-mep-mep' => 'false') + expect(response.dig(:GitalyServer, :call_metadata)).to include('gitaly-feature-enforce-requests-limits' => 'true', + 'gitaly-feature-mep-mep' => 'false') end it 'sets the flag to false when there is no project' do snippet = create(:personal_snippet, :repository) response = described_class.git_http_ok(snippet.repository, Gitlab::GlRepository::SNIPPET, user, action) - expect(response.dig(:GitalyServer, :features)).to eq('gitaly-feature-enforce-requests-limits' => 'true', - 'gitaly-feature-mep-mep' => 'false') + expect(response.dig(:GitalyServer, :call_metadata)).to include('gitaly-feature-enforce-requests-limits' => 'true', + 'gitaly-feature-mep-mep' => 'false') end end end @@ -368,7 +364,6 @@ RSpec.describe Gitlab::Workhorse do Gitlab::ApplicationContext.with_context(remote_ip: "1.2.3.4") do result = described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action) end - expect(result[:RemoteIP]).to eql("1.2.3.4") expect(result[:GitalyServer][:call_metadata]['remote_ip']).to eql("1.2.3.4") end end @@ -376,7 +371,6 @@ RSpec.describe Gitlab::Workhorse do context 'when remote_ip is not available in the application context' do it 'does not include RemoteIP params' do result = described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action) - expect(result).not_to have_key(:RemoteIP) expect(result[:GitalyServer][:call_metadata]).not_to have_key('remote_ip') end end @@ -460,7 +454,6 @@ RSpec.describe Gitlab::Workhorse do expect(params).to eq({ 'GitalyServer' => { 'call_metadata' => features, - 'features' => features, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -541,7 +534,6 @@ RSpec.describe Gitlab::Workhorse do expect(params).to eq( 'GitalyServer' => { 'call_metadata' => features, - 'features' => features, 'address' => Gitlab::GitalyClient.address(project.repository_storage), 'token' => Gitlab::GitalyClient.token(project.repository_storage) }, diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb index fcbb4b97a75..df24c92149d 100644 --- a/spec/models/ci/bridge_spec.rb +++ b/spec/models/ci/bridge_spec.rb @@ -21,8 +21,8 @@ RSpec.describe Ci::Bridge do { trigger: { project: 'my/project', branch: 'master' } } end - it 'has one sourced pipeline' do - expect(bridge).to have_one(:sourced_pipeline) + it 'has many sourced pipelines' do + expect(bridge).to have_many(:sourced_pipelines) end it_behaves_like 'has ID tokens', :ci_bridge diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 52d35f6d79d..3585fda78c3 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -24,6 +24,7 @@ RSpec.describe Ci::Build do it { is_expected.to belong_to(:erased_by) } it { is_expected.to have_many(:needs) } + it { is_expected.to have_many(:sourced_pipelines) } it { is_expected.to have_one(:sourced_pipeline) } it { is_expected.to have_many(:job_variables) } it { is_expected.to have_many(:report_results) } diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb index 004716fffc4..e62e5f84a6d 100644 --- a/spec/models/ci/processable_spec.rb +++ b/spec/models/ci/processable_spec.rb @@ -81,7 +81,7 @@ RSpec.describe Ci::Processable do commit_id deployment erased_by_id project_id runner_id tag_taggings taggings tags trigger_request_id user_id auto_canceled_by_id retried failure_reason - sourced_pipeline artifacts_file_store artifacts_metadata_store + sourced_pipelines sourced_pipeline artifacts_file_store artifacts_metadata_store metadata runner_session trace_chunks upstream_pipeline_id artifacts_file artifacts_metadata artifacts_size commands resource resource_group_id processed security_scans author diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 68c284a913c..2ece04c7158 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -11,6 +11,32 @@ RSpec.describe ServiceHook do it { is_expected.to validate_presence_of(:integration) } end + describe 'executable?' do + let!(:hooks) do + [ + [0, Time.current], + [0, 1.minute.from_now], + [1, 1.minute.from_now], + [3, 1.minute.from_now], + [4, nil], + [4, 1.day.ago], + [4, 1.minute.from_now], + [0, nil], + [0, 1.day.ago], + [1, nil], + [1, 1.day.ago], + [3, nil], + [3, 1.day.ago] + ].map do |(recent_failures, disabled_until)| + create(:service_hook, recent_failures: recent_failures, disabled_until: disabled_until) + end + end + + it 'is always true' do + expect(hooks).to all(be_executable) + end + end + describe 'execute' do let(:hook) { build(:service_hook) } let(:data) { { key: 'value' } } diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml index 2ff4cd72f1e..da478a3547e 100644 --- a/spec/requests/api/project_attributes.yml +++ b/spec/requests/api/project_attributes.yml @@ -43,6 +43,7 @@ itself: # project - storage_version - topic_list - updated_at + - mirror_branch_regex remapped_attributes: avatar: avatar_url build_allow_git_fetch: build_git_strategy diff --git a/spec/requests/api/project_snapshots_spec.rb b/spec/requests/api/project_snapshots_spec.rb index 954091635a1..5a06800c8f6 100644 --- a/spec/requests/api/project_snapshots_spec.rb +++ b/spec/requests/api/project_snapshots_spec.rb @@ -7,7 +7,6 @@ RSpec.describe API::ProjectSnapshots do let(:project) { create(:project) } let(:admin) { create(:admin) } - let(:features) { { 'gitaly-feature-foobar' => 'true' } } before do allow(Feature::Gitaly).to receive(:server_feature_flags).and_return({ @@ -22,8 +21,7 @@ RSpec.describe API::ProjectSnapshots do expect(type).to eq('git-snapshot') expect(params).to eq( 'GitalyServer' => { - 'call_metadata' => features, - 'features' => features, + 'call_metadata' => { 'gitaly-feature-foobar' => 'true' }, 'address' => Gitlab::GitalyClient.address(repository.project.repository_storage), 'token' => Gitlab::GitalyClient.token(repository.project.repository_storage) }, diff --git a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb index 20dd0f89f53..0ed699f4e8c 100644 --- a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb +++ b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb @@ -55,18 +55,21 @@ RSpec.describe RuboCop::Cop::Gitlab::StrongMemoizeAttr do end context 'when strong_memoize() is not the entire body of the method' do - it 'does not register an offense or autocorrect' do - expect_no_offenses(<<~RUBY) + it 'registers an offense and does not autocorrect' do + expect_offense(<<~RUBY) class Foo def memoized_method msg = 'This is a memoized method' strong_memoize(:memoized_method) do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `strong_memoize_attr`, instead of using `strong_memoize` directly msg end end end RUBY + + expect_no_corrections end end end diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb index 751d976dd10..9c02c5218f1 100644 --- a/spec/services/ci/create_downstream_pipeline_service_spec.rb +++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb @@ -110,7 +110,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do expect(pipeline.user).to eq bridge.user expect(pipeline.project).to eq downstream_project - expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline + expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline expect(pipeline.source_bridge).to eq bridge expect(pipeline.source_bridge).to be_a ::Ci::Bridge @@ -131,7 +131,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do context 'when bridge job has already any downstream pipelines' do before do - bridge.create_sourced_pipeline!( + bridge.sourced_pipelines.create!( source_pipeline: bridge.pipeline, source_project: bridge.project, project: bridge.project, @@ -178,7 +178,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do expect(pipeline.user).to eq bridge.user expect(pipeline.project).to eq downstream_project - expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline + expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline expect(pipeline.source_bridge).to eq bridge expect(pipeline.source_bridge).to be_a ::Ci::Bridge @@ -231,7 +231,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do expect(pipeline.builds.map(&:name)).to match_array(%w[rspec echo]) expect(pipeline.user).to eq bridge.user expect(pipeline.project).to eq bridge.project - expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline + expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline expect(pipeline.source_bridge).to eq bridge expect(pipeline.source_bridge).to be_a ::Ci::Bridge diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index d8ea546742b..4b3e774ff3c 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -225,7 +225,7 @@ RSpec.describe Ci::PipelineTriggerService do expect { result }.to change { Ci::PipelineVariable.count }.by(2) .and change { Ci::Sources::Pipeline.count }.by(1) expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables) - expect(job.sourced_pipeline.pipeline_id).to eq(result[:pipeline].id) + expect(job.sourced_pipelines.last.pipeline_id).to eq(result[:pipeline].id) end end diff --git a/workhorse/gitaly_integration_test.go b/workhorse/gitaly_integration_test.go index a2826c3edc4..ed44aaddbc3 100644 --- a/workhorse/gitaly_integration_test.go +++ b/workhorse/gitaly_integration_test.go @@ -58,7 +58,6 @@ func ensureGitalyRepository(t *testing.T, apiResponse *api.Response) error { ctx, namespace, err := gitaly.NewNamespaceClient( context.Background(), apiResponse.GitalyServer, - gitaly.WithFeatures(apiResponse.GitalyServer.Features), ) if err != nil { diff --git a/workhorse/gitaly_test.go b/workhorse/gitaly_test.go index b9cf4fcc685..2d7f727003f 100644 --- a/workhorse/gitaly_test.go +++ b/workhorse/gitaly_test.go @@ -78,7 +78,7 @@ func TestGetInfoRefsProxiedToGitalySuccessfully(t *testing.T) { for k, v := range badMetadata { features[k] = v } - apiResponse.GitalyServer.Features = features + apiResponse.GitalyServer.CallMetadata = features testCases := []struct { showAllRefs bool @@ -272,7 +272,6 @@ func TestPostReceivePackProxiedToGitalySuccessfully(t *testing.T) { require.Equal(t, apiResponse.Repository.RelativePath, gitalyRequest.Repository.RelativePath) require.Equal(t, apiResponse.GL_ID, gitalyRequest.GlId) require.Equal(t, apiResponse.GL_USERNAME, gitalyRequest.GlUsername) - require.Equal(t, apiResponse.RemoteIp, "1.2.3.4") require.Equal(t, apiResponse.GitConfigOptions, gitalyRequest.GitConfigOptions) require.Equal(t, gitProtocol, gitalyRequest.GitProtocol) diff --git a/workhorse/internal/api/api.go b/workhorse/internal/api/api.go index ba27a3e6ec9..011890be569 100644 --- a/workhorse/internal/api/api.go +++ b/workhorse/internal/api/api.go @@ -129,9 +129,6 @@ type Response struct { // 'git push' and 'git pull' GL_REPOSITORY string - // RemoteIp holds the IP of the request issuing the action - RemoteIp string - // GitConfigOptions holds the custom options that we want to pass to the git command GitConfigOptions []string // StoreLFSPath is provided by the GitLab Rails application to mark where the tmp file should be placed. @@ -166,9 +163,9 @@ type Response struct { } type GitalyServer struct { - Address string `json:"address"` - Token string `json:"token"` - Features map[string]string `json:"features"` + Address string `json:"address"` + Token string `json:"token"` + CallMetadata map[string]string `json:"call_metadata"` } // singleJoiningSlash is taken from reverseproxy.go:singleJoiningSlash diff --git a/workhorse/internal/git/archive.go b/workhorse/internal/git/archive.go index 4c7b519310f..5c6bc2e2266 100644 --- a/workhorse/internal/git/archive.go +++ b/workhorse/internal/git/archive.go @@ -132,11 +132,7 @@ func (a *archive) Inject(w http.ResponseWriter, r *http.Request, sendData string func handleArchiveWithGitaly(r *http.Request, params *archiveParams, format gitalypb.GetArchiveRequest_Format) (io.Reader, error) { var request *gitalypb.GetArchiveRequest - ctx, c, err := gitaly.NewRepositoryClient( - r.Context(), - params.GitalyServer, - gitaly.WithFeatures(params.GitalyServer.Features), - ) + ctx, c, err := gitaly.NewRepositoryClient(r.Context(), params.GitalyServer) if err != nil { return nil, err diff --git a/workhorse/internal/git/blob.go b/workhorse/internal/git/blob.go index 39bd4490e66..a6d9cd8b1da 100644 --- a/workhorse/internal/git/blob.go +++ b/workhorse/internal/git/blob.go @@ -27,11 +27,7 @@ func (b *blob) Inject(w http.ResponseWriter, r *http.Request, sendData string) { return } - ctx, blobClient, err := gitaly.NewBlobClient( - r.Context(), - params.GitalyServer, - gitaly.WithFeatures(params.GitalyServer.Features), - ) + ctx, blobClient, err := gitaly.NewBlobClient(r.Context(), params.GitalyServer) if err != nil { helper.Fail500(w, r, fmt.Errorf("blob.GetBlob: %v", err)) diff --git a/workhorse/internal/git/diff.go b/workhorse/internal/git/diff.go index b4878384e2b..9ae95bb6680 100644 --- a/workhorse/internal/git/diff.go +++ b/workhorse/internal/git/diff.go @@ -34,11 +34,7 @@ func (d *diff) Inject(w http.ResponseWriter, r *http.Request, sendData string) { return } - ctx, diffClient, err := gitaly.NewDiffClient( - r.Context(), - params.GitalyServer, - gitaly.WithFeatures(params.GitalyServer.Features), - ) + ctx, diffClient, err := gitaly.NewDiffClient(r.Context(), params.GitalyServer) if err != nil { helper.Fail500(w, r, fmt.Errorf("diff.RawDiff: %v", err)) return diff --git a/workhorse/internal/git/format-patch.go b/workhorse/internal/git/format-patch.go index 264a4001232..d0b2e875c95 100644 --- a/workhorse/internal/git/format-patch.go +++ b/workhorse/internal/git/format-patch.go @@ -34,11 +34,7 @@ func (p *patch) Inject(w http.ResponseWriter, r *http.Request, sendData string) return } - ctx, diffClient, err := gitaly.NewDiffClient( - r.Context(), - params.GitalyServer, - gitaly.WithFeatures(params.GitalyServer.Features), - ) + ctx, diffClient, err := gitaly.NewDiffClient(r.Context(), params.GitalyServer) if err != nil { helper.Fail500(w, r, fmt.Errorf("diff.RawPatch: %v", err)) diff --git a/workhorse/internal/git/info-refs.go b/workhorse/internal/git/info-refs.go index 89db2954e30..b7f825839f8 100644 --- a/workhorse/internal/git/info-refs.go +++ b/workhorse/internal/git/info-refs.go @@ -55,12 +55,7 @@ func handleGetInfoRefs(rw http.ResponseWriter, r *http.Request, a *api.Response) } func handleGetInfoRefsWithGitaly(ctx context.Context, responseWriter *HttpResponseWriter, a *api.Response, rpc, gitProtocol, encoding string) error { - ctx, smarthttp, err := gitaly.NewSmartHTTPClient( - ctx, - a.GitalyServer, - gitaly.WithFeatures(a.GitalyServer.Features), - gitaly.WithLoggingMetadata(a), - ) + ctx, smarthttp, err := gitaly.NewSmartHTTPClient(ctx, a.GitalyServer) if err != nil { return err } diff --git a/workhorse/internal/git/receive-pack.go b/workhorse/internal/git/receive-pack.go index b312bbad621..e3af472fffa 100644 --- a/workhorse/internal/git/receive-pack.go +++ b/workhorse/internal/git/receive-pack.go @@ -20,12 +20,7 @@ func handleReceivePack(w *HttpResponseWriter, r *http.Request, a *api.Response) gitProtocol := r.Header.Get("Git-Protocol") - ctx, smarthttp, err := gitaly.NewSmartHTTPClient( - r.Context(), - a.GitalyServer, - gitaly.WithFeatures(a.GitalyServer.Features), - gitaly.WithLoggingMetadata(a), - ) + ctx, smarthttp, err := gitaly.NewSmartHTTPClient(r.Context(), a.GitalyServer) if err != nil { return fmt.Errorf("smarthttp.ReceivePack: %v", err) } diff --git a/workhorse/internal/git/snapshot.go b/workhorse/internal/git/snapshot.go index 70832ec9211..aadb35a5189 100644 --- a/workhorse/internal/git/snapshot.go +++ b/workhorse/internal/git/snapshot.go @@ -41,11 +41,7 @@ func (s *snapshot) Inject(w http.ResponseWriter, r *http.Request, sendData strin return } - ctx, c, err := gitaly.NewRepositoryClient( - r.Context(), - params.GitalyServer, - gitaly.WithFeatures(params.GitalyServer.Features), - ) + ctx, c, err := gitaly.NewRepositoryClient(r.Context(), params.GitalyServer) if err != nil { helper.Fail500(w, r, fmt.Errorf("SendSnapshot: gitaly.NewRepositoryClient: %v", err)) diff --git a/workhorse/internal/git/upload-pack.go b/workhorse/internal/git/upload-pack.go index 13c0069cde2..74995fb61c8 100644 --- a/workhorse/internal/git/upload-pack.go +++ b/workhorse/internal/git/upload-pack.go @@ -44,12 +44,7 @@ func handleUploadPack(w *HttpResponseWriter, r *http.Request, a *api.Response) e } func handleUploadPackWithGitaly(ctx context.Context, a *api.Response, clientRequest io.Reader, clientResponse io.Writer, gitProtocol string) error { - ctx, smarthttp, err := gitaly.NewSmartHTTPClient( - ctx, - a.GitalyServer, - gitaly.WithFeatures(a.GitalyServer.Features), - gitaly.WithLoggingMetadata(a), - ) + ctx, smarthttp, err := gitaly.NewSmartHTTPClient(ctx, a.GitalyServer) if err != nil { return fmt.Errorf("get gitaly client: %w", err) } diff --git a/workhorse/internal/gitaly/gitaly.go b/workhorse/internal/gitaly/gitaly.go index 799159689ae..af7425be1cf 100644 --- a/workhorse/internal/gitaly/gitaly.go +++ b/workhorse/internal/gitaly/gitaly.go @@ -67,44 +67,23 @@ func InitializeSidechannelRegistry(logger *logrus.Logger) { } } -type MetadataFunc func(metadata.MD) - -func WithFeatures(features map[string]string) MetadataFunc { - return func(md metadata.MD) { - for k, v := range features { - if !strings.HasPrefix(k, "gitaly-feature-") { - continue - } - md.Append(k, v) - } - } -} - -func WithLoggingMetadata(r *api.Response) MetadataFunc { - return func(md metadata.MD) { - if r.GL_ID != "" { - md.Append("user_id", r.GL_ID) - } - if r.GL_USERNAME != "" { - md.Append("username", r.GL_USERNAME) - } - if r.RemoteIp != "" { - md.Append("remote_ip", r.RemoteIp) - } - } +var allowedMetadataKeys = map[string]bool{ + "user_id": true, + "username": true, + "remote_ip": true, } -func withOutgoingMetadata(ctx context.Context, addMetadataFuncs ...MetadataFunc) context.Context { +func withOutgoingMetadata(ctx context.Context, gs api.GitalyServer) context.Context { md := metadata.New(nil) - - for _, f := range addMetadataFuncs { - f(md) + for k, v := range gs.CallMetadata { + if strings.HasPrefix(k, "gitaly-feature-") || allowedMetadataKeys[k] { + md.Set(k, v) + } } - return metadata.NewOutgoingContext(ctx, md) } -func NewSmartHTTPClient(ctx context.Context, server api.GitalyServer, metadataFuncs ...MetadataFunc) (context.Context, *SmartHTTPClient, error) { +func NewSmartHTTPClient(ctx context.Context, server api.GitalyServer) (context.Context, *SmartHTTPClient, error) { conn, err := getOrCreateConnection(server) if err != nil { return nil, nil, err @@ -114,48 +93,44 @@ func NewSmartHTTPClient(ctx context.Context, server api.GitalyServer, metadataFu SmartHTTPServiceClient: grpcClient, sidechannelRegistry: sidechannelRegistry, } - - return withOutgoingMetadata( - ctx, - metadataFuncs..., - ), smartHTTPClient, nil + return withOutgoingMetadata(ctx, server), smartHTTPClient, nil } -func NewBlobClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *BlobClient, error) { +func NewBlobClient(ctx context.Context, server api.GitalyServer) (context.Context, *BlobClient, error) { conn, err := getOrCreateConnection(server) if err != nil { return nil, nil, err } grpcClient := gitalypb.NewBlobServiceClient(conn) - return withOutgoingMetadata(ctx, addMetadataFuncs...), &BlobClient{grpcClient}, nil + return withOutgoingMetadata(ctx, server), &BlobClient{grpcClient}, nil } -func NewRepositoryClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *RepositoryClient, error) { +func NewRepositoryClient(ctx context.Context, server api.GitalyServer) (context.Context, *RepositoryClient, error) { conn, err := getOrCreateConnection(server) if err != nil { return nil, nil, err } grpcClient := gitalypb.NewRepositoryServiceClient(conn) - return withOutgoingMetadata(ctx, addMetadataFuncs...), &RepositoryClient{grpcClient}, nil + return withOutgoingMetadata(ctx, server), &RepositoryClient{grpcClient}, nil } // NewNamespaceClient is only used by the Gitaly integration tests at present -func NewNamespaceClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *NamespaceClient, error) { +func NewNamespaceClient(ctx context.Context, server api.GitalyServer) (context.Context, *NamespaceClient, error) { conn, err := getOrCreateConnection(server) if err != nil { return nil, nil, err } grpcClient := gitalypb.NewNamespaceServiceClient(conn) - return withOutgoingMetadata(ctx, addMetadataFuncs...), &NamespaceClient{grpcClient}, nil + return withOutgoingMetadata(ctx, server), &NamespaceClient{grpcClient}, nil } -func NewDiffClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *DiffClient, error) { +func NewDiffClient(ctx context.Context, server api.GitalyServer) (context.Context, *DiffClient, error) { conn, err := getOrCreateConnection(server) if err != nil { return nil, nil, err } grpcClient := gitalypb.NewDiffServiceClient(conn) - return withOutgoingMetadata(ctx, addMetadataFuncs...), &DiffClient{grpcClient}, nil + return withOutgoingMetadata(ctx, server), &DiffClient{grpcClient}, nil } func getOrCreateConnection(server api.GitalyServer) (*grpc.ClientConn, error) { diff --git a/workhorse/internal/gitaly/gitaly_test.go b/workhorse/internal/gitaly/gitaly_test.go index f81dc16149a..0ea5da20da3 100644 --- a/workhorse/internal/gitaly/gitaly_test.go +++ b/workhorse/internal/gitaly/gitaly_test.go @@ -21,17 +21,9 @@ func TestNewSmartHTTPClient(t *testing.T) { ctx, client, err := NewSmartHTTPClient( context.Background(), serverFixture(), - WithFeatures(features()), - WithLoggingMetadata(&api.Response{ - GL_USERNAME: "gl_username", - GL_ID: "gl_id", - RemoteIp: "1.2.3.4", - }), ) require.NoError(t, err) testOutgoingMetadata(t, ctx) - testOutgoingIDAndUsername(t, ctx) - testOutgoingRemoteIP(t, ctx) require.NotNil(t, client.sidechannelRegistry) } @@ -39,7 +31,6 @@ func TestNewBlobClient(t *testing.T) { ctx, _, err := NewBlobClient( context.Background(), serverFixture(), - WithFeatures(features()), ) require.NoError(t, err) testOutgoingMetadata(t, ctx) @@ -49,7 +40,6 @@ func TestNewRepositoryClient(t *testing.T) { ctx, _, err := NewRepositoryClient( context.Background(), serverFixture(), - WithFeatures(features()), ) require.NoError(t, err) @@ -60,7 +50,6 @@ func TestNewNamespaceClient(t *testing.T) { ctx, _, err := NewNamespaceClient( context.Background(), serverFixture(), - WithFeatures(features()), ) require.NoError(t, err) testOutgoingMetadata(t, ctx) @@ -70,69 +59,45 @@ func TestNewDiffClient(t *testing.T) { ctx, _, err := NewDiffClient( context.Background(), serverFixture(), - WithFeatures(features()), ) require.NoError(t, err) testOutgoingMetadata(t, ctx) } func testOutgoingMetadata(t *testing.T, ctx context.Context) { + t.Helper() md, ok := metadata.FromOutgoingContext(ctx) require.True(t, ok, "get metadata from context") - for k, v := range allowedFeatures() { - actual := md[k] - require.Len(t, actual, 1, "expect one value for %v", k) - require.Equal(t, v, actual[0], "value for %v", k) - } - - for k := range badFeatureMetadata() { - require.Empty(t, md[k], "value for bad key %v", k) - } -} - -func testOutgoingIDAndUsername(t *testing.T, ctx context.Context) { - md, ok := metadata.FromOutgoingContext(ctx) - require.True(t, ok, "get metadata from context") - - require.Equal(t, md["user_id"], []string{"gl_id"}) - require.Equal(t, md["username"], []string{"gl_username"}) -} - -func testOutgoingRemoteIP(t *testing.T, ctx context.Context) { - md, ok := metadata.FromOutgoingContext(ctx) - require.True(t, ok, "get metadata from context") - - require.Equal(t, md["remote_ip"], []string{"1.2.3.4"}) -} - -func features() map[string]string { - features := make(map[string]string) - for k, v := range allowedFeatures() { - features[k] = v - } - - for k, v := range badFeatureMetadata() { - features[k] = v - } - - return features + require.Equal(t, metadata.MD{"username": {"janedoe"}}, md) } func serverFixture() api.GitalyServer { - return api.GitalyServer{Address: "tcp://localhost:123"} -} - -func allowedFeatures() map[string]string { - return map[string]string{ - "gitaly-feature-foo": "bar", - "gitaly-feature-qux": "baz", + return api.GitalyServer{ + Address: "tcp://localhost:123", + CallMetadata: map[string]string{"username": "janedoe"}, } } -func badFeatureMetadata() map[string]string { - return map[string]string{ - "bad-metadata-1": "bad-value-1", - "bad-metadata-2": "bad-value-2", - } +func TestWithOutgoingMetadata(t *testing.T) { + ctx := withOutgoingMetadata(context.Background(), api.GitalyServer{ + CallMetadata: map[string]string{ + "gitaly-feature-abc": "true", + "gitaly-featuregarbage": "blocked", + "bad-header": "blocked", + "user_id": "234", + "username": "janedoe", + "remote_ip": "1.2.3.4", + }, + }) + + md, ok := metadata.FromOutgoingContext(ctx) + require.True(t, ok) + + require.Equal(t, metadata.MD{ + "gitaly-feature-abc": {"true"}, + "user_id": {"234"}, + "username": {"janedoe"}, + "remote_ip": {"1.2.3.4"}, + }, md) } diff --git a/workhorse/main_test.go b/workhorse/main_test.go index 8dce3480e0b..5ebc26c7ac7 100644 --- a/workhorse/main_test.go +++ b/workhorse/main_test.go @@ -813,7 +813,6 @@ func gitOkBody(t *testing.T) *api.Response { return &api.Response{ GL_ID: "user-123", GL_USERNAME: "username", - RemoteIp: "1.2.3.4", Repository: gitalypb.Repository{ StorageName: "default", RelativePath: "foo/bar.git", |