codex-computer-use-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +26 -0
- package/LICENSE +21 -0
- package/PROOF.md +81 -0
- package/README.md +195 -0
- package/SECURITY.md +38 -0
- package/dist/audit.d.ts +25 -0
- package/dist/audit.js +42 -0
- package/dist/audit.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/lock.d.ts +16 -0
- package/dist/lock.js +108 -0
- package/dist/lock.js.map +1 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +134 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/policy.d.ts +42 -0
- package/dist/policy.js +428 -0
- package/dist/policy.js.map +1 -0
- package/dist/prompt.d.ts +62 -0
- package/dist/prompt.js +119 -0
- package/dist/prompt.js.map +1 -0
- package/dist/runner.d.ts +55 -0
- package/dist/runner.js +494 -0
- package/dist/runner.js.map +1 -0
- package/dist/service.d.ts +17 -0
- package/dist/service.js +382 -0
- package/dist/service.js.map +1 -0
- package/dist/system.d.ts +17 -0
- package/dist/system.js +228 -0
- package/dist/system.js.map +1 -0
- package/integrations/pi/README.md +50 -0
- package/integrations/pi/index.ts +135 -0
- package/integrations/pi/mcp.json.example +15 -0
- package/npm-shrinkwrap.json +1600 -0
- package/package.json +65 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Contributions are welcome, especially compatibility fixes, adversarial policy tests, and clearer host diagnostics.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm ci
|
|
9
|
+
npm run check
|
|
10
|
+
npm test
|
|
11
|
+
npm run build
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Development and live acceptance require macOS plus the official ChatGPT app. Tests that verify the bundled broker and compile disposable native harnesses are intentionally host integration tests.
|
|
15
|
+
|
|
16
|
+
## Pull requests
|
|
17
|
+
|
|
18
|
+
- Keep safe mode list-only; do not add targeted dispatch without a preventive mechanism that preserves official signed-parent authentication.
|
|
19
|
+
- Do not add credential extraction, app injection, re-signing, private protocol bypasses, TCC automation, or automatic approval acceptance.
|
|
20
|
+
- Add a regression test for every policy or cleanup fix.
|
|
21
|
+
- Avoid logging task text, typed values, screenshots, app-state payloads, or model output.
|
|
22
|
+
- Document any new fixed ChatGPT bundle path or CLI assumption.
|
|
23
|
+
- Include `npm run check`, `npm test`, and `npm run build` results.
|
|
24
|
+
- For targeted behavior changes, include a benign stopped-app acceptance and external focus evidence, and label post-dispatch checks honestly.
|
|
25
|
+
|
|
26
|
+
Security-boundary changes should receive an independent exact-head review before merge. See `SECURITY.md` for private vulnerability reporting.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Mustier
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/PROOF.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Proof and acceptance record
|
|
2
|
+
|
|
3
|
+
This records evidence for the standalone MCP extraction. It does not guarantee compatibility with future ChatGPT macOS versions.
|
|
4
|
+
|
|
5
|
+
## Supported path
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
MCP client → wrapper → app-bundled signed Codex CLI → signed SkyComputerUseClient → official Computer Use service
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Direct unsigned access was rejected by sender authentication. The wrapper does not bypass that boundary. It verifies the fixed app-bundled Codex and Computer Use client with `codesign --verify --strict` and OpenAI Team ID `2DC432GLL2` before each run.
|
|
12
|
+
|
|
13
|
+
## Preventive-boundary finding
|
|
14
|
+
|
|
15
|
+
An independent `gpt-5.6-sol`/`xhigh` review of the first standalone candidate found that streamed target and argument checks occur after official-client dispatch. A model deviation could therefore reach a different already-approved app before the wrapper killed the worker.
|
|
16
|
+
|
|
17
|
+
A local MCP proxy was prototyped and proved capable of rejecting a wrong target before forwarding. It was not adopted: making the unsigned proxy the official client's parent breaks the signed-parent sender-authentication chain and caused live Computer Use to fail. Injection, re-signing, credential extraction, and authentication bypass were rejected as out of bounds.
|
|
18
|
+
|
|
19
|
+
The public authorization model was changed instead:
|
|
20
|
+
|
|
21
|
+
- safe mode is list-only;
|
|
22
|
+
- all targeted modes are rejected and audited before worker launch;
|
|
23
|
+
- full-permissions mode is explicitly acknowledged broad authorization;
|
|
24
|
+
- streamed target/method/argument/focus/cleanup checks are documented as post-dispatch detection and completion criteria, not a preventive sandbox.
|
|
25
|
+
|
|
26
|
+
## Other review remediation
|
|
27
|
+
|
|
28
|
+
The same review found and prompted fixes for:
|
|
29
|
+
|
|
30
|
+
- incomplete operations returning a non-error tool status;
|
|
31
|
+
- policy-validation failures missing audits;
|
|
32
|
+
- lease-release failure suppressing the audit attempt;
|
|
33
|
+
- cancellation losing available runner metadata;
|
|
34
|
+
- ASN lookup failures being permanently deduplicated;
|
|
35
|
+
- final focus sampling not draining an in-flight sample;
|
|
36
|
+
- caret-ranged published dependencies without a shrinkwrap;
|
|
37
|
+
- status claiming a healthy boundary without verifying the signed broker;
|
|
38
|
+
- insufficient release provenance guidance.
|
|
39
|
+
|
|
40
|
+
A second exact-tree review accepted the P1 architectural remediation and found two further P2 races: shutdown-only focus events could exhaust the single post-stop ASN lookup, and cancellation audits stored only a count rather than ordered methods. The watcher now performs a bounded awaited drain after listener closure and fails closed if any ASN remains unresolved. Cancellation now returns structured non-retryable error details and persists the ordered sanitized method list plus cleanup uncertainty. Combined regressions cover both cases.
|
|
41
|
+
|
|
42
|
+
## Test and host evidence
|
|
43
|
+
|
|
44
|
+
The original reviewed core demonstrated:
|
|
45
|
+
|
|
46
|
+
- strict TypeScript compilation;
|
|
47
|
+
- signed broker and ten-method schema verification;
|
|
48
|
+
- crash-release and bounded hashed-lock tests;
|
|
49
|
+
- streamed event, failed-status, call-budget, timeout, and cancellation tests;
|
|
50
|
+
- focus watcher drain/final-query tests;
|
|
51
|
+
- secure config/audit no-follow, mode, and fsync checks;
|
|
52
|
+
- fresh stopped-Calculator background action with `2 + 2 = 4`, `AC → 0`, cleanup verified, and zero Calculator-frontmost samples;
|
|
53
|
+
- all ten official methods, different-app concurrency, same-app exclusion, and cancellation cleanup in earlier benign harness acceptance.
|
|
54
|
+
|
|
55
|
+
The standalone MCP server additionally demonstrated a real stdio client handshake and safe-mode `list` call:
|
|
56
|
+
|
|
57
|
+
- result `ok`;
|
|
58
|
+
- 39 apps;
|
|
59
|
+
- one successful `list_apps` method;
|
|
60
|
+
- background preserved;
|
|
61
|
+
- separate Codex usage reported;
|
|
62
|
+
- private sanitized audit written.
|
|
63
|
+
|
|
64
|
+
After remediation, release validation must rerun the exact current test count, build, dependency audit, package inspection, read-only list acceptance, Pi adapter smoke, and independent exact-head review. The GitHub release should bind the final commit, tracked-tree aggregate hash, package integrity, host versions, and reviewer verdict.
|
|
65
|
+
|
|
66
|
+
## Release gate
|
|
67
|
+
|
|
68
|
+
Before publishing:
|
|
69
|
+
|
|
70
|
+
1. Run `npm ci`, `npm run check`, `npm test`, `npm run build`, and `npm audit --omit=dev`.
|
|
71
|
+
2. Inspect `npm pack --dry-run`; verify `npm-shrinkwrap.json` and exact runtime dependency versions are included.
|
|
72
|
+
3. Verify ChatGPT/Codex/client signatures and Team ID on the acceptance host.
|
|
73
|
+
4. Run fresh stdio MCP `list` acceptance in safe mode.
|
|
74
|
+
5. Run one benign stopped-app action only after explicitly enabling full-permissions, with external focus sampling and cleanup verification.
|
|
75
|
+
6. Check for leaked workers, listeners, lock holders, owner records, and harness apps.
|
|
76
|
+
7. Independently review the exact release tree. Do not publish with unresolved P0/P1/P2 findings.
|
|
77
|
+
8. Record commit, aggregate hash, package integrity, host versions, test count, and review verdict in the release.
|
|
78
|
+
|
|
79
|
+
## Non-goals
|
|
80
|
+
|
|
81
|
+
This project does not provide a Sky protocol clone, browser-host integration, credential extraction, TCC automation, app injection, re-signing, sender-authentication bypass, or automatic approval acceptance.
|
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Codex Computer Use MCP
|
|
2
|
+
|
|
3
|
+
A local MCP server that lets compatible agents use the official, signed Computer Use broker bundled with the OpenAI ChatGPT macOS app.
|
|
4
|
+
|
|
5
|
+
It exposes all ten typed Computer Use methods while preserving:
|
|
6
|
+
|
|
7
|
+
- official OpenAI code-signing checks;
|
|
8
|
+
- first-party app approvals and sensitive-action prompts;
|
|
9
|
+
- macOS Screen Recording and Accessibility permissions;
|
|
10
|
+
- a deliberately list-only safe default;
|
|
11
|
+
- explicit acknowledgement before broad full-permissions mode;
|
|
12
|
+
- per-app kernel locks;
|
|
13
|
+
- foreground/focus telemetry with fail-closed background guarantees;
|
|
14
|
+
- output schemas, call budgets, timeout and process-group cleanup;
|
|
15
|
+
- sanitized, mode-`0600` metadata audits.
|
|
16
|
+
|
|
17
|
+
> **Independent project.** This is not an OpenAI product and is not endorsed by OpenAI. It depends on implementation details in the macOS ChatGPT app and may need updates when that app changes.
|
|
18
|
+
|
|
19
|
+
## Important authorization model
|
|
20
|
+
|
|
21
|
+
The official Computer Use client authenticates its signed parent process. Putting an unsigned local MCP proxy between app-bundled Codex and that client breaks the official sender-authentication boundary. Therefore wrapper checks of a nested model's target and arguments can only observe events **after** the signed client has dispatched them.
|
|
22
|
+
|
|
23
|
+
This project does not pretend that post-dispatch observation is a preventive sandbox:
|
|
24
|
+
|
|
25
|
+
- **Safe mode permits only `list`.** No target app or mutation is dispatched.
|
|
26
|
+
- **Full-permissions mode broadly authorizes the wrapper to use official Computer Use.** It retains first-party OpenAI/macOS controls and detects target, method, argument, call-budget, focus, and cleanup drift, but detection cannot undo an action already dispatched.
|
|
27
|
+
|
|
28
|
+
Do not enable full-permissions if you need the wrapper itself to provide a preventive per-app security boundary.
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
- macOS
|
|
33
|
+
- Node.js 22 or newer
|
|
34
|
+
- the official ChatGPT macOS app at `/Applications/ChatGPT.app`
|
|
35
|
+
- a Codex account/session available to the app-bundled Codex CLI
|
|
36
|
+
- required first-party OpenAI app approvals and macOS privacy permissions, completed in their official UI
|
|
37
|
+
|
|
38
|
+
The server never extracts credentials, re-signs or injects into an app, changes TCC permissions, forges sender authentication, or self-accepts first-party approvals.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
### From npm (after a release is published)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install -g codex-computer-use-mcp
|
|
46
|
+
codex-computer-use-mcp --status
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### From source
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/tmustier/codex-computer-use-mcp.git
|
|
53
|
+
cd codex-computer-use-mcp
|
|
54
|
+
npm ci
|
|
55
|
+
npm test
|
|
56
|
+
npm run build
|
|
57
|
+
node dist/mcp-server.js --status
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Running `codex-computer-use-mcp` with no arguments starts the stdio MCP server.
|
|
61
|
+
|
|
62
|
+
## Tools
|
|
63
|
+
|
|
64
|
+
### `background_computer_use`
|
|
65
|
+
|
|
66
|
+
| Mode | Purpose | Permission mode |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `list` | List apps visible to official Computer Use | Safe or full |
|
|
69
|
+
| `inspect` | Read one app | Full only |
|
|
70
|
+
| `act` | Perform a concrete app task | Full only |
|
|
71
|
+
| `dictionary_lookup` | Constrained local Apple Dictionary workflow | Full only |
|
|
72
|
+
|
|
73
|
+
Optional fields include `cleanup`, `cleanup_instructions`, and `required_capabilities`. The latter can require observed successful use of official methods:
|
|
74
|
+
|
|
75
|
+
`list_apps`, `get_app_state`, `click`, `perform_secondary_action`, `set_value`, `select_text`, `scroll`, `drag`, `press_key`, `type_text`.
|
|
76
|
+
|
|
77
|
+
### `background_computer_use_status`
|
|
78
|
+
|
|
79
|
+
Returns the permission mode, state/audit locations, broker verification and version, model, approval boundary, and supported methods.
|
|
80
|
+
|
|
81
|
+
## Permission modes
|
|
82
|
+
|
|
83
|
+
### Safe mode (default)
|
|
84
|
+
|
|
85
|
+
Safe mode is intentionally list-only. Targeted requests are rejected and audited before a Codex worker starts.
|
|
86
|
+
|
|
87
|
+
### Full-permissions mode
|
|
88
|
+
|
|
89
|
+
This broadly authorizes targeted official Computer Use operations. It does **not** bypass official OpenAI approvals, sensitive-action prompts, macOS privacy controls, signing checks, focus monitoring, locks, call budgets, timeout cleanup, or audit logging.
|
|
90
|
+
|
|
91
|
+
Enable it only with explicit acknowledgement:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
codex-computer-use-mcp --configure full-permissions --acknowledge-full-permissions
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Return to safe mode:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
codex-computer-use-mcp --configure safe
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
State defaults to `~/.codex-computer-use-mcp`. Override it with `CODEX_COMPUTER_USE_HOME`. Configuration is mode `0600` and audited; an audit failure rolls a mode change back.
|
|
104
|
+
|
|
105
|
+
## MCP client configuration
|
|
106
|
+
|
|
107
|
+
### Pi native adapter
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pi install npm:codex-computer-use-mcp@0.1.0
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This registers `background_computer_use`, `/background-computer-use-status`, and `/background-computer-use-mode`.
|
|
114
|
+
|
|
115
|
+
### Pi MCP gateway
|
|
116
|
+
|
|
117
|
+
Alternatively add this to `~/.pi/agent/mcp.json`. `directTools: false` keeps the capability intentional instead of injecting it into every turn:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"mcpServers": {
|
|
122
|
+
"codex-computer-use": {
|
|
123
|
+
"command": "npx",
|
|
124
|
+
"args": ["-y", "codex-computer-use-mcp@0.1.0"],
|
|
125
|
+
"lifecycle": "lazy",
|
|
126
|
+
"requestTimeoutMs": 360000,
|
|
127
|
+
"directTools": false
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
See [`integrations/pi/`](integrations/pi/). Do not load both Pi adapters under the same tool name.
|
|
134
|
+
|
|
135
|
+
### Claude Desktop
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"mcpServers": {
|
|
140
|
+
"codex-computer-use": {
|
|
141
|
+
"command": "npx",
|
|
142
|
+
"args": ["-y", "codex-computer-use-mcp@0.1.0"]
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
For a source checkout, replace `npx` and its arguments with `node` and the absolute path to `dist/mcp-server.js`.
|
|
149
|
+
|
|
150
|
+
## How it works
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
MCP client
|
|
154
|
+
→ this local server
|
|
155
|
+
→ ChatGPT.app's signed app-bundled Codex CLI
|
|
156
|
+
→ signed SkyComputerUseClient
|
|
157
|
+
→ official Computer Use service
|
|
158
|
+
→ target macOS app
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The nested Codex turn is pinned to `gpt-5.6-sol`; reasoning is `low` for list, `high` for inspect/Dictionary, and `xhigh` for act. It receives a mode-specific tool allowlist, runs with shell/web/remote plugins disabled, and emits a constrained result schema. Streamed events are checked against the requested target, method set, argument constraints, and call budget. These checks are detection and fail-closed completion criteria, not pre-dispatch mediation.
|
|
162
|
+
|
|
163
|
+
Target apps are background-launched with `open -g`. The server samples frontmost state and consumes global focus notifications. If the target becomes frontmost, completion fails. Unrelated user focus changes are recorded but do not invalidate the operation.
|
|
164
|
+
|
|
165
|
+
## Usage, privacy, and audits
|
|
166
|
+
|
|
167
|
+
Each operation starts a separate Codex turn and consumes separate Codex plan/API usage. Results report token usage.
|
|
168
|
+
|
|
169
|
+
Audits include timestamps, operation/mode, canonical or hashed app identity, byte counts, outcome, methods, usage, and cleanup/focus results. They do **not** include task text, typed content, screenshots, app-state payloads, or model output. Policy-rejected requests are also audited once a secure state directory is available.
|
|
170
|
+
|
|
171
|
+
## Known limitations
|
|
172
|
+
|
|
173
|
+
- The integration targets fixed bundle paths inside the ChatGPT macOS app.
|
|
174
|
+
- App updates may change bundled paths, CLI flags, plugin schemas, or signing layout.
|
|
175
|
+
- First-party approvals may need completion in an official interactive OpenAI session.
|
|
176
|
+
- Browser-host Computer Use is not exposed; this project targets native macOS apps.
|
|
177
|
+
- In full-permissions mode, a target/method/focus/cleanup failure is detected after streamed events; mutations may already have occurred. Inspect and restore manually before retrying.
|
|
178
|
+
- Secure config-path failures may prevent audit creation because the server refuses to write through an untrusted path.
|
|
179
|
+
|
|
180
|
+
## Development
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npm ci
|
|
184
|
+
npm run check
|
|
185
|
+
npm test
|
|
186
|
+
npm run build
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Runtime dependencies are exact-pinned and the published graph is bound by `npm-shrinkwrap.json`.
|
|
190
|
+
|
|
191
|
+
See [`PROOF.md`](PROOF.md), [`SECURITY.md`](SECURITY.md), and [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Do not open a public issue for a vulnerability that could weaken code-signing checks, safe-mode dispatch restrictions, approval boundaries, focus guarantees, audit integrity, or cleanup behavior.
|
|
6
|
+
|
|
7
|
+
Use GitHub's private vulnerability reporting. Include affected versions, the smallest non-sensitive reproduction, expected versus observed behavior, and whether app state changed or cleanup was unverified.
|
|
8
|
+
|
|
9
|
+
Never include credentials, tokens, private/customer content, sensitive screenshots, raw app-state payloads, or private audit files.
|
|
10
|
+
|
|
11
|
+
## Authorization model
|
|
12
|
+
|
|
13
|
+
The signed official client authenticates its parent. An unsigned wrapper cannot synchronously proxy each Computer Use call without breaking that official sender-authentication chain. Streamed target, method, argument, call-budget, focus, and cleanup checks therefore occur after dispatch.
|
|
14
|
+
|
|
15
|
+
For that reason:
|
|
16
|
+
|
|
17
|
+
- safe mode is list-only and rejects targeted work before starting Codex;
|
|
18
|
+
- full-permissions mode is broad wrapper authorization, not a preventive per-app sandbox;
|
|
19
|
+
- post-dispatch validation can fail completion and surface cleanup risk, but cannot undo a mutation;
|
|
20
|
+
- official OpenAI app approvals, sensitive-action prompts, and macOS privacy controls remain authoritative.
|
|
21
|
+
|
|
22
|
+
## Security invariants
|
|
23
|
+
|
|
24
|
+
1. Only the fixed OpenAI app-bundled Codex and Computer Use client paths may broker a run.
|
|
25
|
+
2. Both binaries must pass strict code-signing verification and OpenAI Team ID checks.
|
|
26
|
+
3. First-party OpenAI and macOS approvals are never self-accepted.
|
|
27
|
+
4. Safe mode dispatches only `list_apps`; every targeted mode fails before worker launch.
|
|
28
|
+
5. Full-permissions mode requires explicit acknowledgement and never claims preventive target isolation.
|
|
29
|
+
6. The target app must not become frontmost; watcher health, queued events, in-flight samples, and final state are checked.
|
|
30
|
+
7. Streamed calls must match the mode allowlist, requested target aliases, argument constraints, and call budget before completion is trusted.
|
|
31
|
+
8. Same-app work remains kernel-excluded.
|
|
32
|
+
9. Timeout and cancellation terminate the full worker process group and retain available partial metadata.
|
|
33
|
+
10. Audits remain private and content-safe; policy rejections are audited, and audit failure is fatal once a secure state path exists.
|
|
34
|
+
11. Runtime dependencies are exact-pinned and published with `npm-shrinkwrap.json`.
|
|
35
|
+
|
|
36
|
+
## Supported versions
|
|
37
|
+
|
|
38
|
+
Only the latest release is supported. Compatibility is evaluated against current ChatGPT macOS releases rather than guaranteed indefinitely.
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface AuditRecord {
|
|
2
|
+
timestamp: string;
|
|
3
|
+
runId: string;
|
|
4
|
+
operation: string;
|
|
5
|
+
permissionMode: "safe" | "full-permissions";
|
|
6
|
+
app: string | null;
|
|
7
|
+
mutating: boolean;
|
|
8
|
+
cleanupRequested: boolean;
|
|
9
|
+
userConfirmed: boolean;
|
|
10
|
+
authorization: "none" | "full_permissions_config";
|
|
11
|
+
inputBytes: number;
|
|
12
|
+
outcome: string;
|
|
13
|
+
durationMs: number;
|
|
14
|
+
model: string;
|
|
15
|
+
usage: {
|
|
16
|
+
input: number;
|
|
17
|
+
cachedInput: number;
|
|
18
|
+
output: number;
|
|
19
|
+
};
|
|
20
|
+
computerUseCalls: number;
|
|
21
|
+
computerUseMethods: string[];
|
|
22
|
+
backgroundPreserved: boolean | null;
|
|
23
|
+
cleanupVerified: boolean | null;
|
|
24
|
+
}
|
|
25
|
+
export declare function appendAudit(stateDir: string, record: AuditRecord, fileName?: string): Promise<string>;
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { chmod, lstat, mkdir, open } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
async function ensurePrivateDirectory(directory) {
|
|
5
|
+
try {
|
|
6
|
+
const info = await lstat(directory);
|
|
7
|
+
if (info.isSymbolicLink() || !info.isDirectory())
|
|
8
|
+
throw new Error("Audit state path must be a non-symlink directory");
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error?.code !== "ENOENT")
|
|
12
|
+
throw error;
|
|
13
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
14
|
+
const info = await lstat(directory);
|
|
15
|
+
if (info.isSymbolicLink() || !info.isDirectory())
|
|
16
|
+
throw new Error("Audit state path must be a non-symlink directory");
|
|
17
|
+
}
|
|
18
|
+
await chmod(directory, 0o700);
|
|
19
|
+
}
|
|
20
|
+
export async function appendAudit(stateDir, record, fileName = "background-computer-use.jsonl") {
|
|
21
|
+
if (path.basename(fileName) !== fileName)
|
|
22
|
+
throw new Error("Audit filename must not contain a path");
|
|
23
|
+
await ensurePrivateDirectory(stateDir);
|
|
24
|
+
const auditDir = path.join(stateDir, "audit");
|
|
25
|
+
await ensurePrivateDirectory(auditDir);
|
|
26
|
+
const auditPath = path.join(auditDir, fileName);
|
|
27
|
+
const flags = constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_NOFOLLOW;
|
|
28
|
+
const handle = await open(auditPath, flags, 0o600);
|
|
29
|
+
try {
|
|
30
|
+
const info = await handle.stat();
|
|
31
|
+
if (!info.isFile())
|
|
32
|
+
throw new Error("Audit target must be a regular file");
|
|
33
|
+
await handle.chmod(0o600);
|
|
34
|
+
await handle.writeFile(`${JSON.stringify(record)}\n`, "utf8");
|
|
35
|
+
await handle.sync();
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await handle.close();
|
|
39
|
+
}
|
|
40
|
+
return auditPath;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;AAuB7B,KAAK,UAAU,sBAAsB,CAAC,SAAiB;IACtD,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACvH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACrB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC1C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACvH,CAAC;IACD,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,QAAgB,EAChB,MAAmB,EACnB,QAAQ,GAAG,+BAA+B;IAE1C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACpG,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC;IACjG,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC3E,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9D,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;YAAS,CAAC;QACV,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PermissionMode } from "./policy.ts";
|
|
2
|
+
export interface ExtensionConfig {
|
|
3
|
+
version: 1;
|
|
4
|
+
permissionMode: PermissionMode;
|
|
5
|
+
}
|
|
6
|
+
export declare const DEFAULT_CONFIG: ExtensionConfig;
|
|
7
|
+
export declare class ConfigError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function configPath(stateDir: string): string;
|
|
11
|
+
export declare function loadConfig(stateDir: string): Promise<ExtensionConfig>;
|
|
12
|
+
export declare function saveConfig(stateDir: string, config: ExtensionConfig): Promise<string>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { chmod, lstat, mkdir, open, rename, rm } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export const DEFAULT_CONFIG = { version: 1, permissionMode: "safe" };
|
|
5
|
+
export class ConfigError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "ConfigError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function configPath(stateDir) {
|
|
12
|
+
return path.join(stateDir, "config.json");
|
|
13
|
+
}
|
|
14
|
+
function parseConfig(value) {
|
|
15
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
16
|
+
throw new ConfigError("Computer Use config must be an object");
|
|
17
|
+
const record = value;
|
|
18
|
+
if (Object.keys(record).some((key) => !["version", "permissionMode"].includes(key))) {
|
|
19
|
+
throw new ConfigError("Computer Use config contains unknown keys");
|
|
20
|
+
}
|
|
21
|
+
if (record.version !== 1)
|
|
22
|
+
throw new ConfigError("Unsupported Computer Use config version");
|
|
23
|
+
if (record.permissionMode !== "safe" && record.permissionMode !== "full-permissions") {
|
|
24
|
+
throw new ConfigError("permissionMode must be safe or full-permissions");
|
|
25
|
+
}
|
|
26
|
+
return { version: 1, permissionMode: record.permissionMode };
|
|
27
|
+
}
|
|
28
|
+
async function inspectStateDirectory(stateDir, create) {
|
|
29
|
+
try {
|
|
30
|
+
const info = await lstat(stateDir);
|
|
31
|
+
if (info.isSymbolicLink() || !info.isDirectory())
|
|
32
|
+
throw new ConfigError("Computer Use state must be a non-symlink directory");
|
|
33
|
+
if ((info.mode & 0o022) !== 0)
|
|
34
|
+
throw new ConfigError("Computer Use state directory must not be group/world writable");
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error?.code !== "ENOENT")
|
|
39
|
+
throw error;
|
|
40
|
+
if (!create)
|
|
41
|
+
return false;
|
|
42
|
+
await mkdir(stateDir, { recursive: true, mode: 0o700 });
|
|
43
|
+
const info = await lstat(stateDir);
|
|
44
|
+
if (info.isSymbolicLink() || !info.isDirectory())
|
|
45
|
+
throw new ConfigError("Computer Use state must be a non-symlink directory");
|
|
46
|
+
await chmod(stateDir, 0o700);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function loadConfig(stateDir) {
|
|
51
|
+
if (!(await inspectStateDirectory(stateDir, false)))
|
|
52
|
+
return { ...DEFAULT_CONFIG };
|
|
53
|
+
const file = configPath(stateDir);
|
|
54
|
+
let handle;
|
|
55
|
+
try {
|
|
56
|
+
handle = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
57
|
+
const info = await handle.stat();
|
|
58
|
+
if (!info.isFile())
|
|
59
|
+
throw new ConfigError("Computer Use config must be a regular non-symlink file");
|
|
60
|
+
if ((info.mode & 0o777) !== 0o600)
|
|
61
|
+
throw new ConfigError("Computer Use config must have mode 0600");
|
|
62
|
+
return parseConfig(JSON.parse(await handle.readFile("utf8")));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error?.code === "ENOENT")
|
|
66
|
+
return { ...DEFAULT_CONFIG };
|
|
67
|
+
if (error instanceof ConfigError)
|
|
68
|
+
throw error;
|
|
69
|
+
throw new ConfigError("Could not read the Computer Use config");
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
await handle?.close().catch(() => undefined);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export async function saveConfig(stateDir, config) {
|
|
76
|
+
const validated = parseConfig(config);
|
|
77
|
+
await inspectStateDirectory(stateDir, true);
|
|
78
|
+
await chmod(stateDir, 0o700);
|
|
79
|
+
const destination = configPath(stateDir);
|
|
80
|
+
const temporary = path.join(stateDir, `.config.${process.pid}.${Date.now()}.tmp`);
|
|
81
|
+
let handle;
|
|
82
|
+
try {
|
|
83
|
+
const flags = constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW;
|
|
84
|
+
handle = await open(temporary, flags, 0o600);
|
|
85
|
+
await handle.chmod(0o600);
|
|
86
|
+
await handle.writeFile(`${JSON.stringify(validated, null, 2)}\n`, "utf8");
|
|
87
|
+
await handle.sync();
|
|
88
|
+
await handle.close();
|
|
89
|
+
handle = undefined;
|
|
90
|
+
await rename(temporary, destination);
|
|
91
|
+
const directory = await open(stateDir, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
92
|
+
try {
|
|
93
|
+
await directory.sync();
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
await directory.close();
|
|
97
|
+
}
|
|
98
|
+
return destination;
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
await handle?.close().catch(() => undefined);
|
|
102
|
+
await rm(temporary, { force: true });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lock.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface LockOwner {
|
|
2
|
+
runId: string;
|
|
3
|
+
pid: number;
|
|
4
|
+
app: string;
|
|
5
|
+
startedAt: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class AppBusyError extends Error {
|
|
8
|
+
readonly owner?: Partial<LockOwner>;
|
|
9
|
+
constructor(app: string, owner?: Partial<LockOwner>);
|
|
10
|
+
}
|
|
11
|
+
export interface AppLock {
|
|
12
|
+
path: string;
|
|
13
|
+
owner: LockOwner;
|
|
14
|
+
release(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function acquireAppLock(stateDir: string, app: string, runId: string, _staleAfterMs?: number): Promise<AppLock>;
|