diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 34858a522041363a4e0ed03109b1400d874a83b0..73ae623b81b1ce6ac95aefb1ae1eacb4ac34578d 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -111,3 +111,7 @@ = render_if_exists "layouts/frontend_monitor" %meta{ name: "description", content: page_description } %meta{ name: 'theme-color', content: user_theme_primary_color } + + - if Gitlab.config.gitlab.respond_to?(:custom_html_header_tags) + - unless Gitlab.config.gitlab.custom_html_header_tags.empty? + = Gitlab.config.gitlab.custom_html_header_tags.html_safe diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 86457f339b82c1ebab946abe0df0d6e9626977a3..afb7697472e38633944441b2ce46f2fda6228a7e 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -139,6 +139,15 @@ production: &base ## 11 - Dark Mode (alpha) # default_theme: 1 # default: 1 + ## Custom html header tags + # In some cases some custom header tags are needed + # e.g., to add the EU cookie consent + # Tip: you must add the externals source to the content_security_policy as + # well, typically the script_src and style_src. + # custom_html_header_tags: | + # <script src="https://example.com/cookie-consent.js"></script> + # <link rel="stylesheet" href="https://example.com/cookie-consent.css"/> + ## Automatic issue closing # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. # This happens when the commit is pushed or merged into the default branch of a project. diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index feda8a86af68568196f186ca057f3afa61f616bc..1a37895853c4befe6a426c32823bc4d13159cc95 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -187,6 +187,7 @@ # `default_can_create_group` is deprecated since GitLab 15.5 in favour of the `can_create_group` column on `ApplicationSetting`. Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil? Settings.gitlab['default_theme'] = Gitlab::Themes::APPLICATION_DEFAULT if Settings.gitlab['default_theme'].nil? +Settings.gitlab['custom_html_header_tags'] ||= Settings.gitlab['custom_html_header_tags'] || '' Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost' Settings.gitlab['cdn_host'] ||= ENV['GITLAB_CDN_HOST'].presence Settings.gitlab['ssh_host'] ||= Settings.gitlab.host diff --git a/doc/administration/configure.md b/doc/administration/configure.md index 7ea3b19ea33cc222c313d31022006f8ad2e85827..df6f280e11d01910cc32a8115303c4fdd0e210e9 100644 --- a/doc/administration/configure.md +++ b/doc/administration/configure.md @@ -47,3 +47,4 @@ Customize and configure your self-managed GitLab installation. - [Issue closing pattern](../administration/issue_closing_pattern.md) - [Snippets](../administration/snippets/index.md) - [Host the product documentation](../administration/docs_self_host.md) +- [Custom HTML header tags](../administration/custom_html_header_tags.md) diff --git a/doc/administration/custom_html_header_tags.md b/doc/administration/custom_html_header_tags.md new file mode 100644 index 0000000000000000000000000000000000000000..6a8b509411fa90abf1f75535676933b44a2c8ba1 --- /dev/null +++ b/doc/administration/custom_html_header_tags.md @@ -0,0 +1,70 @@ +--- +stage: Govern +group: Compliance +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +description: Learn how to modify the HTML header tags of your GitLab instance. +--- + +# Custom HTML header tags + +DETAILS: +**Tier:** Free, Premium, Ultimate +**Offering:** Self-managed + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/153877) in GitLab 17.1. + +If you self-manage a GitLab instance in the EU, or any jurisdiction that +requires a cookie consent banner, additional HTML header tags are needed to +add scripts and stylesheets. + +## Security implications + +Before enabling this feature, you should understand the security implications this might have. + +A previously legit external resource could end up being compromised and then used to extract +pretty much any data from any user in the GitLab instance. For that reason, +you should never add resources from untrusted external sources. If possible, you should always +use integrity checks like [Subresource Integrity](https://www.w3.org/TR/SRI/) with third-party +resources to confirm the authenticity of the resources that are loaded. + +Limit the functionality you are adding by using HTML header tags to the minimum. +Otherwise, it could cause also stability or functionality issues if you, for example, +interact with other application code from GitLab. + +## Add a custom HTML header tag + +You must add the externals sources to the Content Security Policy which is +available in the `content_security_policy` option. For the following example, you +must extend the `script_src` and `style_src`. + +To add a custom HTML header tag: + +::Tabs + +:::TabTitle Self-compiled + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + gitlab: + custom_html_header_tags: | + <script src="https://example.com/cookie-consent.js" integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" crossorigin="anonymous"></script> + <link rel="stylesheet" href="https://example.com/cookie-consent.css" integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" crossorigin="anonymous"> + content_security_policy: + directives: + script_src: "'self' 'unsafe-eval' https://example.com http://localhost:* https://www.google.com/recaptcha/ https://www.recaptcha.net/ https://www.gstatic.com/recaptcha/ https://apis.google.com" + style_src: "'self' 'unsafe-inline' https://example.com" + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs diff --git a/spec/views/layouts/_head.html.haml_spec.rb b/spec/views/layouts/_head.html.haml_spec.rb index 5ef25bdbde42e0812055072083a969c03b20ea10..992edcf95f3212bd04d9fad34b0f177bd6a6764d 100644 --- a/spec/views/layouts/_head.html.haml_spec.rb +++ b/spec/views/layouts/_head.html.haml_spec.rb @@ -95,6 +95,17 @@ end end + context 'when custom_html_header_tags are set' do + before do + allow(Gitlab.config.gitlab).to receive(:custom_html_header_tags).and_return('<script src="https://example.com/cookie-consent.js"></script>') + end + + it 'adds the custom html header tag' do + render + expect(rendered).to match('<script src="https://example.com/cookie-consent.js"></script>') + end + end + context 'when an asset_host is set and snowplow url is set', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/346542' do let(:asset_host) { 'http://test.host' } let(:snowplow_collector_hostname) { 'www.snow.plow' }