m4/org/openalice-browseci ok

openalice-browse

[Atlas card](https://atlas.blal.pro/repos/openalice-browse)

Features
5
Status
·unknown
Last activity
1mo ago
Branch
mvp

Architecture rating

C1mo ago
consistencyB

Clean AST — 0 circular deps, 0 dead imports, 0 god modules, 0 naming violations, avg complexity 3.0 — and explicitly built as the sibling of openalice-pty following shared health/metrics/manifest conventions; minor drift (undeclared BROWSE_INTERNAL_SECRET, 1 format issue) keeps it below exemplary.

docsB

Valid present manifest with a clear summary, 7 enumerated exposed endpoints, 5 @feature annotations, AGENTS.md, README and a live Atlas card drive a strong docs score; weakened by 17 missing docstrings and a thin roadmap (Atlas roadmap 30/100).

observabilityB-

GET /metrics Prometheus exposition and a working GET /health probe (matched, status 200) are present and live-verified; however 13 console statements suggest ad-hoc logging rather than structured logs, and no tracing signal — solid basics, gaps in log discipline and distributed tracing.

securityC

Manifest exposes auth-sensitive session/command HTTP+WS endpoints and Atlas flags an undeclared-but-used BROWSE_INTERNAL_SECRET implying shared-secret auth exists, but it's undocumented/drifting; a headless-browser command channel (navigate/click/type) is inherently SSRF-prone and no rate-limit, security-header, or input-guard signal is present, so authz depth is unverified — grading conservatively.

testingC-

Four focused test files (session, session-unit, command-endpoint, registry) cover the core session lifecycle and command path with passing CI (2026-05-22), but it's a small count for a CDP/WebSocket screencast service — no evidenced streaming, SSRF, or failure-path regression tests, so critical-path coverage is partial.

data layerC-

Stateless service: manifest_owns_tables is empty and there are no migrations — sessions are in-memory (registry.test.js), so no schema/RLS/FK/GDPR surface to evaluate; scored neutral-conservative as not-applicable rather than well-engineered persistence.

reliabilityD

Health endpoint live (200, 100% 24h uptime) and low complexity (avg 3, max 11) help, but 3 bare/broad excepts plus a long-lived Chromium/CDP+WebSocket service with no evidenced graceful-shutdown, timeout, retry, or session-reaping signal is a real risk for leaked browser processes; idempotency on session/command unverified.

source · auto-grader-2026-06-16

Ecosystem manifest

.atlas-deps.yml

Headless Chromium browser service — Playwright CDP screencast over WebSocket, JSON command channel for click/type/navigate. Sibling of openalice-pty.

Runtime deps
  • via INTERNAL_SECRET
    Agent Desktop BrowserApp connects over WS to receive JPEG screencast frames and send click/type/navigate commands
Consumed env
  • INTERNAL_SECRET
  • BROWSE_PORT
  • BROWSE_HEADLESS
  • BROWSE_DEFAULT_URL
  • BROWSE_PUBLIC_HOST
  • BROWSE_PUBLIC_WS_SCHEME
Exposes
  • http_endpoint: POST /v1/sessions — create browser session
  • http_endpoint: GET /v1/sessions — list sessions
  • http_endpoint: DELETE /v1/sessions/:id — close session
  • http_endpoint: POST /v1/sessions/:id/command — send command to session
  • ws_endpoint: ws://.../v1/sessions/:id/stream — JPEG screencast stream
  • http_endpoint: GET /health
  • http_endpoint: GET /metrics — Prometheus exposition
Env drift · manifest ⇄ code

Atlas grepped the repo's source for env reads (rust env::var · ts process.env · py os.environ · shell $VAR) and diffed against the manifest's consumes_env. Two lists below: stale declarations and undeclared reads.

Code reads, manifest omits
  • BROWSE_INTERNAL_SECRET
Observed reads: 7 · declared: 6

Code composition

tokei · loc
1.4kloc
  • JavaScript93.4%
  • YAML3.3%
  • JSON1.8%
  • Dockerfile1.4%
  • JavaScript93.4%· 1,264
  • YAML3.3%· 45
  • JSON1.8%· 25
  • Dockerfile1.4%· 19
Language% codecodecommentsblanksfiles
JavaScript93.4%1,2642741657
YAML3.3%452532
JSON1.8%25001
Dockerfile1.4%1920101
Markdown0.0%091412

Telemetry ribbon · last 90 days

2 events
MAYJUNJUL2026-05-21 · commit · new commit 62700d6 → 56067c72026-05-22 · commit · new commit 56067c7 → 8404b6aNOW
commitmanifestlifecyclekind

browse/api

2 features
  • browse.api.command-dispatch
    src/main.js:164
    Agent-side control endpoint — POST a single JSON command into an existing session. Body shape mirrors the WebSocket frames session.dispatch() already handles, so the openalice-live-control dispatcher (and any future server-side caller) can drive click / type / navigate / etc. without holding a WS open. 200 returns whatever session.dispatch produces (or `{ ok: true }` for fire-and-forget commands). 404 when session is missing, 400 when dispatch surfaces an `error` reply.
  • browse.api.session-lifecycle
    src/registry.js:4
    Maintains the authoritative `Map<sessionId, Session>`. Exposes add / get / list / remove for the HTTP control plane. The idle sweep (`startSweep`) runs every 15 s and closes sessions whose last WebSocket client disconnected more than `idleTimeoutMs` ago (default 60 s) — preventing zombie Chromium tabs from accumulating. @feature browse.ops.observability Tracks `metrics.totalScreencastFrames`, `totalSessionsCreated`, and `totalSessionsClosed` in-process counters that `GET /metrics` exposes as Prometheus text. v0 is single-process: one Chromium browser instance, one Map of sessionId -> Session. Per-tenant browser pods come later; for now we rely on Playwright's BrowserContext for isolated cookies and local-storage between sessions inside the same Chromium process. Idle sweep: every 15s we look for sessions that have had no subscribed WS clients for `idleTimeoutMs` (default 60s) and tear them down. Keeps zombie tabs from piling up if a frontend window is closed without sending DELETE.

browse/core

2 features
  • browse.core.cdp-screencast
    src/main.js:4
    Boots a single shared headless Chromium via Playwright. Sessions use CDP `Page.startScreencast` to stream JPEG frames; each frame is forwarded as a binary WebSocket message to every subscribed client. @feature browse.api.session-lifecycle Express HTTP control plane: POST/GET/DELETE /v1/sessions manage the session lifecycle. GET /health and GET /metrics are public probes; all other routes require x-internal-secret or ?token= auth. Boots: - one shared headless Chromium via Playwright - an Express HTTP control plane (POST/GET/DELETE /v1/sessions, /health, /metrics) - a `ws` server bound to the SAME http.Server, only handling the /v1/sessions/:id/stream upgrade path Auth model — v0: Every HTTP entrypoint (except /health) requires `x-internal-secret: $INTERNAL_SECRET` OR `?token=$INTERNAL_SECRET` (WS upgrade only supports query-string tokens because browsers can't add custom headers to WebSocket handshakes). This service is intended to live behind Traefik on the internal `proxy` network and never be reached directly from the public internet. Process model — v0: Single Node process, single Chromium. Each session is its own BrowserContext (isolated cookies / localStorage). For real multi-tenant isolation, fan out to a per-tenant Docker pod and run one of these services in each.
  • browse.core.cdp-screencast
    src/session.js:4
    Starts a CDP screencast (`Page.startScreencast`) on the session's Page. Each `Page.screencastFrame` event is decoded from base64 and broadcast as a binary WebSocket frame to every subscribed client. Frame acks (`Page.screencastFrameAck`) are sent immediately so CDP never stalls due to an unacknowledged backlog. @feature browse.api.command-dispatch `dispatch(message)` routes JSON command objects — click, mousemove, type, key, navigate, scroll, resize, screenshot, url — to the corresponding Playwright / CDP method. Both the WebSocket handler (main.js) and the HTTP command endpoint call this same method. Lifecycle: 1. constructor stashes options. 2. start() creates the BrowserContext from the shared Browser, opens a Page, navigates to the requested URL, attaches a CDPSession and starts the JPEG screencast. 3. attachClient(ws) subscribes a WS to receive binary frames. Multiple clients per session are allowed; useful for the "share my browser" review flow. 4. dispatch(message) accepts a single JSON command and routes it to the right Playwright/CDP method. 5. close() stops the screencast, closes the page, closes the context. Browser stays alive for the next session. Coordinate space: the screencast frames the frontend renders are `viewport.width x viewport.height` device-pixels. Click coords sent back to us MUST be in that same pixel space — the BrowserApp is responsible for mapping mouse events through the canvas bounding rectangle.

browse/ops

1 feature
  • browse.ops.observability
    src/main.js:100
    no description