Skip to content

Commit d444cee

Browse files
committed
기능: 격리 프레임 자동화 공급자 완성
credentialless sandbox와 인증된 제어 채널로 cooperative 페이지를 제어한다. 관찰, 순차 동작, 이동, 화면 첨부물이 같은 공간 계약과 권한 경계를 공유한다. 검증: test, types, contracts, package, control-product, frame-space, python-sdk 통과
1 parent 55fdc53 commit d444cee

31 files changed

Lines changed: 1873 additions & 28 deletions

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ jobs:
103103
PYPROC_BROWSER: /usr/bin/google-chrome
104104
# 같은 제품 런타임의 언어 중립 Control Protocol, cancel, binary attachment를 설치물에서 검증한다.
105105
- run: npm run test:control-product
106+
- run: npm run test:frame-space
106107
env:
107108
PYPROC_BROWSER: /usr/bin/google-chrome
108109
- run: python -m pip install -r pythonSdk/buildRequirements.txt
@@ -158,6 +159,7 @@ jobs:
158159
- run: npm run test:mcp
159160
- run: npm run test:mcp-product
160161
- run: npm run test:control-product
162+
- run: npm run test:frame-space
161163
- run: python -m pip install -r pythonSdk/buildRequirements.txt
162164
- run: npm run test:python-sdk
163165
- run: npm run test:browser-control

