relmio 0.3.1 → 0.4.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/CHANGELOG.md CHANGED
@@ -7,6 +7,38 @@ checks the registry separately after publication.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## [0.4.0] - 2026-08-13
11
+
12
+ ### Added
13
+
14
+ - Add a local Docker wizard for private compatible clients through a
15
+ Platform-key-backed OpenAI-compatible `/v1` endpoint, plus a separate
16
+ official experimental Codex App Server target for trusted ChatGPT-sign-in
17
+ clients.
18
+ - Add compact Ko-fi support links to the hosted navigation and public package
19
+ guides.
20
+
21
+ ### Changed
22
+
23
+ - Make the local credential boundary explicit across the product: a Platform
24
+ API key powers compatible `/v1` requests, while ChatGPT sign-in powers only
25
+ the experimental Codex App Server protocol.
26
+
27
+ ### Fixed
28
+
29
+ - Keep the controlling terminal attached when the macOS/Linux installer is
30
+ piped through `sh`, so the Relmio wizard can open its interactive browser
31
+ setup flow.
32
+ - Install Homebrew dependencies in their required order during release-candidate
33
+ validation.
34
+
35
+ ### Security
36
+
37
+ - Bind local endpoints exclusively to loopback, require one-time Relmio
38
+ capabilities, pin every managed operation to an attested local Docker
39
+ socket, and isolate provider credentials in target-specific containers.
40
+ - Restrict the managed Codex endpoint to the ChatGPT login method.
41
+
10
42
  ## [0.3.1] - 2026-08-10
11
43
 
12
44
  ### Changed
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/brand/relmio-mark.svg" alt="Relmio logo" width="88">
3
3
  <h1>Relmio</h1>
4
- <p>Relay a supported ChatGPT/Codex sign-in to OpenAI-compatible clients, starting with self-hosted n8n.</p>
4
+ <p>Set up private n8n relays, Platform-key OpenAI-compatible local endpoints, and experimental Codex App Server sessions.</p>
5
5
  <p>
6
6
  <a href="https://github.com/Demonbane18/relmio">Full guide</a>
7
7
  &nbsp;·&nbsp;
@@ -11,6 +11,9 @@
11
11
  &nbsp;·&nbsp;
12
12
  <a href="https://github.com/Demonbane18/relmio/blob/main/docs/roadmap.md">Roadmap</a>
13
13
  </p>
14
+ <p>
15
+ <a href="https://ko-fi.com/paldogies"><img src="https://img.shields.io/badge/Ko--fi-support-ff5e5b.svg?logo=ko-fi&logoColor=white" alt="Support Relmio on Ko-fi"></a>
16
+ </p>
14
17
  </div>
15
18
 
16
19
  ## See it working first
@@ -40,11 +43,12 @@ Telegram, or AppBuildersPH.
40
43
  <figcaption>Telegram received the HTTP Request, Basic LLM Chain, and AI Agent outputs sent by that workflow.</figcaption>
41
44
  </figure>
42
45
 
