← Commit history

Doctrine catch-up (#146): sandbox storage contract + sensitive-pages section

Colby Knox ·fdefa522a7 ·2mo ago ·parent a89f082
1 file changed +40−3
SKILL.md+40−3
@@ -114,9 +114,26 @@ your headings ids, listen for that message, find the element, and post  SANDBOX LIMITS. Scripts run, but `connect-src` is the wiki origin only: you cannot `fetch()` an arbitrary origin, so INLINE your assets (JS, JSON, fonts as data-URIs). No cookies, no real-origin storage, no direct access to the wiki page;-communicate with the page only through `postMessage`. A `readme.html` over 4 MiB-is refused (`README_TOO_LARGE`). Keep it lean; large media are page assets.+URIs). No cookies, no direct access to the wiki page; communicate with the page+only through `postMessage`. A `readme.html` over 4 MiB is refused+(`README_TOO_LARGE`). Keep it lean; large media are page assets.++STORAGE IS SAFE (2026-08-21). The server injects a localStorage/sessionStorage+shim into every sandboxed document (both the readme render and the render/+routes a readme iframes its viewers from), so bundles that touch storage during+init work; author-side shims are no longer needed and remain harmless. The+remaining sandbox traps are LINTED at push with advisory hints:+`RENDER_SIZE_CAP` (a referenced file over 4 MB fails silently),+`SANDBOX_BLOB` (no `blob:` in the CSP; `URL.createObjectURL` output is refused+at runtime, including glTF loaders blobbing embedded textures -- use `data:`+URIs), `SANDBOX_RELATIVE_PATHS` (bare-relative asset paths 404 because the+document base is `/readme/<owner>/<type>/<slug>`; reference repo assets+absolutely: `https://wiki.adom.inc/<owner>/<slug>/render/<path>`),+`README_HEIGHT_MISSING` (post the readme-height message or content below the+fold is unreachable), `SANDBOX_FONT_FACE` (remote `@font-face` fails CORS from+the null origin; inline as `data:` or use the system stack), plus+`GLB_ORIENTATION` on hardware pages (glTF is Y-up, the wiki viewer is Z-up;+bake a +90 degree X rotation or the board renders standing on edge).  ## Package vs release: install payload vs downloadable binaries @@ -400,6 +417,26 @@ puts Symbol & Footprint above the README; omit it for the kind default order. Pushing a `page.json` with `sections` returns a `SECTIONS_DECLARED` hint echoing what was kept vs dropped. +## Sensitive pages: the flag and the human-approval gate++The `sensitive` flag is a content classification, not protection: it does not+hide the page, it gates CHANGES. It is set manually (`adom-wiki page sensitive+<ref> --set --reason "..."`, free for anyone with manage rights) or+automatically at push by high-precision detectors (private-key blocks, live+API-token formats, Luhn-valid card numbers, IBAN/SSN shapes, explicit+confidentiality markers -- a hit flags the page and emits `SENSITIVE_FLAGGED`,+never blocks the push). While flagged, any visibility WIDENING (page+private->public, releases/pkg to public, unsealing source, the batch endpoint)+and clearing the flag itself refuse with `APPROVAL_REQUIRED`: the change is+not applied and a pending approval request is filed (expires ~24h). A page+manager approves from the page's Visibility panel in a BROWSER: the approval+link is deliberately never returned over the API, so an agent that hit the+gate cannot approve its own request. Do not retry and do not look for a+bypass; the request is already filed, and the failure is the feature working.+Narrowing (making things more private) is never gated. CLI surface since+adom-wiki 1.7.5: `adom-wiki page sensitive <ref> --set [--reason]/--clear`;+the gated `--clear` exits 0 with the pending-request rendering.+ ## Decision table  | You want to | Do this |