The website is not the device
apps/web builds nullroute.diy. It is a Next.js site, it obviously uses the
network, and it is fenced off from the device build the same way
packages/bridge is:
- nothing in
apps/webever ships to the Pi MANIFEST.lockand the manifest root hash coverpackages/,spec/,provisioning/,package.jsonandpackage-lock.json, which is whatmake print-manifest-rootsprints. This line saidpackages/only, so anyone following it computed a root hash matching neither the device nor the release.- the no-network lint rule applies to
packages/, not toapps/web apps/webmust never import frompackages/daemon
The site renders docs/ from the repository root, which is deliberate: the
published documentation and the documentation in the repository are the same
files, so the site cannot drift from the device.
If you find yourself wanting to import device code into the website to show
something off, that is the boundary doing its job. Copy the values into
docs/ or generate a static artifact instead.
Editing a page changes the CSP
vercel.json carries a strict Content-Security-Policy with no 'unsafe-inline'
anywhere, including for styles. Next inlines a small RSC bootstrap into every
page, so script-src enumerates the sha256 hash of each of those blocks.
Those hashes are content-derived, which means any edit to any page changes them. After changing the site, run:
make web-build
node tools/gen-csp.mjs # rewrites vercel.json
make web-csp fails in CI if you forget. That is friction, and it is the price
of not writing 'unsafe-inline' and moving on. A policy with 'unsafe-inline'
in script-src permits exactly the injection the policy exists to prevent, on
the site that tells people to verify things.
This works only because the hashes are stable across builds, which is only true
because next.config.mjs pins generateBuildId. Do not remove that pin.
Rendered from CONTRIBUTING.md, the same bytes that ship with the code. SHA-256 80ae67da20b1d79a061ae1ffe5ac6af62ad6b80566961c8d27c3a1b5fb0e265d