Repository navigation
Expand file tree
/
Copy pathnetlify.toml
More file actions
96 lines (88 loc) · 5.13 KB
/
Copy pathnetlify.toml
File metadata and controls
96 lines (88 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Build settings for the Netlify site `endusers` (ADR 0005). This file is the
# single source of truth; the Netlify UI build settings defer to it.
#
# build:netlify runs every validate:* target ci.yml runs, then the production
# build. Automation pull requests are authored by github.token and never start
# ci.yml (#755), so this build is the only gate their data passes before it
# publishes: a failed validator fails the deploy and the previous deploy stays
# live. SITE_URL is derived per deploy context by scripts/netlify-build.mjs
# (production: URL; previews: DEPLOY_PRIME_URL), so canonical and Open Graph
# URLs follow the host without a config change at the DNS cutover.
[build]
command = "npm run build:netlify"
publish = "build"
[build.environment]
NODE_VERSION = "22"
# Response headers (#1494). These are the controls the <meta> policy in
# docusaurus.config.js cannot deliver: browsers ignore frame-ancestors in a
# meta tag, and no meta tag reaches a .svg or .json opened directly. The
# fetch directives (img-src, script-src and the rest) deliberately stay in
# docusaurus.config.js, where they are built from the host allowlists shared
# with scripts/lib/; restating them here would give one policy two sources of
# truth. tests/netlify-publish-contract.test.mjs pins this block.
#
# Strict-Transport-Security is the one control here that protects the response
# rather than constrains it. Netlify does not send it on its own -- its HTTPS
# documentation requires the site to set it in this file -- so without it a
# browser sent to http:// makes one cleartext request before the redirect, and
# an attacker on that path answers it instead of redirecting. Every other
# header in this block travels *inside* the response, so a stripped connection
# simply omits them all; this is the only one that survives, because the
# browser remembers it. max-age is one year, the hstspreload.org minimum.
# includeSubDomains is safe for a host that serves no sub-subdomains of its
# own. `preload` is deliberately absent: it is an effectively irreversible
# commitment held by browser vendors over the apex domain, so it belongs to
# whoever administers cncf.io, not to this file, and can be added later
# without rework.
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = "frame-ancestors 'self'"
Strict-Transport-Security = "max-age=31536000; includeSubDomains"
X-Frame-Options = "SAMEORIGIN"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "same-origin"
# Directly-opened assets. A browser that navigates to an SVG renders it as a
# document in this origin, so the SVG gate in validate:architecture-assets is the
# primary control and the <meta> fetch directives in docusaurus.config.js never
# reach the response at all (CONTENT-SECURITY.md, "Residual risks"). A response
# header does reach it. script-src 'none' is not a second copy of the host
# allowlists kept in docusaurus.config.js -- it is a flat denial that is only
# correct for a response that is never a page, so it cannot drift from them.
#
# default-src 'none' is here for the reason docusaurus.config.js gives for the
# meta policy: a fetch directive this header does not name is unrestricted, not
# inherited. Without it, script-src and object-src made a directly-opened SVG
# inert but left it free to *fetch* -- an <image href> on any host, an @import,
# a url() in a presentation attribute, a remote @font-face, an <iframe> inside
# <foreignObject> -- so a visitor's IP, User-Agent and Referer still reached a
# host the diagram's author chose whenever the parser gate was bypassed. That
# gate is the primary control; this is the layer that has to hold when it does
# not.
#
# The three allowances are what the published corpus actually uses and nothing
# more: inline <style> blocks and style= attributes from draw.io exports,
# inline data:image/png payloads, and (for parity with docusaurus.config.js)
# same-origin fonts, of which static/ currently declares none. Still no host
# list, so this block cannot drift from the allowlists in docusaurus.config.js.
#
# These paths are every directory scripts/validate-architecture-assets.mjs walks,
# which is every directory in static/ that holds an SVG. The site-wide values are
# restated because Netlify does not document how it merges a header name set by
# both a broad and a narrow matching rule; restating is correct either way.
[[headers]]
for = "/img/*"
[headers.values]
Content-Security-Policy = "frame-ancestors 'self'; default-src 'none'; script-src 'none'; object-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'"
Strict-Transport-Security = "max-age=31536000; includeSubDomains"
X-Frame-Options = "SAMEORIGIN"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "same-origin"
[[headers]]
for = "/favicons/*"
[headers.values]
Content-Security-Policy = "frame-ancestors 'self'; default-src 'none'; script-src 'none'; object-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'"
Strict-Transport-Security = "max-age=31536000; includeSubDomains"
X-Frame-Options = "SAMEORIGIN"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "same-origin"