diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-09 00:09:47 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-09 00:09:47 +0300 |
commit | 66108e3b34cdba3eab53e07fdde76f799c0edc9b (patch) | |
tree | 1ada683cd997f7e68c69d014e90c24e2a630049e | |
parent | c0c1433fa5a9f31c8eb4292d13de744aa74e9e83 (diff) |
Add latest changes from gitlab-org/gitlab@master
28 files changed, 1147 insertions, 39 deletions
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index a6c5a6d8526..e96d0c4b1c4 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -8,7 +8,7 @@ class RegistrationsController < Devise::RegistrationsController layout :choose_layout - skip_before_action :required_signup_info, only: [:welcome, :update_registration] + skip_before_action :required_signup_info, :check_two_factor_requirement, only: [:welcome, :update_registration] prepend_before_action :check_captcha, only: :create before_action :whitelist_query_limiting, only: [:destroy] before_action :ensure_terms_accepted, diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb new file mode 100644 index 00000000000..068546cd39f --- /dev/null +++ b/app/graphql/resolvers/projects_resolver.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Resolvers + class ProjectsResolver < BaseResolver + type Types::ProjectType, null: true + + argument :membership, GraphQL::BOOLEAN_TYPE, + required: false, + description: 'Limit projects that the current user is a member of' + + argument :search, GraphQL::STRING_TYPE, + required: false, + description: 'Search criteria' + + def resolve(**args) + ProjectsFinder + .new(current_user: current_user, params: project_finder_params(args)) + .execute + end + + private + + def project_finder_params(params) + { + without_deleted: true, + non_public: params[:membership], + search: params[:search] + }.compact + end + end +end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index e8f6eeff3e9..e0479c8227b 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -9,6 +9,11 @@ module Types resolver: Resolvers::ProjectResolver, description: "Find a project" + field :projects, Types::ProjectType.connection_type, + null: true, + resolver: Resolvers::ProjectsResolver, + description: "Find projects visible to the current user" + field :group, Types::GroupType, null: true, resolver: Resolvers::GroupResolver, diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index c96f086684f..1276ef4ed8c 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -43,7 +43,10 @@ module ApplicationSettingImplementation authorized_keys_enabled: true, # TODO default to false if the instance is configured to use AuthorizedKeysCommand commit_email_hostname: default_commit_email_hostname, container_expiration_policies_enable_historic_entries: false, + container_registry_features: [], container_registry_token_expire_delay: 5, + container_registry_vendor: '', + container_registry_version: '', default_artifacts_expire_in: '30 days', default_branch_protection: Settings.gitlab['default_branch_protection'], default_ci_config_path: nil, diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 1564ba7c373..c962f8c8c26 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1300,6 +1300,12 @@ class MergeRequest < ApplicationRecord compare_reports(Ci::CompareTestReportsService) end + def has_accessibility_reports? + return false unless Feature.enabled?(:accessibility_report_view, project) + + actual_head_pipeline.present? && actual_head_pipeline.has_reports?(Ci::JobArtifact.accessibility_reports) + end + def has_coverage_reports? return false unless Feature.enabled?(:coverage_report_view, project) diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml index ccf109968fc..7cf5de8947c 100644 --- a/app/views/projects/snippets/show.html.haml +++ b/app/views/projects/snippets/show.html.haml @@ -3,7 +3,7 @@ - breadcrumb_title @snippet.to_reference - page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets") -- if Feature.enabled?(:snippets_vue) +- if Feature.enabled?(:snippets_vue, default_enabled: true) #js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} } - else = render 'shared/snippets/header' diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index 741e38e3d84..819f02b78fe 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -4,7 +4,7 @@ - breadcrumb_title @snippet.to_reference - page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets") -- if Feature.enabled?(:snippets_vue) +- if Feature.enabled?(:snippets_vue, default_enabled: true) #js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} } - else = render 'shared/snippets/header' diff --git a/changelogs/unreleased/204839-registry-application-settings.yml b/changelogs/unreleased/204839-registry-application-settings.yml new file mode 100644 index 00000000000..a04fd2e756d --- /dev/null +++ b/changelogs/unreleased/204839-registry-application-settings.yml @@ -0,0 +1,5 @@ +--- +title: Add container registry settings to application_settings table +merge_request: 31125 +author: +type: added diff --git a/changelogs/unreleased/207235-snippets-vue-ff-on-by-default.yml b/changelogs/unreleased/207235-snippets-vue-ff-on-by-default.yml new file mode 100644 index 00000000000..352d80eaa93 --- /dev/null +++ b/changelogs/unreleased/207235-snippets-vue-ff-on-by-default.yml @@ -0,0 +1,5 @@ +--- +title: Refactored Snippet view to Vue +merge_request: 31450 +author: +type: added diff --git a/changelogs/unreleased/214583-add-ability-to-query-projects.yml b/changelogs/unreleased/214583-add-ability-to-query-projects.yml new file mode 100644 index 00000000000..57187afa250 --- /dev/null +++ b/changelogs/unreleased/214583-add-ability-to-query-projects.yml @@ -0,0 +1,5 @@ +--- +title: Add ability to query Projects using GraphQL API +merge_request: 30146 +author: +type: added diff --git a/changelogs/unreleased/215955-redirect-loop-when-logging-in-for-the-experimental-sign_up-flow.yml b/changelogs/unreleased/215955-redirect-loop-when-logging-in-for-the-experimental-sign_up-flow.yml new file mode 100644 index 00000000000..c0a1a586d44 --- /dev/null +++ b/changelogs/unreleased/215955-redirect-loop-when-logging-in-for-the-experimental-sign_up-flow.yml @@ -0,0 +1,5 @@ +--- +title: Fix redirect loop on .com when 2FA is required +merge_request: 31229 +author: +type: fixed diff --git a/config/prometheus/common_metrics.yml b/config/prometheus/common_metrics.yml index 4d0ea4a345d..f0491df3db9 100644 --- a/config/prometheus/common_metrics.yml +++ b/config/prometheus/common_metrics.yml @@ -10,7 +10,7 @@ panel_groups: weight: 4 metrics: - id: system_metrics_kubernetes_container_memory_total - query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024' + query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-(.*)",namespace="{{kube_namespace}}"}) by (job)) without (job) /1024/1024/1024' label: Total (GB) unit: GB - title: "Core Usage (Total)" @@ -19,7 +19,7 @@ panel_groups: weight: 3 metrics: - id: system_metrics_kubernetes_container_cores_total - query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job)' + query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-(.*)",namespace="{{kube_namespace}}"}[15m])) by (job)) without (job)' label: Total (cores) unit: "cores" - title: "Memory Usage (Pod average)" @@ -28,7 +28,7 @@ panel_groups: weight: 2 metrics: - id: system_metrics_kubernetes_container_memory_average - query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024' + query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="{{kube_namespace}}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="{{kube_namespace}}"}) without (job)) /1024/1024' label: Pod average (MB) unit: MB - title: "Canary: Memory Usage (Pod Average)" @@ -37,7 +37,7 @@ panel_groups: weight: 2 metrics: - id: system_metrics_kubernetes_container_memory_average_canary - query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024' + query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-canary-(.*)",namespace="{{kube_namespace}}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-canary-(.*)",namespace="{{kube_namespace}}"}) without (job)) /1024/1024' label: Pod average (MB) unit: MB track: canary @@ -47,7 +47,7 @@ panel_groups: weight: 1 metrics: - id: system_metrics_kubernetes_container_core_usage - query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))' + query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="{{kube_namespace}}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="{{kube_namespace}}"}[15m])) by (pod_name))' label: Pod average (cores) unit: "cores" - title: "Canary: Core Usage (Pod Average)" @@ -56,7 +56,7 @@ panel_groups: weight: 1 metrics: - id: system_metrics_kubernetes_container_core_usage_canary - query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))' + query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-canary-(.*)",namespace="{{kube_namespace}}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^{{ci_environment_slug}}-canary-(.*)",namespace="{{kube_namespace}}"}[15m])) by (pod_name))' label: Pod average (cores) unit: "cores" track: canary @@ -66,7 +66,7 @@ panel_groups: weight: 1 metrics: - id: system_metrics_knative_function_invocation_count - query_range: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_service=~"%{function_name}.*"}[1m])*60))' + query_range: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="{{kube_namespace}}", destination_service=~"{{function_name}}.*"}[1m])*60))' label: invocations / minute unit: requests # NGINX Ingress metrics for pre-0.16.0 versions @@ -79,7 +79,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_ingress_throughput_status_code - query_range: 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) by (status_code)' + query_range: 'sum(rate(nginx_upstream_responses_total{upstream=~"{{kube_namespace}}-{{ci_environment_slug}}-.*"}[2m])) by (status_code)' unit: req / sec label: Status Code - title: "Latency" @@ -90,7 +90,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_ingress_latency_pod_average - query_range: 'avg(nginx_upstream_response_msecs_avg{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"})' + query_range: 'avg(nginx_upstream_response_msecs_avg{upstream=~"{{kube_namespace}}-{{ci_environment_slug}}-.*"})' label: Pod average (ms) unit: ms - title: "HTTP Error Rate" @@ -101,7 +101,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_ingress_http_error_rate - query_range: 'sum(rate(nginx_upstream_responses_total{status_code="5xx", upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) / sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) * 100' + query_range: 'sum(rate(nginx_upstream_responses_total{status_code="5xx", upstream=~"{{kube_namespace}}-{{ci_environment_slug}}-.*"}[2m])) / sum(rate(nginx_upstream_responses_total{upstream=~"{{kube_namespace}}-{{ci_environment_slug}}-.*"}[2m])) * 100' label: 5xx Errors (%) unit: "%" # NGINX Ingress metrics for post-0.16.0 versions @@ -114,7 +114,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_ingress_16_throughput_status_code - query_range: 'sum(label_replace(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m]), "status_code", "${1}xx", "status", "(.)..")) by (status_code)' + query_range: 'sum(label_replace(rate(nginx_ingress_controller_requests{namespace="{{kube_namespace}}",ingress=~".*{{ci_environment_slug}}.*"}[2m]), "status_code", "${1}xx", "status", "(.)..")) by (status_code)' unit: req / sec label: Status Code - title: "Latency" @@ -123,7 +123,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_ingress_16_latency_pod_average - query_range: 'sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_sum{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_count{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 1000' + query_range: 'sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_sum{namespace="{{kube_namespace}}",ingress=~".*{{ci_environment_slug}}.*"}[2m])) / sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_count{namespace="{{kube_namespace}}",ingress=~".*{{ci_environment_slug}}.*"}[2m])) * 1000' label: Pod average (ms) unit: ms - title: "HTTP Error Rate" @@ -132,7 +132,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_ingress_16_http_error_rate - query_range: 'sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 100' + query_range: 'sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="{{kube_namespace}}",ingress=~".*{{ci_environment_slug}}.*"}[2m])) / sum(rate(nginx_ingress_controller_requests{namespace="{{kube_namespace}}",ingress=~".*{{ci_environment_slug}}.*"}[2m])) * 100' label: 5xx Errors (%) unit: "%" - group: Response metrics (HA Proxy) @@ -144,7 +144,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_ha_proxy_throughput_status_code - query_range: 'sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) by (code)' + query_range: 'sum(rate(haproxy_frontend_http_requests_total{ {{environment_filter}} }[2m])) by (code)' unit: req / sec label: Status Code - title: "HTTP Error Rate" @@ -153,7 +153,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_ha_proxy_http_error_rate - query_range: 'sum(rate(haproxy_frontend_http_responses_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_responses_total{%{environment_filter}}[2m]))' + query_range: 'sum(rate(haproxy_frontend_http_responses_total{code="5xx",{{environment_filter}} }[2m])) / sum(rate(haproxy_frontend_http_responses_total{ {{environment_filter}} }[2m]))' label: HTTP Errors (%) unit: "%" - group: Response metrics (AWS ELB) @@ -165,7 +165,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_aws_elb_throughput_requests - query_range: 'sum(aws_elb_request_count_sum{%{environment_filter}}) / 60' + query_range: 'sum(aws_elb_request_count_sum{ {{environment_filter}} }) / 60' label: Total (req/sec) unit: req / sec - title: "Latency" @@ -174,7 +174,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_aws_elb_latency_average - query_range: 'avg(aws_elb_latency_average{%{environment_filter}}) * 1000' + query_range: 'avg(aws_elb_latency_average{ {{environment_filter}} }) * 1000' label: Average (ms) unit: ms - title: "HTTP Error Rate" @@ -183,7 +183,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_aws_elb_http_error_rate - query_range: 'sum(aws_elb_httpcode_backend_5_xx_sum{%{environment_filter}}) / sum(aws_elb_request_count_sum{%{environment_filter}})' + query_range: 'sum(aws_elb_httpcode_backend_5_xx_sum{ {{environment_filter}} }) / sum(aws_elb_request_count_sum{ {{environment_filter}} })' label: HTTP Errors (%) unit: "%" - group: Response metrics (NGINX) @@ -195,7 +195,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_throughput_status_code - query_range: 'sum(rate(nginx_server_requests{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) by (code)' + query_range: 'sum(rate(nginx_server_requests{server_zone!="*", server_zone!="_", {{environment_filter}} }[2m])) by (code)' unit: req / sec label: Status Code - title: "Latency" @@ -204,7 +204,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_latency - query_range: 'avg(nginx_server_requestMsec{%{environment_filter}})' + query_range: 'avg(nginx_server_requestMsec{ {{environment_filter}} })' label: Upstream (ms) unit: ms - title: "HTTP Error Rate (Errors / Sec)" @@ -215,7 +215,7 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_http_error_rate - query_range: 'sum(rate(nginx_server_requests{code="5xx", %{environment_filter}}[2m]))' + query_range: 'sum(rate(nginx_server_requests{code="5xx", {{environment_filter}} }[2m]))' label: HTTP Errors unit: "errors / sec" - title: "HTTP Error Rate" @@ -224,7 +224,6 @@ panel_groups: weight: 1 metrics: - id: response_metrics_nginx_http_error_percentage - query_range: 'sum(rate(nginx_server_requests{code=~"5.*", host="*", %{environment_filter}}[2m])) / sum(rate(nginx_server_requests{code="total", host="*", %{environment_filter}}[2m])) * 100' + query_range: 'sum(rate(nginx_server_requests{code=~"5.*", host="*", {{environment_filter}} }[2m])) / sum(rate(nginx_server_requests{code="total", host="*", {{environment_filter}} }[2m])) * 100' label: 5xx Errors (%) unit: "%" - diff --git a/db/migrate/20200424135319_create_nuget_dependency_link_metadata.rb b/db/migrate/20200424135319_create_nuget_dependency_link_metadata.rb new file mode 100644 index 00000000000..8aa3d98aa80 --- /dev/null +++ b/db/migrate/20200424135319_create_nuget_dependency_link_metadata.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class CreateNugetDependencyLinkMetadata < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + CONSTRAINT_NAME = 'packages_nuget_dependency_link_metadata_target_framework_constraint' + + def up + unless table_exists?(:packages_nuget_dependency_link_metadata) + create_table :packages_nuget_dependency_link_metadata, id: false do |t| + t.references :dependency_link, primary_key: true, default: nil, foreign_key: { to_table: :packages_dependency_links, on_delete: :cascade }, index: { name: 'index_packages_nuget_dl_metadata_on_dependency_link_id' }, type: :bigint + t.text :target_framework, null: false + end + end + + add_text_limit :packages_nuget_dependency_link_metadata, :target_framework, 255, constraint_name: CONSTRAINT_NAME + end + + def down + drop_table :packages_nuget_dependency_link_metadata + end +end diff --git a/db/migrate/20200505164958_add_registry_settings_to_application_settings.rb b/db/migrate/20200505164958_add_registry_settings_to_application_settings.rb new file mode 100644 index 00000000000..65407d69191 --- /dev/null +++ b/db/migrate/20200505164958_add_registry_settings_to_application_settings.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class AddRegistrySettingsToApplicationSettings < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + # rubocop:disable Migration/AddLimitToTextColumns + def up + add_column_with_default(:application_settings, + :container_registry_vendor, + :text, + default: '', + allow_null: false) + + add_column_with_default(:application_settings, + :container_registry_version, + :text, + default: '', + allow_null: false) + end + # rubocop:enable Migration/AddLimitToTextColumns + + def down + remove_column :application_settings, :container_registry_vendor + remove_column :application_settings, :container_registry_version + end +end diff --git a/db/migrate/20200505171834_add_text_limit_to_container_registry_vendor.rb b/db/migrate/20200505171834_add_text_limit_to_container_registry_vendor.rb new file mode 100644 index 00000000000..242dcc9a837 --- /dev/null +++ b/db/migrate/20200505171834_add_text_limit_to_container_registry_vendor.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddTextLimitToContainerRegistryVendor < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_text_limit :application_settings, :container_registry_vendor, 255 + end + + def down + remove_text_limit :application_settings, :container_registry_vendor + end +end diff --git a/db/migrate/20200505172405_add_text_limit_to_container_registry_version.rb b/db/migrate/20200505172405_add_text_limit_to_container_registry_version.rb new file mode 100644 index 00000000000..36589c9cc75 --- /dev/null +++ b/db/migrate/20200505172405_add_text_limit_to_container_registry_version.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddTextLimitToContainerRegistryVersion < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_text_limit :application_settings, :container_registry_version, 255 + end + + def down + remove_text_limit :application_settings, :container_registry_version + end +end diff --git a/db/migrate/20200507221434_add_container_registry_features_to_application_settings.rb b/db/migrate/20200507221434_add_container_registry_features_to_application_settings.rb new file mode 100644 index 00000000000..b333db56eee --- /dev/null +++ b/db/migrate/20200507221434_add_container_registry_features_to_application_settings.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddContainerRegistryFeaturesToApplicationSettings < ActiveRecord::Migration[6.0] + DOWNTIME = false + + def up + add_column :application_settings, :container_registry_features, :text, array: true, default: [], null: false # rubocop:disable Migration/AddLimitToTextColumns + end + + def down + remove_column :application_settings, :container_registry_features + end +end diff --git a/db/structure.sql b/db/structure.sql index df1eac0303a..d1cb47dd55d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -438,7 +438,12 @@ CREATE TABLE public.application_settings ( container_expiration_policies_enable_historic_entries boolean DEFAULT false NOT NULL, issues_create_limit integer DEFAULT 300 NOT NULL, push_rule_id bigint, - group_owners_can_manage_default_branch_protection boolean DEFAULT true NOT NULL + group_owners_can_manage_default_branch_protection boolean DEFAULT true NOT NULL, + container_registry_vendor text DEFAULT ''::text NOT NULL, + container_registry_version text DEFAULT ''::text NOT NULL, + container_registry_features text[] DEFAULT '{}'::text[] NOT NULL, + CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)), + CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255)) ); CREATE SEQUENCE public.application_settings_id_seq @@ -4617,6 +4622,12 @@ CREATE SEQUENCE public.packages_maven_metadata_id_seq ALTER SEQUENCE public.packages_maven_metadata_id_seq OWNED BY public.packages_maven_metadata.id; +CREATE TABLE public.packages_nuget_dependency_link_metadata ( + dependency_link_id bigint NOT NULL, + target_framework text NOT NULL, + CONSTRAINT packages_nuget_dependency_link_metadata_target_framework_constr CHECK ((char_length(target_framework) <= 255)) +); + CREATE TABLE public.packages_package_files ( id bigint NOT NULL, package_id bigint NOT NULL, @@ -8476,6 +8487,9 @@ ALTER TABLE ONLY public.packages_dependency_links ALTER TABLE ONLY public.packages_maven_metadata ADD CONSTRAINT packages_maven_metadata_pkey PRIMARY KEY (id); +ALTER TABLE ONLY public.packages_nuget_dependency_link_metadata + ADD CONSTRAINT packages_nuget_dependency_link_metadata_pkey PRIMARY KEY (dependency_link_id); + ALTER TABLE ONLY public.packages_package_files ADD CONSTRAINT packages_package_files_pkey PRIMARY KEY (id); @@ -10104,6 +10118,8 @@ CREATE INDEX index_packages_dependency_links_on_dependency_id ON public.packages CREATE INDEX index_packages_maven_metadata_on_package_id_and_path ON public.packages_maven_metadata USING btree (package_id, path); +CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON public.packages_nuget_dependency_link_metadata USING btree (dependency_link_id); + CREATE INDEX index_packages_package_files_on_package_id_and_file_name ON public.packages_package_files USING btree (package_id, file_name); CREATE INDEX index_packages_packages_on_name_trigram ON public.packages_packages USING gin (name public.gin_trgm_ops); @@ -12302,6 +12318,9 @@ ALTER TABLE ONLY public.user_canonical_emails ALTER TABLE ONLY public.project_repositories ADD CONSTRAINT fk_rails_c3258dc63b FOREIGN KEY (shard_id) REFERENCES public.shards(id) ON DELETE RESTRICT; +ALTER TABLE ONLY public.packages_nuget_dependency_link_metadata + ADD CONSTRAINT fk_rails_c3313ee2e4 FOREIGN KEY (dependency_link_id) REFERENCES public.packages_dependency_links(id) ON DELETE CASCADE; + ALTER TABLE ONLY public.merge_request_user_mentions ADD CONSTRAINT fk_rails_c440b9ea31 FOREIGN KEY (note_id) REFERENCES public.notes(id) ON DELETE CASCADE; @@ -13702,11 +13721,16 @@ COPY "schema_migrations" (version) FROM STDIN; 20200424043515 20200424050250 20200424101920 +20200424135319 20200427064130 20200429015603 20200429181335 20200429181955 20200429182245 +20200505164958 +20200505171834 +20200505172405 20200506125731 +20200507221434 \. diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 9f08e8ebf58..89b3bbac938 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -6221,6 +6221,7 @@ type Mutation { mergeRequestSetSubscription(input: MergeRequestSetSubscriptionInput!): MergeRequestSetSubscriptionPayload mergeRequestSetWip(input: MergeRequestSetWipInput!): MergeRequestSetWipPayload removeAwardEmoji(input: RemoveAwardEmojiInput!): RemoveAwardEmojiPayload + removeProjectFromSecurityDashboard(input: RemoveProjectFromSecurityDashboardInput!): RemoveProjectFromSecurityDashboardPayload todoMarkDone(input: TodoMarkDoneInput!): TodoMarkDonePayload todoRestore(input: TodoRestoreInput!): TodoRestorePayload todoRestoreMany(input: TodoRestoreManyInput!): TodoRestoreManyPayload @@ -8089,6 +8090,41 @@ type Query { ): Project """ + Find projects visible to the current user + """ + projects( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + + """ + Limit projects that the current user is a member of + """ + membership: Boolean + + """ + Search criteria + """ + search: String + ): ProjectConnection + + """ Find Snippets visible to the current user """ snippets( @@ -8366,6 +8402,36 @@ type RemoveAwardEmojiPayload { errors: [String!]! } +""" +Autogenerated input type of RemoveProjectFromSecurityDashboard +""" +input RemoveProjectFromSecurityDashboardInput { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + ID of the project to remove from the Instance Security Dashboard + """ + projectId: ID! +} + +""" +Autogenerated return type of RemoveProjectFromSecurityDashboard +""" +type RemoveProjectFromSecurityDashboardPayload { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + Reasons why the mutation failed. + """ + errors: [String!]! +} + type Repository { """ Indicates repository has no visible content @@ -10669,10 +10735,9 @@ type Vulnerability { id: ID! """ - The JSON location metadata for the vulnerability. Its format depends on the - type of the security scan that found the vulnerability + Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability """ - location: JSON + location: VulnerabilityLocation """ The project on which the vulnerability was found @@ -10746,6 +10811,101 @@ type VulnerabilityEdge { } """ +Represents a vulnerability location. The fields with data will depend on the vulnerability report type +""" +union VulnerabilityLocation = VulnerabilityLocationContainerScanning | VulnerabilityLocationDast | VulnerabilityLocationDependencyScanning | VulnerabilityLocationSast + +""" +Represents the location of a vulnerability found by a container security scan +""" +type VulnerabilityLocationContainerScanning { + """ + Dependency containing the vulnerability + """ + dependency: VulnerableDependency + + """ + Name of the vulnerable container image + """ + image: String + + """ + Operating system that runs on the vulnerable container image + """ + operatingSystem: String +} + +""" +Represents the location of a vulnerability found by a DAST scan +""" +type VulnerabilityLocationDast { + """ + Domain name of the vulnerable request + """ + hostname: String + + """ + Query parameter for the URL on which the vulnerability occurred + """ + param: String + + """ + URL path and query string of the vulnerable request + """ + path: String + + """ + HTTP method of the vulnerable request + """ + requestMethod: String +} + +""" +Represents the location of a vulnerability found by a dependency security scan +""" +type VulnerabilityLocationDependencyScanning { + """ + Dependency containing the vulnerability + """ + dependency: VulnerableDependency + + """ + Path to the vulnerable file + """ + file: String +} + +""" +Represents the location of a vulnerability found by a SAST scan +""" +type VulnerabilityLocationSast { + """ + Number of the last relevant line in the vulnerable file + """ + endLine: String + + """ + Path to the vulnerable file + """ + file: String + + """ + Number of the first relevant line in the vulnerable file + """ + startLine: String + + """ + Class containing the vulnerability + """ + vulnerableClass: String + + """ + Method containing the vulnerability + """ + vulnerableMethod: String +} + +""" Check permissions for the current user on a vulnerability """ type VulnerabilityPermissions { @@ -10855,4 +11015,29 @@ enum VulnerabilityState { DETECTED DISMISSED RESOLVED +} + +""" +Represents a vulnerable dependency. Used in vulnerability location data +""" +type VulnerableDependency { + """ + The package associated with the vulnerable dependency + """ + package: VulnerablePackage + + """ + The version of the vulnerable dependency + """ + version: String +} + +""" +Represents a vulnerable package. Used in vulnerability dependency data +""" +type VulnerablePackage { + """ + The name of the vulnerable package + """ + name: String }
\ No newline at end of file diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 1b6d719acd6..3e845667e80 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -18272,6 +18272,33 @@ "deprecationReason": null }, { + "name": "removeProjectFromSecurityDashboard", + "description": null, + "args": [ + { + "name": "input", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "RemoveProjectFromSecurityDashboardInput", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "RemoveProjectFromSecurityDashboardPayload", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "todoMarkDone", "description": null, "args": [ @@ -23888,6 +23915,79 @@ "deprecationReason": null }, { + "name": "projects", + "description": "Find projects visible to the current user", + "args": [ + { + "name": "membership", + "description": "Limit projects that the current user is a member of", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "search", + "description": "Search criteria", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "ProjectConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "snippets", "description": "Find Snippets visible to the current user", "args": [ @@ -24615,6 +24715,94 @@ "possibleTypes": null }, { + "kind": "INPUT_OBJECT", + "name": "RemoveProjectFromSecurityDashboardInput", + "description": "Autogenerated input type of RemoveProjectFromSecurityDashboard", + "fields": null, + "inputFields": [ + { + "name": "projectId", + "description": "ID of the project to remove from the Instance Security Dashboard", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "RemoveProjectFromSecurityDashboardPayload", + "description": "Autogenerated return type of RemoveProjectFromSecurityDashboard", + "fields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "errors", + "description": "Reasons why the mutation failed.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { "kind": "OBJECT", "name": "Repository", "description": null, @@ -31744,13 +31932,13 @@ }, { "name": "location", - "description": "The JSON location metadata for the vulnerability. Its format depends on the type of the security scan that found the vulnerability", + "description": "Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability", "args": [ ], "type": { - "kind": "SCALAR", - "name": "JSON", + "kind": "UNION", + "name": "VulnerabilityLocation", "ofType": null }, "isDeprecated": false, @@ -31979,6 +32167,285 @@ "possibleTypes": null }, { + "kind": "UNION", + "name": "VulnerabilityLocation", + "description": "Represents a vulnerability location. The fields with data will depend on the vulnerability report type", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "VulnerabilityLocationContainerScanning", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationDast", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationDependencyScanning", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationSast", + "ofType": null + } + ] + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationContainerScanning", + "description": "Represents the location of a vulnerability found by a container security scan", + "fields": [ + { + "name": "dependency", + "description": "Dependency containing the vulnerability", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "VulnerableDependency", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "image", + "description": "Name of the vulnerable container image", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "operatingSystem", + "description": "Operating system that runs on the vulnerable container image", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationDast", + "description": "Represents the location of a vulnerability found by a DAST scan", + "fields": [ + { + "name": "hostname", + "description": "Domain name of the vulnerable request", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "param", + "description": "Query parameter for the URL on which the vulnerability occurred", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "path", + "description": "URL path and query string of the vulnerable request", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "requestMethod", + "description": "HTTP method of the vulnerable request", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationDependencyScanning", + "description": "Represents the location of a vulnerability found by a dependency security scan", + "fields": [ + { + "name": "dependency", + "description": "Dependency containing the vulnerability", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "VulnerableDependency", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "file", + "description": "Path to the vulnerable file", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "VulnerabilityLocationSast", + "description": "Represents the location of a vulnerability found by a SAST scan", + "fields": [ + { + "name": "endLine", + "description": "Number of the last relevant line in the vulnerable file", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "file", + "description": "Path to the vulnerable file", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "startLine", + "description": "Number of the first relevant line in the vulnerable file", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "vulnerableClass", + "description": "Class containing the vulnerability", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "vulnerableMethod", + "description": "Method containing the vulnerability", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { "kind": "OBJECT", "name": "VulnerabilityPermissions", "description": "Check permissions for the current user on a vulnerability", @@ -32351,6 +32818,74 @@ }, { "kind": "OBJECT", + "name": "VulnerableDependency", + "description": "Represents a vulnerable dependency. Used in vulnerability location data", + "fields": [ + { + "name": "package", + "description": "The package associated with the vulnerable dependency", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "VulnerablePackage", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "version", + "description": "The version of the vulnerable dependency", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "VulnerablePackage", + "description": "Represents a vulnerable package. Used in vulnerability dependency data", + "fields": [ + { + "name": "name", + "description": "The name of the vulnerable package", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [ diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 3259ce316e7..3ca7164bff5 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -1180,6 +1180,15 @@ Autogenerated return type of RemoveAwardEmoji | `clientMutationId` | String | A unique identifier for the client performing the mutation. | | `errors` | String! => Array | Reasons why the mutation failed. | +## RemoveProjectFromSecurityDashboardPayload + +Autogenerated return type of RemoveProjectFromSecurityDashboard + +| Name | Type | Description | +| --- | ---- | ---------- | +| `clientMutationId` | String | A unique identifier for the client performing the mutation. | +| `errors` | String! => Array | Reasons why the mutation failed. | + ## Repository | Name | Type | Description | @@ -1632,7 +1641,7 @@ Represents a vulnerability. | --- | ---- | ---------- | | `description` | String | Description of the vulnerability | | `id` | ID! | GraphQL ID of the vulnerability | -| `location` | JSON | The JSON location metadata for the vulnerability. Its format depends on the type of the security scan that found the vulnerability | +| `location` | VulnerabilityLocation | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability | | `project` | Project | The project on which the vulnerability was found | | `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST) | | `severity` | VulnerabilitySeverity | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL) | @@ -1641,6 +1650,48 @@ Represents a vulnerability. | `userPermissions` | VulnerabilityPermissions! | Permissions for the current user on the resource | | `vulnerabilityPath` | String | URL to the vulnerability's details page | +## VulnerabilityLocationContainerScanning + +Represents the location of a vulnerability found by a container security scan + +| Name | Type | Description | +| --- | ---- | ---------- | +| `dependency` | VulnerableDependency | Dependency containing the vulnerability | +| `image` | String | Name of the vulnerable container image | +| `operatingSystem` | String | Operating system that runs on the vulnerable container image | + +## VulnerabilityLocationDast + +Represents the location of a vulnerability found by a DAST scan + +| Name | Type | Description | +| --- | ---- | ---------- | +| `hostname` | String | Domain name of the vulnerable request | +| `param` | String | Query parameter for the URL on which the vulnerability occurred | +| `path` | String | URL path and query string of the vulnerable request | +| `requestMethod` | String | HTTP method of the vulnerable request | + +## VulnerabilityLocationDependencyScanning + +Represents the location of a vulnerability found by a dependency security scan + +| Name | Type | Description | +| --- | ---- | ---------- | +| `dependency` | VulnerableDependency | Dependency containing the vulnerability | +| `file` | String | Path to the vulnerable file | + +## VulnerabilityLocationSast + +Represents the location of a vulnerability found by a SAST scan + +| Name | Type | Description | +| --- | ---- | ---------- | +| `endLine` | String | Number of the last relevant line in the vulnerable file | +| `file` | String | Path to the vulnerable file | +| `startLine` | String | Number of the first relevant line in the vulnerable file | +| `vulnerableClass` | String | Class containing the vulnerability | +| `vulnerableMethod` | String | Method containing the vulnerability | + ## VulnerabilityPermissions Check permissions for the current user on a vulnerability @@ -1668,3 +1719,20 @@ Represents vulnerability counts by severity | `low` | Int | Number of vulnerabilities of LOW severity of the project | | `medium` | Int | Number of vulnerabilities of MEDIUM severity of the project | | `unknown` | Int | Number of vulnerabilities of UNKNOWN severity of the project | + +## VulnerableDependency + +Represents a vulnerable dependency. Used in vulnerability location data + +| Name | Type | Description | +| --- | ---- | ---------- | +| `package` | VulnerablePackage | The package associated with the vulnerable dependency | +| `version` | String | The version of the vulnerable dependency | + +## VulnerablePackage + +Represents a vulnerable package. Used in vulnerability dependency data + +| Name | Type | Description | +| --- | ---- | ---------- | +| `name` | String | The name of the vulnerable package | diff --git a/doc/api/packages.md b/doc/api/packages.md index 8671de006d2..c68c16e92a7 100644 --- a/doc/api/packages.md +++ b/doc/api/packages.md @@ -68,6 +68,7 @@ GET /groups/:id/packages | `order_by`| string | no | The field to use as order. One of `created_at` (default), `name`, `version`, `type`, or `project_path`. | | `sort` | string | no | The direction of the order, either `asc` (default) for ascending order or `desc` for descending order. | | `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi` or `nuget`. (_Introduced in GitLab 12.9_) | +| `package_name` | string | no | Filter the project packages with a fuzzy search by name. (_[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30980) in GitLab 13.0_) ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/packages?exclude_subgroups=true diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index 1f8ba51913e..84840718c92 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -42,7 +42,7 @@ module Gitlab # Initialize gon.features with any flags that should be # made globally available to the frontend - push_frontend_feature_flag(:snippets_vue, default_enabled: false) + push_frontend_feature_flag(:snippets_vue, default_enabled: true) push_frontend_feature_flag(:monaco_blobs, default_enabled: false) push_frontend_feature_flag(:monaco_ci, default_enabled: false) push_frontend_feature_flag(:snippets_edit_vue, default_enabled: false) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 049af882dd9..b339c52ce09 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -14611,6 +14611,9 @@ msgstr "" msgid "Package type must be Maven" msgstr "" +msgid "Package type must be NuGet" +msgstr "" + msgid "Package was removed" msgstr "" diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index eda8b8655a1..41822a5a34c 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -419,24 +419,34 @@ describe RegistrationsController do describe '#welcome' do subject { get :welcome } - before do - sign_in(create(:user)) - end - context 'signup_flow experiment enabled' do before do stub_experiment_for_user(signup_flow: true) end it 'renders the devise_experimental_separate_sign_up_flow layout' do + sign_in(create(:user)) + expected_layout = Gitlab.ee? ? :checkout : :devise_experimental_separate_sign_up_flow expect(subject).to render_template(expected_layout) end + + context '2FA is required from group' do + before do + user = create(:user, require_two_factor_authentication_from_group: true) + sign_in(user) + end + + it 'does not perform a redirect' do + expect(subject).not_to redirect_to(profile_two_factor_auth_path) + end + end end context 'signup_flow experiment disabled' do before do + sign_in(create(:user)) stub_experiment_for_user(signup_flow: false) end diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 5916e76dce1..b10c04a37f7 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -121,6 +121,18 @@ FactoryBot.define do end end + trait :with_accessibility_reports do + after(:build) do |merge_request| + merge_request.head_pipeline = build( + :ci_pipeline, + :success, + :with_accessibility_reports, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + end + trait :with_coverage_reports do after(:build) do |merge_request| merge_request.head_pipeline = build( diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb new file mode 100644 index 00000000000..73ff99a2520 --- /dev/null +++ b/spec/graphql/resolvers/projects_resolver_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::ProjectsResolver do + include GraphqlHelpers + + describe '#resolve' do + subject { resolve(described_class, obj: nil, args: filters, ctx: { current_user: current_user }) } + + let_it_be(:project) { create(:project, :public) } + let_it_be(:other_project) { create(:project, :public) } + let_it_be(:private_project) { create(:project, :private) } + let_it_be(:other_private_project) { create(:project, :private) } + + let_it_be(:user) { create(:user) } + + let(:filters) { {} } + + before_all do + project.add_developer(user) + private_project.add_developer(user) + end + + context 'when user is not logged in' do + let(:current_user) { nil } + + context 'when no filters are applied' do + it 'returns all public projects' do + is_expected.to contain_exactly(project, other_project) + end + + context 'when search filter is provided' do + let(:filters) { { search: project.name } } + + it 'returns matching project' do + is_expected.to contain_exactly(project) + end + end + + context 'when membership filter is provided' do + let(:filters) { { membership: true } } + + it 'returns empty list' do + is_expected.to be_empty + end + end + end + end + + context 'when user is logged in' do + let(:current_user) { user } + + context 'when no filters are applied' do + it 'returns all visible projects for the user' do + is_expected.to contain_exactly(project, other_project, private_project) + end + + context 'when search filter is provided' do + let(:filters) { { search: project.name } } + + it 'returns matching project' do + is_expected.to contain_exactly(project) + end + end + + context 'when membership filter is provided' do + let(:filters) { { membership: true } } + + it 'returns projects that user is member of' do + is_expected.to contain_exactly(project, private_project) + end + end + end + end + end +end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 1a168e564dd..0642d96efa5 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1612,6 +1612,32 @@ describe MergeRequest do end end + describe '#has_accessibility_reports?' do + subject { merge_request.has_accessibility_reports? } + + let(:project) { create(:project, :repository) } + + context 'when head pipeline has an accessibility reports' do + let(:merge_request) { create(:merge_request, :with_accessibility_reports, source_project: project) } + + it { is_expected.to be_truthy } + + context 'when feature flag is disabled' do + before do + stub_feature_flags(accessibility_report_view: false) + end + + it { is_expected.to be_falsey } + end + end + + context 'when head pipeline does not have accessibility reports' do + let(:merge_request) { create(:merge_request, source_project: project) } + + it { is_expected.to be_falsey } + end + end + describe '#has_coverage_reports?' do subject { merge_request.has_coverage_reports? } |