cspresso.cafe/src/content/_index.html
Miguel Jacq 257df86f04
All checks were successful
CI / test (push) Successful in 1m42s
Content/logo tweaks
2026-02-06 17:41:07 +11:00

238 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "cspresso - Brew a Content Security Policy"
description: "cspresso crawls a site with headless Chromium (Playwright) and emits a draft Content-Security-Policy based on what loads."
---
<main>
<header class="hero py-5">
<div class="container py-4">
<div class="row align-items-center g-4">
<div class="col-lg-6">
<h1 class="display-5 fw-800 lh-1 mb-3" style="letter-spacing:-0.03em;">Automatically generate a CSP for your site.</h1>
<p class="lead mb-4">
cspresso crawls up to <em>N</em> sameorigin pages with headless Chromium (Playwright), watches the assets that load,
and emits a <strong>draft</strong> <code>Content-Security-Policy</code> header.
</p>
<div class="d-flex flex-wrap gap-2 mb-4">
<a class="btn btn-dark btn-lg" href="docs.html"><i class="bi bi-journal-text"></i> Docs</a>
<a class="btn btn-outline-secondary btn-lg" href="evaluate.html"><i class="bi bi-shield-check"></i> Evaluate</a>
<a class="btn btn-outline-secondary btn-lg" href="https://pypi.org/project/cspresso/" target="_blank" rel="noreferrer"><i class="bi bi-box-seam"></i> PyPI</a>
</div>
<div class="d-flex flex-wrap gap-2">
<span class="chip">--json</span>
<span class="chip">--evaluate</span>
<span class="chip">--bypass-csp</span>
<span class="chip">--include-sourcemaps</span>
</div>
</div>
<div class="col-lg-6">
<div class="codeblock">
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#heroCode"><i class="bi bi-clipboard"></i> Copy</button>
<pre class="terminal mb-0"><code id="heroCode">pipx install cspresso
cspresso https://mig5.net --max-pages 10
# visited: https://mig5.net/
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; ...;</code></pre>
</div>
</div>
</div>
</div>
</header>
<section class="py-5" id="how">
<div class="container">
<div class="row g-4 align-items-start">
<div class="col-lg-5">
<h2 class="section-title display-6 fw-bold mb-2">How it works</h2>
<p class="text-muted mb-0">
cspresso lets the browser do the hard part: execute the page, watch what it loads, and distill origins into directives.
</p>
<br />
<p class="text-muted mb-0">
It uses Playwright (a tool designed to run a browser in 'headless' mode, originally to help automate performing frontend testing of websites) to visit the website in the background and learn what directives of a Content-Security Policy would be needed in order to set such a header and still have the website function properly.
</p>
<br />
<p class="text-muted mb-0">
It can also evaluate a provided CSP against a site and see if normal use of the site would trigger violations of the policy, before you ship it.
</p>
</div>
<div class="col-lg-7">
<div class="row g-3">
<div class="col-md-6">
<div class="card feature-card h-100"><div class="card-body p-4">
<div class="icon-pill mb-3"><i class="bi bi-globe2"></i></div>
<div class="fw-semibold mb-1">Crawl</div>
<div class="text-muted">Visit up to <code>--max-pages</code> same-origin pages and let the apps JS run.</div>
</div></div>
</div>
<div class="col-md-6">
<div class="card feature-card h-100"><div class="card-body p-4">
<div class="icon-pill mb-3"><i class="bi bi-activity"></i></div>
<div class="fw-semibold mb-1">Observe</div>
<div class="text-muted">Track scripts, styles, images, fonts, frames, and “connect-like” requests.</div>
</div></div>
</div>
<div class="col-md-6">
<div class="card feature-card h-100"><div class="card-body p-4">
<div class="icon-pill mb-3"><i class="bi bi-shield-lock"></i></div>
<div class="fw-semibold mb-1">Draft a CSP</div>
<div class="text-muted">Emit a baseline policy plus observed origins per directive.</div>
</div></div>
</div>
<div class="col-md-6">
<div class="card feature-card h-100"><div class="card-body p-4">
<div class="icon-pill mb-3"><i class="bi bi-check2-square"></i></div>
<div class="fw-semibold mb-1">Evaluate</div>
<div class="text-muted">Inject a candidate as ReportOnly and capture violations with an exit code for CI.</div>
</div></div>
</div>
</div>
<div class="mt-3 small text-secondary">
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.
</div>
</div>
</div>
</div>
</section>
<section class="py-5 bg-light" id="flags">
<div class="container">
<div class="row g-3 align-items-end mb-3">
<div class="col-lg-8">
<h2 class="section-title display-6 fw-bold mb-2">Popular flags</h2>
<p class="text-muted mb-0">A few options that tend to matter in real deployments.</p>
</div>
</div>
<div class="row g-3">
<div class="col-md-6 col-lg-4"><div class="card feature-card h-100"><div class="card-body p-4">
<div class="fw-semibold mb-2"><span class="chip">--bypass-csp</span></div>
<div class="text-muted">Strip existing CSP response headers so they dont block discovery or evaluation.</div>
</div></div></div>
<div class="col-md-6 col-lg-4"><div class="card feature-card h-100"><div class="card-body p-4">
<div class="fw-semibold mb-2"><span class="chip">--evaluate</span></div>
<div class="text-muted">Inject a candidate policy as ReportOnly and exit 1 if any violations are detected.</div>
</div></div></div>
<div class="col-md-6 col-lg-4"><div class="card feature-card h-100"><div class="card-body p-4">
<div class="fw-semibold mb-2"><span class="chip">--include-sourcemaps</span></div>
<div class="text-muted">Heuristically discover sourcemap origins and add them to <code>connect-src</code>.</div>
</div></div></div>
<div class="col-md-6 col-lg-4"><div class="card feature-card h-100"><div class="card-body p-4">
<div class="fw-semibold mb-2"><span class="chip">--upgrade-insecure-requests</span></div>
<div class="text-muted">Emit <code>upgrade-insecure-requests</code> in the proposed policy.</div>
</div></div></div>
<div class="col-md-6 col-lg-4"><div class="card feature-card h-100"><div class="card-body p-4">
<div class="fw-semibold mb-2"><span class="chip">--browsers-path</span></div>
<div class="text-muted">Control where Playwright installs Chromium (handy for AppImage/CI caches).</div>
</div></div></div>
<div class="col-md-6 col-lg-4"><div class="card feature-card h-100"><div class="card-body p-4">
<div class="fw-semibold mb-2"><span class="chip">--json</span></div>
<div class="text-muted">Machine-readable output: CSP, visited URLs, notes, and evaluation violations.</div>
</div></div></div>
</div>
</div>
</section>
<section class="py-5" id="install">
<div class="container">
<div class="row g-3 align-items-end mb-3">
<div class="col-lg-8">
<h2 class="section-title display-6 fw-bold mb-2">Install</h2>
<p class="text-muted mb-0">pipx, pip, Poetry, or a standalone AppImage from Releases.</p>
</div>
<div class="col-lg-4 text-lg-end">
<a class="btn btn-outline-dark" href="https://git.mig5.net/mig5/cspresso/releases" target="_blank" rel="noreferrer"><i class="bi bi-download"></i> Releases</a>
</div>
</div>
<ul class="nav nav-pills gap-2" id="installTabs" role="tablist">
<li class="nav-item" role="presentation"><button class="nav-link active" id="inst1-tab" data-bs-toggle="pill" data-bs-target="#inst1" type="button" role="tab">pipx / pip</button></li>
<li class="nav-item" role="presentation"><button class="nav-link" id="inst2-tab" data-bs-toggle="pill" data-bs-target="#inst2" type="button" role="tab">Poetry</button></li>
<li class="nav-item" role="presentation"><button class="nav-link" id="inst3-tab" data-bs-toggle="pill" data-bs-target="#inst3" type="button" role="tab">AppImage</button></li>
</ul>
<div class="tab-content mt-3">
<div class="tab-pane fade show active" id="inst1" role="tabpanel" aria-labelledby="inst1-tab">
<div class="row g-3">
<div class="col-lg-6">
<div class="codeblock">
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#inst1code"><i class="bi bi-clipboard"></i> Copy</button>
<pre class="terminal mb-0"><code id="inst1code"># Recommended
pipx install cspresso
# Or plain pip (use a venv)
pip install cspresso</code></pre>
</div>
</div>
<div class="col-lg-6">
<div class="callout p-4 h-100">
<div class="fw-semibold mb-2">Playwright browsers</div>
<div class="text-muted">
cspresso can auto-install Chromium for Playwright if it isnt present. By default it installs into <code>./.pw-browsers</code>
for deterministic builds and easy CI caching.
</div>
<hr>
<div class="small text-secondary">
Override with <code>--browsers-path</code> or <code>PLAYWRIGHT_BROWSERS_PATH</code>.
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="inst2" role="tabpanel" aria-labelledby="inst2-tab">
<div class="row g-3">
<div class="col-lg-6">
<div class="codeblock">
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#inst2code"><i class="bi bi-clipboard"></i> Copy</button>
<pre class="terminal mb-0"><code id="inst2code">poetry add cspresso</code></pre>
</div>
</div>
<div class="col-lg-6">
<div class="callout p-4 h-100">
<div class="fw-semibold mb-2">Linux deps</div>
<div class="text-muted">
If Chromium wont start due to missing libraries, try <code>--with-deps</code> (may require elevated privileges).
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="inst3" role="tabpanel" aria-labelledby="inst3-tab">
<div class="row g-3">
<div class="col-lg-6">
<div class="codeblock">
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#inst3code"><i class="bi bi-clipboard"></i> Copy</button>
<pre class="terminal mb-0"><code id="inst3code">chmod +x cspresso.AppImage
./cspresso.AppImage https://example.com \
--browsers-path "$HOME/.cache/cspresso/pw-browsers"</code></pre>
</div>
</div>
<div class="col-lg-6">
<div class="callout p-4 h-100">
<div class="fw-semibold mb-2">Tip</div>
<div class="text-muted">
AppImages mount read-only - use <code>--browsers-path</code> to install browsers into a writable cache directory.
</div>
<hr>
<div class="small text-secondary">
Verify releases with the mig5 GPG key (fingerprint <code>00AE817C24A10C2540461A9C1D7CDE0234DB458D</code>).
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</main>