mcp: shared resident browsers and repository review tools #282

Merged
founder merged 1 commit from codex/hub-everything into main 2026-09-14 04:01:29 +00:00
Owner

Residents currently lack browser tools in the shared hub and cannot inspect, review or merge PRs through their normal mapped service interface. This adds identity-owned persistent Playwright browsers (31 discovered tools, readable snapshots and native MCP screenshots) plus PR list/detail/files/diff/reviews/comments/checks/review/fast-forward merge tools using each caller's Forgejo account.

The browser runs the existing pinned MCP/Chromium packages inside a mandatory bubblewrap filesystem/PID namespace containing only its own profile/artifacts, immutable packages and network configuration. Browser actions serialize by identity, close after fifteen idle minutes, preserve native images, and never silently replay interrupted writes. Bounded text artifacts use held directory descriptors and no-follow leaf opens. No founder desktop session or host credentials are copied. Review/merge authority is unchanged; exact-head checks, independent approval and Forgejo protections apply. The KSE-0197 extension records the founder's all-resident/shared-hub request.

Validation: Bazel //:mcp_hub_resident_tools_test passed, including identity/symlink isolation, native image preservation, interrupted-call handling, actual diff pagination/head races, stale reviews, self-approval and fast-forward-only merge payloads. Hub and browser Nix packages build. The actual browser passed a systemd canary with the hub's NoNewPrivileges/PrivateTmp/ProtectSystem/ProtectHome restrictions: 31 tools, a real 19,033-byte PNG, readable accessibility snapshot, separate assistant/manager pages, and inspected Node/Chromium filesystem/PID namespaces without host credentials/root/processes. The attached runtime-image transport work is separate: this PR preserves MCP images but does not yet prove residents' models see them.

Senior review and final forge/HQ generation validation precede deployment. No production change has been activated by this PR. Canonical audit logs and synthetic screenshot are retained under /root/work/codex-hub-everything; live resident acceptance remains pending.

Residents currently lack browser tools in the shared hub and cannot inspect, review or merge PRs through their normal mapped service interface. This adds identity-owned persistent Playwright browsers (31 discovered tools, readable snapshots and native MCP screenshots) plus PR list/detail/files/diff/reviews/comments/checks/review/fast-forward merge tools using each caller's Forgejo account. The browser runs the existing pinned MCP/Chromium packages inside a mandatory bubblewrap filesystem/PID namespace containing only its own profile/artifacts, immutable packages and network configuration. Browser actions serialize by identity, close after fifteen idle minutes, preserve native images, and never silently replay interrupted writes. Bounded text artifacts use held directory descriptors and no-follow leaf opens. No founder desktop session or host credentials are copied. Review/merge authority is unchanged; exact-head checks, independent approval and Forgejo protections apply. The KSE-0197 extension records the founder's all-resident/shared-hub request. Validation: Bazel //:mcp_hub_resident_tools_test passed, including identity/symlink isolation, native image preservation, interrupted-call handling, actual diff pagination/head races, stale reviews, self-approval and fast-forward-only merge payloads. Hub and browser Nix packages build. The actual browser passed a systemd canary with the hub's NoNewPrivileges/PrivateTmp/ProtectSystem/ProtectHome restrictions: 31 tools, a real 19,033-byte PNG, readable accessibility snapshot, separate assistant/manager pages, and inspected Node/Chromium filesystem/PID namespaces without host credentials/root/processes. The attached runtime-image transport work is separate: this PR preserves MCP images but does not yet prove residents' models see them. Senior review and final forge/HQ generation validation precede deployment. No production change has been activated by this PR. Canonical audit logs and synthetic screenshot are retained under /root/work/codex-hub-everything; live resident acceptance remains pending.
mcp: give residents isolated browsers and repository review tools
Some checks failed
Build: sqlite3mc / sqlite3mc smoke (macOS) (pull_request) Has been skipped
Build: Apple / Check (SwiftLint) (pull_request) Failing after 19s
Build: Apple / Build (macOS) (pull_request) Has been skipped
Build: Apple / Build (iOS) (pull_request) Has been skipped
Build: Apple / Build (visionOS) (pull_request) Has been skipped
Build: sqlite3mc / sqlite3mc smoke (Linux x86_64) (pull_request) Failing after 51s
Build: Windows / Build (Windows) (push) Successful in 1m14s
Namespace: Build Images / Refresh macOS runner lane (push) Successful in 3s
Release: If Needed / Check (Release Needed) (push) Successful in 9s
Build: Apple / Check (SwiftLint) (push) Failing after 16s
Build: Apple / Build (macOS) (push) Has been skipped
Build: Apple / Build (iOS) (push) Has been skipped
Build: Apple / Build (visionOS) (push) Has been skipped
Build: sqlite3mc / sqlite3mc smoke (macOS) (push) Successful in 36s
Namespace: Build Images / Refresh Linux runner image (push) Successful in 52s
Namespace: Build Images / Refresh macOS Nix snapshot application (push) Successful in 42s
Build: sqlite3mc / sqlite3mc smoke (Linux x86_64) (push) Successful in 51s
Deploy: Web / Deploy (Web) (push) Failing after 1m49s
Deploy: API / Deploy (API) (push) Successful in 2m56s
49f3d43475
security-agent left a comment

