Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bbd6b2a
Add a capability-scoped local-file Tool viewer
nedtwigg Sep 15, 2026
b797168
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 15, 2026
965da76
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 15, 2026
2b9a880
Resolve shared CLI modules in standalone host bundles
nedtwigg Sep 15, 2026
9db4780
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
9ce15a6
Simplify the built-in file viewer and its lib plumbing
nedtwigg Sep 16, 2026
3166f6e
Preserve file viewer CSP through the iframe proxy
nedtwigg Sep 16, 2026
3fd4f6b
Pin built-in file reuse across Tool authority scopes
nedtwigg Sep 16, 2026
e31a53f
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
a79462d
Serialize preserved CSP policies for both host type contracts
nedtwigg Sep 16, 2026
9e72491
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
46c9a52
Account for the Tool argv restore contract in the spec budget
nedtwigg Sep 16, 2026
ef0f8ce
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
ee19a7d
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
12ec63e
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
e0cc1ea
Clarify file viewer errors and skip source-preview dependencies
nedtwigg Sep 16, 2026
5af49eb
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
3ee7516
Prefer known file formats over source-name fallbacks
nedtwigg Sep 16, 2026
f73dee2
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
0ab40a3
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
2d109d3
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
4c7f901
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
cfa1690
Expose Dor Tools toggle in experimental settings
nedtwigg Sep 16, 2026
df7c9cb
Let dor open take over its calling terminal
nedtwigg Sep 16, 2026
f1ea63a
Keep Tool faces hidden with their workspace
nedtwigg Sep 16, 2026
f196bea
Make Dor Tools available without an experimental flag
nedtwigg Sep 16, 2026
2816530
Assert both Tool faces after workspace visibility returns
nedtwigg Sep 16, 2026
aa3075a
Clarify persistent Tool placement and parking contracts
nedtwigg Sep 16, 2026
3986206
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
ea10a65
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
7720b83
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
043dd90
Merge branch 'dor-open-dispatch' into dor-file-viewer
nedtwigg Sep 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/audit/application-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ it prints; test listeners and self-test fixtures need no further investigation.
The lint scans all tracked JavaScript and TypeScript. Search the same files for
`createServer`, `.listen(`, `serve(` and `WebSocket` too, because a new API or a
host built at runtime can escape its patterns.
The Local-file viewer subsection adds a tokenized file grant: read
`dor/src/file-viewer.ts` and `dor/src/file-viewer-loopback-guard.ts`, including
its static asset discovery, descriptor lifetime, and every request gate.

For the rest of `docs/specs/security-local.md`, read each section's owner first
— `docs/specs/terminal-escapes.md`, `docs/specs/dor-browser.md`,
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ A spec is the accurate reference for the current code: it states the invariants
- **`docs/specs/theme.md`** — The two-layer CSS variable strategy, consumed-token resolver, terminal color contract, theme debugger.
- **`docs/specs/dor-cli.md`** — The `dor` CLI on every Dormouse terminal's `PATH`: bundling and env contract, `spawnAndCapture` rules, control-socket plumbing, the Surface handle model, the command set.
- **`docs/specs/dor-browser.md`** — The browser surface: `BrowserPanel` with swappable `renderMode`, browser chrome, the agent-browser stack, the iframe proxy and CSP boundaries.
- **`docs/specs/dor-tool.md`** — Dor Tools: the `tool` Surface — a terminal and a browser on one Session spine — its capability-gated verbs and OSC 367 contract. Designation, trust, serving, and persistence are built behind the Tools flag.
- **`docs/specs/dor-tool.md`** — Dor Tools: the `tool` Surface — a terminal and a browser on one Session spine — its capability-gated verbs, OSC 367 contract, designation, trust, serving, and persistence.
- **`docs/specs/vscode.md`** — VS Code host: webview hosting, webview ↔ Workspace mapping, persistence ordering, theme integration, CSP, the build/dogfood pipeline.
- **`docs/specs/standalone.md`** — Tauri host: the Rust ↔ Node-sidecar bridge, boot sequence, AppBar, persistence, shutdown ordering, the build/dev workflow.
- **`docs/specs/auto-update.md`** — Standalone auto-update: check → approved download → install-on-quit, the Baseboard notice, Windows sidecar teardown, per-platform quit behavior.
Expand Down
9 changes: 6 additions & 3 deletions docs/specs/dor-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,16 @@ Header rewriting:
| request | `Accept-Encoding` | deleted, so HTML comes back identity for rewriting |
| request | `Cookie` | dropped, including WebSocket handshakes |
| response | `Set-Cookie` | dropped, including successful and refused WebSocket handshakes |
| response | `X-Frame-Options`, `Content-Security-Policy`, `Content-Security-Policy-Report-Only` | with validated chain, replaced **whole** by `frame-ancestors 'self' <validated chain>` (rationale) |
| response | `X-Frame-Options`, CSP headers | with validated chain, replaced by `frame-ancestors 'self' <validated chain>`; opted-in CSP policies remain alongside it (rationale) |
| response | `X-Dormouse-Preserve-CSP: 1` | consumed; preserves upstream CSP headers and meta policies |
| response | hop-by-hop (RFC 7230 §6.1) | dropped |
| response | `Location` | upstream origin rewritten back to the proxy origin, so a redirect stays inside the proxy |
| response body | `<meta http-equiv="content-security-policy">` | removed, like the header |
| response body | `<meta http-equiv="content-security-policy">` | removed unless the response opts into CSP preservation |

