From 85ecaf2014e2fa09e9990f119d2dae61d8225637 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Fri, 2 Jan 2026 15:23:46 +1100 Subject: [PATCH] Initial commit --- .gitignore | 1 + src/assets/css/site.css | 167 +++++++++++++++ src/assets/img/cspresso.svg | 30 +++ src/assets/img/enroll.svg | 107 ++++++++++ src/assets/img/hamburger.svg | 4 + src/assets/js/site.js | 60 ++++++ src/docs.html | 244 +++++++++++++++++++++ src/evaluate.html | 189 +++++++++++++++++ src/examples.html | 13 ++ src/favicon.ico | Bin 0 -> 4286 bytes src/index.html | 397 +++++++++++++++++++++++++++++++++++ src/recipes.html | 174 +++++++++++++++ src/security.html | 162 ++++++++++++++ upload.sh | 10 + 14 files changed, 1558 insertions(+) create mode 100644 .gitignore create mode 100644 src/assets/css/site.css create mode 100644 src/assets/img/cspresso.svg create mode 100644 src/assets/img/enroll.svg create mode 100644 src/assets/img/hamburger.svg create mode 100644 src/assets/js/site.js create mode 100644 src/docs.html create mode 100644 src/evaluate.html create mode 100644 src/examples.html create mode 100644 src/favicon.ico create mode 100644 src/index.html create mode 100644 src/recipes.html create mode 100644 src/security.html create mode 100755 upload.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/src/assets/css/site.css b/src/assets/css/site.css new file mode 100644 index 0000000..f15e34d --- /dev/null +++ b/src/assets/css/site.css @@ -0,0 +1,167 @@ +:root{ + --cspresso-mint:#2DD4BF; + --cspresso-violet:#A78BFA; + --cspresso-ink:#0b1220; + --cspresso-ink-2:#111827; + --cspresso-cream:#F6F0E7; + + --bs-link-color: var(--cspresso-mint); + --bs-link-hover-color: var(--cspresso-violet); + --bs-link-color-rgb: 45, 212, 191; + --bs-link-hover-color-rgb: 167, 139, 250; + + --bs-nav-pills-link-active-bg: rgba(45,212,191,0.18); + --bs-nav-pills-link-active-color: var(--cspresso-ink); +} + +html{scroll-behavior:smooth;} + +body{ + font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; + color: var(--cspresso-ink); +} + +.navbar{ + backdrop-filter: blur(10px); +} + +.navbar-toggler-icon{ + background-image: url("../img/hamburger.svg"); +} + +.brand-mark{width:84px;height:84px;} + +.hero{ + background: + radial-gradient(900px 600px at 15% 15%, rgba(45,212,191,0.28), rgba(45,212,191,0.00) 60%), + radial-gradient(900px 600px at 85% 35%, rgba(167,139,250,0.26), rgba(167,139,250,0.00) 60%), + linear-gradient(180deg, rgba(11,18,32,0.02), rgba(11,18,32,0.00)); +} + +.hero .lead{ + color: rgba(15,23,42,0.78); +} + +.hero-card{ + background: rgba(255,255,255,0.70); + border: 1px solid rgba(15,23,42,0.08); + box-shadow: 0 18px 48px rgba(15,23,42,0.10); + border-radius: 1.25rem; +} + +.kicker{ + display: inline-flex; + align-items: center; + gap: .5rem; + font-weight: 600; + font-size: .95rem; + padding: .45rem .75rem; + border-radius: 999px; + background: rgba(45,212,191,0.12); + border: 1px solid rgba(45,212,191,0.25); + color: var(--cspresso-ink); +} + +.section-title{ + letter-spacing: -0.02em; +} + +.icon-pill{ + width: 42px; + height: 42px; + border-radius: 14px; + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(45,212,191,0.12); + border: 1px solid rgba(45,212,191,0.25); + color: var(--cspresso-ink); +} + +.feature-card{ + border: 1px solid rgba(15,23,42,0.08); + border-radius: 1.25rem; + box-shadow: 0 12px 30px rgba(15,23,42,0.06); +} + +.terminal{ + background: #0b1220; + color: #e5e7eb; + border-radius: 1rem; + padding: 1.25rem; + border: 1px solid rgba(255,255,255,0.06); + box-shadow: 0 18px 52px rgba(11,18,32,0.35); +} + +.terminal .prompt{ color: #93c5fd; } +.terminal code{ color: #e5e7eb; } + +.codeblock{ + position: relative; +} + +.copy-btn{ + position: absolute; + top: .75rem; + right: .75rem; +} + +.badge-soft{ + background: rgba(15,23,42,0.06); + border: 1px solid rgba(15,23,42,0.10); + color: rgba(15,23,42,0.85); +} + +.callout{ + border: 1px solid rgba(15,23,42,0.10); + border-radius: 1rem; + background: rgba(255,255,255,0.78); +} + +footer{ + background: + radial-gradient(900px 300px at 20% 0%, rgba(45,212,191,0.12), rgba(45,212,191,0.00) 60%), + radial-gradient(900px 300px at 80% 0%, rgba(167,139,250,0.10), rgba(167,139,250,0.00) 60%), + linear-gradient(180deg, #ffffff 0%, #f8fafc 100%); + border-top: 1px solid rgba(15,23,42,0.06); +} + +.smallprint{ color: rgba(15,23,42,0.65); } + +/* Make anchor scrolling nicer under sticky nav */ +.scroll-mt-nav{ scroll-margin-top: 90px; } + +a{ text-decoration-color: rgba(45,212,191,0.55); } +a:hover{ text-decoration-color: rgba(167,139,250,0.85); } + +/* Quickstart pills */ +.nav-pills .nav-link{ + border: 1px solid rgba(45,212,191,0.25); + color: var(--cspresso-ink); + background: rgba(45,212,191,0.10); + border-radius: 999px; +} +.nav-pills .nav-link:hover{ + background: rgba(167,139,250,0.10); + border-color: rgba(45,212,191,0.55); +} +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link{ + background: rgba(45,212,191,0.18); + color: var(--cspresso-ink); + border-color: rgba(15,23,42,0.18); +} + + +.chip{ + display: inline-flex; + align-items: center; + gap: .35rem; + padding: .25rem .55rem; + border-radius: 999px; + font-size: .85rem; + background: rgba(15,23,42,0.06); + border: 1px solid rgba(15,23,42,0.10); + color: rgba(15,23,42,0.88); + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} diff --git a/src/assets/img/cspresso.svg b/src/assets/img/cspresso.svg new file mode 100644 index 0000000..8ba6656 --- /dev/null +++ b/src/assets/img/cspresso.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 'self' + + + diff --git a/src/assets/img/enroll.svg b/src/assets/img/enroll.svg new file mode 100644 index 0000000..2a03d41 --- /dev/null +++ b/src/assets/img/enroll.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/hamburger.svg b/src/assets/img/hamburger.svg new file mode 100644 index 0000000..5994d3e --- /dev/null +++ b/src/assets/img/hamburger.svg @@ -0,0 +1,4 @@ + + + diff --git a/src/assets/js/site.js b/src/assets/js/site.js new file mode 100644 index 0000000..6866eb2 --- /dev/null +++ b/src/assets/js/site.js @@ -0,0 +1,60 @@ +(function(){ + // Copy-to-clipboard for code blocks + function setupCopyButtons(){ + document.querySelectorAll('[data-copy-target]').forEach(function(btn){ + btn.addEventListener('click', async function(){ + var sel = btn.getAttribute('data-copy-target'); + var el = document.querySelector(sel); + if(!el) return; + var text = el.innerText || el.textContent || ''; + try{ + await navigator.clipboard.writeText(text.trim()); + var old = btn.innerHTML; + btn.innerHTML = 'Copied'; + btn.classList.add('btn-success'); + btn.classList.remove('btn-outline-secondary'); + setTimeout(function(){ + btn.innerHTML = old; + btn.classList.remove('btn-success'); + btn.classList.add('btn-outline-secondary'); + }, 1200); + }catch(e){ + // Fallback + var ta = document.createElement('textarea'); + ta.value = text.trim(); + document.body.appendChild(ta); + ta.select(); + try{ document.execCommand('copy'); }catch(_){} + document.body.removeChild(ta); + } + }); + }); + } + + // Asciinema embed helper: + // Put
+ // Or provide a self-hosted player by swapping the script URL. + function setupAsciinema(){ + document.querySelectorAll('.asciicast[data-asciinema-id]').forEach(function(el){ + var id = el.getAttribute('data-asciinema-id'); + if(!id || id === 'REPLACE_ME'){ + el.innerHTML = '
Add your asciinema id here: data-asciinema-id.
'; + return; + } + // Avoid injecting twice + if(document.getElementById('asciinema-embed-'+id)) return; + + var s = document.createElement('script'); + s.src = 'https://asciinema.org/a/' + encodeURIComponent(id) + '.js'; + s.id = 'asciinema-embed-'+id; + s.async = true; + // The script replaces a placeholder div with the player if it's directly after it. + el.appendChild(s); + }); + } + + document.addEventListener('DOMContentLoaded', function(){ + setupCopyButtons(); + setupAsciinema(); + }); +})(); diff --git a/src/docs.html b/src/docs.html new file mode 100644 index 0000000..a7f0552 --- /dev/null +++ b/src/docs.html @@ -0,0 +1,244 @@ + + + + + + cspresso Docs + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
On this page
+ + +
+ Prefer canonical docs? See the README. +
+
+
+ +
+
+
Docs
+

Usage

+

+ cspresso crawls up to --max-pages same-origin pages in Chromium, observes what loads, and emits a draft CSP. +

+
+ +
+

Install

+
+
+
+ +
# Recommended
+pipx install cspresso
+
+# Or plain pip (use a venv)
+pip install cspresso
+
+# An AppImage is also available on the
+# git repo Releases page.
+
+
+
+
+
+
Python + Playwright
+
+ You need Python 3.10+ and Playwright’s Chromium. cspresso can auto-install Chromium if missing. +
+
+
+ Verify Releases artifacts with the mig5 key: + https://mig5.net/static/mig5.asc + (fingerprint 00AE817C24A10C2540461A9C1D7CDE0234DB458D). +
+
+
+
+
+ +
+

Run

+
+ +
cspresso https://example.com --max-pages 10
+
+
+ The crawl stays on the same origin (it follows internal links) and will wait for networkidle plus a small “settle” + delay to catch late fetches. +
+
+ +
+

Output

+

+ Default output prints visited URLs as comments and then the proposed header line. + Use --json for machine-readable output. +

+
+ +
cspresso https://example.com --json
+
+
+ +
+

Inline scripts & styles

+
+
Why this is hard
+
+ If the page uses nonces, you must generate a new nonce per HTML response and inject it into both the CSP header and the HTML tags. + Hashes only work when inline content is stable byte-for-byte. For style="..." and on* attributes, + browsers require 'unsafe-hashes' for hashes to apply.
Not to worry, cspresso will detect these and generate the hashes + in its response, offering them as style-src-attr options or with unsafe-hashes for older browsers. +
+
+
+ +
+

Evaluate (Report-Only)

+

+ Provide a CSP string to --evaluate and cspresso will inject it as + Content-Security-Policy-Report-Only on HTML responses during the crawl. If any violations are detected, it exits with code 1. +

+

This is a great way of testing a cspresso-brewed CSP before actually adding it to your site.

+ +
+ +
cspresso https://example.com \
+  --bypass-csp \
+  --evaluate "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net;" \
+  --json
+
+ +
+ Recommendation: use --bypass-csp with --evaluate so existing CSP enforcement doesn’t change the page’s behaviour during testing. +
+
+ +
+

Flags

+

A condensed reference of the most-used options:

+ +
+
+
Crawling
+
--max-pages --timeout-ms --settle-ms --headed
+
+
+
Policy shaping
+
--include-sourcemaps --upgrade-insecure-requests --allow-blob --unsafe-eval
+
+
+
Playwright
+
--browsers-path --no-install --with-deps
+
+
+
Evaluation
+
--bypass-csp --evaluate --ignore-non-html --json
+
+
+ +
+ +
+
+
+
+ + + + + + diff --git a/src/evaluate.html b/src/evaluate.html new file mode 100644 index 0000000..5ec9913 --- /dev/null +++ b/src/evaluate.html @@ -0,0 +1,189 @@ + + + + + + cspresso Evaluate + + + + + + + + + + + + + + + + + + +
+
+
+
Evaluate
+

Test a CSP before you enforce it

+

+ Use --evaluate to inject a candidate policy as Content-Security-Policy-Report-Only, + collect violations, and fail the run if anything would break. +

+
+ +
+
+
+
+ +
cspresso https://example.com \
+  --bypass-csp \
+  --evaluate "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net;" \
+  --json
+
+
+
+
+
Exit codes
+
+
0 → no Report‑Only violations detected
+
1 → violations detected (ideal for CI gates)
+
+
+
+ Tip: keep your CSP string quoted; it usually contains spaces and semicolons. +
+
+
+
+
+ +
+

Why --bypass-csp matters

+

+ If the target site already sets an enforcing CSP, it can block loads and change runtime behaviour. + That can hide potential violations in your candidate policy. Using --bypass-csp strips existing CSP headers + on HTML responses during the crawl. +

+
+
Safety note
+
+ Bypassing CSP means you’re letting the page execute without those protections. Run evaluation only on sites you trust, + or in a sandboxed environment. +
+
+
+ +
+

CI example (GitHub Actions)

+
+ +
- name: Evaluate CSP
+  run: |
+    pipx install cspresso
+    cspresso https://example.com \
+      --bypass-csp \
+      --evaluate "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net;" \
+      --json
+
+
+ If you cache Playwright browsers, set --browsers-path to a persistent directory. +
+
+ +
+

Troubleshooting

+
+
+
+
Sourcemaps causing connect-src noise
+
+ DevTools often fetches sourcemaps even when headless browsing doesn’t. If you want to model those requests, + use --include-sourcemaps to add sourcemap origins to connect-src. +
+
+
+
+
+
Non-HTML crawled resources
+
+ If your site has downloadable files on the same origin, consider --ignore-non-html to avoid edge cases + like browser “word-wrap” injected styles affecting hashes. +
+
+
+
+
+
+
+ + + + + + diff --git a/src/examples.html b/src/examples.html new file mode 100644 index 0000000..73af062 --- /dev/null +++ b/src/examples.html @@ -0,0 +1,13 @@ + + + + + + cspresso - Recipes + + + + +

Redirecting to recipes.html

+ + diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..77181af45e9705c27c79096b98a28169fe933e77 GIT binary patch literal 4286 zcmeI0?N5_e7{&=>g%mg>zd*6_)vPu zh{}d8+a4$hl}mX{{3`moGjz!H&U^apaU6P;c$R?@cb`scKm6|19L4Es8%hjL7+>T5{FsqQ1mZD}!S8%=X%fx3zK8|U!~0CdSr@ZBDR!_$w3RyTC!c2pZ3QaZCs*4o_t7!W<|4TZ!1dT0Oi46Gf! zIH_qss#1@QS#?OtHsP~htyr65$J$&+R3c}MYwTe!J@k_CvcbPMPv0=o3k*m;VMJ1) z8%bw-kbKUE^{PQ^s8~j#zP@}wYF$aM@OY#*{ft4f$V@aGULU^9)?rhH4_oz*kep}3 z$7v<_Xm`Pi`s9alBxlxPOI{;3E9;STvPpW$AdAdIV*JqrcIFtc_0lL(uTNr|?mjl3 zwqQ?bGmcd`ada7FTx`R)<#z1S58_943yxGdu3`^$eFg`N<5J9*>yh3i4w+=Hwtp}b!f~}3 zN39dca?VI)E{(ByY)n1pz@}fWNHLGqUmRcbl1VoASS?EQHe{H_klQtjoX%%b%BAu7 zynPx6YX@+mZAyx{Qq*GW9AEU1MJCztqRs8YfvOuQ><-|JXAT8Is@^#idgr2Z?>tW0 z9%0+52IRW@Qp{N^5Nq_XmmYfMT(HO_J6=rB%!>Qei2M#e%6bDR?U_eKUjSudJl`M9 z&vg2cuI)sTds>P)YwTkWdzsTq23cg1ok%#n12|OK26cY`8o?>~gmy3p-Eau1 zo>`ptg`nvVN-<}RYwTgK^aw8*WRaO@@PDnLxf91~I-vE<<5cr73R>2A nUQaL>lFu^F + + + + + cspresso - Brew a Content Security Policy + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
Brew a Content Security Policy
+

Turn real page loads into a CSP you can ship.

+

+ cspresso crawls up to N same‑origin pages with headless Chromium (Playwright), watches the assets that load, + and emits a draft Content-Security-Policy header. +

+ + +
+ --json + --evaluate + --bypass-csp + --include-sourcemaps +
+
+ +
+
+ +
pipx install cspresso
+cspresso https://example.com --max-pages 10
+
+# visited: https://example.com/
+Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; ...;
+
+
+ Remember: it’s only a starting point: crawls may not hit every flow, and inline hashing/nonces require care. +
+
+
+
+
+ +
+
+
+
+

Quickstart

+
+
+
+
+
+ +
+                  
+cspresso https://mig5.net \
+  --ignore-non-html \
+  --max-pages 10
+                  
+                
+
+
+ +
+
+
What you’ll get
+
+ A header line you can paste into your vhost, or parseable info with --json +
+
+
+ Tip: if an existing CSP might block loads during analysis, add --bypass-csp. +
+
+
+ +
+
+ +
# Evaluate a candidate CSP (Report-Only) and fail CI on violations
+cspresso https://mig5.net \
+  --bypass-csp \
+  --evaluate "default-src 'self'; img-src 'none';" \
+  --json
+
+{
+  [...]
+  "violations": [
+    {
+      "console": true,
+      "disposition": "report",
+      "documentURI": "https://mig5.net/",
+      "text": "Loading the image 'https://mig5.net/logo.svg' violates the following Content Security Policy directive: \"img-src 'none'\". The policy is report-only, so the violation has been logged but no further action has been taken.",
+      "type": "info"
+    },
+    {
+      "console": true,
+      "disposition": "report",
+      "documentURI": "https://mig5.net/static/mig5.asc",
+      "text": "Applying inline style violates the following Content Security Policy directive 'default-src 'self''. Either the 'unsafe-inline' keyword, a hash ('sha256-4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback. The policy is report-only, so the violation has been logged but no further action has been taken.",
+      "type": "info"
+    }
+  ]
+}
+
+# exit code: 1 if violations detected
+
+
+ +
+
+
+
+
+ +
+
+
+
+

How it works

+

+ cspresso lets the browser do the hard part: execute the page, watch what it loads, and distill origins into directives. +

+
+
+
+
+
+
+
Crawl
+
Visit up to --max-pages same-origin pages and let the app’s JS run.
+
+
+
+
+
+
Observe
+
Track scripts, styles, images, fonts, frames, and “connect-like” requests.
+
+
+
+
+
+
Draft a CSP
+
Emit a baseline policy plus observed origins per directive.
+
+
+
+
+
+
Evaluate
+
Inject a candidate as Report‑Only and capture violations with an exit code for CI.
+
+
+
+ +
+ Inline script/style is tricky: nonces must be generated per response, and hashes must match bytes exactly. + cspresso reports what it sees, but you should review and tighten before enforcing. +
+
+
+
+
+ +
+
+
+
+

Popular flags

+

A few options that tend to matter in real deployments.

+
+
+ +
+
+
--bypass-csp
+
Strip existing CSP response headers so they don’t block discovery or evaluation.
+
+ +
+
--evaluate
+
Inject a candidate policy as Report‑Only and exit 1 if any violations are detected.
+
+ +
+
--include-sourcemaps
+
Heuristically discover sourcemap origins and add them to connect-src.
+
+ +
+
--upgrade-insecure-requests
+
Emit upgrade-insecure-requests in the proposed policy.
+
+ +
+
--browsers-path
+
Control where Playwright installs Chromium (handy for AppImage/CI caches).
+
+ +
+
--json
+
Machine-readable output: CSP, visited URLs, notes, and evaluation violations.
+
+
+
+
+ +
+
+
+
+

Install

+

pipx, pip, Poetry, or a standalone AppImage from Releases.

+
+ +
+ + + +
+
+
+
+
+ +
# Recommended
+pipx install cspresso
+
+# Or plain pip (use a venv)
+pip install cspresso
+
+
+
+
+
Playwright browsers
+
+ cspresso can auto-install Chromium for Playwright if it isn’t present. By default it installs into ./.pw-browsers + for deterministic builds and easy CI caching. +
+
+
+ Override with --browsers-path or PLAYWRIGHT_BROWSERS_PATH. +
+
+
+
+
+ +
+
+
+
+ +
poetry add cspresso
+
+
+
+
+
Linux deps
+
+ If Chromium won’t start due to missing libraries, try --with-deps (may require elevated privileges). +
+
+
+
+
+ +
+
+
+
+ +
chmod +x cspresso.AppImage
+./cspresso.AppImage https://example.com \
+  --browsers-path "$HOME/.cache/cspresso/pw-browsers"
+
+
+
+
+
Tip
+
+ AppImages mount read-only - use --browsers-path to install browsers into a writable cache directory. +
+
+
+ Verify releases with the mig5 GPG key (fingerprint 00AE817C24A10C2540461A9C1D7CDE0234DB458D). +
+
+
+
+
+ +
+
+
+
+ + + + + + diff --git a/src/recipes.html b/src/recipes.html new file mode 100644 index 0000000..d0107f9 --- /dev/null +++ b/src/recipes.html @@ -0,0 +1,174 @@ + + + + + + cspresso Recipes + + + + + + + + + + + + + + + + + + +
+
+
+
Recipes
+

Practical workflows

+

A handful of commands that cover most real-world cspresso usage.

+
+ +
+
+

Draft a CSP

+
+ +
cspresso https://example.com --max-pages 10
+
+
+ Start here, then audit the output. Crawls won’t cover every flow (auth-only pages, conditional loads, A/B tests, etc.). +
+
+ +
+

Headed debugging

+
+ +
cspresso https://example.com --headed --settle-ms 2500
+
+
+ Useful when the site does delayed loads or you want to visually confirm what’s happening during the crawl. +
+
+ +
+

Sourcemaps & connect-src

+
+ +
cspresso https://example.com --include-sourcemaps
+
+
+ If browsers/devtools fetch *.map files from a CDN, this helps make sure the CDN origin lands in connect-src. +
+
+ +
+

Upgrade insecure requests

+
+ +
cspresso https://example.com --upgrade-insecure-requests
+
+
+ Handy during migrations when you still have a few stray HTTP URLs. +
+
+ +
+

AppImage (writable browser cache)

+
+ +
./cspresso.AppImage https://example.com \
+  --browsers-path "$HOME/.cache/cspresso/pw-browsers"
+
+
+ AppImages mount read-only. Set --browsers-path so Playwright can install Chromium into a writable directory. +
+
+ +
+

CI gate with --evaluate

+
+ +
cspresso https://example.com \
+  --bypass-csp \
+  --evaluate "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net;" \
+  --json
+
+
+ Exits 1 if the candidate policy would be violated - great for PR checks. +
+
+
+
+
+ + + + + + diff --git a/src/security.html b/src/security.html new file mode 100644 index 0000000..eda79ef --- /dev/null +++ b/src/security.html @@ -0,0 +1,162 @@ + + + + + + cspresso Security + + + + + + + + + + + + + + + + + + +
+
+
+
Security
+

Security notes

+

+ cspresso runs a real browser. That’s the point - and also the main safety consideration. +

+
+ +
+
+
+

What cspresso does

+

+ cspresso launches Chromium via Playwright and loads your target pages. The site’s JavaScript and CSS execute like a normal browser session. + Network requests are observed to build a draft CSP, and (optionally) a candidate policy is injected as Report‑Only to capture violations. +

+
+ +
+

About --bypass-csp

+
+
It can change risk
+
+ Bypassing CSP strips existing CSP headers on HTML responses. This option is provided in order to avoid the outcome of the rendering negatively influencing what cspresso thinks a good CSP should be. + If a site is compromised, CSP might have been limiting what injected scripts could do (that's the whole point of a CSP!); bypassing removes that layer. +
+
+
+ Recommendation: only use --bypass-csp on sites you trust, or run cspresso inside a sandboxed environment (VM/container). +
+
+
+ +
+

Data handling

+

+ cspresso’s primary output is a policy string and metadata (visited URLs, notes, and - in evaluation mode - detected violations). + Treat the output as sensitive if your site URLs or CSP reveal internal endpoints. +

+
+ +
+

Hardening tips

+
+
+
Prefer CI / disposable environments
+
Running in CI makes it easy to isolate and to cache Chromium via --browsers-path.
+
+
+
Limit crawl scope
+
Keep --max-pages small and start from a stable landing page to reduce surprises.
+
+
+
Review before enforcing
+
cspresso emits a draft. Tighten directives (especially script-src/connect-src) and consider nonces.
+
+
+
Verify releases
+
mig5 key: https://mig5.net/static/mig5.asc
Fingerprint: 00AE817C24A10C2540461A9C1D7CDE0234DB458D
+
+
+
+
+ +
+
+
+ + + + + + diff --git a/upload.sh b/upload.sh new file mode 100755 index 0000000..79697a4 --- /dev/null +++ b/upload.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -eou pipefail + +SRC="src" +DEST="/opt/www/cspresso.cafe" + +rsync -aHPvz ${SRC}/ root@lupin.mig5.net:${DEST}/ + +ssh root@lupin.mig5.net "chown -R web:web ${DEST}"