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>2020-05-09 00:09:47 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-09 00:09:47 +0300
commit66108e3b34cdba3eab53e07fdde76f799c0edc9b (patch)
tree1ada683cd997f7e68c69d014e90c24e2a630049e
parentc0c1433fa5a9f31c8eb4292d13de744aa74e9e83 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/controllers/registrations_controller.rb2
-rw-r--r--app/graphql/resolvers/projects_resolver.rb31
-rw-r--r--app/graphql/types/query_type.rb5
-rw-r--r--app/models/application_setting_implementation.rb3
-rw-r--r--app/models/merge_request.rb6
-rw-r--r--app/views/projects/snippets/show.html.haml2
-rw-r--r--app/views/snippets/show.html.haml2
-rw-r--r--changelogs/unreleased/204839-registry-application-settings.yml5
-rw-r--r--changelogs/unreleased/207235-snippets-vue-ff-on-by-default.yml5
-rw-r--r--changelogs/unreleased/214583-add-ability-to-query-projects.yml5
-rw-r--r--changelogs/unreleased/215955-redirect-loop-when-logging-in-for-the-experimental-sign_up-flow.yml5
-rw-r--r--config/prometheus/common_metrics.yml45
-rw-r--r--db/migrate/20200424135319_create_nuget_dependency_link_metadata.rb26
-rw-r--r--db/migrate/20200505164958_add_registry_settings_to_application_settings.rb30
-rw-r--r--db/migrate/20200505171834_add_text_limit_to_container_registry_vendor.rb17
-rw-r--r--db/migrate/20200505172405_add_text_limit_to_container_registry_version.rb17
-rw-r--r--db/migrate/20200507221434_add_container_registry_features_to_application_settings.rb13
-rw-r--r--db/structure.sql26
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql191
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json541
-rw-r--r--doc/api/graphql/reference/index.md70
-rw-r--r--doc/api/packages.md1
-rw-r--r--lib/gitlab/gon_helper.rb2
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/controllers/registrations_controller_spec.rb18
-rw-r--r--spec/factories/merge_requests.rb12
-rw-r--r--spec/graphql/resolvers/projects_resolver_spec.rb77
-rw-r--r--spec/models/merge_request_spec.rb26
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? }