**Must update this table whenever header rewriting changes.**

**Must preserve enforced and report-only CSP verbatim when the upstream response sends `X-Dormouse-Preserve-CSP: 1`.** Add the validated ancestor policy separately, for every MIME type; preserve meta policies during HTML instrumentation. Never infer this opt-in from request headers. Additional upstream restrictions may prevent framing or shim execution. (rationale)

**One dedicated `127.0.0.1:0` server per grant, with no token in the path** — the
origin itself is the grant boundary (rationale). Grants have a sliding idle TTL
and a hard cap; **a request refused by the `Host` check must not refresh the
Expand Down Expand Up @@ -556,7 +559,7 @@ Security boundaries:
- no user script is injected,
- link-local/cloud-metadata ranges are blocked,
- every other user-supplied `http://` target is trusted as the user's command,
at the cost of the upstream's own XSS policy inside the frame.
at the cost of the upstream's own XSS policy unless it opts into preservation.

**Must replace framing controls with exactly `frame-ancestors 'self'
<validated embedder chain>`.** `'self'` permits same-grant nesting; foreign
Expand Down
2 changes: 2 additions & 0 deletions docs/specs/dor-browser.rationale.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ A post-open blank-tab sweep can become such a query when a later relaunch, expli

**Why CSP is dropped whole rather than per-directive.** The injected shim is an inline script, so a surviving `script-src` blocks it as surely as `frame-ancestors` blocks the frame; salvaging the remaining directives would leave a frame that looks instrumented and silently is not.

The built-in local-file viewer supplies its own content boundary and permits the inline shim, so removing its CSP would expand active documents' resource access. Its response opts into preservation without new renderer or host-bridge state. The proxy adds an independent ancestor policy: CSP policies intersect, so no directive parser or partial reconstruction can accidentally weaken the upstream. An opt-in upstream with stricter framing or script restrictions keeps those restrictions even if the shim cannot run.

**Why a grant gets its own origin instead of a path token.** A dedicated origin keeps root-relative resources and client-side routers working with no body URL rewriting; a path token would have to survive every link, redirect and `fetch` the page makes.

## Iframe Shim
Expand Down
4 changes: 3 additions & 1 deletion docs/specs/dor-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ and Tauri's `resource_dir()` hands out a verbatim prefix (rationale).
misparses LF-only batch files (rationale), and staging copies bytes verbatim.
`.gitattributes` pins it (`*.cmd text eol=crlf`; the POSIX launcher `eol=lf`).

**Must keep browser-shared CLI modules free of Node runtime dependencies**, even though the CLI package uses Node types. `dor/test/browser-shared.test.mjs` bundles their dependency graphs for the browser. (rationale)

### Git Bash PATH survival

**On Windows the `PATH` prepend must survive Git Bash / MSYS login:** the PTY
Expand Down Expand Up @@ -645,7 +647,7 @@ Source of truth: `buildDorSurfacesInternal` in `lib/src/components/Wall.tsx`; `d

## Dor Tools

**Must route `dor tool` and `dor open` through the Tool launch contract**, including feature gating, approval, explicit-key reuse, and focus-neutral placement (`docs/specs/dor-tool.md` → CLI). Generated help owns syntax.
**Must route `dor tool` and `dor open` through the Tool launch contract**, including approval, explicit-key reuse, and placement (`docs/specs/dor-tool.md` → CLI). Generated help owns syntax.

Source of truth: `toolCommand` in `dor/src/commands/tool.ts`; `openCommand` in `dor/src/commands/open.ts`; `ToolSurfaceResponse` in `dor/src/commands/types.ts`.

Expand Down
2 changes: 2 additions & 0 deletions docs/specs/dor-cli.rationale.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## Bundling And PATH

The file viewer needs Node types, but the renderer imports CLI protocol and shell helpers as values. A browser-platform bundle check rejects Node imports in those helpers and their dependencies without splitting the CLI into separate TypeScript projects.

**What a missing `ELECTRON_RUN_AS_NODE` looks like.** Under VS Code `DORMOUSE_NODE` is the editor's Electron binary — Node only when that variable is set, and terminals routinely strip it from the ambient env. Without it Electron launches its GUI, ignores the script, and exits 0: no error, no output, success exit code, reading as "the command did nothing" rather than as a launcher bug.

**Why the standalone's bundled node is GUI-subsystem.** A console-subsystem node pops a stray terminal window every time Rust spawns the sidecar, so the bundled binary is patched to the GUI subsystem — and that same patch leaves it no console to inherit.
Expand Down
Loading
Loading