feat: SPEC-049 content-author directives + SPEC-050 component islands #65

Merged
anuna-02 merged 0 commits from refs/pull/65/head into main 2026-06-26 05:55:00 +00:00
anuna-02 commented 2026-06-26 01:29:46 +00:00 (Migrated from codeberg.org)

Implements SPEC-049 (content-author Markdown directives) and SPEC-050 (component islands & inter-island messaging) on top of the shipped SPEC-048 component core. Both are opt-in behind default-on cargo features (content-components, component-islands) with byte-identical backward-compatible defaults.

SPEC-049 — content directives (src/web/components/)

:::name{…} / ::name{} invoke theme components from untrusted Markdown. The template is trusted; the directive's props and body are not:

  • directive recogniser (CON-4901); isolated body sanitiser (CON-4902, ammonia); untrusted prop recognition + url ingestion (REQ-4904);
  • CON-4904 sound static HTML-context lint over minijinja's AST (fails the build if a content value reaches a JS/CSS/URL/unquoted context, transitively, fail-closed);
  • transform-stage expansion with a per-provenance barrier (REQ-4906); restricted deny-by-default content context (REQ-4907). Inline :name[…] form deferred (Q2).

SPEC-050 — component islands (src/web/islands/ + src/web/assets/islands.js)

Sandboxed Web-Worker islands paint via a controlled-element renderer (Remote DOM); a retained replay-on-subscribe window.zetl bus; capability-scoped grants; typed payloads; persisted topics + pre-paint; lazy hydration; per-page default-deny CSP.

Security model & verification

Trusted host is the sole reference monitor; untrusted Worker output passes the CON-5007 allowlist renderer (no script/iframe/style/on*, scheme-validated URLs, egress-taint, bounds). Two fresh-context adversarial reviews (PROTO-001 Principle 12) + a Codex review were run; all findings fixed. Tests: lib 2,531; LangSec property/fuzz (sanitiser, URL recogniser, CON-4904 lint, grammars); islands.js node tests (recogniser + renderer); integration suites for both specs; clippy clean; --no-default-features compiles.

⚠️ Caveats (read before relying on this in production)

Both specs are non-converged strawmen. Per their own text, the untrusted-content trust boundary needs a human security expert + executable fuzzing before production use — this branch makes that review possible (working PoC + tests) but does not replace it. The iframe escape-hatch transport is stubbed (Worker is the v1 default); the bridge grant logic is covered by build-side wiring tests + a manual browser playtest.

Plan: specs/IMPL-049-050-plan.spl. Docs: docs/content-directives.md, docs/islands.md.

🤖 Generated with Claude Code

Implements SPEC-049 (content-author Markdown directives) and SPEC-050 (component islands & inter-island messaging) on top of the shipped SPEC-048 component core. Both are opt-in behind default-on cargo features (`content-components`, `component-islands`) with **byte-identical backward-compatible defaults**. ## SPEC-049 — content directives (`src/web/components/`) `:::name{…}` / `::name{}` invoke theme components from untrusted Markdown. The template is trusted; the directive's props and body are not: - directive recogniser (CON-4901); isolated body sanitiser (CON-4902, ammonia); untrusted prop recognition + `url` ingestion (REQ-4904); - **CON-4904 sound static HTML-context lint** over minijinja's AST (fails the build if a content value reaches a JS/CSS/URL/unquoted context, transitively, fail-closed); - transform-stage expansion with a per-provenance barrier (REQ-4906); restricted deny-by-default content context (REQ-4907). Inline `:name[…]` form deferred (Q2). ## SPEC-050 — component islands (`src/web/islands/` + `src/web/assets/islands.js`) Sandboxed Web-Worker islands paint via a controlled-element renderer (Remote DOM); a retained replay-on-subscribe `window.zetl` bus; capability-scoped grants; typed payloads; persisted topics + pre-paint; lazy hydration; per-page default-deny CSP. ## Security model & verification Trusted host is the sole reference monitor; untrusted Worker output passes the CON-5007 allowlist renderer (no script/iframe/`style`/`on*`, scheme-validated URLs, egress-taint, bounds). Two fresh-context adversarial reviews (PROTO-001 Principle 12) + a Codex review were run; all findings fixed. Tests: lib 2,531; LangSec property/fuzz (sanitiser, URL recogniser, CON-4904 lint, grammars); islands.js node tests (recogniser + renderer); integration suites for both specs; clippy clean; `--no-default-features` compiles. ## ⚠️ Caveats (read before relying on this in production) Both specs are **non-converged strawmen**. Per their own text, the untrusted-content trust boundary needs a **human security expert + executable fuzzing** before production use — this branch makes that review *possible* (working PoC + tests) but does not replace it. The iframe escape-hatch transport is stubbed (Worker is the v1 default); the bridge grant logic is covered by build-side wiring tests + a manual browser playtest. Plan: `specs/IMPL-049-050-plan.spl`. Docs: `docs/content-directives.md`, `docs/islands.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
anuna-research/zetl!65
No description provided.