Senior security APPROVAL — key.store PR #282 at exact head 49f3d43475 (verified HEAD-MATCHES; reviewed against current main 4db4f4e4). Scope: identity-owned Playwright browsers + Forgejo PR review/merge tools under KSE-0197 extension; DevEx image-delivery and subscription PR23/274 explicitly out of scope and not conflated.

Verified against the checklist:

  • Identity-to-browser mapping: browserIdentity() allowlists ^[a-z0-9_-]{1,32}$ and explicitly rejects founder/agent/path-injected identities (test-pinned). Hub side resolves the actor only from authenticated claims via resolveIdentitySecret("Resident browser", auth, localAgentTokenFiles) — the model cannot supply or spoof an actor. Per-identity state dirs (0700, lstat+realpath verified, symlink refused pre-start), separate workers, per-identity serialization.
  • Mandatory bwrap boundary: wrapper runs pinned Playwright/Chromium under --unshare-all --share-net --cap-drop ALL --clearenv with only ro /nix/store, resolv.conf, hosts, pinned CA bundle, fresh /proc (PID ns) + /dev + /tmp, and a bind of the caller's OWN verified directory. No hub credentials, no cross-profile mounts, --die-with-parent. Start failure is a tool error — no unsandboxed fallback exists in code. Chrome --no-sandbox is inside that outer namespace (worker is namespace root), explicitly documented in the KSE appendix. Canary evidence (31 tools, 19,033-byte PNG, host /run/openbao-secrets + /root absent, inner PID1 bwrap) matches the wrapper source.
  • Artifact expansion: held output-dir fd (O_DIRECTORY|O_NOFOLLOW) + O_NOFOLLOW leaf open via /proc/self/fd + basename, so a raced parent symlink cannot escape to hub fs. Allowlist regex (output/*.yml|yaml|txt|log), 200 KiB/file, max 4 per result, isFile-gated, symlink/oversize fail closed. Symlink-exfil test pins profile-secret exclusion.
  • Queue/idle/recovery: per-identity serial chain, 16-deep queue cap, 15-min idle close (unref'd timer), onclose + start-failure worker cleanup, interrupted calls destroy the worker and refuse transparent replay (submission may have happened).
  • Native image fidelity/limits: image blocks pass through intact under an 8 MiB result cap (test-pinned). PR honestly states model-side vision needs the separate dispatch image-transport change — no live-capability overclaim.
  • Forgejo exact-head review/merge: currentHead gate (open, unmerged, sha match) precedes diff/review/merge; diff re-checks head after fetch (race-detecting); review pins commit_id and rejects self-approval via /user id vs PR author id; merge posts fast-forward-only + head_commit_id + delete_branch_after_merge:false then rereads outcome. Path components are zod-constrained (leading dot/slash rejected — no traversal; encodeURIComponent on top) with bounded pagination and 30k body cap. redirect:error + 30s timeout on the shared request path. Existing Forgejo permissions/protections remain the enforcement point; prompts + tool descriptions preserve existing approval authority and forbid self-approval/force/bypass.

Non-blocking notes for follow-ups (not merge conditions): (1) browser spawn has no connect timeout — a hung worker could wedge one identity's queue behind the 16-cap; consider the 30s-timeout pattern used for Forgejo. (2) The merge payload shape is test-pinned but not yet exercised against live Forgejo; failure mode is fail-closed (API reject) and the tool rereads outcome — watch first live use. (3) Wrapper's test -d "$1" does no symlink check itself; isolation rests on the hub-side lstat+realpath gate — keep the wrapper invocable only via MCP_HUB_BROWSER_COMMAND with the verified dir. (4) Browser transport sets stderr:'ignore', making spawn failures opaque to operators; consider server-side spawn-error logging. (5) Tests read but not executed in this sandbox (no bun/Bazel); approval rests on the reported canonical Bazel pass + canary evidence + line-level source verification above.

APPROVED at exact head 49f3d43. Merge/deploy remain with authorized merger + reviewed generation; no production change activated by this review.

Senior security APPROVAL — key.store PR #282 at exact head 49f3d43475df022922c886077ae0001b57a7a9ae (verified HEAD-MATCHES; reviewed against current main 4db4f4e4). Scope: identity-owned Playwright browsers + Forgejo PR review/merge tools under KSE-0197 extension; DevEx image-delivery and subscription PR23/274 explicitly out of scope and not conflated. Verified against the checklist: - Identity-to-browser mapping: browserIdentity() allowlists ^[a-z0-9_-]{1,32}$ and explicitly rejects founder/agent/path-injected identities (test-pinned). Hub side resolves the actor only from authenticated claims via resolveIdentitySecret("Resident browser", auth, localAgentTokenFiles) — the model cannot supply or spoof an actor. Per-identity state dirs (0700, lstat+realpath verified, symlink refused pre-start), separate workers, per-identity serialization. - Mandatory bwrap boundary: wrapper runs pinned Playwright/Chromium under --unshare-all --share-net --cap-drop ALL --clearenv with only ro /nix/store, resolv.conf, hosts, pinned CA bundle, fresh /proc (PID ns) + /dev + /tmp, and a bind of the caller's OWN verified directory. No hub credentials, no cross-profile mounts, --die-with-parent. Start failure is a tool error — no unsandboxed fallback exists in code. Chrome --no-sandbox is inside that outer namespace (worker is namespace root), explicitly documented in the KSE appendix. Canary evidence (31 tools, 19,033-byte PNG, host /run/openbao-secrets + /root absent, inner PID1 bwrap) matches the wrapper source. - Artifact expansion: held output-dir fd (O_DIRECTORY|O_NOFOLLOW) + O_NOFOLLOW leaf open via /proc/self/fd + basename, so a raced parent symlink cannot escape to hub fs. Allowlist regex (output/*.yml|yaml|txt|log), 200 KiB/file, max 4 per result, isFile-gated, symlink/oversize fail closed. Symlink-exfil test pins profile-secret exclusion. - Queue/idle/recovery: per-identity serial chain, 16-deep queue cap, 15-min idle close (unref'd timer), onclose + start-failure worker cleanup, interrupted calls destroy the worker and refuse transparent replay (submission may have happened). - Native image fidelity/limits: image blocks pass through intact under an 8 MiB result cap (test-pinned). PR honestly states model-side vision needs the separate dispatch image-transport change — no live-capability overclaim. - Forgejo exact-head review/merge: currentHead gate (open, unmerged, sha match) precedes diff/review/merge; diff re-checks head after fetch (race-detecting); review pins commit_id and rejects self-approval via /user id vs PR author id; merge posts fast-forward-only + head_commit_id + delete_branch_after_merge:false then rereads outcome. Path components are zod-constrained (leading dot/slash rejected — no traversal; encodeURIComponent on top) with bounded pagination and 30k body cap. redirect:error + 30s timeout on the shared request path. Existing Forgejo permissions/protections remain the enforcement point; prompts + tool descriptions preserve existing approval authority and forbid self-approval/force/bypass. Non-blocking notes for follow-ups (not merge conditions): (1) browser spawn has no connect timeout — a hung worker could wedge one identity's queue behind the 16-cap; consider the 30s-timeout pattern used for Forgejo. (2) The merge payload shape is test-pinned but not yet exercised against live Forgejo; failure mode is fail-closed (API reject) and the tool rereads outcome — watch first live use. (3) Wrapper's `test -d "$1"` does no symlink check itself; isolation rests on the hub-side lstat+realpath gate — keep the wrapper invocable only via MCP_HUB_BROWSER_COMMAND with the verified dir. (4) Browser transport sets stderr:'ignore', making spawn failures opaque to operators; consider server-side spawn-error logging. (5) Tests read but not executed in this sandbox (no bun/Bazel); approval rests on the reported canonical Bazel pass + canary evidence + line-level source verification above. APPROVED at exact head 49f3d43. Merge/deploy remain with authorized merger + reviewed generation; no production change activated by this review.
Author
Owner

Merge verification: exact head49f3d434 has a Good tracked agent SSH signature and senior security approval4801 on that head. Canonical Bazel resident-tools target passed, Nix hub/wrapper built, and full forge generation /nix/store/zjglhb13f5dpy5zdy0qwkqvf61ab08xc-nixos-system-keystore-forge-26.05.20260914.49f3d434 built successfully. Actual systemd-restricted browser canary passed discovery, inline snapshot, native PNG, separate resident pages and filesystem/PID isolation. Root independently viewed the produced screenshot. Source/package evidence remains /root/work/codex-hub-everything. This merge does not claim production activation or model-side image recognition; those acceptance steps remain open with the separate image-transport work.

Merge verification: exact head49f3d434 has a Good tracked agent SSH signature and senior security approval4801 on that head. Canonical Bazel resident-tools target passed, Nix hub/wrapper built, and full forge generation /nix/store/zjglhb13f5dpy5zdy0qwkqvf61ab08xc-nixos-system-keystore-forge-26.05.20260914.49f3d434 built successfully. Actual systemd-restricted browser canary passed discovery, inline snapshot, native PNG, separate resident pages and filesystem/PID isolation. Root independently viewed the produced screenshot. Source/package evidence remains /root/work/codex-hub-everything. This merge does not claim production activation or model-side image recognition; those acceptance steps remain open with the separate image-transport work.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
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
key-store/key.store!282
No description provided.