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

gitlab.com/gitlab-org/gitlab-docs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Erasmus <jerasmus@gitlab.com>2020-10-23 11:39:22 +0300
committerJacques Erasmus <jerasmus@gitlab.com>2020-10-23 11:39:22 +0300
commitfdd1fc948cd47c6b130e78e00b6b9e8f4e1b39eb (patch)
treeca1eab05519e5539429492c65f9d9d11a401ee55
parent8ef6a7cd62318cc50f091133428f04ccaaa23df8 (diff)
parentf494d1179980f1c116929f7e1c7196a99b4fcc9e (diff)
Merge branch 'csp-headers' into 'master'
Add CSP meta tag Closes #850 See merge request gitlab-org/gitlab-docs!1217
-rw-r--r--README.md54
-rw-r--r--content/assets/javascripts/disqus.js26
-rw-r--r--content/assets/javascripts/docsearch.js19
-rw-r--r--content/assets/javascripts/facebook_analytics.js12
-rw-r--r--content/assets/javascripts/google_tagmanager.js9
-rw-r--r--content/assets/javascripts/gtag_analytics.js8
-rw-r--r--content/assets/javascripts/linkedin_analytics.js12
-rw-r--r--content/assets/javascripts/marketo_analytics.js24
-rw-r--r--content/assets/javascripts/mermaid.js (renamed from layouts/mermaid.html)18
-rw-r--r--content/assets/javascripts/toggle_popover.js10
-rw-r--r--layouts/analytics.html53
-rw-r--r--layouts/csp.html1
-rw-r--r--layouts/default.html11
-rw-r--r--layouts/docsearch.html18
-rw-r--r--layouts/feedback.html25
-rw-r--r--layouts/head.html13
16 files changed, 201 insertions, 112 deletions
diff --git a/README.md b/README.md
index 29b5df85..e7981077 100644
--- a/README.md
+++ b/README.md
@@ -484,3 +484,57 @@ want to receive weekly reports of the search usage, search the Google doc with
title "Email, Slack, and GitLab Groups and Aliases", search for `docsearch`,
and add a comment with your email to be added to the alias that gets the weekly
reports.
+
+## CSP header
+
+The GitLab docs site uses a [Content Security Policy (CSP) header](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
+as an added layer of security that helps to detect and mitigate certain types of
+attacks, including Cross Site Scripting (XSS) and data injection attacks.
+Although it is a static site, and the potential for injection of scripts is very
+low, there are customer concerns around not having this header applied.
+
+It's enabled by default on <https://docs.gitlab.com>, but if you want to build the
+site on your own and disable the inclusion of the CSP header, you can do so with
+the `DISABLE_CSP` environment variable:
+
+```shell
+DISABLE_CSP=1 bundle exec nanoc compile
+```
+
+### Adding or updating domains in the CSP header
+
+The CSP header and the allowed domains can be found in the [`csp.html`](/layouts/csp.html)
+layout. Every time a new font or Javascript file is added, or maybe updated in
+case of a versioned file, you need to update the `csp.html` layout, otherwise
+it can cause the site to misbehave and be broken.
+
+### No inline scripts allowed
+
+To avoid allowing `'unsafe-line'` in the CSP, we cannot use any inline scripts.
+For example, this is prohibited:
+
+```html
+<script>
+$(function () {
+ $('[data-toggle="popover"]').popover();
+ $('.popover-dismiss').popover({
+ trigger: 'focus'
+ })
+})
+</script>
+```
+
+Instead, this should be extracted to its own files in the
+[`/content/assets/javascripts/`](/content/assets/javascripts/) directory,
+and then be included in the HTML file that you want. The example above lives
+under `/content/assets/javascripts/toggle_popover.js`, and you would call
+it with:
+
+```html
+<script src="<%= @items['/assets/javascripts/toggle_popover.*'].path %>"></script>
+```
+
+### Testing the CSP header for conformity
+
+To test that the CSP header works as expected, you can visit
+<https://cspvalidator.org/> and paste the URL that you want tested.
diff --git a/content/assets/javascripts/disqus.js b/content/assets/javascripts/disqus.js
new file mode 100644
index 00000000..de2c7a60
--- /dev/null
+++ b/content/assets/javascripts/disqus.js
@@ -0,0 +1,26 @@
+---
+version: 1
+---
+
+var disqus_config = function () {
+ this.page.url = '<%= @config[:base_url] %><%= @item.identifier.without_ext + '.html' %>';
+ this.page.title = '<%= @item.key?(:title) ? "#{item[:title]} - GitLab Documentation" : "GitLab Documentation" %>';
+<% if @item[:disqus_identifier] %>
+ this.page.identifier = '<%= @item[:disqus_identifier] %>';
+<% else %>
+ this.page.identifier = '<%= @config[:base_url] %><%= @item.identifier.without_ext + '.html' %>';
+<% end %>
+};
+
+var is_disqus_loaded = false;
+window.loadDisqus = function() {
+ if (!is_disqus_loaded){
+ is_disqus_loaded = true;
+ var disqusThread = document.getElementById('disqus_thread');
+ var d = document, s = d.createElement('script');
+ disqusThread.innerHTML = '';
+ s.src = 'https://gitlab-docs.disqus.com/embed.js';
+ s.setAttribute('data-timestamp', +new Date());
+ (d.head || d.body).appendChild(s);
+ }
+};
diff --git a/content/assets/javascripts/docsearch.js b/content/assets/javascripts/docsearch.js
new file mode 100644
index 00000000..ac788034
--- /dev/null
+++ b/content/assets/javascripts/docsearch.js
@@ -0,0 +1,19 @@
+---
+version: 1
+---
+
+var search = docsearch({
+ apiKey: 'ce1690e1421303458a1fcbea0cc4a927',
+ indexName: 'gitlab',
+ inputSelector: '.docsearch',
+ algoliaOptions: {
+ // Filter by tags as described in https://github.com/algolia/docsearch-configs/blob/master/configs/gitlab.json
+ 'filters': "tags:gitlab<score=4> OR tags:omnibus<score=3> OR tags:runner<score=2> OR tags:charts<score=1>",
+ // Number of results shown in the search dropdown
+ 'hitsPerPage': 10
+ },
+ debug: false, // Set debug to true if you want to inspect the dropdown
+ autocompleteOptions: {
+ 'autoselect': false
+ }
+});
diff --git a/content/assets/javascripts/facebook_analytics.js b/content/assets/javascripts/facebook_analytics.js
new file mode 100644
index 00000000..2eb7121a
--- /dev/null
+++ b/content/assets/javascripts/facebook_analytics.js
@@ -0,0 +1,12 @@
+---
+version: 1
+---
+
+!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
+n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
+n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
+t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
+document,'script','//connect.facebook.net/en_US/fbevents.js');
+
+fbq('init', '1689559637958103');
+fbq('track', "PageView");
diff --git a/content/assets/javascripts/google_tagmanager.js b/content/assets/javascripts/google_tagmanager.js
new file mode 100644
index 00000000..6b5f2d00
--- /dev/null
+++ b/content/assets/javascripts/google_tagmanager.js
@@ -0,0 +1,9 @@
+---
+version: 1
+---
+
+(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
+new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
+j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
+'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
+})(window,document,'script','dataLayer','GTM-WZCXKT5');
diff --git a/content/assets/javascripts/gtag_analytics.js b/content/assets/javascripts/gtag_analytics.js
new file mode 100644
index 00000000..35fafbe9
--- /dev/null
+++ b/content/assets/javascripts/gtag_analytics.js
@@ -0,0 +1,8 @@
+---
+version: 1
+---
+
+window.dataLayer = window.dataLayer || [];
+function gtag(){dataLayer.push(arguments);}
+gtag('js', new Date());
+gtag('config', 'AW-923339191');
diff --git a/content/assets/javascripts/linkedin_analytics.js b/content/assets/javascripts/linkedin_analytics.js
new file mode 100644
index 00000000..57a62add
--- /dev/null
+++ b/content/assets/javascripts/linkedin_analytics.js
@@ -0,0 +1,12 @@
+---
+version: 1
+---
+
+_linkedin_partner_id = "30694";
+window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
+window._linkedin_data_partner_ids.push(_linkedin_partner_id);
+ (function(){var s = document.getElementsByTagName("script")[0];
+ var b = document.createElement("script");
+ b.type = "text/javascript";b.async = true;
+ b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js";
+ s.parentNode.insertBefore(b, s);})();
diff --git a/content/assets/javascripts/marketo_analytics.js b/content/assets/javascripts/marketo_analytics.js
new file mode 100644
index 00000000..421f36fe
--- /dev/null
+++ b/content/assets/javascripts/marketo_analytics.js
@@ -0,0 +1,24 @@
+---
+version: 1
+---
+
+(function() {
+ var didInit = false;
+ function initMunchkin() {
+ if(didInit === false) {
+ didInit = true;
+ Munchkin.init('194-VVC-221');
+ }
+ }
+ var s = document.createElement('script');
+ s.type = 'text/javascript';
+ s.async = true;
+ s.src = 'https://munchkin.marketo.net/munchkin.js';
+ s.onreadystatechange = function() {
+ if (this.readyState == 'complete' || this.readyState == 'loaded') {
+ initMunchkin();
+ }
+ };
+ s.onload = initMunchkin;
+ document.getElementsByTagName('head')[0].appendChild(s);
+})();
diff --git a/layouts/mermaid.html b/content/assets/javascripts/mermaid.js
index fe282055..f22b67ee 100644
--- a/layouts/mermaid.html
+++ b/content/assets/javascripts/mermaid.js
@@ -1,18 +1,20 @@
-<script type="text/javascript">
- function loadMermaidJsIfNeeded() {
+---
+version: 1
+---
+
+function loadMermaidJsIfNeeded() {
if (document.querySelector('.mermaid') === null) {
- return;
- }
+ return;
+ }
var element = document.createElement("script");
element.src = "//cdnjs.cloudflare.com/ajax/libs/mermaid/8.8.0/mermaid.min.js";
element.onload = function(){mermaid.init();};
document.body.appendChild(element);
- }
+}
if (window.addEventListener)
- window.addEventListener("load", loadMermaidJsIfNeeded, false);
+ window.addEventListener("load", loadMermaidJsIfNeeded, false);
else if (window.attachEvent)
- window.attachEvent("onload", loadMermaidJsIfNeeded);
+ window.attachEvent("onload", loadMermaidJsIfNeeded);
else window.onload = loadMermaidJsIfNeeded;
-</script>
diff --git a/content/assets/javascripts/toggle_popover.js b/content/assets/javascripts/toggle_popover.js
new file mode 100644
index 00000000..0500ef31
--- /dev/null
+++ b/content/assets/javascripts/toggle_popover.js
@@ -0,0 +1,10 @@
+---
+version: 1
+---
+
+$(function () {
+ $('[data-toggle="popover"]').popover();
+ $('.popover-dismiss').popover({
+ trigger: 'focus'
+ })
+})
diff --git a/layouts/analytics.html b/layouts/analytics.html
index 0e49e3c4..3f8a9985 100644
--- a/layouts/analytics.html
+++ b/layouts/analytics.html
@@ -1,66 +1,21 @@
<!-- Facebook -->
-<script>
- !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
- n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
- n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
- t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
- document,'script','//connect.facebook.net/en_US/fbevents.js');
-
- fbq('init', '1689559637958103');
- fbq('track', "PageView");
-</script>
+<script src="<%= @items['/assets/javascripts/facebook_analytics.*'].path %>"></script>
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=1689559637958103&ev=PageView&noscript=1"
/></noscript>
<!-- Marketo -->
-<script type="text/javascript">
- (function() {
- var didInit = false;
- function initMunchkin() {
- if(didInit === false) {
- didInit = true;
- Munchkin.init('194-VVC-221');
- }
- }
- var s = document.createElement('script');
- s.type = 'text/javascript';
- s.async = true;
- s.src = 'https://munchkin.marketo.net/munchkin.js';
- s.onreadystatechange = function() {
- if (this.readyState == 'complete' || this.readyState == 'loaded') {
- initMunchkin();
- }
- };
- s.onload = initMunchkin;
- document.getElementsByTagName('head')[0].appendChild(s);
- })();
-</script>
+<script src="<%= @items['/assets/javascripts/marketo_analytics.*'].path %>"></script>
<!-- Bizible -->
<script type="text/javascript" src="https://cdn.bizible.com/scripts/bizible.js" async=""></script>
<!-- Global site tag (gtag.js) - Google Ads: 923339191 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=AW-923339191"></script>
-<script>
-window.dataLayer = window.dataLayer || [];
-function gtag(){dataLayer.push(arguments);}
-gtag('js', new Date());
-gtag('config', 'AW-923339191');
-</script>
+<script src="<%= @items['/assets/javascripts/gtag_analytics.*'].path %>"></script>
<!-- Linkedin -->
-<script type="text/javascript">
-_linkedin_partner_id = "30694";
-window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
-window._linkedin_data_partner_ids.push(_linkedin_partner_id);
-</script><script type="text/javascript">
- (function(){var s = document.getElementsByTagName("script")[0];
- var b = document.createElement("script");
- b.type = "text/javascript";b.async = true;
- b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js";
- s.parentNode.insertBefore(b, s);})();
-</script>
+<script src="<%= @items['/assets/javascripts/linkedin_analytics.*'].path %>"></script>
<noscript>
<img height="1" width="1" style="display:none;" alt="" src="https://dc.ads.linkedin.com/collect/?pid=30694&fmt=gif" />
</noscript>
diff --git a/layouts/csp.html b/layouts/csp.html
new file mode 100644
index 00000000..38fa6aff
--- /dev/null
+++ b/layouts/csp.html
@@ -0,0 +1 @@
+<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-eval' https://assets.gitlab-static.net/assets/snowplow/ https://cdn.bizible.com/scripts/bizible.js https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js https://cdnjs.cloudflare.com/ajax/libs/popper.js/ cdnjs.cloudflare.com/ajax/libs/mermaid/ connect.facebook.net/en_US/fbevents.js https://consent.cookiebot.com https://consentcdn.cookiebot.com https://googleads.g.doubleclick.net/pagead/viewthroughconversion/923339191/ https://munchkin.marketo.net/munchkin.js https://script.hotjar.com/ https://snap.licdn.com/li.lms-analytics/insight.min.js https://stackpath.bootstrapcdn.com/bootstrap/ https://static.hotjar.com/c/ https://www.google-analytics.com/analytics.js https://www.googleadservices.com/pagead/conversion_async.js https://www.googletagmanager.com/gtm.js https://cdn.jsdelivr.net/npm/jquery@3.5.1/ https://*.algolia.net https://*.algolianet.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://fonts.googleapis.com https://stackpath.bootstrapcdn.com; object-src 'none'; base-uri 'self'; connect-src 'self' https://*.algolia.net https://*.algolianet.com https://*.mktoresp.com https://snowplow.trx.gitlab.net https://stats.g.doubleclick.net https://www.google-analytics.com https://www.google.com; font-src 'self' https://cdnjs.cloudflare.com https://fonts.gstatic.com; frame-src 'self' https://bid.g.doubleclick.net https://consentcdn.cookiebot.com https://vars.hotjar.com; img-src 'self' https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';">
diff --git a/layouts/default.html b/layouts/default.html
index 4ec6f3ca..9fd650f4 100644
--- a/layouts/default.html
+++ b/layouts/default.html
@@ -70,19 +70,12 @@
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.1/umd/popper.min.js" integrity="sha512-ubuT8Z88WxezgSqf3RLuNi5lmjstiJcyezx34yIU2gAHonIi27Na7atqzUZCOoY4CExaoFumzOsFQ2Ch+I/HCw==" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
- <script>
- $(function () {
- $('[data-toggle="popover"]').popover();
- $('.popover-dismiss').popover({
- trigger: 'focus'
- })
- })
- </script>
+ <script src="<%= @items['/assets/javascripts/toggle_popover.*'].path %>"></script>
<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script type="application/javascript" src="<%= @items['/assets/javascripts/clipboardjs.*'].path %>"></script>
<script type="application/javascript" src="<%= @items['/assets/javascripts/badges.*'].path %>"></script>
<%= render '/docsearch.*' %>
- <%= render '/mermaid.*' %>
+ <script src="<%= @items['/assets/javascripts/mermaid.*'].path %>"></script>
<% if is_production? %>
<%# Add analytics only in production %>
<%= render '/analytics.*' %>
diff --git a/layouts/docsearch.html b/layouts/docsearch.html
index 88dd752e..21037f14 100644
--- a/layouts/docsearch.html
+++ b/layouts/docsearch.html
@@ -1,19 +1,3 @@
<!-- Algolia docsearch https://community.algolia.com/docsearch/ -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
-<script type="text/javascript">
-var search = docsearch({
- apiKey: 'ce1690e1421303458a1fcbea0cc4a927',
- indexName: 'gitlab',
- inputSelector: '.docsearch',
- algoliaOptions: {
- // Filter by tags as described in https://github.com/algolia/docsearch-configs/blob/master/configs/gitlab.json
- 'filters': "tags:gitlab<score=4> OR tags:omnibus<score=3> OR tags:runner<score=2> OR tags:charts<score=1>",
- // Number of results shown in the search dropdown
- 'hitsPerPage': 10
- },
- debug: false, // Set debug to true if you want to inspect the dropdown
- autocompleteOptions: {
- 'autoselect': false
- }
-});
-</script>
+<script src="<%= @items['/assets/javascripts/docsearch.*'].path %>"></script>
diff --git a/layouts/feedback.html b/layouts/feedback.html
index 5c69e7eb..235ffdd1 100644
--- a/layouts/feedback.html
+++ b/layouts/feedback.html
@@ -60,30 +60,7 @@
<div id="disqus_thread" class="disqus-comments-gitlab"></div>
- <script>
- var disqus_config = function () {
- this.page.url = '<%= @config[:base_url] %><%= @item.identifier.without_ext + '.html' %>';
- this.page.title = '<%= @item.key?(:title) ? "#{item[:title]} - GitLab Documentation" : "GitLab Documentation" %>';
- <% if @item[:disqus_identifier] %>
- this.page.identifier = '<%= @item[:disqus_identifier] %>';
- <% else %>
- this.page.identifier = '<%= @config[:base_url] %><%= @item.identifier.without_ext + '.html' %>';
- <% end %>
- };
-
- var is_disqus_loaded = false;
- window.loadDisqus = function() {
- if (!is_disqus_loaded){
- is_disqus_loaded = true;
- var disqusThread = document.getElementById('disqus_thread');
- var d = document, s = d.createElement('script');
- disqusThread.innerHTML = '';
- s.src = 'https://gitlab-docs.disqus.com/embed.js';
- s.setAttribute('data-timestamp', +new Date());
- (d.head || d.body).appendChild(s);
- }
- };
- </script>
+ <script src="<%= @items['/assets/javascripts/disqus.*'].path %>"></script>
<script src="<%= @items['/frontend/feedback/feedback.*'].path %>"></script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
<% end %>
diff --git a/layouts/head.html b/layouts/head.html
index 71871884..bffb09fa 100644
--- a/layouts/head.html
+++ b/layouts/head.html
@@ -20,6 +20,13 @@
<% else %>
<meta name="docsearch:version" content="master" />
<% end %>
+
+<!-- Enable CSP headers -->
+<% unless ENV['DISABLE_CSP'] %>
+<%= render '/csp.*' %>
+<% end %>
+<!-- End of CSP headers -->
+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<link rel="stylesheet" href="<%= @items['/assets/stylesheets/stylesheet.*'].path %>">
<link rel="stylesheet" href="<%= @items['/assets/stylesheets/highlight.*'].path %>">
@@ -38,11 +45,7 @@
<script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" data-cbid="36a06ac5-ddb4-4f91-8337-067ad19ad8d5" type="text/javascript"></script>
<!-- Google Tag Manager -->
- <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
- new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
- j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
- 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
- })(window,document,'script','dataLayer','GTM-WZCXKT5');</script>
+ <script src="<%= @items['/assets/javascripts/google_tagmanager.*'].path %>"></script>
<!-- End Google Tag Manager -->
<!-- Google webmasters verification -->