README.ko.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ npx pyproc-engine --out /absolute/path/to/pyodide
282282
"engine": { "root": "/absolute/path/to/pyodide" },
283283
"browser": {
284284
"enabled": true,
285+
"provider": "nativeCdp",
285286
"allowedOrigins": ["https://example.test"],
286287
"maxRisk": "externalEffect",
287288
"actions": ["snapshot", "screenshot", "waitFor", "hydrateLazy", "navigate", "fill", "click"],
@@ -327,6 +328,10 @@ with PyProcClient.start("pyproc-mcp.json") as client:
327328
네 Python 도구만 노출한다. browser를 켜면 lifecycle, compatibility, semantic observation, 순차 action,
328329
별도 allowlist raw command, artifact read/delete를 위한 열 개 도구가 추가된다.
329330

331+
`"provider": "frame"`을 지정하면 DevTools port 없이 cooperative credentialless sandbox를 사용한다.
332+
snapshot 허용 시 browser 도구 아홉 개를 제공하고 raw command는 열지 않으며 target이 출하 bridge를
333+
로딩해야 한다. 정확한 격리와 screenshot 경계는 [FrameSpace 가이드](docs/usage/frameSpace.md)에 있다.
334+
330335
23개 action catalog에는 의미 기반 준비 대기, 명시적 bounded lazy hydration, 정식 순차 `screenshot`
331336
action이 있다. `browserOpen`은 첫 navigation 전에 viewport와 계측을 적용하고 redacted startup trace를
332337
돌려준다. inline 상한 안의 screenshot은 native MCP image content로 바로 도착한다. screenshot과

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ Create `pyproc-mcp.json`, using exact origins and the smallest action set requir
284284
"engine": { "root": "/absolute/path/to/pyodide" },
285285
"browser": {
286286
"enabled": true,
287+
"provider": "nativeCdp",
287288
"allowedOrigins": ["https://example.test"],
288289
"maxRisk": "externalEffect",
289290
"actions": ["snapshot", "screenshot", "waitFor", "hydrateLazy", "navigate", "fill", "click"],
@@ -330,6 +331,10 @@ With `{ "enabled": false }`, the server exposes exactly four Python tools: `pyth
330331
`checkpointRestore`, and `sandboxReset`. Enabling the browser adds ten tools for lifecycle, compatibility,
331332
semantic observation, ordered actions, separately allowlisted raw commands, and artifact read/delete.
332333

334+
Set `"provider": "frame"` for a cooperative credentialless sandbox that opens no DevTools port. It exposes
335+
nine browser tools when snapshot is allowed, omits raw commands, and requires the target to load the shipped
336+
bridge. See the [FrameSpace guide](docs/usage/frameSpace.md) for its exact isolation and screenshot boundary.
337+
333338
The 23-action catalog includes semantic readiness waits, explicit bounded lazy hydration, and a first-class
334339
ordered `screenshot` action. `browserOpen` applies the viewport before navigation and returns the redacted
335340
first-navigation trace. Screenshot results that fit the inline bound arrive as native MCP image content at

docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Language: `usage/`, `reference/`, and `product/` are English. `operations/` is t
3434
| | [controlProtocol.md](usage/controlProtocol.md) | Language-neutral installed control: handshake, operations, cancellation, outcomes, and verified binary attachments |
3535
| | [pythonSdk.md](usage/pythonSdk.md) | Official Python client: clean installation, persistent execution, checkpoint recovery, cancellation, and screenshots |
3636
| | [automationSpace.md](usage/automationSpace.md) | Provider-neutral automation lifecycle, authorization, effect, artifact, restore, and replay boundaries |
37+
| | [frameSpace.md](usage/frameSpace.md) | Cooperative credentialless frame automation, target bridge, sandbox, screenshot, and origin boundaries |
3738
| [reference/](reference/) | [api.md](reference/api.md) | The function-level API reference: the six root exports and the machine handle vocabulary, escape hatches and subpaths, the full error code table (a machine gate forces every root export to be anchored) |
3839
| | [bundleFormat.md](reference/bundleFormat.md) | The canonical layout of the portable bundle (`PYBUNDLE1`) envelope: byte placement, header fields, the separation of integrity from signature |
3940

@@ -56,4 +57,5 @@ Language: `usage/`, `reference/`, and `product/` are English. `operations/` is t
5657
- Language-neutral installed control: [usage/controlProtocol.md](usage/controlProtocol.md)
5758
- Official Python client: [usage/pythonSdk.md](usage/pythonSdk.md)
5859
- Automation provider contract: [usage/automationSpace.md](usage/automationSpace.md)
60+
- Cooperative frame provider: [usage/frameSpace.md](usage/frameSpace.md)
5961
- Contributing from outside: [CONTRIBUTING.md](../CONTRIBUTING.md)

docs/usage/automationSpace.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ not replay a provider operation.
5757

5858
The operation list above is abbreviated. `restoreBoundary` is deliberately fixed: restoring Python never
5959
claims to reverse provider effects. `replayBoundary` describes what that provider can do with a recorded
60-
operation. The current native adapter records evidence but does not replay effects.
60+
operation. The current native and frame adapters record evidence but do not replay effects. FrameSpace
61+
declares `dom`, `target`, `screenshot`, and `artifact`, omits `automation.command`, and keeps the same restore
62+
boundary.
6163

6264
Close is idempotent. After close, every new operation fails with `AUTOMATION_SPACE_CLOSED` before provider
6365
code. The provider is responsible for dropping session-owned locators, observations, lifecycle watchers,

docs/usage/browserAutomation.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ The installed `pyproc-mcp` command runs a persistent Python Machine and a separa
44
automation profile in one stdio MCP session. It ships in the npm package, uses no runtime dependency, never
55
attaches to a normal browser profile, and never puts the CDP endpoint inside Python.
66

7-
The same host is available through `pyproc-control` and the Python SDK. Internally, the Chromium path is the
8-
`NativeCdpSpace` provider behind the [AutomationSpace contract](automationSpace.md). It declares DOM,
7+
The same host is available through `pyproc-control` and the Python SDK. `browser.provider` selects a provider
8+
behind the [AutomationSpace contract](automationSpace.md). The default `NativeCdpSpace` declares DOM,
99
network, target, storage, runtime, screenshot, and artifact capabilities while keeping endpoint and provider
10-
objects private.
10+
objects private. The cooperative [FrameSpace provider](frameSpace.md) uses a credentialless sandbox and no
11+
DevTools port.
1112

1213
## Install and start
1314

@@ -28,6 +29,7 @@ Create `pyproc-mcp.json`:
2829
"timeoutMs": 180000,
2930
"browser": {
3031
"enabled": true,
32+
"provider": "nativeCdp",
3133
"allowedOrigins": ["https://example.test"],
3234
"maxRisk": "externalEffect",
3335
"actions": ["snapshot", "screenshot", "waitFor", "hydrateLazy", "navigate", "fill", "click"],
@@ -78,6 +80,7 @@ and incomplete external-effect approval fail closed.
7880
| `engine.indexURL` | Absolute HTTP(S) directory URL without credentials, query, or fragment |
7981
| `timeoutMs` | Positive integer, at most 900000 |
8082
| `browser.executable` | Optional absolute Chrome, Chromium, or Edge executable. Discovery is used when absent |
83+
| `browser.provider` | `nativeCdp` by default, or `frame` for a cooperative credentialless target bridge |
8184
| `browser.headed`, `browser.gpu` | Optional booleans. Headless with an isolated profile is the default |
8285
| `browser.allowedOrigins` | Non-empty list of exact HTTP(S) origins. Paths and credentials are rejected |
8386
| `browser.maxRisk` | `read`, `mutate`, or `externalEffect` |
@@ -89,6 +92,9 @@ and incomplete external-effect approval fail closed.
8992
| `browser.purpose` | Required printable purpose for an external-effect configuration |
9093
| `browser.artifacts` | Optional disk, count, inline, and TTL limits described below |
9194

95+
FrameSpace supports a smaller action catalog and requires `browser.methods` to be empty. Its exact setup,
96+
sandbox, screenshot, and credentialless-session limits are in the [FrameSpace guide](frameSpace.md).
97+
9298
The repository `npm run mcp:sandbox` command still accepts the corresponding `PYPROC_*` environment
9399
variables for development and compatibility. The shipped command's versioned manifest is the product entry.
94100
It clears ambient product variables before projecting the manifest so an inherited shell variable cannot

docs/usage/capabilityMatrix.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ A runnable surface is an example a person opens, a browser gate, a probe, or a t
4949
| Machine journal | Uses idle commits and a WAL to revive a crashed tab from the heap and `/home/web` of the last commit | `machine.history.commit`/`recover`/`watch`/`pack` (`MachineJournal`) | Bounded | OPFS, an idle-commit policy, pack/prune operations, and the same engine and manifest | [journal probe](../../tests/attempts/pythonMachine/journalProbe.html), [large heap journal probe](../../tests/attempts/largeHeapEnvelope/largeHeapProbe.html), [installed-package browser gate](../../tests/browser/installedPackageGate.mjs) | journal probes, `npm run test:installed` | A long-lived blob store grows without pack and prune. It is subject to browser storage quota. Changes after a commit are lost |
5050
| Permission jail | Restricts Python code's net, clipboard, home, and worker permissions through a permission manifest and CSP | `enableJail(permissions)` on `machine.runtime`, returning `{ jail, permissions, connectSrc }` | Probe | A permission manifest, the jail context's CSP, a host allowlist, and a permission UI | [jail probe](../../tests/attempts/pythonMachine/jailProbe.html), [installed-package browser gate](../../tests/browser/installedPackageGate.mjs), [trust and permissions](trustPermissions.md) | `npm run test:installed`, `npm run test:browser` (the enableJail evidence checks), jail probes | Not a sandbox that removes every side channel available to code in the same parent window. Strong isolation requires an opaque-origin design |
5151
| Browser automation product | Lets MCP and native clients run persistent Python, semantic browser actions, deterministic device viewports, first-navigation tracing, native screenshots, and bounded artifact retrieval on an allowed Chromium target | Installed `pyproc-mcp` and `pyproc-control` bins share one version 1 manifest and ControlHost. The 23-action pipeline provides eight-state semantic readiness, explicit lazy hydration, PNG/JPEG/WebP artifact delivery, opaque chunk read/delete, popup and frame handling, and a separately raw-allowlisted command. No browser JavaScript export is added | Bounded | Node 22, a pinned engine root or immutable index URL, Chromium-family major 137 or newer with CDP protocol major 1, a broker-owned temporary profile, exact HTTP(S) origins and actions, fixed risk, filesystem roots for upload, and operator acknowledgement plus purpose for external effects | [browser automation product guide](browserAutomation.md), [Control Protocol guide](controlProtocol.md), installed MCP and native product gates | `npm run test:contracts`, `npm run test:package`, `npm run test:mcp`, 10 installed MCP assertions, six native assertions, 71 assertions in `npm run test:browser-control`, and a 48-action stress gate on Chrome Ubuntu and Edge Windows | The default surface remains four Python operations and opens no CDP authority. Opt-in control does not attach to the user's default profile, expose internal action methods as raw permissions, put the CDP endpoint in Python, or add a proxy listener. Startup traces redact query and secret-shaped values. Native images are bounded by the inline quota and retain the artifact chunk fallback. Lazy hydration is an explicit external effect. Artifact quota, TTL, deletion, and process shutdown bound disk retention. Open shadow roots and authorized frame chains are supported; closed roots are unsupported. Cookie values are absent from metadata reads and traces. Python restore never rolls back browser effects. An interrupted sent effect is `outcomeUnknown` and is not retried. The operator owns legal authority and consequential-action approval |
52-
| Python control SDK | Lets a Python application start the same product host, run persistent Python, checkpoint, cancel, automate a browser, and receive verified screenshot bytes without JavaScript application code | Separate zero-runtime-dependency `pyproc-control` wheel and source distribution with `PyProcClient`, `ControlRequest`, `ControlResult`, `Attachment`, strict codec, and stable errors | Bounded | Python 3.10 or newer, the same-version npm package on `PATH`, a valid product manifest, engine assets, and browser authority for automation operations | [Python SDK guide](pythonSdk.md), [clean install product gate](../../tests/pythonSdk/run.mjs) | `npm run test:python-sdk` builds and installs both distribution forms in separate clean environments, runs 11 codec fixtures, and completes Python, checkpoint, cancel, permission, browser, screenshot, digest, artifact, and single-use ID checks on Chrome Ubuntu and Edge Windows | The SDK is a local client, not a hosted service. It does not bundle Node, Chromium, or the Python engine. A post-send cancellation is `outcomeUnknown`, and Python restore cannot undo external effects |
52+
| Python control SDK | Lets a Python application start the same product host, run persistent Python, checkpoint, cancel, automate a browser, and receive verified screenshot bytes without JavaScript application code | Separate zero-runtime-dependency `pyproc-control` wheel and source distribution with `PyProcClient`, `ControlRequest`, `ControlResult`, `Attachment`, strict codec, and stable errors | Bounded | Python 3.10 or newer, the same-version npm package on `PATH`, a valid product manifest, engine assets, and browser authority for automation operations | [Python SDK guide](pythonSdk.md), [clean install product gate](../../tests/pythonSdk/run.mjs) | `npm run test:python-sdk` builds and installs both distribution forms in separate clean environments, runs 11 codec fixtures, and completes Native CDP plus FrameSpace Python, checkpoint, cancel, permission, screenshot, digest, artifact, and single-use ID checks on Chrome Ubuntu and Edge Windows | The SDK is a local client, not a hosted service. It does not bundle Node, Chromium, or the Python engine. A post-send cancellation is `outcomeUnknown`, and Python restore cannot undo external effects |
5353
| Outbound sockets | Lets Python `socket`, `urllib`, and `http.client` reach an external host:port | `SocketBridge` (`pyproc/socket`) | Probe | A WS-to-TCP relay, JSPI blocking recv, and product operation of that relay | [hermetic socket lane](../../tests/browser/socketLane.mjs), [Python socket probe](../../tests/manualProbes/socketPyProbe.html) | socket bridge probes | Inbound sockets are a browser security wall. For HTTPS the relay handles TLS |
5454
| Device filesystem | Exposes browser features as Python file paths | `machine.runtime.enableDeviceFs()` (`DeviceFs`) | Bounded | Explicit device injection, browser permissions, and a clear file-path policy | [installed-package browser gate](../../tests/browser/installedPackageGate.mjs), [device FS probe](../../tests/attempts/pythonMachine/deviceFsProbe.html), [machine campaign](../../tests/attempts/pythonMachine/README.md) | `npm run test:installed`, device FS probes | Only explicitly configured devices allowed by browser policy exist |
5555
| GPU compute | Uploads f32 arrays to WebGPU and runs a GPU-resident linear algebra pipeline | `GpuCompute`, `GpuArray`, `GpuBridge` (`pyproc/gpu`) | Probe | WebGPU, a windowed browser, a real GPU, and an f32 data path | [GPU campaign](../../tests/manualProbes/README.md), [GPU tiled probe](../../tests/manualProbes/gpuTiledProbe.html), [GPU Python probe](../../tests/manualProbes/gpuPythonProbe.html) | GPU probes on real hardware | WGSL has no f64. Headless CI numbers are not evidence of product performance |

0 commit comments

Comments
 (0)