43
- Relmio is a local browser wizard that installs a private
46
+ Relmio is a local browser wizard with separate setup paths. Its existing
47
+ VPS/n8n path installs a private
44
48
  [openai-oauth](https://github.com/EvanZhouDev/openai-oauth) Docker sidecar
45
- beside an existing self-hosted n8n instance. It guides you through local
46
- ChatGPT/Codex sign-in, SSH host verification, read-only n8n discovery, an
47
- exact change plan, and the final n8n credential settings.
49
+ beside an existing self-hosted n8n instance. Its local Docker path can install
50
+ either an OpenAI-compatible gateway backed by a Platform API key or the
51
+ official Codex App Server backed by ChatGPT sign-in.
48
52
 
49
53
  The existing n8n image, Compose file, container, and workflows stay untouched.
50
54
 
@@ -60,7 +64,7 @@ adds the missing capability without changing n8n.
60
64
  Try the hosted browser demo at
61
65
  [relmio.vercel.app](https://relmio.vercel.app/). It is a separate
62
66
  request-bound ChatGPT experience; the npm package remains the local wizard for
63
- installing the private n8n sidecar.
67
+ the private VPS/n8n sidecar and the separate local Docker endpoint paths.
64
68
 
65
69
  > **Warning — Hosted chat requires the browser extension.** Install the
66
70
  > open-source [Sign in with ChatGPT extension for
@@ -94,6 +98,52 @@ document scrolling on common laptop screens. On narrow phones, it switches to
94
98
  a horizontal progress strip and keeps task scrolling inside the active panel.
95
99
  The hosted site keeps the live GitHub star/version control visible.
96
100
 
101
+ ## Local Docker endpoints
102
+
103
+ Choose **Local endpoints** in the browser wizard to install one of these
104
+ Docker services on the same computer as your app:
105
+
106
+ This local Docker path supports macOS, Linux, and Linux under WSL2. Native
107
+ Windows is not supported in this release because its filesystem permissions do
108
+ not provide the owner-only POSIX mode guarantees used for local credentials.
109
+ The existing VPS/n8n wizard remains available from native Windows.
110
+
111
+ | Option | Local endpoint | Provider credential | Client type |
112
+ |---|---|---|---|
113
+ | **OpenAI API: compatible clients** | `http://127.0.0.1:12435/v1` by default | Server-side OpenAI Platform API key only | Private local app, SDK, or same-owner development web app |
114
+ | **Codex with ChatGPT: agent clients** | `ws://127.0.0.1:14500` by default | ChatGPT sign-in through Codex | Trusted native Codex/App Server client |
115
+
116
+ The OpenAI-compatible `/v1` endpoint is powered only by a Platform API key,
117
+ which the wizard seeds over stdin into a private, labeled Docker volume; it
118
+ does not create a host key file. Your app uses a
119
+ separate Relmio capability that the wizard displays once.
120
+ The bearer remains valid until it is rotated. Browser requests
121
+ must come from an exact origin entered during setup; wildcards are not allowed,
122
+ and the capability must never be embedded in a public frontend bundle. Platform
123
+ requests use that API project's billing, credits, limits, and permissions, not
124
+ a ChatGPT subscription.
125
+
126
+ ChatGPT sign-in powers only the official experimental Codex App Server JSON-RPC
127
+ protocol. It does not expose `/v1`, and Relmio never translates a ChatGPT
128
+ OAuth/session token into a general API credential. OpenAI documents the WebSocket transport as
129
+ experimental and unsupported for production, and it rejects browser-origin
130
+ connections. Use it only with a trusted native client owned by the same person.
131
+ Its capability is high-trust because it can operate the signed-in
132
+ Codex session and files inside the isolated container workspace.
133
+
134
+ Both services bind exactly to `127.0.0.1`, require the generated capability,
135
+ and mount no host directory or Docker socket. The Codex service gets private
136
+ named credential and workspace volumes. This local path does not connect to a
137
+ VPS or modify n8n.
138
+
139
+ Read the complete [Local Docker endpoints
140
+ guide](https://github.com/Demonbane18/relmio/blob/main/docs/local-endpoints.md)
141
+ before installing. It includes the wizard steps, client settings, exact-origin
142
+ rules, billing boundary, container isolation, and official OpenAI documentation
143
+ links. The design is documentation-backed engineering guidance, not legal
144
+ advice or an OpenAI approval. Codex for Open Source membership is not treated
145
+ as permission to broaden credential scope or bypass another agreement.
146
+
97
147
  ## Quick start
98
148
 
99
149
  Choose the terminal already on your own computer. Do not run these commands on
@@ -158,6 +208,10 @@ a browser.
158
208
 
159
209
  ### Requirements
160
210
 
211
+ These requirements are for the VPS/n8n path. For a local Docker endpoint, see
212
+ the [local endpoint
213
+ requirements](https://github.com/Demonbane18/relmio/blob/main/docs/local-endpoints.md#requirements).
214
+
161
215
  - On macOS/Linux/WSL/Git Bash: `curl`, `awk`, `tar`, and either `sha256sum` or
162
216
  `shasum`; Git Bash also needs `unzip`
163
217
  - On native Windows: Command Prompt uses its built-in `curl`, `certutil`, and
@@ -178,16 +232,18 @@ n8n AI node or HTTP Request
178
232
  -> upstream OpenAI service
179
233
  ```
180
234
 
181
- Relmio currently provides tested setup instructions for:
235
+ Relmio's existing VPS/n8n path provides tested setup instructions for:
182
236
 
183
237
  - OpenAI Chat Model
184
238
  - AI Agent
185
239
  - Basic LLM Chain
186
240
  - HTTP Request
187
241
 
188
- The broader direction is to support local chatbots, custom applications,
189
- OpenAI-compatible clients, and provider adapters without tying the public
190
- product name to n8n. SuperGrok/xAI OAuth is a gated feasibility item on the
242
+ The local endpoint path described above now supports compatible private apps
243
+ through a Platform-backed gateway and trusted native clients through Codex App
244
+ Server. The broader direction is to add providers and client adapters without
245
+ weakening their authentication boundaries or tying the public product name to
246
+ n8n. SuperGrok/xAI OAuth is a gated feasibility item on the
191
247
  [provider roadmap](https://github.com/Demonbane18/relmio/blob/main/docs/roadmap.md);
192
248
  it is not currently advertised as supported.
193
249
 
@@ -348,6 +404,7 @@ OpenAI may change or disable the underlying services at any time.
348
404
  ## Documentation
349
405
 
350
406
  - [Complete GitHub README and manual fallback](https://github.com/Demonbane18/relmio#readme)
407
+ - [Local Docker endpoints](https://github.com/Demonbane18/relmio/blob/main/docs/local-endpoints.md)
351
408
  - [Configure n8n AI and HTTP nodes](https://github.com/Demonbane18/relmio/blob/main/docs/n8n-configuration.md)
352
409
  - [Troubleshooting](https://github.com/Demonbane18/relmio/blob/main/docs/troubleshooting.md)
353
410
  - [Security and limitations](https://github.com/Demonbane18/relmio/blob/main/docs/security.md)
@@ -17,6 +17,52 @@ flowchart LR
17
17
  S --> C["OpenAI service used by<br>the upstream helper"]
18
18
  ```
19
19
 
20
+ ## Local endpoint architecture
21
+
22
+ The local installer is a separate path in the same browser wizard. It uses the
23
+ local Docker Engine and never opens SSH, writes to a VPS, or changes the
24
+ existing n8n sidecar project.
25
+
26
+ ```mermaid
27
+ flowchart LR
28
+ B["Local browser<br>127.0.0.1"] --> W["Local Node wizard"]
29
+ W --> D["Local Docker Engine"]
30
+ D --> G["OpenAI-compatible gateway<br>127.0.0.1:12435/v1"]
31
+ D --> A["Codex App Server<br>127.0.0.1:14500"]
32
+ G -->|"Platform API key"| P["OpenAI Platform API"]
33
+ A -->|"Official Codex sign-in"| C["ChatGPT/Codex service"]
34
+ ```
35
+
36
+ The two services are intentionally not interchangeable:
37
+
38
+ | Target | Wire protocol | Upstream credential |
39
+ |---|---|---|
40
+ | `openai-api` | OpenAI-compatible HTTP `/v1` | OpenAI Platform API key |
41
+ | `codex-chatgpt` | Official Codex App Server JSON-RPC | ChatGPT sign-in managed by Codex |
42
+
43
+ Relmio never adapts a ChatGPT/Codex credential into the local `/v1` gateway.
44
+ The OpenAI gateway replaces the caller's Relmio capability with the
45
+ protected Platform key only at the upstream boundary. The Codex service keeps
46
+ the native initialization, thread, turn, approval, and event protocol.
47
+
48
+ Both projects publish exactly one literal `127.0.0.1` binding and require a
49
+ generated bearer capability. Their managed roots are
50
+ `~/.relmio/local/openai-api` and `~/.relmio/local/codex-chatgpt`. The Codex
51
+ credential and workspace use private named Docker volumes; no host directory
52
+ or Docker socket is mounted. See [Local Docker endpoints](local-endpoints.md)
53
+ for setup and trust limitations.
54
+
55
+ Before installation, Relmio resolves the selected Docker context to a local
56
+ Unix socket and pins that exact socket on every later Docker command. Remote
57
+ Docker contexts and Docker environment overrides are rejected. Each endpoint
58
+ gets a random installation ID, a unique Compose project name, and matching
59
+ ownership labels; existing resources must attest to that identity before an
60
+ update or recovery action can run.
61
+
62
+ The local endpoint installer supports macOS, Linux, and Linux under WSL2.
63
+ Native Windows is rejected before filesystem or Docker mutation because this
64
+ release relies on owner-only POSIX modes for managed credentials.
65
+
20
66
  ## Why this integration is possible
21
67
 
22
68
  The design combines four existing interfaces rather than changing n8n:
@@ -114,6 +160,9 @@ sidecar authenticates upstream with the mounted OAuth file.
114
160
  - [Docker Compose networking](https://docs.docker.com/compose/how-tos/networking/)
115
161
  - [Docker Compose `expose`](https://docs.docker.com/reference/compose-file/services/#expose)
116
162
  - [Docker port publishing](https://docs.docker.com/engine/network/port-publishing/)
163
+ - [OpenAI API authentication](https://developers.openai.com/api/reference/overview#authentication)
164
+ - [Codex authentication](https://learn.chatgpt.com/docs/auth)
165
+ - [Codex App Server](https://learn.chatgpt.com/docs/app-server)
117
166
 
118
167
  ## Failure behavior
119
168
 
@@ -125,3 +174,11 @@ sidecar authenticates upstream with the mounted OAuth file.
125
174
  - A failed build or start does not trigger an n8n action.
126
175
  - An unexpected host-port mapping causes verification to fail.
127
176
  - The SSH connection closes after installation or when the wizard stops.
177
+ - A local port collision blocks a new local install or port change.
178
+ - An existing unmanaged or symlinked local path is never overwritten.
179
+ - A local service fails verification unless Docker reports the exact planned
180
+ `127.0.0.1` publication.
181
+ - A remote Docker context, inherited Docker selector, foreign Compose resource,
182
+ or mismatched managed identity blocks local mutation.
183
+ - A Codex login failure returns a sanitized status without returning App
184
+ Server output or ChatGPT tokens.
@@ -0,0 +1,370 @@
1
+ # Spec: Policy-safe local endpoints
2
+
3
+ ## Status
4
+
5
+ Approved for implementation on `codex/local-openai-endpoint` on 2026-08-13.
6
+
7
+ This spec is product and engineering guidance based on the current official
8
+ OpenAI documentation. It is not a legal opinion. Relmio must not claim that
9
+ OpenAI has endorsed, certified, or pre-approved the project.
10
+
11
+ ## Objective
12
+
13
+ Add a local Docker installation path to the Relmio browser wizard without
14
+ weakening the existing VPS/n8n safety boundary.
15
+
16
+ Relmio offers two intentionally different local providers:
17
+
18
+ 1. `openai-api` is an OpenAI-compatible HTTP gateway backed by the user's
19
+ OpenAI Platform API key.
20
+ 2. `codex-chatgpt` is the official Codex App Server protocol backed by the
21
+ user's ChatGPT/Codex sign-in.
22
+
23
+ Relmio must never exchange, translate, or present a ChatGPT/Codex credential as
24
+ a general OpenAI API bearer credential. The Codex provider must not expose an
25
+ OpenAI-shaped `/v1` compatibility surface.
26
+
27
+ ## Official-source boundary
28
+
29
+ - General OpenAI API requests use a Platform API key (or an officially
30
+ supported workload identity credential).
31
+ - ChatGPT subscription access stays inside the official Codex CLI/App Server
32
+ workflow.
33
+ - Codex App Server uses its native JSON-RPC thread, turn, approval, and event
34
+ protocol.
35
+ - Codex App Server WebSocket transport is experimental and unsupported for
36
+ production workloads. Relmio must display that limitation before install and
37
+ in the result screen.
38
+ - Codex for Open Source benefits remain personal, limited, and governed by the
39
+ program terms. Program acceptance does not become a generic credential-scope
40
+ waiver.
41
+
42
+ Primary references:
43
+
44
+ - <https://learn.chatgpt.com/docs/app-server>
45
+ - <https://learn.chatgpt.com/docs/auth>
46
+ - <https://learn.chatgpt.com/docs/enterprise/access-tokens>
47
+ - <https://developers.openai.com/api/reference/overview#authentication>
48
+ - <https://learn.chatgpt.com/docs/codex-for-oss-terms>
49
+
50
+ ## User experience
51
+
52
+ The existing VPS/n8n wizard remains a separate legacy setup path. The wizard
53
+ landing experience adds a prominent **Local endpoints** option which opens a
54
+ dedicated local installer.
55
+
56
+ The local installer starts with two provider cards:
57
+
58
+ ### OpenAI API
59
+
60
+ - Label: **OpenAI API — compatible clients**
61
+ - Default HTTP port: `12435`
62
+ - Requires an OpenAI Platform API key beginning with `sk-`.
63
+ - Accepts zero or more exact browser origins. No wildcard origin is allowed.
64
+ - Result:
65
+ - Base URL: `http://127.0.0.1:<port>/v1`
66
+ - A newly generated Relmio bearer key, displayed once
67
+ - A warning that the upstream Platform API key is seeded over stdin into a
68
+ private labeled Docker volume, never written to a host file, and never
69
+ returned by the wizard
70
+
71
+ ### Codex with ChatGPT
72
+
73
+ - Label: **Codex with ChatGPT — agent clients**
74
+ - Default WebSocket port: `14500`
75
+ - Uses pinned official `@openai/codex@0.147.0`.
76
+ - Result:
77
+ - Endpoint: `ws://127.0.0.1:<port>`
78
+ - A newly generated capability token, displayed once
79
+ - A device-code sign-in action using `account/login/start` with
80
+ `{ "type": "chatgptDeviceCode" }`
81
+ - An explicit statement that this is Codex JSON-RPC, not OpenAI `/v1`
82
+ - An explicit experimental/non-production notice
83
+
84
+ Both flows show a review screen and require a final confirmation before any
85
+ filesystem or Docker write.
86
+
87
+ This release supports macOS, Linux, and Linux under WSL2. Native Windows is
88
+ unsupported because its filesystem permission model does not provide the POSIX
89
+ owner-only protection this installer requires. The UI and documentation must
90
+ say so, and the installer must reject native Windows before any write.
91
+
92
+ ## Wizard API contract
93
+
94
+ Every wizard API route continues to require the existing `X-Setup-Token` and
95
+ same-origin protections.
96
+
97
+ ### `GET /api/local/docker/status`
98
+
99
+ Returns local Docker and Compose availability. It never returns filesystem
100
+ paths containing the user's home directory.
101
+
102
+ ```json
103
+ {
104
+ "dockerAvailable": true,
105
+ "dockerVersion": "27.0.0",
106
+ "composeVersion": "2.29.0"
107
+ }
108
+ ```
109
+
110
+ ### `POST /api/local/plan`
111
+
112
+ Request:
113
+
114
+ ```json
115
+ {
116
+ "target": "openai-api",
117
+ "port": 12435,
118
+ "allowedOrigins": ["http://localhost:3000"]
119
+ }
120
+ ```
121
+
122
+ The request never contains an upstream credential. The response contains an
123
+ opaque, single-use `planId` and the validated binding, managed path alias,
124
+ compatibility type, authentication type, and caveats.
125
+
126
+ ### `POST /api/local/install`
127
+
128
+ Request fields:
129
+
130
+ - `planId`: the opaque identifier returned by the most recent reviewed plan
131
+ - `apiKey`: required only for `openai-api`; accepted only in request memory
132
+ - `confirmed`: must be exactly `true`
133
+
134
+ The server consumes the plan before attempting installation, so callers cannot
135
+ change the reviewed target, port, or origins or replay a failed attempt.
136
+ The response never includes the upstream Platform API key or ChatGPT
137
+ credential. It includes the new local capability once.
138
+
139
+ Only one installation may execute in a wizard process at a time. A concurrent
140
+ attempt receives `409` without consuming its reviewed plan. The in-flight lock
141
+ is released in a `finally` path after both success and failure.
142
+
143
+ ### `POST /api/local/codex/login`
144
+
145
+ Starts an official Codex App Server device-code login through a one-shot stdio
146
+ App Server process attached to the same persistent Codex home volume.
147
+
148
+ Every login attempt resolves the managed Codex directory and attests its
149
+ schema-2 marker and matching Docker resources, even in a fresh wizard process.
150
+ The server passes only the attested Docker host and unique project name to the
151
+ stdio login service. An in-memory "installed" flag is not sufficient. Preview
152
+ mode and rate-limit guards run before attestation.
153
+
154
+ Response:
155
+
156
+ ```json
157
+ {
158
+ "verificationUrl": "https://auth.openai.com/...",
159
+ "userCode": "ABCD-EFGH"
160
+ }
161
+ ```
162
+
163
+ ### `GET /api/local/codex/login/status`
164
+
165
+ Returns `idle`, `pending`, `success`, or `error`. Errors are sanitized; raw
166
+ App Server output is never returned.
167
+
168
+ ## Local OpenAI gateway contract
169
+
170
+ ### Listener
171
+
172
+ - Container listener: `0.0.0.0:10531`
173
+ - Host publication: `127.0.0.1:<selected-port>:10531`
174
+ - A generated Compose file containing `0.0.0.0:<port>` or an unqualified
175
+ `<port>:<port>` mapping is invalid.
176
+
177
+ ### Authentication
178
+
179
+ - Relmio generates 32 random bytes and returns the base64url capability once.
180
+ - Only the SHA-256 verifier is persisted.
181
+ - Every operation that can reach `/v1` upstream requires
182
+ `Authorization: Bearer <Relmio capability>`. An exact-origin `OPTIONS`
183
+ preflight is the sole unauthenticated, non-forwarding metadata exception.
184
+ - Comparison uses a constant-time operation.
185
+ - The upstream OpenAI key replaces, and is never combined with, the client's
186
+ Authorization header.
187
+
188
+ ### Proxy behavior
189
+
190
+ - The upstream origin is fixed to `https://api.openai.com`.
191
+ - Only `GET /v1/models`, `POST /v1/responses`, and
192
+ `POST /v1/chat/completions` are forwarded.
193
+ - `CONNECT`, `TRACE`, absolute-form URLs, protocol-relative URLs, invalid Host
194
+ headers, and oversized headers are rejected.
195
+ - Hop-by-hop, cookie, forwarding, proxy-authorization, origin, and referrer
196
+ headers are not forwarded upstream.
197
+ - Response status, supported end-to-end headers, streaming bodies, client
198
+ cancellation, and backpressure are preserved.
199
+ - Upstream `429` responses and `Retry-After` are passed through unchanged.
200
+ - Local overload responses use `429` and never retry upstream automatically.
201
+
202
+ ### Browser origin policy
203
+
204
+ - Requests without `Origin` are accepted after bearer authentication.
205
+ - Browser requests require an exact configured `http` or `https` origin.
206
+ - Wildcards, `null`, credentials, paths, queries, and fragments are rejected.
207
+ - Preflight allows only the configured origin and a small documented header
208
+ list.
209
+ - Browser credentials are still caller secrets; Relmio must not encourage
210
+ embedding the local key in a public frontend bundle.
211
+
212
+ ### Health
213
+
214
+ - `GET /health` is the only unauthenticated gateway route.
215
+ - It returns only local process readiness and no provider/account details.
216
+
217
+ ## Codex App Server contract
218
+
219
+ The container command is equivalent to:
220
+
221
+ ```text
222
+ codex app-server
223
+ --strict-config
224
+ --listen ws://0.0.0.0:4500
225
+ --ws-auth capability-token
226
+ --ws-token-sha256 <sha256-verifier>
227
+ ```
228
+
229
+ The host mapping is exactly `127.0.0.1:<selected-port>:4500`.
230
+
231
+ - `CODEX_HOME` is a private named Docker volume.
232
+ - Credential storage is forced to file mode inside the container so refreshed
233
+ credentials remain in the private volume.
234
+ - Login mode is forced to ChatGPT.
235
+ - Root-owned managed requirements allow only Relmio's network-disabled
236
+ permission profile (which extends Codex's built-in workspace profile),
237
+ on-request/user-reviewed approvals, disabled web search, no login shell, and
238
+ a closed set of optional features. Clients cannot request
239
+ `danger-full-access` or approval policy `never`.
240
+ - An empty named workspace volume is mounted; no host source directory, Docker
241
+ socket, SSH key, browser profile, or home directory is mounted.
242
+ - `GET /readyz` is the Docker readiness probe.
243
+ - The client sends `Authorization: Bearer <capability>` during WebSocket
244
+ upgrade, then `initialize`, `initialized`, `account/read`, and the normal
245
+ thread/turn protocol.
246
+ - Relmio does not inject or return raw ChatGPT OAuth tokens through the wizard.
247
+ Raw App Server is a high-trust surface: possession of its capability can
248
+ control the isolated container and may expose the signed-in ChatGPT session.
249
+ The capability is therefore password-equivalent and limited to a trusted,
250
+ same-owner native client.
251
+
252
+ ## Local filesystem and process boundary
253
+
254
+ Managed roots:
255
+
256
+ - `~/.relmio/local/openai-api`
257
+ - `~/.relmio/local/codex-chatgpt`
258
+
259
+ `RELMIO_HOME` may replace `~/.relmio` for testing or advanced use, but it must
260
+ be an absolute path whose final component is `.relmio`.
261
+
262
+ Controls:
263
+
264
+ - Managed directories use mode `0700`; generated files use owner-only modes.
265
+ - The Platform API key is seeded over stdin by a transient, network-disabled
266
+ helper into a private labeled named volume and is never written to a host
267
+ file or Compose environment value.
268
+ - Existing unmanaged directories are never overwritten.
269
+ - Symlinks in a managed path are rejected.
270
+ - A schema-2 JSON marker identifies the target, configured port, validated
271
+ Docker host, 32-hex-character install ID, and collision-resistant Compose
272
+ project name; it contains no secrets.
273
+ - Docker is invoked with argument arrays and `shell: false`.
274
+ - The command allowlist is scoped to the selected Relmio Compose project and
275
+ service.
276
+ - No command targets n8n or `/docker/n8n-openai-oauth`.
277
+ - Local port availability is checked before a new install or a port change.
278
+ - Upstream credentials are cleared from request objects after installation
279
+ completes or fails.
280
+ - Native Windows is rejected before filesystem or Docker writes because the
281
+ required POSIX owner-only modes cannot be enforced there.
282
+
283
+ ## Container hardening
284
+
285
+ Both long-running endpoint services:
286
+
287
+ - run as a non-root user;
288
+ - set `no-new-privileges`;
289
+ - drop all Linux capabilities;
290
+ - use a read-only root filesystem;
291
+ - use bounded tmpfs, PID, memory, and CPU resources;
292
+ - have no Docker socket or host filesystem mount;
293
+ - publish one explicit loopback port only;
294
+ - use pinned application dependencies.
295
+
296
+ The OpenAI install also invokes a one-shot credential seed helper. It has no
297
+ network or published port, disables logging, uses the same read-only image,
298
+ sets `no-new-privileges`, and has tight CPU, memory, and PID limits. It runs as
299
+ root only long enough to replace the volume entry atomically and retains only
300
+ the `CHOWN` capability needed to make that entry readable by the non-root
301
+ gateway; it is removed immediately after seeding.
302
+
303
+ ## Threat model
304
+
305
+ ### Assets
306
+
307
+ - OpenAI Platform API key
308
+ - Codex/ChatGPT refresh and access credentials in the Codex volume
309
+ - generated local capability tokens
310
+ - user prompts, outputs, and Codex thread history
311
+ - local applications that trust the endpoint
312
+
313
+ ### Trust boundaries
314
+
315
+ - browser wizard to loopback wizard server
316
+ - wizard process to local filesystem
317
+ - wizard process to Docker Engine
318
+ - local client to published loopback endpoint
319
+ - gateway to `api.openai.com`
320
+ - Codex App Server to OpenAI's Codex services
321
+
322
+ ### Principal threats and controls
323
+
324
+ | Threat | Required control |
325
+ |---|---|
326
+ | LAN/public exposure | literal `127.0.0.1` Compose binding plus template and runtime inspection tests |
327
+ | Local cross-site request | bearer capability, exact Origin allowlist, strict preflight, Host validation |
328
+ | Upstream key disclosure | separate local/upstream credentials, stdin-seeded private named volume, redacted errors, no body logging |
329
+ | ChatGPT token repurposing | official App Server only; no `/v1` adapter for Codex |
330
+ | Command injection | validated scalar values, spawn argument arrays, no shell |
331
+ | Managed-path takeover | refuse unmanaged roots and every symlinked component |
332
+ | Streaming resource exhaustion | header/body/concurrency/time bounds and backpressure |
333
+ | Docker privilege compromise | document Docker control as a privileged local boundary; mount no Docker socket into services |
334
+ | Secret recovery from UI | show capabilities once; never use browser storage; rotate on reinstall |
335
+ | Codex capability compromise | explicit credential-equivalent warning; trusted same-owner native clients only; private container volumes and no host mounts |
336
+
337
+ ## Acceptance criteria
338
+
339
+ - The browser wizard visibly offers both local providers and the legacy VPS
340
+ path remains separate.
341
+ - Platform keys are accepted only by `openai-api`; ChatGPT auth is accepted only
342
+ by official App Server.
343
+ - Generated Compose files publish only literal loopback bindings.
344
+ - Every non-health gateway operation that can reach OpenAI and every App Server
345
+ WebSocket handshake is capability-authenticated; exact-origin CORS preflight
346
+ is a non-forwarding metadata exception.
347
+ - Gateway unit/integration tests cover auth, origins, Host validation,
348
+ streaming, cancellation, upstream errors, and secret redaction.
349
+ - Local installer tests prove confirmation, unmanaged-root refusal, symlink
350
+ refusal, port collision behavior, exact Docker arguments, file modes, and
351
+ absence of n8n commands.
352
+ - Server tests prove install serialization, lock release, and fresh-process
353
+ Codex login only after persisted installation attestation.
354
+ - Codex login tests use a fake stdio App Server process and cover initialization,
355
+ device-code response validation, completion, cancellation, malformed output,
356
+ and bounded output.
357
+ - Existing remote tests remain green.
358
+ - Opera GX runtime QA verifies keyboard flow, responsive layout, clean console,
359
+ no credential persistence, and correct mode-specific copy.
360
+ - Full `npm run check`, `npm audit --audit-level=high`, and
361
+ `npm pack --dry-run` succeed before handoff.
362
+
363
+ ## Out of scope
364
+
365
+ - Public, LAN, hosted, reverse-proxied, or multi-user endpoints
366
+ - Translating Codex turns into `/v1/chat/completions` or `/v1/responses`
367
+ - Sharing, pooling, reselling, or redistributing any ChatGPT account or benefit
368
+ - TLS termination (loopback-only transport is the boundary for this release)
369
+ - Automatic migration or modification of the existing VPS/n8n deployment
370
+ - A production-support promise for experimental Codex WebSocket transport