diff --git a/Gemfile b/Gemfile index 97b1fe2696d..899b7525319 100644 --- a/Gemfile +++ b/Gemfile @@ -153,7 +153,7 @@ gem 'faraday_middleware-aws-sigv4', '~>0.3.0' # Markdown and HTML processing gem 'html-pipeline', '~> 2.13.2' gem 'deckar01-task_list', '2.3.1' -gem 'gitlab-markup', '~> 1.7.1' +gem 'gitlab-markup', '~> 1.8.0' gem 'github-markup', '~> 1.7.0', require: 'github/markup' gem 'commonmarker', '~> 0.23.2' gem 'kramdown', '~> 2.3.1' diff --git a/Gemfile.lock b/Gemfile.lock index 185e018736a..00205c4b827 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -489,7 +489,7 @@ GEM with_env (= 1.1.0) xml-simple (~> 1.1.5) gitlab-mail_room (0.0.9) - gitlab-markup (1.7.1) + gitlab-markup (1.8.0) gitlab-net-dns (0.9.1) gitlab-omniauth-openid-connect (0.8.0) addressable (~> 2.7) @@ -1482,7 +1482,7 @@ DEPENDENCIES gitlab-license (~> 2.0) gitlab-license_finder (~> 6.0) gitlab-mail_room (~> 0.0.9) - gitlab-markup (~> 1.7.1) + gitlab-markup (~> 1.8.0) gitlab-net-dns (~> 0.9.1) gitlab-omniauth-openid-connect (~> 0.8.0) gitlab-sidekiq-fetcher (= 0.8.0) diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss index 63305bc592d..c9ff8205142 100644 --- a/app/assets/stylesheets/startup/startup-dark.scss +++ b/app/assets/stylesheets/startup/startup-dark.scss @@ -1832,6 +1832,7 @@ body.gl-dark .header-search svg { body.gl-dark .header-search input { background-color: transparent; color: rgba(250, 250, 250, 0.8); + box-shadow: inset 0 0 0 1px rgba(250, 250, 250, 0.4); } body.gl-dark .header-search input::placeholder { color: rgba(250, 250, 250, 0.8); diff --git a/app/assets/stylesheets/themes/theme_helper.scss b/app/assets/stylesheets/themes/theme_helper.scss index 1332686a906..e119af716a6 100644 --- a/app/assets/stylesheets/themes/theme_helper.scss +++ b/app/assets/stylesheets/themes/theme_helper.scss @@ -154,6 +154,7 @@ input { background-color: transparent; color: rgba($search-and-nav-links, 0.8); + box-shadow: inset 0 0 0 1px rgba($search-and-nav-links, 0.4); &::placeholder { color: rgba($search-and-nav-links, 0.8); diff --git a/app/services/verify_pages_domain_service.rb b/app/services/verify_pages_domain_service.rb index eab1e91dc89..408ee429a74 100644 --- a/app/services/verify_pages_domain_service.rb +++ b/app/services/verify_pages_domain_service.rb @@ -85,7 +85,8 @@ class VerifyPagesDomainService < BaseService end def check(domain_name, resolver) - records = parse(txt_records(domain_name, resolver)) + # Append '.' to domain_name, indicating absolute FQDN + records = parse(txt_records(domain_name + '.', resolver)) records.any? do |record| record == domain.keyed_verification_code || record == domain.verification_code diff --git a/app/views/admin/hooks/edit.html.haml b/app/views/admin/hooks/edit.html.haml index 93038e63a2e..9c258e10008 100644 --- a/app/views/admin/hooks/edit.html.haml +++ b/app/views/admin/hooks/edit.html.haml @@ -1,6 +1,8 @@ - add_to_breadcrumbs @hook.pluralized_name, admin_hooks_path - page_title _('Edit System Hook') += render 'shared/web_hooks/hook_errors', hook: @hook + .row.gl-mt-3 .col-lg-3 = render 'shared/web_hooks/title_and_docs', hook: @hook diff --git a/app/views/profiles/notifications/_group_settings.html.haml b/app/views/profiles/notifications/_group_settings.html.haml index 82083af9ff1..23fce8e04b6 100644 --- a/app/views/profiles/notifications/_group_settings.html.haml +++ b/app/views/profiles/notifications/_group_settings.html.haml @@ -13,5 +13,5 @@ .js-vue-notification-dropdown{ data: { disabled: emails_disabled.to_s, dropdown_items: notification_dropdown_items(setting).to_json, notification_level: setting.level, group_id: group.id, container_class: 'gl-mr-3', show_label: "true" } } .table-section.section-30 - = form_for setting, url: profile_notifications_group_path(group), method: :put, html: { class: 'update-notifications gl-display-flex' } do |f| + = form_for setting, url: profile_group_notifications_path(group), method: :put, html: { class: 'update-notifications gl-display-flex' } do |f| = f.select :notification_email, @user.public_verified_emails, { include_blank: 'Global notification email' }, class: 'select2 js-group-notification-email' diff --git a/app/views/projects/hooks/edit.html.haml b/app/views/projects/hooks/edit.html.haml index 3358025b237..7d696a988d4 100644 --- a/app/views/projects/hooks/edit.html.haml +++ b/app/views/projects/hooks/edit.html.haml @@ -2,19 +2,7 @@ - add_to_breadcrumbs _('Webhook Settings'), project_hooks_path(@project) - page_title _('Webhook') -- if @hook.rate_limited? - - placeholders = { strong_start: ''.html_safe, - strong_end: ''.html_safe, - limit: @hook.rate_limit, - support_link_start: ''.html_safe, - support_link_end: ''.html_safe } - = render 'shared/global_alert', - title: s_('Webhooks|Webhook was automatically disabled'), - variant: :danger, - is_contained: true, - close_button_class: 'js-close' do - .gl-alert-body - = s_('Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook.').html_safe % placeholders += render 'shared/web_hooks/hook_errors', hook: @hook .row.gl-mt-3 .col-lg-3 diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml index 0e8de3c2bb8..9d5d1de1005 100644 --- a/app/views/projects/merge_requests/_mr_title.html.haml +++ b/app/views/projects/merge_requests/_mr_title.html.haml @@ -4,7 +4,7 @@ - are_close_and_open_buttons_hidden = merge_request_button_hidden?(@merge_request, true) && merge_request_button_hidden?(@merge_request, false) - cache_key = [@project, @merge_request, can_update_merge_request, can_reopen_merge_request, are_close_and_open_buttons_hidden] -= cache_if(Feature.enabled?(:cached_mr_title, @project, default_enabled: :yaml), cache_key, expires_in: 1.day) do += cache(cache_key, expires_in: 1.day) do - if @merge_request.closed_or_merged_without_fork? .gl-alert.gl-alert-danger.gl-mb-5 .gl-alert-container diff --git a/app/views/shared/web_hooks/_hook.html.haml b/app/views/shared/web_hooks/_hook.html.haml index ef1eb6b4e45..45baa7e2184 100644 --- a/app/views/shared/web_hooks/_hook.html.haml +++ b/app/views/shared/web_hooks/_hook.html.haml @@ -5,6 +5,10 @@ = hook.url - if hook.rate_limited? %span.gl-badge.badge-danger.badge-pill.sm= _('Disabled') + - elsif hook.permanently_disabled? + %span.gl-badge.badge-danger.badge-pill.sm= s_('Webhooks|Failed to connect') + - elsif hook.temporarily_disabled? + %span.gl-badge.badge-warning.badge-pill.sm= s_('Webhooks|Fails to connect') %div - hook.class.triggers.each_value do |trigger| diff --git a/app/views/shared/web_hooks/_hook_errors.html.haml b/app/views/shared/web_hooks/_hook_errors.html.haml new file mode 100644 index 00000000000..23010b8349c --- /dev/null +++ b/app/views/shared/web_hooks/_hook_errors.html.haml @@ -0,0 +1,41 @@ +- strong_start = ''.html_safe +- strong_end = ''.html_safe +- link_start = ''.html_safe +- link_end = ''.html_safe + +- if hook.rate_limited? + - support_path = 'https://support.gitlab.com/hc/en-us/requests/new' + - placeholders = { strong_start: strong_start, + strong_end: strong_end, + limit: hook.rate_limit, + support_link_start: link_start % { url: support_path }, + support_link_end: link_end } + = render 'shared/global_alert', + title: s_('Webhooks|Webhook was automatically disabled'), + variant: :danger, + is_contained: true, + close_button_class: 'js-close' do + .gl-alert-body + = s_('Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook.').html_safe % placeholders +- elsif hook.permanently_disabled? + = render 'shared/global_alert', + title: s_('Webhooks|Webhook failed to connect'), + variant: :danger, + is_contained: true, + close_button_class: 'js-close' do + .gl-alert-body + = s_('Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below.').html_safe % { strong_start: strong_start, strong_end: strong_end } +- elsif hook.temporarily_disabled? + - help_path = help_page_path('user/project/integrations/webhooks', anchor: 'webhook-fails-or-multiple-webhook-requests-are-triggered') + - placeholders = { strong_start: strong_start, + strong_end: strong_end, + retry_time: time_interval_in_words(hook.disabled_until - Time.now), + help_link_start: link_start % { url: help_path }, + help_link_end: link_end } + = render 'shared/global_alert', + title: s_('Webhooks|Webhook fails to connect'), + variant: :warning, + is_contained: true, + close_button_class: 'js-close' do + .gl-alert-body + = s_('Webhooks|The webhook %{help_link_start}failed to connect%{help_link_end}, and will retry in %{retry_time}. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below.').html_safe % placeholders diff --git a/config/feature_flags/development/cached_mr_title.yml b/config/feature_flags/development/sbom_survey.yml similarity index 65% rename from config/feature_flags/development/cached_mr_title.yml rename to config/feature_flags/development/sbom_survey.yml index 0284663f441..aac523ee846 100644 --- a/config/feature_flags/development/cached_mr_title.yml +++ b/config/feature_flags/development/sbom_survey.yml @@ -1,8 +1,8 @@ --- -name: cached_mr_title -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61605 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/330907 -milestone: '13.12' +name: sbom_survey +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76446 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348181 +milestone: '14.6' type: development -group: group::source code +group: group::secure default_enabled: false diff --git a/config/routes/profile.rb b/config/routes/profile.rb index 3eda53318e3..b8d4a0c49c2 100644 --- a/config/routes/profile.rb +++ b/config/routes/profile.rb @@ -22,7 +22,14 @@ resource :profile, only: [:show, :update] do end resource :notifications, only: [:show, :update] do - resources :groups, only: :update, constraints: { id: Gitlab::PathRegex.full_namespace_route_regex } + scope(path: 'groups/*id', + id: Gitlab::PathRegex.full_namespace_route_regex, + as: :group, + controller: :groups, + constraints: { format: /(html|json)/ }) do + patch '/', action: :update + put '/', action: :update + end end resource :password, only: [:new, :create, :edit, :update] do diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 18f57965f21..89b402b7b4c 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -511,6 +511,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | Name | Type | Description | | ---- | ---- | ----------- | +| `clusterAgentId` | [`[ClustersAgentID!]`](#clustersagentid) | Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. | | `clusterId` | [`[ClustersClusterID!]`](#clustersclusterid) | Filter vulnerabilities by `cluster_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. | | `hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. | | `hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. | @@ -10995,6 +10996,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | Name | Type | Description | | ---- | ---- | ----------- | +| `clusterAgentId` | [`[ClustersAgentID!]`](#clustersagentid) | Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. | | `clusterId` | [`[ClustersClusterID!]`](#clustersclusterid) | Filter vulnerabilities by `cluster_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. | | `hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. | | `hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. | @@ -13808,6 +13810,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | Name | Type | Description | | ---- | ---- | ----------- | +| `clusterAgentId` | [`[ClustersAgentID!]`](#clustersagentid) | Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. | | `clusterId` | [`[ClustersClusterID!]`](#clustersclusterid) | Filter vulnerabilities by `cluster_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. | | `hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. | | `hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. | diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md index d25caf1d7b4..b0f38e8cfb9 100644 --- a/doc/user/admin_area/index.md +++ b/doc/user/admin_area/index.md @@ -107,15 +107,16 @@ You can combine the filter options. For example, to list only public projects wi 1. Click the **Public** tab. 1. Enter `score` in the **Filter by name...** input box. -#### Deleted projects **(PREMIUM SELF)** +#### Projects pending deletion **(PREMIUM SELF)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37014) in GitLab 13.3. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37014) in GitLab 13.3. +> - [Tab renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/347468) from **Deleted projects** in GitLab 14.7. When delayed project deletion is [enabled for a group](../group/index.md#enable-delayed-project-deletion), projects within that group are not deleted immediately, but only after a delay. To access a list of all projects that are pending deletion: 1. On the top bar, select **Menu > Projects > Explore projects**. -1. Select the **Deleted projects** tab. +1. Select the **Pending deletion** tab (in GitLab 14.7 and later) or the **Deleted projects** tab (GitLab 14.6 and earlier). Listed for each project is: diff --git a/doc/user/application_security/cluster_image_scanning/index.md b/doc/user/application_security/cluster_image_scanning/index.md index 8ad938a0469..c3a2c179590 100644 --- a/doc/user/application_security/cluster_image_scanning/index.md +++ b/doc/user/application_security/cluster_image_scanning/index.md @@ -177,6 +177,7 @@ You can [configure](#customize-the-cluster-image-scanning-settings) analyzers by | `CIS_RESOURCE_NAMESPACE` | `""` | Namespace of the Kubernetes resource you want to filter vulnerabilities for. For example, `production`. | | `CIS_RESOURCE_KIND` | `""` | Kind of the Kubernetes resource you want to filter vulnerabilities for. For example, `deployment`. | | `CIS_CLUSTER_IDENTIFIER` | `""` | ID of the Kubernetes cluster integrated with GitLab. This is used to map vulnerabilities to the cluster so they can be filtered in the Vulnerability Report page. | +| `CIS_CLUSTER_AGENT_IDENTIFIER` | `""` | ID of the Kubernetes cluster agent integrated with GitLab. This maps vulnerabilities to the agent so they can be filtered in the Vulnerability Report page. | #### Override the cluster image scanning template diff --git a/doc/user/markdown.md b/doc/user/markdown.md index ce1a8146f1b..1b3cd5d4478 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -998,6 +998,8 @@ Here's a sample audio clip: ### Inline HTML +> Allowing `rel="license"` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20857) in GitLab 14.6. + To see the second example of Markdown rendered in HTML, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/user/markdown.md#inline-html). @@ -1006,6 +1008,7 @@ You can also use raw HTML in your Markdown, and it usually works pretty well. See the documentation for HTML::Pipeline's [SanitizationFilter](https://github.com/jch/html-pipeline/blob/v2.12.3/lib/html/pipeline/sanitization_filter.rb#L42) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` allowlist, GitLab allows `span`, `abbr`, `details` and `summary` elements. +`rel="license"` is allowed on links to support the [Rel-License microformat](https://microformats.org/wiki/rel-license) and license attribution. ```html
somethingdiff --git a/spec/lib/gitlab/spamcheck/client_spec.rb b/spec/lib/gitlab/spamcheck/client_spec.rb index 0c392bf0b9d..a6e7665569c 100644 --- a/spec/lib/gitlab/spamcheck/client_spec.rb +++ b/spec/lib/gitlab/spamcheck/client_spec.rb @@ -56,36 +56,6 @@ RSpec.describe Gitlab::Spamcheck::Client do end end - describe "Rails environment" do - let(:stub) { double(:spamcheck_stub, check_for_spam_issue: response) } - - context "production" do - before do - allow(Rails.env).to receive(:production?).and_return(true) - end - - it 'uses secure connection' do - expect(Spamcheck::SpamcheckService::Stub).to receive(:new).with(endpoint.sub(%r{^grpc://}, ''), - instance_of(GRPC::Core::ChannelCredentials), - anything).and_return(stub) - subject - end - end - - context "not production" do - before do - allow(Rails.env).to receive(:production?).and_return(false) - end - - it 'uses insecure connection' do - expect(Spamcheck::SpamcheckService::Stub).to receive(:new).with(endpoint.sub(%r{^grpc://}, ''), - :this_channel_is_insecure, - anything).and_return(stub) - subject - end - end - end - describe '#issue_spam?' do before do allow_next_instance_of(::Spamcheck::SpamcheckService::Stub) do |instance| diff --git a/spec/routing/notifications_routing_spec.rb b/spec/routing/notifications_routing_spec.rb index d66aa7f219f..303281c763e 100644 --- a/spec/routing/notifications_routing_spec.rb +++ b/spec/routing/notifications_routing_spec.rb @@ -12,7 +12,8 @@ RSpec.describe "notifications routing" do end it 'routes to group #update' do - expect(put("/-/profile/notifications/groups/gitlab-org")).to route_to("profiles/groups#update", id: 'gitlab-org') - expect(put("/-/profile/notifications/groups/gitlab.org")).to route_to("profiles/groups#update", id: 'gitlab.org') + expect(put("/-/profile/groups/gitlab-org/notifications")).to route_to("profiles/groups#update", id: 'gitlab-org') + expect(put("/-/profile/groups/gitlab.org/notifications/")).to route_to("profiles/groups#update", id: 'gitlab.org') + expect(put("/-/profile/groups/gitlab.org/gitlab/notifications")).to route_to("profiles/groups#update", id: 'gitlab.org/gitlab') end end diff --git a/spec/services/verify_pages_domain_service_spec.rb b/spec/services/verify_pages_domain_service_spec.rb index ae079229891..2a3b3814065 100644 --- a/spec/services/verify_pages_domain_service_spec.rb +++ b/spec/services/verify_pages_domain_service_spec.rb @@ -372,7 +372,8 @@ RSpec.describe VerifyPagesDomainService do allow(resolver).to receive(:getresources) { [] } stubbed_lookups.each do |domain, records| records = Array(records).map { |txt| Resolv::DNS::Resource::IN::TXT.new(txt) } - allow(resolver).to receive(:getresources).with(domain, Resolv::DNS::Resource::IN::TXT) { records } + # Append '.' to domain_name, indicating absolute FQDN + allow(resolver).to receive(:getresources).with(domain + '.', Resolv::DNS::Resource::IN::TXT) { records } end resolver diff --git a/spec/views/projects/hooks/edit.html.haml_spec.rb b/spec/views/projects/hooks/edit.html.haml_spec.rb index 1265334a572..c4ec2149794 100644 --- a/spec/views/projects/hooks/edit.html.haml_spec.rb +++ b/spec/views/projects/hooks/edit.html.haml_spec.rb @@ -30,4 +30,29 @@ RSpec.describe 'projects/hooks/edit' do expect(rendered).to have_text(s_('Webhooks|Webhook was automatically disabled')) end end + + context 'webhook is permanently disabled' do + before do + allow(hook).to receive(:permanently_disabled?).and_return(true) + end + + it 'renders alert' do + render + + expect(rendered).to have_text(s_('Webhooks|Webhook failed to connect')) + end + end + + context 'webhook is temporarily disabled' do + before do + allow(hook).to receive(:temporarily_disabled?).and_return(true) + allow(hook).to receive(:disabled_until).and_return(Time.now + 10.minutes) + end + + it 'renders alert' do + render + + expect(rendered).to have_text(s_('Webhooks|Webhook fails to connect')) + end + end end diff --git a/spec/views/projects/hooks/index.html.haml_spec.rb b/spec/views/projects/hooks/index.html.haml_spec.rb index eb2b7334b98..0cdc3bcecb2 100644 --- a/spec/views/projects/hooks/index.html.haml_spec.rb +++ b/spec/views/projects/hooks/index.html.haml_spec.rb @@ -20,6 +20,8 @@ RSpec.describe 'projects/hooks/index' do expect(rendered).to have_css('h4', text: _('Webhooks')) expect(rendered).to have_text('Project Hooks') expect(rendered).not_to have_css('.gl-badge', text: _('Disabled')) + expect(rendered).not_to have_css('.gl-badge', text: s_('Webhooks|Failed to connect')) + expect(rendered).not_to have_css('.gl-badge', text: s_('Webhooks|Fails to connect')) end context 'webhook is rate limited' do @@ -33,4 +35,28 @@ RSpec.describe 'projects/hooks/index' do expect(rendered).to have_css('.gl-badge', text: _('Disabled')) end end + + context 'webhook is permanently disabled' do + before do + allow(existing_hook).to receive(:permanently_disabled?).and_return(true) + end + + it 'renders "Failed to connect" badge' do + render + + expect(rendered).to have_css('.gl-badge', text: s_('Webhooks|Failed to connect')) + end + end + + context 'webhook is temporarily disabled' do + before do + allow(existing_hook).to receive(:temporarily_disabled?).and_return(true) + end + + it 'renders "Fails to connect" badge' do + render + + expect(rendered).to have_css('.gl-badge', text: s_('Webhooks|Fails to connect')) + end + end end