Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-14 18:13:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-14 18:13:45 +0300
commitd7e72d98df261209772ce059e09381d36226913f (patch)
treea6f3ea3cd212d486de15d4e258585494589ee64e
parent89a0c1fa668ec9af6e7cc39935199f24dbee23b6 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/issue_templates/Feature Flag Cleanup.md2
-rw-r--r--.gitlab/issue_templates/Feature Flag Roll Out.md8
-rw-r--r--app/assets/javascripts/editor/schema/ci.json4
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/base_count_resolver.rb19
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb19
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/base_merge_request_resolver.rb27
-rw-r--r--app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb16
-rw-r--r--app/graphql/resolvers/ci/catalog/resource_resolver.rb20
-rw-r--r--app/models/ci/job_artifact.rb7
-rw-r--r--config/feature_flags/development/blob_blame_info.yml2
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--db/docs/xray_reports.yml12
-rw-r--r--db/migrate/20231129211524_add_project_xray_report_model.rb19
-rw-r--r--db/migrate/20231206144919_add_repository_xray_plan_limit.rb10
-rw-r--r--db/schema_migrations/202311292115241
-rw-r--r--db/schema_migrations/202312061449191
-rw-r--r--db/structure.sql33
-rw-r--r--doc/administration/object_storage.md2
-rw-r--r--doc/api/graphql/reference/index.md36
-rw-r--r--doc/api/issues.md10
-rw-r--r--doc/api/rest/index.md4
-rw-r--r--doc/ci/debugging.md5
-rw-r--r--doc/ci/yaml/artifacts_reports.md4
-rw-r--r--doc/development/backend/create_source_code_be/index.md56
-rw-r--r--doc/development/feature_flags/controls.md2
-rw-r--r--lib/gitlab/ci/config/entry/reports.rb3
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb13
-rw-r--r--spec/frontend/projects/settings/components/new_access_dropdown_spec.js16
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js23
-rw-r--r--spec/frontend/sidebar/components/time_tracking/set_time_estimate_form_spec.js8
-rw-r--r--spec/graphql/resolvers/ci/catalog/resource_resolver_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/entry/reports_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml2
-rw-r--r--spec/models/ci/processable_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/catalog/resource_spec.rb2
-rw-r--r--spec/support/rspec_run_time.rb10
-rw-r--r--spec/support/shared_examples/features/runners_shared_examples.rb2
-rw-r--r--workhorse/internal/api/api.go11
-rw-r--r--workhorse/internal/api/api_test.go85
-rw-r--r--workhorse/internal/upload/uploads.go11
-rw-r--r--workhorse/internal/upload/uploads_test.go51
41 files changed, 399 insertions, 174 deletions
diff --git a/.gitlab/issue_templates/Feature Flag Cleanup.md b/.gitlab/issue_templates/Feature Flag Cleanup.md
index 466c5c878c7..7c2efe71ac2 100644
--- a/.gitlab/issue_templates/Feature Flag Cleanup.md
+++ b/.gitlab/issue_templates/Feature Flag Cleanup.md
@@ -42,7 +42,7 @@ Are there any other stages or teams involved that need to be kept in the loop?
the feature can be officially announced in a release blog post.
- [ ] `/chatops run auto_deploy status <merge-commit-of-cleanup-mr>`
- [ ] Close [the feature issue](ISSUE LINK) to indicate the feature will be released in the current milestone.
-- [ ] If not already done, clean up the feature flag from all environments by running these chatops command in `#production` channel: `/chatops run feature delete <feature-flag-name> --dev --ops --pre --staging --staging-ref --production`
+- [ ] If not already done, clean up the feature flag from all environments by running these chatops command in `#production` channel: `/chatops run feature delete <feature-flag-name> --dev --pre --staging --staging-ref --production`
- [ ] Close this rollout issue.
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md
index aad6c931915..19796eda71a 100644
--- a/.gitlab/issue_templates/Feature Flag Roll Out.md
+++ b/.gitlab/issue_templates/Feature Flag Roll Out.md
@@ -32,10 +32,10 @@ Note: Please make sure to run the chatops commands in the Slack channel that get
- Verify the MR with the feature flag is merged to `master` and have been deployed to non-production environments with `/chatops run auto_deploy status <merge-commit-of-your-feature>`
<!-- Delete Incremental roll out if it is not relevant to this deploy -->
-- [ ] Deploy the feature flag at a percentage (recommended percentage: 50%) with `/chatops run feature set <feature-flag-name> <rollout-percentage> --actors --dev --staging --staging-ref`
+- [ ] Deploy the feature flag at a percentage (recommended percentage: 50%) with `/chatops run feature set <feature-flag-name> <rollout-percentage> --actors --dev --pre --staging --staging-ref`
- [ ] Monitor that the error rates did not increase (repeat with a different percentage as necessary).
<!-- End of block for deletes -->
-- [ ] Enable the feature globally on non-production environments with `/chatops run feature set <feature-flag-name> true --dev --staging --staging-ref`
+- [ ] Enable the feature globally on non-production environments with `/chatops run feature set <feature-flag-name> true --dev --pre --staging --staging-ref`
- [ ] Verify that the feature works as expected.
The best environment to validate the feature in is [`staging-canary`](https://about.gitlab.com/handbook/engineering/infrastructure/environments/#staging-canary)
as this is the first environment deployed to. Make sure you are [configured to use canary](https://next.gitlab.com/).
@@ -103,7 +103,7 @@ To do so, follow these steps:
- [ ] Ensure that the default-enabling MR has been included in the release package.
If the merge request was deployed before [the monthly release was tagged](https://about.gitlab.com/handbook/engineering/releases/#self-managed-releases-1),
the feature can be officially announced in a release blog post: `/chatops run release check <merge-request-url> <milestone>`
-- [ ] Consider cleaning up the feature flag from all environments by running these chatops command in `#production` channel. Otherwise these settings may override the default enabled: `/chatops run feature delete <feature-flag-name> --dev --staging --staging-ref --production`
+- [ ] Consider cleaning up the feature flag from all environments by running these chatops command in `#production` channel. Otherwise these settings may override the default enabled: `/chatops run feature delete <feature-flag-name> --dev --pre --staging --staging-ref --production`
- [ ] Close [the feature issue][main-issue] to indicate the feature will be released in the current milestone.
- [ ] Set the next milestone to this rollout issue for scheduling [the flag removal](#release-the-feature).
- [ ] (Optional) You can [create a separate issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Feature%20Flag%20Cleanup) for scheduling the steps below to [Release the feature](#release-the-feature).
@@ -132,7 +132,7 @@ You can either [create a follow-up issue for Feature Flag Cleanup](https://gitla
If the merge request was deployed before [the monthly release was tagged](https://about.gitlab.com/handbook/engineering/releases/#self-managed-releases-1),
the feature can be officially announced in a release blog post: `/chatops run release check <merge-request-url> <milestone>`
- [ ] Close [the feature issue][main-issue] to indicate the feature will be released in the current milestone.
-- [ ] Clean up the feature flag from all environments by running these chatops command in `#production` channel: `/chatops run feature delete <feature-flag-name> --dev --ops --pre --staging --staging-ref --production`
+- [ ] Clean up the feature flag from all environments by running these chatops command in `#production` channel: `/chatops run feature delete <feature-flag-name> --dev --pre --staging --staging-ref --production`
- [ ] Close this rollout issue.
## Rollback Steps
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 139f99ba893..1fb68394912 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -333,6 +333,10 @@
"load_performance": {
"$ref": "#/definitions/string_file_list",
"markdownDescription": "Path to file or list of files with load performance testing report(s). [Learn More](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsload_performance)."
+ },
+ "repository_xray": {
+ "$ref": "#/definitions/string_file_list",
+ "description": "Path to file or list of files with Repository X-Ray report(s)."
}
}
}
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/base_count_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/base_count_resolver.rb
index 82d38ff89d9..565638903e8 100644
--- a/app/graphql/resolvers/analytics/cycle_analytics/base_count_resolver.rb
+++ b/app/graphql/resolvers/analytics/cycle_analytics/base_count_resolver.rb
@@ -32,6 +32,25 @@ module Resolvers
super
end
+
+ # :project level: no customization, returning the original resolver
+ # :group level: add the project_ids argument
+ def self.[](context = :project)
+ case context
+ when :project
+ self
+ when :group
+ Class.new(self) do
+ argument :project_ids, [GraphQL::Types::ID],
+ required: false,
+ description: 'Project IDs within the group hierarchy.'
+
+ define_method :finder_params do
+ { group_id: object.id, include_subgroups: true }
+ end
+ end
+ end
+ end
end
end
end
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb
index 768265752d5..587077d7fd4 100644
--- a/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb
+++ b/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb
@@ -25,25 +25,6 @@ module Resolvers
def finder_params
{ project_id: object.project.id }
end
-
- # :project level: no customization, returning the original resolver
- # :group level: add the project_ids argument
- def self.[](context = :project)
- case context
- when :project
- self
- when :group
- Class.new(self) do
- argument :project_ids, [GraphQL::Types::ID],
- required: false,
- description: 'Project IDs within the group hierarchy.'
-
- define_method :finder_params do
- { group_id: object.id, include_subgroups: true }
- end
- end
- end
- end
end
end
end
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/base_merge_request_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/base_merge_request_resolver.rb
new file mode 100644
index 00000000000..81b6f1f4e23
--- /dev/null
+++ b/app/graphql/resolvers/analytics/cycle_analytics/base_merge_request_resolver.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Analytics
+ module CycleAnalytics
+ class BaseMergeRequestResolver < BaseCountResolver
+ type Types::Analytics::CycleAnalytics::MetricType, null: true
+
+ argument :assignee_usernames, [GraphQL::Types::String],
+ required: false,
+ description: 'Usernames of users assigned to the merge request.'
+
+ argument :author_username, GraphQL::Types::String,
+ required: false,
+ description: 'Username of the author of the merge request.'
+
+ argument :milestone_title, GraphQL::Types::String,
+ required: false,
+ description: 'Milestone applied to the merge request.'
+
+ argument :label_names, [GraphQL::Types::String],
+ required: false,
+ description: 'Labels applied to the merge request.'
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb
index 2d722b02bf1..95080110699 100644
--- a/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb
+++ b/app/graphql/resolvers/analytics/cycle_analytics/deployment_count_resolver.rb
@@ -28,22 +28,6 @@ module Resolvers
finder.execute.count
end
-
- # :project level: no customization, returning the original resolver
- # :group level: add the project_ids argument
- def self.[](context = :project)
- case context
- when :project
- self
- when :group
- Class.new(self) do
- argument :project_ids, [GraphQL::Types::ID],
- required: false,
- description: 'Project IDs within the group hierarchy.'
- end
-
- end
- end
end
end
end
diff --git a/app/graphql/resolvers/ci/catalog/resource_resolver.rb b/app/graphql/resolvers/ci/catalog/resource_resolver.rb
index 4b722bd3ec7..3ea730a5768 100644
--- a/app/graphql/resolvers/ci/catalog/resource_resolver.rb
+++ b/app/graphql/resolvers/ci/catalog/resource_resolver.rb
@@ -6,8 +6,6 @@ module Resolvers
class ResourceResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
- authorize :read_code
-
type ::Types::Ci::Catalog::ResourceType, null: true
argument :id, ::Types::GlobalIDType[::Ci::Catalog::Resource],
@@ -28,19 +26,15 @@ module Resolvers
end
def resolve(id: nil, full_path: nil)
- if full_path.present?
- project = Project.find_by_full_path(full_path)
- authorize!(project)
-
- raise_resource_not_available_error! unless project.catalog_resource
+ catalog_resource = if full_path.present?
+ ::Ci::Catalog::Listing.new(current_user).find_resource(full_path: full_path)
+ else
+ ::Ci::Catalog::Listing.new(current_user).find_resource(id: id.model_id)
+ end
- project.catalog_resource
- else
- catalog_resource = ::Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(id))
- authorize!(catalog_resource&.project)
+ raise_resource_not_available_error! unless catalog_resource
- catalog_resource
- end
+ catalog_resource
end
end
end
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 2fd71fbe463..369737d78c8 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -58,7 +58,8 @@ module Ci
coverage_fuzzing: 'gl-coverage-fuzzing.json',
api_fuzzing: 'gl-api-fuzzing-report.json',
cyclonedx: 'gl-sbom.cdx.json',
- annotations: 'gl-annotations.json'
+ annotations: 'gl-annotations.json',
+ repository_xray: 'gl-repository-xray.json'
}.freeze
INTERNAL_TYPES = {
@@ -78,6 +79,7 @@ module Ci
lsif: :zip,
cyclonedx: :gzip,
annotations: :gzip,
+ repository_xray: :gzip,
# Security reports and license scanning reports are raw artifacts
# because they used to be fetched by the frontend, but this is not the case anymore.
@@ -221,7 +223,8 @@ module Ci
cluster_image_scanning: 27, ## EE-specific
cyclonedx: 28, ## EE-specific
requirements_v2: 29, ## EE-specific
- annotations: 30
+ annotations: 30,
+ repository_xray: 31 ## EE-specifric
}
# `file_location` indicates where actual files are stored.
diff --git a/config/feature_flags/development/blob_blame_info.yml b/config/feature_flags/development/blob_blame_info.yml
index 106ceb60cfe..0066fbafc52 100644
--- a/config/feature_flags/development/blob_blame_info.yml
+++ b/config/feature_flags/development/blob_blame_info.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/425272
milestone: '16.5'
type: development
group: group::source code
-default_enabled: false
+default_enabled: true
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index f81d904f4c5..d10dd1528ea 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -33,6 +33,8 @@
- 1
- - admin_emails
- 1
+- - ai_store_repository_xray
+ - 1
- - analytics_code_review_metrics
- 1
- - analytics_devops_adoption_create_snapshot
diff --git a/db/docs/xray_reports.yml b/db/docs/xray_reports.yml
new file mode 100644
index 00000000000..5fa36d990f2
--- /dev/null
+++ b/db/docs/xray_reports.yml
@@ -0,0 +1,12 @@
+---
+table_name: xray_reports
+classes:
+- Projects::XrayReport
+feature_categories:
+- code_suggestions
+description: The stored JSON output of repository X-Ray for a project
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138220
+milestone: '16.7'
+gitlab_schema: gitlab_main_cell
+sharding_key:
+ project_id: projects
diff --git a/db/migrate/20231129211524_add_project_xray_report_model.rb b/db/migrate/20231129211524_add_project_xray_report_model.rb
new file mode 100644
index 00000000000..eed1ed2c6eb
--- /dev/null
+++ b/db/migrate/20231129211524_add_project_xray_report_model.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddProjectXrayReportModel < Gitlab::Database::Migration[2.2]
+ enable_lock_retries!
+ milestone '16.7'
+
+ def change
+ create_table :xray_reports, if_not_exists: true do |t|
+ # we create an index manually below, don't create one here
+ t.references :project, null: false, index: false, foreign_key: { on_delete: :cascade }
+ t.timestamps_with_timezone null: false
+ t.text :lang, null: false, limit: 255
+ t.jsonb :payload, null: false
+ t.binary :file_checksum, null: false
+ end
+
+ add_index :xray_reports, [:project_id, :lang], unique: true, name: 'index_xray_reports_on_project_id_and_lang'
+ end
+end
diff --git a/db/migrate/20231206144919_add_repository_xray_plan_limit.rb b/db/migrate/20231206144919_add_repository_xray_plan_limit.rb
new file mode 100644
index 00000000000..8d276aa9100
--- /dev/null
+++ b/db/migrate/20231206144919_add_repository_xray_plan_limit.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddRepositoryXrayPlanLimit < Gitlab::Database::Migration[2.2]
+ enable_lock_retries!
+ milestone '16.7'
+
+ def change
+ add_column :plan_limits, :ci_max_artifact_size_repository_xray, :bigint, default: 1.gigabyte, null: false
+ end
+end
diff --git a/db/schema_migrations/20231129211524 b/db/schema_migrations/20231129211524
new file mode 100644
index 00000000000..cbc92b47f14
--- /dev/null
+++ b/db/schema_migrations/20231129211524
@@ -0,0 +1 @@
+0ee8b127bcdf66b2fe4639e8397d39052f61c16186b491039ce478f5b477a6a3 \ No newline at end of file
diff --git a/db/schema_migrations/20231206144919 b/db/schema_migrations/20231206144919
new file mode 100644
index 00000000000..b99c72d6ad1
--- /dev/null
+++ b/db/schema_migrations/20231206144919
@@ -0,0 +1 @@
+c5ccd76e1245234f4e78413d3afde72eb4c0c84ab723dffc6ac83abb619f43a9 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 484a667b113..03a9df13d29 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -21110,7 +21110,8 @@ CREATE TABLE plan_limits (
ci_job_annotations_size integer DEFAULT 81920 NOT NULL,
ci_job_annotations_num integer DEFAULT 20 NOT NULL,
file_size_limit_mb double precision DEFAULT 100.0 NOT NULL,
- audit_events_amazon_s3_configurations integer DEFAULT 5 NOT NULL
+ audit_events_amazon_s3_configurations integer DEFAULT 5 NOT NULL,
+ ci_max_artifact_size_repository_xray bigint DEFAULT 1073741824 NOT NULL
);
CREATE SEQUENCE plan_limits_id_seq
@@ -25765,6 +25766,26 @@ CREATE SEQUENCE x509_issuers_id_seq
ALTER SEQUENCE x509_issuers_id_seq OWNED BY x509_issuers.id;
+CREATE TABLE xray_reports (
+ id bigint NOT NULL,
+ project_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ lang text NOT NULL,
+ payload jsonb NOT NULL,
+ file_checksum bytea NOT NULL,
+ CONSTRAINT check_6da5a3b473 CHECK ((char_length(lang) <= 255))
+);
+
+CREATE SEQUENCE xray_reports_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE xray_reports_id_seq OWNED BY xray_reports.id;
+
CREATE TABLE zentao_tracker_data (
id bigint NOT NULL,
integration_id bigint NOT NULL,
@@ -27455,6 +27476,8 @@ ALTER TABLE ONLY x509_commit_signatures ALTER COLUMN id SET DEFAULT nextval('x50
ALTER TABLE ONLY x509_issuers ALTER COLUMN id SET DEFAULT nextval('x509_issuers_id_seq'::regclass);
+ALTER TABLE ONLY xray_reports ALTER COLUMN id SET DEFAULT nextval('xray_reports_id_seq'::regclass);
+
ALTER TABLE ONLY zentao_tracker_data ALTER COLUMN id SET DEFAULT nextval('zentao_tracker_data_id_seq'::regclass);
ALTER TABLE ONLY zoekt_indexed_namespaces ALTER COLUMN id SET DEFAULT nextval('zoekt_indexed_namespaces_id_seq'::regclass);
@@ -30162,6 +30185,9 @@ ALTER TABLE ONLY x509_commit_signatures
ALTER TABLE ONLY x509_issuers
ADD CONSTRAINT x509_issuers_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY xray_reports
+ ADD CONSTRAINT xray_reports_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY zentao_tracker_data
ADD CONSTRAINT zentao_tracker_data_pkey PRIMARY KEY (id);
@@ -35271,6 +35297,8 @@ CREATE INDEX index_x509_commit_signatures_on_x509_certificate_id ON x509_commit_
CREATE INDEX index_x509_issuers_on_subject_key_identifier ON x509_issuers USING btree (subject_key_identifier);
+CREATE UNIQUE INDEX index_xray_reports_on_project_id_and_lang ON xray_reports USING btree (project_id, lang);
+
CREATE INDEX index_zentao_tracker_data_on_integration_id ON zentao_tracker_data USING btree (integration_id);
CREATE INDEX index_zoekt_indexed_namespaces_on_namespace_id ON zoekt_indexed_namespaces USING btree (namespace_id);
@@ -38672,6 +38700,9 @@ ALTER TABLE ONLY reviews
ALTER TABLE ONLY draft_notes
ADD CONSTRAINT fk_rails_2a8dac9901 FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY xray_reports
+ ADD CONSTRAINT fk_rails_2b13fbecf9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY dependency_proxy_image_ttl_group_policies
ADD CONSTRAINT fk_rails_2b1896d021 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md
index b26419c9a52..9a9b2811cf0 100644
--- a/doc/administration/object_storage.md
+++ b/doc/administration/object_storage.md
@@ -814,7 +814,7 @@ or add fault tolerance and redundancy, you may be
looking at removing dependencies on block or network file systems.
See the following additional guides:
-1. Make sure the [`git` user home directory](https://docs.gitlab.com/omnibus/settings/configuration.html#moving-the-home-directory-for-a-user) is on local disk.
+1. Make sure the [`git` user home directory](https://docs.gitlab.com/omnibus/settings/configuration.html#move-the-home-directory-for-a-user) is on local disk.
1. Configure [database lookup of SSH keys](operations/fast_ssh_key_lookup.md)
to eliminate the need for a shared `authorized_keys` file.
1. [Prevent local disk usage for job logs](job_logs.md#prevent-local-disk-usage).
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 46dd4067fd7..7d3c4099440 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -20466,6 +20466,24 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Timestamp marking the end date and time. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeweight"></a>`weight` | [`Int`](#int) | Weight applied to the issue. |
+##### `GroupValueStreamAnalyticsFlowMetrics.timeToMerge`
+
+Median time from merge request creation to merge request merged.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the merge request. |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the merge request. |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergefrom"></a>`from` | [`Time!`](#time) | Timestamp marking the start date and time. |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the merge request. |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the merge request. |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergeprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
+| <a id="groupvaluestreamanalyticsflowmetricstimetomergeto"></a>`to` | [`Time!`](#time) | Timestamp marking the end date and time. |
+
### `GroupWikiRepositoryRegistry`
Represents the Geo sync and verification state of a group wiki repository.
@@ -25914,6 +25932,23 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| <a id="projectvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Timestamp marking the end date and time. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimeweight"></a>`weight` | [`Int`](#int) | Weight applied to the issue. |
+##### `ProjectValueStreamAnalyticsFlowMetrics.timeToMerge`
+
+Median time from merge request creation to merge request merged.
+
+Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectvaluestreamanalyticsflowmetricstimetomergeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the merge request. |
+| <a id="projectvaluestreamanalyticsflowmetricstimetomergeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the merge request. |
+| <a id="projectvaluestreamanalyticsflowmetricstimetomergefrom"></a>`from` | [`Time!`](#time) | Timestamp marking the start date and time. |
+| <a id="projectvaluestreamanalyticsflowmetricstimetomergelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the merge request. |
+| <a id="projectvaluestreamanalyticsflowmetricstimetomergemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the merge request. |
+| <a id="projectvaluestreamanalyticsflowmetricstimetomergeto"></a>`to` | [`Time!`](#time) | Timestamp marking the end date and time. |
+
### `ProjectWikiRepositoryRegistry`
Represents the Geo replication and verification state of a project_wiki_repository.
@@ -30502,6 +30537,7 @@ Iteration ID wildcard values.
| <a id="jobartifactfiletypemetrics_referee"></a>`METRICS_REFEREE` | METRICS REFEREE job artifact file type. |
| <a id="jobartifactfiletypenetwork_referee"></a>`NETWORK_REFEREE` | NETWORK REFEREE job artifact file type. |
| <a id="jobartifactfiletypeperformance"></a>`PERFORMANCE` | PERFORMANCE job artifact file type. |
+| <a id="jobartifactfiletyperepository_xray"></a>`REPOSITORY_XRAY` | REPOSITORY XRAY job artifact file type. |
| <a id="jobartifactfiletyperequirements"></a>`REQUIREMENTS` | REQUIREMENTS job artifact file type. |
| <a id="jobartifactfiletyperequirements_v2"></a>`REQUIREMENTS_V2` | REQUIREMENTS V2 job artifact file type. |
| <a id="jobartifactfiletypesast"></a>`SAST` | SAST job artifact file type. |
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 681f4901b47..b2c6f0cb739 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -63,7 +63,7 @@ Supported attributes:
| `health_status` **(ULTIMATE ALL)** | string | No | Return issues with the specified `health_status`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370721) in GitLab 15.4)._ In [GitLab 15.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/370721), `None` returns issues with no health status assigned, and `Any` returns issues with a health status assigned.
| `iids[]` | integer array | No | Return only the issues having the given `iid`. |
| `in` | string | No | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description`. |
-| `issue_type` | string | No | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. |
+| `issue_type` | string | No | Filter to a given type of issue. One of `issue`, `incident`, `test_case` or `task`. |
| `iteration_id` **(PREMIUM ALL)** | integer | No | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. |
| `iteration_title` **(PREMIUM ALL)** | string | No | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. |
| `labels` | string | No | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
@@ -295,7 +295,7 @@ Supported attributes:
| `due_date` | string | No | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `any`, `today`, `tomorrow`, `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. |
| `epic_id` **(PREMIUM ALL)** | integer | No | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. |
| `iids[]` | integer array | No | Return only the issues having the given `iid`. |
-| `issue_type` | string | No | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. |
+| `issue_type` | string | No | Filter to a given type of issue. One of `issue`, `incident`, `test_case` or `task`. |
| `iteration_id` **(PREMIUM ALL)** | integer | No | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. |
| `iteration_title` **(PREMIUM ALL)** | string | No | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. |
| `labels` | string | No | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
@@ -502,7 +502,7 @@ Supported attributes:
| `due_date` | string | No | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `any`, `today`, `tomorrow`, `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. |
| `epic_id` **(PREMIUM ALL)** | integer | No | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. |
| `iids[]` | integer array | No | Return only the issues having the given `iid`. |
-| `issue_type` | string | No | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. |
+| `issue_type` | string | No | Filter to a given type of issue. One of `issue`, `incident`, `test_case` or `task`. |
| `iteration_id` **(PREMIUM ALL)** | integer | No | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. |
| `iteration_title` **(PREMIUM ALL)** | string | No | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. |
| `labels` | string | No | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
@@ -1030,7 +1030,7 @@ Supported attributes:
| `epic_id` **(PREMIUM ALL)** | integer | No | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
| `epic_iid` **(PREMIUM ALL)** | integer | No | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5). |
| `iid` | integer/string | No | The internal ID of the project's issue (requires administrator or project owner rights). |
-| `issue_type` | string | No | The type of issue. One of `issue`, `incident`, or `test_case`. Default is `issue`. |
+| `issue_type` | string | No | The type of issue. One of `issue`, `incident`, `test_case` or `task`. Default is `issue`. |
| `labels` | string | No | Comma-separated label names for an issue. |
| `merge_request_to_resolve_discussions_of` | integer | No | The IID of a merge request in which to resolve all issues. This fills out the issue with a default description and mark all discussions as resolved. When passing a description or title, these values take precedence over the default values.|
| `milestone_id` | integer | No | The global ID of a milestone to assign issue. To find the `milestone_id` associated with a milestone, view an issue with the milestone assigned and [use the API](#single-project-issue) to retrieve the issue's details. |
@@ -1201,7 +1201,7 @@ Supported attributes:
| `due_date` | string | No | The due date. Date time string in the format `YYYY-MM-DD`, for example `2016-03-11`. |
| `epic_id` **(PREMIUM ALL)** | integer | No | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
| `epic_iid` **(PREMIUM ALL)** | integer | No | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5). |
-| `issue_type` | string | No | Updates the type of issue. One of `issue`, `incident`, or `test_case`. |
+| `issue_type` | string | No | Updates the type of issue. One of `issue`, `incident`, `test_case` or `task`. |
| `labels` | string | No | Comma-separated label names for an issue. Set to an empty string to unassign all labels. |
| `milestone_id` | integer | No | The global ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.|
| `remove_labels`| string | No | Comma-separated label names to remove from an issue. |
diff --git a/doc/api/rest/index.md b/doc/api/rest/index.md
index ff823dcdea3..76db6273399 100644
--- a/doc/api/rest/index.md
+++ b/doc/api/rest/index.md
@@ -374,7 +374,7 @@ This resource has been moved permanently to https://gitlab.example.com/api/v4/pr
GitLab supports the following pagination methods:
- Offset-based pagination. The default method and available on all endpoints except,
- in GitLab 16.5 and later, the `\users` endpoint.
+ in GitLab 16.5 and later, the `users` endpoint.
- Keyset-based pagination. Added to selected endpoints but being
[progressively rolled out](https://gitlab.com/groups/gitlab-org/-/epics/2039).
@@ -383,7 +383,7 @@ For large collections, you should use keyset pagination
### Offset-based pagination
-> The `\users` endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/426547) for offset-based pagination in GitLab 16.5 and is planned for removal in 17.0. This change is a breaking change. Use keyset-based pagination for this endpoint instead.
+> The `users` endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/426547) for offset-based pagination in GitLab 16.5 and is planned for removal in 17.0. This change is a breaking change. Use keyset-based pagination for this endpoint instead.
Sometimes, the returned result spans many pages. When listing resources, you can
pass the following parameters:
diff --git a/doc/ci/debugging.md b/doc/ci/debugging.md
index b52608dc23c..8a60b5f649e 100644
--- a/doc/ci/debugging.md
+++ b/doc/ci/debugging.md
@@ -292,3 +292,8 @@ These errors can happen if the following are both true:
To resolve this issue, add any projects with CI/CD jobs that fetch images from the container
registry to the target project's [job token allowlist](jobs/ci_job_token.md#allow-access-to-your-project-with-a-job-token).
+
+These errors might also happen when trying to use a [project access token](../user/project/settings/project_access_tokens.md)
+to access images in another project. Project access tokens are scoped to one project,
+and therefore cannot access images in other projects. You must use [a different token type](../security/token_overview.md)
+with wider scope.
diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md
index 572d92f9554..2c6b52bb856 100644
--- a/doc/ci/yaml/artifacts_reports.md
+++ b/doc/ci/yaml/artifacts_reports.md
@@ -312,6 +312,10 @@ artifact and existing [requirements](../../user/project/requirements/index.md) a
GitLab can display the results of one or more reports in the
[project requirements](../../user/project/requirements/index.md#view-a-requirement).
+## `artifacts:reports:repository_xray` **(ULTIMATE ALL)**
+
+The `repository_xray` report collects information about your repository for use by AI in code suggestions.
+
## `artifacts:reports:sast`
> [Moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) from GitLab Ultimate to GitLab Free in 13.3.
diff --git a/doc/development/backend/create_source_code_be/index.md b/doc/development/backend/create_source_code_be/index.md
index c2a489c7a6c..6f444369129 100644
--- a/doc/development/backend/create_source_code_be/index.md
+++ b/doc/development/backend/create_source_code_be/index.md
@@ -11,31 +11,41 @@ that fall under the [Source Code group](https://about.gitlab.com/handbook/produc
of the [Create stage](https://about.gitlab.com/handbook/product/categories/#create-stage)
of the [DevOps lifecycle](https://about.gitlab.com/handbook/product/categories/#devops-stages).
-We interface with the Gitaly and Code Review teams. The features
-we work with are listed on the
+The Source Code Management team interfaces with the Gitaly and Code Review teams and works across three codebases: Workhorse, GitLab Shell and GitLab Rails.
+
+## Source Code Features Reference
+
+Features owned by the Source Code Management group are listed on the
[Features by Group Page](https://about.gitlab.com/handbook/product/categories/features/#createsource-code-group).
-The team works across three codebases: Workhorse, GitLab Shell and GitLab Rails.
+### Code Owners
-## Workhorse
+Source Code Management shares ownership of Code Owners with the Code Review group.
-[GitLab Workhorse](../../workhorse/index.md) is a smart reverse proxy for GitLab. It handles "large" HTTP
-requests such as file downloads, file uploads, `git push`, `git pull` and `git` archive downloads.
+- [Feature homepage](../../../user/project/codeowners/index.md)
+- [Developer Reference](../../code_owners/index.md)
-Workhorse itself is not a feature, but there are several features in GitLab
-that would not work efficiently without Workhorse.
+### Approval Rules
-## GitLab Shell
+- [Approval Rules](../../merge_request_concepts/approval_rules.md)
-GitLab Shell handles Git SSH sessions for GitLab and modifies the list of authorized keys.
-For more information, refer to the [GitLab Shell documentation](../../gitlab_shell/index.md).
+### Protected Branches
-To learn about the reasoning behind our creation of `gitlab-sshd`, read the blog post
-[Why we implemented our own SSHD solution](https://about.gitlab.com/blog/2022/08/17/why-we-have-implemented-our-own-sshd-solution-on-gitlab-sass/).
+Details about Protected Branches models can be found in the [Code Owners](../../code_owners/index.md#related-models) technical reference page.
+
+### Repositories
+
+- [Project Repository Storage Moves](../../repository_storage_moves/index.md)
+
+### Project Templates
+
+- [Custom group-level project templates development guidelines](../../project_templates/index.md)
+
+### Git LFS
-## CODEOWNERS
+- [Git LFS Development guidelines](../../lfs.md)
-Source Code Management shares ownership of [Code Owners](../../code_owners/index.md) with the Code Review group.
+## Technical Stack
## GitLab Rails
@@ -58,3 +68,19 @@ The `:source_code_management` annotation indicates which code belongs to the Sou
group in the Rails codebase. The annotated objects are presented on
[this page](https://gitlab-com.gitlab.io/gl-infra/platform/stage-groups-index/source-code.html) along
with the [Error Budgets dashboards](https://dashboards.gitlab.net/d/stage-groups-source_code/stage-groups3a-source-code3a-group-dashboard?orgId=1).
+
+## GitLab Workhorse
+
+[GitLab Workhorse](../../workhorse/index.md) is a smart reverse proxy for GitLab. It handles "large" HTTP
+requests such as file downloads, file uploads, `git push`, `git pull` and `git` archive downloads.
+
+Workhorse itself is not a feature, but there are several features in GitLab
+that would not work efficiently without Workhorse.
+
+## GitLab Shell
+
+GitLab Shell handles Git SSH sessions for GitLab and modifies the list of authorized keys.
+For more information, refer to the [GitLab Shell documentation](../../gitlab_shell/index.md).
+
+To learn about the reasoning behind our creation of `gitlab-sshd`, read the blog post
+[Why we implemented our own SSHD solution](https://about.gitlab.com/blog/2022/08/17/why-we-have-implemented-our-own-sshd-solution-on-gitlab-sass/).
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index 1fffd3c652b..5006b21965e 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -509,5 +509,5 @@ record still exists in the database that the flag was deployed too.
The record can be deleted once the MR is deployed to all the environments:
```shell
-/chatops run feature delete <feature-flag-name> --dev --ops --pre --staging --staging-ref --production
+/chatops run feature delete <feature-flag-name> --dev --pre --staging --staging-ref --production
```
diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb
index 3c180674f2a..16755ac320c 100644
--- a/lib/gitlab/ci/config/entry/reports.rb
+++ b/lib/gitlab/ci/config/entry/reports.rb
@@ -17,7 +17,7 @@ module Gitlab
dast performance browser_performance load_performance license_scanning metrics lsif
dotenv terraform accessibility
coverage_fuzzing api_fuzzing cluster_image_scanning
- requirements requirements_v2 coverage_report cyclonedx annotations].freeze
+ requirements requirements_v2 coverage_report cyclonedx annotations repository_xray].freeze
attributes ALLOWED_KEYS
@@ -51,6 +51,7 @@ module Gitlab
validates :requirements_v2, array_of_strings_or_string: true
validates :cyclonedx, array_of_strings_or_string: true
validates :annotations, array_of_strings_or_string: true
+ validates :repository_xray, array_of_strings_or_string: true
end
end
diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
index f36b1faa82b..572b7c61767 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
@@ -168,19 +168,6 @@ module QA
{ name: "add_milestone", label: "0.0.1" }
]
)
- # TODO: reenable once https://gitlab.com/gitlab-org/gitlab/-/issues/386714 fixed
- # currently this doesn't work as expected if reviewer is not matched by public email
- # event for assigning approver is created with reviewer being user doing import but mr actually doesn't
- # contain reviewers or the approved state
- #
- # reviews = merge_request.reviews.map do |review|
- # {
- # id: review.dig(:user, :id),
- # username: review.dig(:user, :username),
- # state: review[:state]
- # }
- # end
- # expect(reviews).to eq([{ id: user.id, username: user.username, state: "approved" }])
end
def verify_release_import
diff --git a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
index 7c8cc1bb38d..4e3554131c6 100644
--- a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
+++ b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
@@ -8,6 +8,7 @@ import {
import { last } from 'lodash';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import { getUsers, getGroups, getDeployKeys } from '~/projects/settings/api/access_dropdown_api';
import AccessDropdown, { i18n } from '~/projects/settings/components/access_dropdown.vue';
@@ -77,6 +78,7 @@ describe('Access Level Dropdown', () => {
label,
disabled,
preselectedItems,
+ stubs = {},
} = {}) => {
wrapper = shallowMountExtended(AccessDropdown, {
propsData: {
@@ -90,6 +92,7 @@ describe('Access Level Dropdown', () => {
stubs: {
GlSprintf,
GlDropdown,
+ ...stubs,
},
});
};
@@ -373,15 +376,22 @@ describe('Access Level Dropdown', () => {
});
describe('on dropdown open', () => {
+ const focusInput = jest.fn();
+
beforeEach(() => {
- createComponent();
+ createComponent({
+ stubs: {
+ GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
+ methods: { focusInput },
+ }),
+ },
+ });
});
it('should set the search input focus', () => {
- wrapper.vm.$refs.search.focusInput = jest.fn();
findDropdown().vm.$emit('shown');
- expect(wrapper.vm.$refs.search.focusInput).toHaveBeenCalled();
+ expect(focusInput).toHaveBeenCalled();
});
});
diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js
index cd391765dde..bcef99afc46 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_create_view_spec.js
@@ -14,13 +14,14 @@ Vue.use(Vuex);
describe('DropdownContentsCreateView', () => {
let wrapper;
+ let store;
+
const colors = Object.keys(mockSuggestedColors).map((color) => ({
[color]: mockSuggestedColors[color],
}));
const createComponent = (initialState = mockConfig) => {
- const store = new Vuex.Store(labelSelectModule());
-
+ store = new Vuex.Store(labelSelectModule());
store.dispatch('setInitialState', initialState);
wrapper = shallowMountExtended(DropdownContentsCreateView, {
@@ -47,7 +48,7 @@ describe('DropdownContentsCreateView', () => {
it('returns `true` when `labelCreateInProgress` is true', async () => {
await findColorSelectorInput().vm.$emit('input', '#ff0000');
await findLabelTitleInput().vm.$emit('input', 'Foo');
- wrapper.vm.$store.dispatch('requestCreateLabel');
+ store.dispatch('requestCreateLabel');
await nextTick();
@@ -81,7 +82,6 @@ describe('DropdownContentsCreateView', () => {
describe('getColorName', () => {
it('returns color name from color object', () => {
expect(findAllLinks().at(0).attributes('title')).toBe(Object.values(colors[0]).pop());
- expect(wrapper.vm.getColorName(colors[0])).toBe(Object.values(colors[0]).pop());
});
});
@@ -97,20 +97,17 @@ describe('DropdownContentsCreateView', () => {
describe('handleCreateClick', () => {
it('calls action `createLabel` with object containing `labelTitle` & `selectedColor`', async () => {
- jest.spyOn(wrapper.vm, 'createLabel').mockImplementation();
-
+ jest.spyOn(store, 'dispatch').mockImplementation();
await findColorSelectorInput().vm.$emit('input', '#ff0000');
await findLabelTitleInput().vm.$emit('input', 'Foo');
findCreateClickButton().vm.$emit('click');
await nextTick();
- expect(wrapper.vm.createLabel).toHaveBeenCalledWith(
- expect.objectContaining({
- title: 'Foo',
- color: '#ff0000',
- }),
- );
+ expect(store.dispatch).toHaveBeenCalledWith('createLabel', {
+ title: 'Foo',
+ color: '#ff0000',
+ });
});
});
});
@@ -186,7 +183,7 @@ describe('DropdownContentsCreateView', () => {
});
it('shows gl-loading-icon within create button element when `labelCreateInProgress` is `true`', async () => {
- wrapper.vm.$store.dispatch('requestCreateLabel');
+ store.dispatch('requestCreateLabel');
await nextTick();
const loadingIconEl = wrapper.find('.dropdown-actions').findComponent(GlLoadingIcon);
diff --git a/spec/frontend/sidebar/components/time_tracking/set_time_estimate_form_spec.js b/spec/frontend/sidebar/components/time_tracking/set_time_estimate_form_spec.js
index 657fb52d62c..37d7b3b6781 100644
--- a/spec/frontend/sidebar/components/time_tracking/set_time_estimate_form_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/set_time_estimate_form_spec.js
@@ -6,6 +6,7 @@ import setIssueTimeEstimateWithoutErrors from 'test_fixtures/graphql/issue_set_t
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent } from 'helpers/stub_component';
import SetTimeEstimateForm from '~/sidebar/components/time_tracking/set_time_estimate_form.vue';
import issueSetTimeEstimateMutation from '~/sidebar/queries/issue_set_time_estimate.mutation.graphql';
@@ -75,10 +76,13 @@ describe('Set Time Estimate Form', () => {
timeTracking,
},
apolloProvider: createMockApollo([[issueSetTimeEstimateMutation, mutationResolverMock]]),
+ stubs: {
+ GlModal: stubComponent(GlModal, {
+ methods: { close: modalCloseMock },
+ }),
+ },
});
- wrapper.vm.$refs.modal.close = modalCloseMock;
-
findModal().vm.$emit('show');
await nextTick();
};
diff --git a/spec/graphql/resolvers/ci/catalog/resource_resolver_spec.rb b/spec/graphql/resolvers/ci/catalog/resource_resolver_spec.rb
index 19fc0c7fc4c..313d1d337da 100644
--- a/spec/graphql/resolvers/ci/catalog/resource_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/catalog/resource_resolver_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Resolvers::Ci::Catalog::ResourceResolver, feature_category: :pipe
let_it_be(:namespace) { create(:group) }
let_it_be(:project) { create(:project, :private, namespace: namespace) }
- let_it_be(:resource) { create(:ci_catalog_resource, project: project) }
+ let_it_be(:resource) { create(:ci_catalog_resource, :published, project: project) }
let_it_be(:user) { create(:user) }
describe '#resolve' do
@@ -20,7 +20,7 @@ RSpec.describe Resolvers::Ci::Catalog::ResourceResolver, feature_category: :pipe
context 'when resource is found' do
it 'returns a single CI/CD Catalog resource' do
result = resolve(described_class, ctx: { current_user: user },
- args: { id: resource.to_global_id.to_s })
+ args: { id: resource.to_global_id })
expect(result.id).to eq(resource.id)
expect(result.class).to eq(Ci::Catalog::Resource)
@@ -30,7 +30,9 @@ RSpec.describe Resolvers::Ci::Catalog::ResourceResolver, feature_category: :pipe
context 'when resource is not found' do
it 'raises ResourceNotAvailable error' do
result = resolve(described_class, ctx: { current_user: user },
- args: { id: "gid://gitlab/Ci::Catalog::Resource/not-a-real-id" })
+ args: { id: GlobalID.new(
+ ::Gitlab::GlobalId.build(model_name: '::Ci::Catalog::Resource', id: "not-a-real-id")
+ ) })
expect(result).to be_a(::Gitlab::Graphql::Errors::ResourceNotAvailable)
end
@@ -40,7 +42,7 @@ RSpec.describe Resolvers::Ci::Catalog::ResourceResolver, feature_category: :pipe
context 'when user is not authorised to view the resource' do
it 'raises ResourceNotAvailable error' do
result = resolve(described_class, ctx: { current_user: user },
- args: { id: resource.to_global_id.to_s })
+ args: { id: resource.to_global_id })
expect(result).to be_a(::Gitlab::Graphql::Errors::ResourceNotAvailable)
end
@@ -115,7 +117,7 @@ RSpec.describe Resolvers::Ci::Catalog::ResourceResolver, feature_category: :pipe
expect_graphql_error_to_be_created(::Gitlab::Graphql::Errors::ArgumentError,
"Exactly one of 'id' or 'full_path' arguments is required.") do
resolve(described_class, ctx: { current_user: user },
- args: { full_path: resource.project.full_path, id: resource.to_global_id.to_s })
+ args: { full_path: resource.project.full_path, id: resource.to_global_id })
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
index d610c3ce2f6..a6675229c62 100644
--- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
@@ -49,6 +49,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports, feature_category: :pipeline_c
:accessibility | 'gl-accessibility.json'
:cyclonedx | 'gl-sbom.cdx.zip'
:annotations | 'gl-annotations.json'
+ :repository_xray | 'gl-repository-xray.json'
end
with_them do
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 0361e2967e4..688487df778 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -422,6 +422,7 @@ builds:
- job_artifacts_cluster_image_scanning
- job_artifacts_cyclonedx
- job_artifacts_requirements_v2
+- job_artifacts_repository_xray
- runner_manager
- runner_manager_build
- runner_session
@@ -833,6 +834,7 @@ project:
- target_branch_rules
- organization
- dora_performance_scores
+- xray_reports
award_emoji:
- awardable
- user
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index c7bd6c590f7..5d457c4f213 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -76,7 +76,7 @@ RSpec.describe Ci::Processable, feature_category: :continuous_integration do
job_artifacts_network_referee job_artifacts_dotenv
job_artifacts_cobertura needs job_artifacts_accessibility
job_artifacts_requirements job_artifacts_coverage_fuzzing
- job_artifacts_requirements_v2
+ job_artifacts_requirements_v2 job_artifacts_repository_xray
job_artifacts_api_fuzzing terraform_state_versions job_artifacts_cyclonedx
job_annotations job_artifacts_annotations].freeze
end
diff --git a/spec/requests/api/graphql/ci/catalog/resource_spec.rb b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
index d4d6b039605..87d09d05f44 100644
--- a/spec/requests/api/graphql/ci/catalog/resource_spec.rb
+++ b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
)
end
- let_it_be(:resource) { create(:ci_catalog_resource, project: project) }
+ let_it_be(:resource) { create(:ci_catalog_resource, :published, project: project) }
let(:query) do
<<~GQL
diff --git a/spec/support/rspec_run_time.rb b/spec/support/rspec_run_time.rb
index 841f714e369..976e902258d 100644
--- a/spec/support/rspec_run_time.rb
+++ b/spec/support/rspec_run_time.rb
@@ -9,6 +9,8 @@ module Support
class RSpecFormatter < RSpec::Core::Formatters::BaseFormatter
include Tooling::Helpers::DurationFormatter
+ TIME_LIMIT_IN_MINUTES = 80
+
RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished
def start(_notification)
@@ -20,6 +22,11 @@ module Support
end
def example_group_started(notification)
+ if @last_elapsed_seconds && @last_elapsed_seconds > TIME_LIMIT_IN_MINUTES * 60
+ RSpec::Expectations.fail_with(
+ "Rspec suite is exceeding the #{TIME_LIMIT_IN_MINUTES} minute limit and is forced to exit with error.")
+ end
+
if @group_level == 0
@current_group_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
file_path = spec_file_path(notification)
@@ -37,7 +44,8 @@ module Support
time_now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
actual_duration = time_now - @current_group_start_time
- output.puts "\n# [RSpecRunTime] #{file_path} took #{readable_duration(actual_duration)}. " \
+ output.puts "\n# [RSpecRunTime] Finishing example group #{file_path}. " \
+ "It took #{readable_duration(actual_duration)}. " \
"#{expected_run_time(file_path)}"
end
diff --git a/spec/support/shared_examples/features/runners_shared_examples.rb b/spec/support/shared_examples/features/runners_shared_examples.rb
index 3755200f282..8e1e2b10bef 100644
--- a/spec/support/shared_examples/features/runners_shared_examples.rb
+++ b/spec/support/shared_examples/features/runners_shared_examples.rb
@@ -178,7 +178,7 @@ RSpec.shared_examples 'submits edit runner form' do
context 'when a runner is updated', :js do
before do
- fill_in s_('Runners|Runner description'), with: 'new-runner-description'
+ fill_in s_('Runners|Runner description'), with: 'new-runner-description', fill_options: { clear: :backspace }
click_on _('Save changes')
end
diff --git a/workhorse/internal/api/api.go b/workhorse/internal/api/api.go
index 4b36c9ddcbb..91bf37fec55 100644
--- a/workhorse/internal/api/api.go
+++ b/workhorse/internal/api/api.go
@@ -38,6 +38,15 @@ type API struct {
Version string
}
+type PreAuthorizeFixedPathError struct {
+ StatusCode int
+ Status string
+}
+
+func (p *PreAuthorizeFixedPathError) Error() string {
+ return fmt.Sprintf("no api response: status %d", p.StatusCode)
+}
+
var (
requestsCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
@@ -326,7 +335,7 @@ func (api *API) PreAuthorizeFixedPath(r *http.Request, method string, path strin
failureResponse.Body.Close()
if apiResponse == nil {
- return nil, fmt.Errorf("no api response: status %d", failureResponse.StatusCode)
+ return nil, &PreAuthorizeFixedPathError{StatusCode: failureResponse.StatusCode, Status: failureResponse.Status}
}
return apiResponse, nil
diff --git a/workhorse/internal/api/api_test.go b/workhorse/internal/api/api_test.go
index e3457eb0f47..71a0b703cea 100644
--- a/workhorse/internal/api/api_test.go
+++ b/workhorse/internal/api/api_test.go
@@ -47,38 +47,7 @@ func TestGetGeoProxyDataForResponses(t *testing.T) {
}
}
-func getGeoProxyDataGivenResponse(t *testing.T, givenInternalApiResponse string) (*GeoProxyData, error) {
- t.Helper()
- ts := testRailsServer(regexp.MustCompile(`/api/v4/geo/proxy`), 200, givenInternalApiResponse)
- defer ts.Close()
- backend := helper.URLMustParse(ts.URL)
- version := "123"
- rt := roundtripper.NewTestBackendRoundTripper(backend)
- testhelper.ConfigureSecret()
-
- apiClient := NewAPI(backend, version, rt)
-
- geoProxyData, err := apiClient.GetGeoProxyData()
-
- return geoProxyData, err
-}
-
-func testRailsServer(url *regexp.Regexp, code int, body string) *httptest.Server {
- return testhelper.TestServerWithHandlerWithGeoPolling(url, func(w http.ResponseWriter, r *http.Request) {
- // return a 204 No Content response if we don't receive the JWT header
- if r.Header.Get(secret.RequestHeader) == "" {
- w.WriteHeader(204)
- return
- }
-
- w.Header().Set("Content-Type", ResponseContentType)
-
- w.WriteHeader(code)
- fmt.Fprint(w, body)
- })
-}
-
-func TestPreAuthorizeFixedPath(t *testing.T) {
+func TestPreAuthorizeFixedPath_OK(t *testing.T) {
var (
upstreamHeaders http.Header
upstreamQuery url.Values
@@ -91,6 +60,7 @@ func TestPreAuthorizeFixedPath(t *testing.T) {
upstreamHeaders = r.Header
upstreamQuery = r.URL.Query()
+
w.Header().Set("Content-Type", ResponseContentType)
io.WriteString(w, `{"TempPath":"HELLO!!"}`)
}))
@@ -109,3 +79,54 @@ func TestPreAuthorizeFixedPath(t *testing.T) {
"original query must propagate")
require.Equal(t, "HELLO!!", resp.TempPath, "sanity check: successful API call")
}
+
+func TestPreAuthorizeFixedPath_Unauthorized(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/my/api/path" {
+ return
+ }
+
+ w.WriteHeader(http.StatusUnauthorized)
+ }))
+ defer ts.Close()
+
+ req, err := http.NewRequest("GET", "/original/request/path?q1=Q1&q2=Q2", nil)
+ require.NoError(t, err)
+
+ api := NewAPI(helper.URLMustParse(ts.URL), "123", http.DefaultTransport)
+ resp, err := api.PreAuthorizeFixedPath(req, "POST", "/my/api/path")
+ require.Nil(t, resp)
+ preAuthError := &PreAuthorizeFixedPathError{StatusCode: 401, Status: "Unauthorized 401"}
+ require.ErrorAs(t, err, &preAuthError)
+}
+
+func getGeoProxyDataGivenResponse(t *testing.T, givenInternalApiResponse string) (*GeoProxyData, error) {
+ t.Helper()
+ ts := testRailsServer(regexp.MustCompile(`/api/v4/geo/proxy`), 200, givenInternalApiResponse)
+ defer ts.Close()
+ backend := helper.URLMustParse(ts.URL)
+ version := "123"
+ rt := roundtripper.NewTestBackendRoundTripper(backend)
+ testhelper.ConfigureSecret()
+
+ apiClient := NewAPI(backend, version, rt)
+
+ geoProxyData, err := apiClient.GetGeoProxyData()
+
+ return geoProxyData, err
+}
+
+func testRailsServer(url *regexp.Regexp, code int, body string) *httptest.Server {
+ return testhelper.TestServerWithHandlerWithGeoPolling(url, func(w http.ResponseWriter, r *http.Request) {
+ // return a 204 No Content response if we don't receive the JWT header
+ if r.Header.Get(secret.RequestHeader) == "" {
+ w.WriteHeader(204)
+ return
+ }
+
+ w.Header().Set("Content-Type", ResponseContentType)
+
+ w.WriteHeader(code)
+ fmt.Fprint(w, body)
+ })
+}
diff --git a/workhorse/internal/upload/uploads.go b/workhorse/internal/upload/uploads.go
index efd3d5be0bd..4a40c998a03 100644
--- a/workhorse/internal/upload/uploads.go
+++ b/workhorse/internal/upload/uploads.go
@@ -69,13 +69,14 @@ func interceptMultipartFiles(w http.ResponseWriter, r *http.Request, h http.Hand
return
}
- var protocolErr textproto.ProtocolError
- if errors.As(err, &protocolErr) {
+ switch t := err.(type) {
+ case textproto.ProtocolError:
fail.Request(w, r, err, fail.WithStatus(http.StatusBadRequest))
- return
+ case *api.PreAuthorizeFixedPathError:
+ fail.Request(w, r, err, fail.WithStatus(t.StatusCode), fail.WithBody(t.Status))
+ default:
+ fail.Request(w, r, fmt.Errorf("handleFileUploads: extract files from multipart: %v", err))
}
-
- fail.Request(w, r, fmt.Errorf("handleFileUploads: extract files from multipart: %v", err))
}
return
}
diff --git a/workhorse/internal/upload/uploads_test.go b/workhorse/internal/upload/uploads_test.go
index 14ad6a92cd9..981f7e649b9 100644
--- a/workhorse/internal/upload/uploads_test.go
+++ b/workhorse/internal/upload/uploads_test.go
@@ -232,20 +232,7 @@ func TestUploadProcessingField(t *testing.T) {
func TestUploadingMultipleFiles(t *testing.T) {
testhelper.ConfigureSecret()
- var buffer bytes.Buffer
-
- writer := multipart.NewWriter(&buffer)
- for i := 0; i < 11; i++ {
- _, err := writer.CreateFormFile(fmt.Sprintf("file %v", i), "my.file")
- require.NoError(t, err)
- }
- require.NoError(t, writer.Close())
-
- httpRequest, err := http.NewRequest("PUT", "/url/path", &buffer)
- require.NoError(t, err)
- httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
-
- response := httptest.NewRecorder()
+ httpRequest, response := setupMultipleFiles(t)
testInterceptMultipartFiles(t, response, httpRequest, nilHandler, &testFormProcessor{})
@@ -357,6 +344,23 @@ func TestBadMultipartHeader(t *testing.T) {
require.Equal(t, 400, response.Code)
}
+func TestUnauthorizedMultipartHeader(t *testing.T) {
+ testhelper.ConfigureSecret()
+
+ httpRequest, response := setupMultipleFiles(t)
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusUnauthorized)
+ }))
+ defer ts.Close()
+
+ api := api.NewAPI(helper.URLMustParse(ts.URL), "123", http.DefaultTransport)
+ interceptMultipartFiles(response, httpRequest, nilHandler, &testFormProcessor{}, &apiAuthorizer{api}, &DefaultPreparer{})
+
+ require.Equal(t, 401, response.Code)
+ require.Equal(t, "401 Unauthorized\n", response.Body.String())
+}
+
func TestMalformedMimeHeader(t *testing.T) {
testhelper.ConfigureSecret()
@@ -571,3 +575,22 @@ func testInterceptMultipartFiles(t *testing.T, w http.ResponseWriter, r *http.Re
interceptMultipartFiles(w, r, h, filter, fa, preparer)
}
+
+func setupMultipleFiles(t *testing.T) (*http.Request, *httptest.ResponseRecorder) {
+ var buffer bytes.Buffer
+
+ t.Helper()
+
+ writer := multipart.NewWriter(&buffer)
+ for i := 0; i < 11; i++ {
+ _, err := writer.CreateFormFile(fmt.Sprintf("file %v", i), "my.file")
+ require.NoError(t, err)
+ }
+ require.NoError(t, writer.Close())
+
+ httpRequest, err := http.NewRequest("PUT", "/url/path", &buffer)
+ require.NoError(t, err)
+ httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
+
+ return httpRequest, httptest.NewRecorder()
+}