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 +32 -0
- package/README.md +67 -10
- package/docs/architecture.md +57 -0
- package/docs/local-endpoints-spec.md +370 -0
- package/docs/local-endpoints.md +374 -0
- package/docs/npm-publish.md +121 -201
- package/docs/security.md +92 -3
- package/package.json +2 -2
- package/src/domain/local-endpoints.js +460 -0
- package/src/gateway/openai.js +834 -0
- package/src/infrastructure/local-process.js +375 -0
- package/src/services/codex-login.js +711 -0
- package/src/services/local-installer.js +1120 -0
- package/src/ui/app.js +4 -0
- package/src/ui/index.html +13 -0
- package/src/ui/local.css +262 -0
- package/src/ui/local.html +442 -0
- package/src/ui/local.js +550 -0
- package/src/web/server.js +247 -12
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>
|
|
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
|
·
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
·
|
|
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
|
|
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.
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
189
|
-
|
|
190
|
-
|
|
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)
|
package/docs/architecture.md
CHANGED
|
@@ -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
|