1/**
2 * webPreferences override applied to every preview `<webview>` element via
3 * its `webpreferences="..."` attribute. Single source of truth so all guest
4 * surfaces inherit the same security posture.
5 *
6 * Lives in its own electron-free module so the value is unit-testable
7 * without importing `Manager.ts` (which transitively imports
8 * `electron` and blows up under vitest).
9 *
10 * - `contextIsolation=false`: the picker preload needs to share `globalThis`
11 * with the page so react-grab/bippy can read the React DevTools hook
12 * (`__REACT_DEVTOOLS_GLOBAL_HOOK__`) and resolve component names. Without
13 * this every pick comes back with `componentName: null` even on dev React
14 * apps.
15 * - `sandbox=true`: keeps the OS-level renderer sandbox enabled. Critical
16 * when paired with `contextIsolation=false` — without sandbox, the preload
17 * has full Node access (`require`, `fs`, `child_process`, ...) and that
18 * `require` would land on the page's shared `globalThis`, giving any
19 * third-party page in the preview full Node + IPC access to the host.
20 * In sandboxed mode Electron still synthesizes the `electron` module for
21 * the preload's `import { ipcRenderer }` line, but no Node globals leak.
22 * - `nodeIntegration=false`: pinned for clarity (the page itself never gets
23 * Node access).
24 *
25 * Format notes (locked down by `WebviewPreferences.test.ts`):
26 * - Whitespace-free. Electron's webpreferences parser splits on `,` and
27 * does not trim, so a leading space would turn a key into an unknown one
28 * and silently drop it.
29 * - Values are JS-boolean strings (`true`/`false`) — `yes`/`no` are not
30 * special-cased by the parser; `value="no"` becomes the truthy STRING
31 * `"no"` when assigned to a boolean webPreferences key. Most critically,
32 * `contextIsolation="no"` is truthy → contextIsolation stays ENABLED →
33 * react-grab can't see the React DevTools hook.
34 *
35 * Defense in depth: `apps/desktop/src/main.ts` also runs a
36 * `will-attach-webview` handler that force-sets `sandbox: true` and
37 * `nodeIntegration*: false` on the actual webPreferences object, gated on
38 * the preview partition, so even if this string is ever wrong, the
39 * security-critical flags can't regress on preview tabs.
40 */
41export const PREVIEW_WEBVIEW_PREFERENCES =
42 "contextIsolation=false,sandbox=true,nodeIntegration=false";