-
Notifications
You must be signed in to change notification settings - Fork 7
feat: Add Content-Security-Policy meta tag for GitHub Pages #596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,20 +7,59 @@ const {themes} = require('prism-react-renderer'); | |
| require('dotenv').config(); | ||
| /** @type {import('@docusaurus/types').Config} */ | ||
|
|
||
| // Content Security Policy directives for GitHub Pages (meta tag based) | ||
| // Note: Report-Only mode and frame-ancestors are not supported via meta tags, only via HTTP headers | ||
| // This policy is enforced directly - test thoroughly before deployment | ||
| const cspDirectives = [ | ||
| "default-src 'self'", | ||
| // Scripts: 'unsafe-inline' required for Docusaurus theme init, gtag, and runtime scripts | ||
| "script-src 'self' 'unsafe-inline' https://www.google-analytics.com https://www.googletagmanager.com", | ||
| // Styles: 'unsafe-inline' required for react-select Emotion CSS-in-JS | ||
| "style-src 'self' 'unsafe-inline'", | ||
|
||
| // Images: Google Analytics pixel tracking | ||
| "img-src 'self' data: https://www.google-analytics.com https://www.googletagmanager.com", | ||
| // Fonts: Self-hosted only (Inter, Plus Jakarta Sans) | ||
| "font-src 'self'", | ||
| // API connections: Algolia search, Google Analytics (includes regional endpoints) | ||
| "connect-src 'self' https://www.google-analytics.com https://*.google-analytics.com https://www.googletagmanager.com https://*.algolia.net https://*.algolianet.com", | ||
RichardSlater marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Embedded frames: YouTube for ReactPlayer video embeds | ||
| "frame-src 'self' https://www.youtube.com https://www.youtube-nocookie.com", | ||
| // Form submissions | ||
| "form-action 'self'", | ||
| // Base URI restriction | ||
| "base-uri 'self'", | ||
| // Object/embed elements (Flash, etc.) - not needed | ||
| "object-src 'none'", | ||
| // Upgrade insecure requests | ||
| "upgrade-insecure-requests" | ||
| ].join('; '); | ||
|
|
||
| const config = { | ||
| title: "Ensono Stacks", | ||
| tagline: | ||
| "Helping projects gain momentum on digital transformation, with opinionated and modular boilerplate solutions", | ||
| url: "https://stacks.ensono.com", | ||
| baseUrl: "/", | ||
| baseUrlIssueBanner: false, // Disabled to reduce inline scripts for CSP | ||
| trailingSlash: false, | ||
| onBrokenLinks: "warn", | ||
| favicon: "img/icons/favicon.ico", | ||
| // Content Security Policy meta tag for GitHub Pages | ||
| headTags: [ | ||
| { | ||
| tagName: "meta", | ||
| attributes: { | ||
| "http-equiv": "Content-Security-Policy", | ||
| content: cspDirectives, | ||
| }, | ||
| }, | ||
| ], | ||
| organizationName: "Ensono", // Usually your GitHub org/user name. | ||
| projectName: "amido.github.io", // Usually your repo name. | ||
| customFields: { | ||
| description: 'Ensono Stacks is a catalogue of workload templates that\n' + | ||
| 'instantly scaffold and deploy boilerplate software projects. Slash the time it takes to get productive on your software project.', | ||
| description: | ||
| "Ensono Stacks is a catalogue of workload templates that\n" + | ||
| "instantly scaffold and deploy boilerplate software projects. Slash the time it takes to get productive on your software project.", | ||
| keywords: [ | ||
| "Microsoft Azure", | ||
| "Google Cloud Platform", | ||
|
|
@@ -50,7 +89,7 @@ const config = { | |
| appId: process.env.ALGOLIA_APP_ID, | ||
| apiKey: process.env.ALGOLIA_API_KEY, | ||
| indexName: process.env.ALGOLIA_INDEX_NAME, | ||
| } | ||
| }, | ||
| }, | ||
| themeConfig: { | ||
| colorMode: { | ||
|
|
@@ -59,7 +98,14 @@ const config = { | |
| prism: { | ||
| theme: themes.github, | ||
| darkTheme: themes.vsDark, | ||
| additionalLanguages: ['csharp', 'docker', 'powershell', 'java', 'bash', 'json'], | ||
| additionalLanguages: [ | ||
| "csharp", | ||
| "docker", | ||
| "powershell", | ||
| "java", | ||
| "bash", | ||
| "json", | ||
| ], | ||
| }, | ||
| navbar: { | ||
| title: "", | ||
|
|
@@ -69,7 +115,7 @@ const config = { | |
| href: "/", | ||
| width: 150, | ||
| height: 36, | ||
| className: "custom-navbar-logo-class" | ||
| className: "custom-navbar-logo-class", | ||
| }, | ||
| items: [ | ||
| { | ||
|
|
@@ -84,19 +130,19 @@ const config = { | |
| { | ||
| href: "https://www.ensono.com/company/lets-connect/", | ||
| label: "Connect", | ||
| position: 'right' | ||
| position: "right", | ||
| }, | ||
| ], | ||
| }, | ||
| footer: { | ||
| footer: { | ||
| links: [ | ||
| { | ||
| title: "Documentation", | ||
| items: [ | ||
| { | ||
| label: "Getting Started", | ||
| to: "docs/", | ||
| } | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
|
|
@@ -133,27 +179,27 @@ const config = { | |
| "@docusaurus/preset-classic", | ||
| { | ||
| docs: { | ||
| sidebarPath: require.resolve('./sidebars.js'), | ||
| remarkPlugins: [remarkImages.default || remarkImages], | ||
| sidebarPath: require.resolve("./sidebars.js"), | ||
| remarkPlugins: [remarkImages.default || remarkImages], | ||
| }, | ||
| theme: { | ||
| customCss: require.resolve("./src/css/custom.css") | ||
| customCss: require.resolve("./src/css/custom.css"), | ||
| }, | ||
| sitemap: { | ||
| changefreq: "weekly", | ||
| priority: 0.5 | ||
| priority: 0.5, | ||
| }, | ||
| gtag: { | ||
| trackingID: 'G-EKCQBC5CSJ', | ||
| trackingID: "G-EKCQBC5CSJ", | ||
| anonymizeIP: true, // Should IPs be anonymized? (optional) | ||
| }, | ||
| googleAnalytics: { | ||
| trackingID: 'G-EKCQBC5CSJ', | ||
| trackingID: "G-EKCQBC5CSJ", | ||
| anonymizeIP: true, // Should IPs be anonymized? | ||
| }, | ||
| } | ||
| ] | ||
| ] | ||
| }, | ||
| ], | ||
| ], | ||
| }; | ||
|
|
||
| module.exports = config; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
'unsafe-inline'directive inscript-srcsignificantly weakens XSS protection. Consider using nonces or hashes for inline scripts instead. If Docusaurus requires inline scripts, document this as a known security trade-off with a plan to migrate to CSP Level 3 nonces when feasible.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docusaurus doesn't support this, possibly could be mitigated by another engine (Hugo), however due to the
metabased implementation if a site is compromised then it would be trivial for the attacker to modify the CSP.