Repository navigation
Conversation
Design Review (Opus 5.5, fork) — ✅ PASS (a BLOCK with no Trigger and no Outcome does not block)Design-level review of Design-Verdict: PASS cannot evaluate: missing screenshot of the Import cookies dialog and the cookie status chip. The PR adds a new panel surface under BlockersNo rendered evidence for the new Browser panel controls Notes
[DESIGN-REVIEWED] b0de981 Description read[DESCRIPTION-READ] 3f8f75706626ba89431f929bf9a5b1a49dd28c862577ceca04a4e34f2344b9aa That sha256 names everything this verdict read: the PR description, plus the 1 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with |
Opus 5.5 Review (fork) — 🔴 changes requested (blocking)Reviewed Importing cookies writes the full cookie file to a temporary file in the data-home root first, and that temp name is not masked from agent sandboxes. The PR says the stored cookies are bind-masked out of every sandbox; this temp file is not. BLOCKING — src/kiro_crew/browser_cli/cookies.py:397 |
First Principles Review (Opus 5.5, fork) — ✅ PASSPremise-level review of First-Principles-Verdict: PASS Nothing blocks. Every item has a named harm and there is no product-shape change. Three subtractions are left: a second transport used only by Clear, two API fields nothing reads, and a new name for a cookie leaf that is already masked. Notes
What this change shipsInventory (10 items) — 7 justifiedIntent: let the owner of a remote gateway sign the agent's browser in by importing cookies from their own logged-in browser — ADDITION.
[FIRST-PRINCIPLES-REVIEWED] b0de981 Description read[DESCRIPTION-READ] 23f9f12e4adf575ae9989d18ff9a40bbd29ad608d03ceeac9d3854e62b0ff553 That sha256 names the PR description this verdict read. Recompute it with |
GPT 6.1 Review (fork) — 🔴 changes requested (blocking)Reviewed 3 of 4 blocking finding(s) are security-class and were withheld from adjudication, so the blocking verdict stands. BLOCKING -- src/kiro_crew/browser_cli/cookies.py:895 -- Serialize watcher injection with import and clear
BLOCKING -- src/kiro_crew/browser_cli/cookies.py:658 -- Enforce the absolute deadline during reply reads
BLOCKING -- website/src/hooks/useBrowserCookies.ts:98 -- Refresh all session-scoped cookie-status caches
BLOCKING -- website/src/components/WebPreviewCookies.tsx:310 -- Surface cookie-status and live-injection failures
[BLOCK-MERGE] b0de981 Adjudication (Opus 5.5) — is blocking on each finding proportionate?F2 — MEDIUM, agent-triggerable. A peer on a |
|
Addressed the GPT 5.6 findings and the CI failures on cookies.py:54 — imported credentials exposed to the agent (BLOCKING). Fixed. client.ts — restricted sessions bypass cookie isolation (BLOCKING). Fixed. messaging.py:4010 — clearing leaves live sessions authenticated (BLOCKING). Fixed. DELETE runs feature map (BLOCKING). The Browser-panel row now lists Import cookies / read-only chip / Clear, the More-actions navigation, errors-use-error-notice (BLOCKING). A failed import (400/5xx) renders through max-two-buttons-per-row (BLOCKING). The header cookie button is gone and the chip is read-only (status + domain tooltip). Import and Clear are items in the existing "More actions" overflow; Clear is two-step (arm → "Click again to clear", menu stays open via top-level-imports (finding). CI on Not verified live: the pre-warm path with the real CLI on a running gateway (launching a browser from the sandbox that wrote this was refused); it rests on the daemon reading |
d4b6cce to
ff18b5b
Compare
|
Follow-up in cookies.py — deeply nested JSON crashes the handler (BLOCKING). cookies.py — non-finite expiry corrupts the persisted state (BLOCKING). check-bundle-size.mjs — undeclared build-gate change (finding). Declared, not dropped: the |
Security Scope Review (fork) — 🔴 BLOCK (blocking)Which legitimate operations does the per-platform reports could not be folded Scope-Verdict: PASS Reason: The only stricter rule is one new exact-name leaf, TIGHTENING: Exact-name secret leaf added to the file-tool read+write fence and to the OS sandbox mask. The ONE threat it refuses is an agent reading the owner's imported session cookies off disk, through its file tools or through ADJUDICATED: 17 candidates, 0 confirmed newly-refused PLATFORM COVERAGE: Candidates cover posix, windows and any. The posix rows use UNADJUDICATED:
[SCOPE-REVIEWED] b0de981 |
ff18b5b to
ee62663
Compare
|
Round 3 in cookies.py — gateway pre-warmed daemon bypasses the OS sandbox (BLOCKING). Accepted and removed entirely: acp/client.py — filesystem I/O on the event loop (BLOCKING). Moot: nothing cookie-related runs at agent spawn any more; both spawn sites are unchanged from messaging.py — concurrent import and clear (BLOCKING). One module-level cookies.py — Frontend Tests (2) — bn |
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value.
b0de981 to
c52591f
Compare
|
|
|
|
|
This change continues in #23332, a branch of this repository, because the Sensitive Change Review gate cannot pass a fork PR that touches the sandbox and security path lists. The content is this PR's head rebased onto current main, plus two fixes for checks that were red here (a docs lint path and the regenerated pseudolocale). Your authorship is kept with a |
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value. Supersedes #12377 Co-authored-by: Alejandro Diez Crespo <alejacre@amazon.com>
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value. Supersedes #12377 Co-authored-by: Alejandro Diez Crespo <alejacre@amazon.com>
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value. Supersedes #12377 Co-authored-by: Alejandro Diez Crespo <alejacre@amazon.com>
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value. Supersedes #12377 Co-authored-by: Alejandro Diez Crespo <alejacre@amazon.com>
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value. Supersedes #12377 Co-authored-by: Alejandro Diez Crespo <alejacre@amazon.com>
…oard Add "Import cookies" to the Browser panel. The dashboard owner exports cookies from the browser where they are logged in (a Playwright storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscape cookies.txt) and imports them. The gateway normalises them into an owner-only storageState under the data home, a leaf masked from every agent sandbox and fenced at the tool gate, and hands them to the agent's own browser daemons over each daemon's control socket: one cookie-set request per cookie in the daemon's newline-delimited JSON protocol, sent from the gateway process, so no cookie value is ever on an argv. Live sessions get them at import; a gateway-side watcher reaches sessions that start later. Clear removes the file and runs cookie-clear on live sessions. GET/POST/DELETE /api/browser/cookies are owner-only, refused in a restricted session, SEL-audited with counts and domains only, and capped at 2 MiB and 5000 cookies. The summary the panel shows never carries a cookie value. Supersedes #12377 Co-authored-by: Alejandro Diez Crespo <alejacre@amazon.com>
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
…oard Adds Import cookies and Clear cookies to the Browser panel. The gateway parses a Playwright storageState, a browser extension JSON export or a Netscape cookies.txt, stores it in a directory masked from the agent in every sandbox mode, and hands the cookies to the agent's own browser over its control socket, so a remote gateway's browser can start signed in. The dialog says in plain words where the values are saved (only on the computer running the product), and the two late status read tests wait on the read completing instead of a fixed delay. Supersedes #12377.
Problem / Motivation
Goal: one click in the dashboard, no config editing, no restart, values never shown: the agent's browser sessions on a remote gateway start signed in from cookies the owner imports.
On a remote gateway (the common cloud-desktop-over-SSH setup) the agent's browser has no way to become a logged-in browser.
attach --extensionneeds the CLI and the user's browser on the same machine, and the dashboard's own address bar is owner-only by design. The only path today is a hand-writtenPLAYWRIGHT_MCP_CONFIGpointing at a storageState the user assembled themselves, which is undocumented for most users and silently ignored when the file is wrong. Related asks: #6546, #12319, #11382.The Codex desktop app solves the same gap with an "Import cookies" button. This PR adds the equivalent to the Browser panel.
Why it matters
Any user whose gateway runs somewhere other than their laptop cannot have the agent read a page behind their SSO today without a manual config edit. Every "open this internal page for me" turn stops at a login form, and the failure looks like an expired session rather than a missing capability.
Not a goal
What changed (motivation → approach → change)
The Browser panel gets Import cookies and Clear cookies in its overflow menu, plus a read-only chip that shows how many cookies are stored, for which sites and when the first one expires. The owner pastes or uploads a cookie export from the browser they are logged into, and the agent's browser sessions start signed in. A session that refuses the set, or a status read that keeps failing, is said in an error notice rather than hidden; every open slot shows the same stored set.
browser_cli/cookies.py)storageState, a Cookie-Editor / "Get cookies.txt" JSON export, or Netscapecookies.txt; normalises to Playwright's cookie shape, drops expired cookies, caps input at 2 MiB / 5000 cookies, and writesbrowser-cookie-import/storage-state.json(0600, in a 0700 directory) under the data home.browser-cookie-importdirectory is masked in every sandbox mode (sandbox_leaves.py), made before every spawn so the mask always mounts (sandbox_precreate.py), and fenced at the tool gate (security/paths_lists.py). A sandbox started before the first import, and the write's temp file, both stay behind the mask. No config the agent or its daemon reads names it.cookie-setrequest per cookie in the daemon's own newline-delimited JSON protocol. No process is spawned, so a cookie value is never on any argv, and a failure reports a fixed reason, never reply text. Every exchange is bounded by one absolute deadline, re-applied before each read. Live sessions get them at import; a gateway thread (SessionWatcher) reaches sessions that start later. It starts only once a set is stored (server_runtime/browser_lifecycle.pyand the import route), never where the platform has noAF_UNIX, and it shares one lock with import and clear, so a clear cannot be undone by a tick in flight.messaging_api/browser_routes.py,server_runtime/mcp_routes.py)GET/POST/DELETE /api/browser/cookies: owner-only, refused in a restricted session, SEL-audited with counts and domains only, import and clear serialised by one lock.WebPreviewCookies.tsx,useBrowserCookies.ts, the client endpoints inapi/client/browserAndComputerUse.ts, 20 keys in everywebsite/src/i18ncatalog, and a dev-only capture harness (website/capture/cookie-import.tsx) for the screenshots below.Docs:
docs/system-specs/modules/browser.md, the agent-facingsrc/kiro_crew/docs/browser-control.md, and the feature map.Backwards compatibility
Compatible: every change is additive;
desired_config()is unchanged, and no existing route, key or file changes shape.Removes nothing: the diff only adds a stored file, three routes and panel controls.
Tests
test/test_browser_cookies.py: the three parsers and their normalisation, limits, the 0600 write, the value-free summary, thecookie-setrequest shape, injection over a faked socket (one request per cookie, stop at first failure, fixed value-free reasons for refused / malformed / timed-out / unreachable daemons, a trickled reply ending at the deadline, and that no process is spawned), one round trip over a realsocketpair, the watcher (no thread before a set exists or withoutAF_UNIX, ticks under the import/clear lock), the pre-created masked directory, and the three handlers (owner 403, restricted 403, both locks held). Injection tests skip where the platform has noAF_UNIX.test/test_handlers_messaging_composition_contract.py,test/test_json_object_body_guard.py,test/spawn_audit_helpers.py,test/test_browser_cli_journeys.py,test/test_sandbox_governance_mask.py,test/test_dashboard_server_composition_contract_reach.py,test/test_sandbox_protected_name_holds.py,test/test_security_gate_liveness.py: the repository guards name the new routes and their order, the body read, the two value-free spawns (list,cookie-clear), the masked directory, its one new protected name per tier and one more line in the security package.website/src/test/useBrowserCookies.test.tsx,website/src/test/WebPreviewPanel.cookies.test.tsx,website/src/test/ApiClient.refactor.surface.test.ts: status, import, 400 inline error, a partial live failure kept on screen, a failing status read settling into a notice after bounded retries, another slot refetching after import and clear, clear, chip, 403 hides the control, the two-buttons-per-row guard, and the three client methods in the pinned key order.Manual verification
Against a real
playwright-clidaemon on Linux: started a session, sent cookies through the socket path, andcookie-listshowed them, including a name and value starting with-and a fractional expiry; a cookie with an invalidsameSitecame back as "the browser refused the cookie". Not verified: Windows, where the injection reports "unsupported platform" because the daemon socket is a named pipe there.Screenshots / video
Import dialog (file picker or paste):
Status chip in the Live view header after an import (domains in the tooltip, two-step Clear):
Related Issues
Related asks: #6546, #12319, #11382. No tracking issue yet.
Checklist