Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## Unreleased

### Security

- Validate the actual client address and require a separate caller token for
explicitly enabled non-loopback access.
- Refuse insecure non-loopback startup configurations.

### Changed

- Reject unknown or malformed model IDs before routing instead of silently
substituting `deepseek-v4-flash`.
- Avoid reverse-DNS lookup delays while starting the local listener.
- Clarify the project's independent, single-user credential and policy boundary.

## [0.4.10] - 2026-08-14

## [0.4.8] - 2026-08-14
Expand Down
329 changes: 204 additions & 125 deletions README.md

Large diffs are not rendered by default.

49 changes: 42 additions & 7 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Security

`opencode-go-proxy` is intended to run as a local adapter between Codex
and an upstream Chat Completions API.
`opencode-go-proxy` is an independent, single-user local adapter between Codex
and user-selected model providers. It is not affiliated with, sponsored by, or
endorsed by OpenAI or OpenCode.

The project is not an account-sharing service. It does not provide pooled
accounts, shared credentials, subscription resale, or rate-limit
circumvention. Users must use accounts and credentials they are authorized to
use and remain responsible for current provider terms and policies.

## Secrets

Expand All @@ -11,12 +17,40 @@ upstream API key in this order:
1. The configured environment variable, defaulting to `OPENCODE_GO_API_KEY`.
2. The macOS keychain entry `opencode-go-api-key` (override with `CODEX_KEYCHAIN_SERVICE`).

Only credential-source metadata is traced. Credential values are retained only
in process memory and are not written to the proxy's meter, trace, catalog, or
support bundle.

Native OpenAI requests are a separate path. If a requested model is in the
captured native Codex catalog, the proxy relays the client's existing
authorization to the configured native HTTPS endpoint. It does not store that
authorization, convert it into an OpenCode credential, or send the OpenCode
key to the native endpoint. Only set `OPENCODE_GO_PROXY_NATIVE_BASE_URL` to an
endpoint you trust with that native authorization.

## Network exposure

Bind to `127.0.0.1` unless you have a deliberate reason to expose the proxy.
The proxy emits a `security.warning` trace when bound to a non-localhost address.
Codex should talk to the local `/v1/responses` endpoint, and the proxy should
be the only process that talks to the upstream API with the real provider key.
The default bind is `127.0.0.1`. Requests are checked against both their `Host`
header and the actual socket peer address, and browser-originated requests are
rejected.

A non-loopback bind fails closed unless:

1. `OPENCODE_GO_PROXY_ALLOW_REMOTE=1` is set.
2. `OPENCODE_GO_PROXY_CALLER_TOKEN` contains at least 32 characters.
3. Every non-loopback client sends that value in
`X-OpenCode-Go-Proxy-Token`.

The caller token protects access to the proxy; it is not an upstream provider
credential. The proxy does not forward `X-OpenCode-Go-Proxy-Token` to native or
routed providers. Use a random token, TLS, and network-level access controls
for any deliberate remote deployment. Do not expose a plaintext listener to
the public internet.

For OpenCode routes, the proxy constructs upstream authorization from the
user-owned environment or keychain credential; it does not forward the
client's bearer token. Native relaying has an explicit header allowlist and
excludes hop-by-hop and proxy-control headers.

## SSRF protection

Expand All @@ -32,4 +66,5 @@ that could be used to probe internal services via the upstream.
## Reports

Open a private security advisory or contact the maintainers before publishing a
bug report that includes credentials, prompts, tool outputs, or request traces.
bug report involving credentials, prompts, tool outputs, or request traces.
Never include live credentials or authorization headers in a report.
112 changes: 112 additions & 0 deletions contrib/opencode-go-models.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions contrib/systemd/opencode-go-proxy.service
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ Environment=HOME=%h
Environment=PATH=%h/.local/bin:%h/.cargo/bin:%h/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONUNBUFFERED=1
Environment=CODEX_MODEL_CATALOG=%h/.codex/opencode-go-proxy/opencode-go-catalog.json
Environment=OPENCODE_GO_PROXY_USER_AGENT=codex/1.0
ExecStart=/usr/bin/env uvx --from git+https://github.com/kartikkabadi/opencode-go-proxy opencode-go-proxy --bind 127.0.0.1 --port 8787 --chat-base-url https://opencode.ai/zen/go/v1
ExecStart=/usr/bin/env uvx --from git+https://github.com/kartikkabadi/opencode-go-proxy@v0.4.10 opencode-go-proxy --bind 127.0.0.1 --port 8787 --chat-base-url https://opencode.ai/zen/go/v1
Restart=on-failure
RestartSec=3

Expand Down
10 changes: 5 additions & 5 deletions macos/MenuBarApp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The menu bar shows a small branch icon (no long "opencode go/" text). The menu s
- Today's turns and tokens, plus a 7-day token bar list (from `GET /state`)
- current model (the most recent meter event, else the proxy default)
- Start/Stop Proxy: launches `uvx --from git+... opencode-go-proxy` as a child process,
writing logs to `~/.codex/logs/opencode-go-proxy.{log,err}` (same paths as the launchd plist)
writing logs to `~/.codex/logs/opencode-go-proxy.{log,err}`
- Open Logs / Reveal Log File
- Copy Port
- Quit (stops the child proxy first)
Expand Down Expand Up @@ -41,10 +41,10 @@ cp -R .build/release/OpenCodeGoMenuBar OpenCodeGoMenuBar.app/Contents/MacOS/
## Notes

- The Python bridge is untouched; the app only manages it as a child process.
- Single-port guard: the app refuses to Start if another process already listens on
127.0.0.1:8787 (for example the launchd agent), instead of spawning a second proxy that
would fail to bind. One proxy per port. To switch from launchd to the menu bar, stop the
launchd agent first (`launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.opencode-go.proxy.plist`).
- Single-service, single-port: the menu bar app is the macOS supervisor and owns one
child proxy on `127.0.0.1:8787`. It refuses to start when another process owns the
port and automatically unloads the recognized pre-0.3.0 launchd job during migration.
Do not run a separate launchd proxy alongside the app.
- The spawned proxy resolves the API key exactly as the CLI does: `$OPENCODE_GO_API_KEY`
first, then `$OPENCODE_API_KEY`, then the macOS keychain services `opencode-go-api-key`
and `codex-router-opencode-go`.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ enum ProxySourceResolver {
static let defaultsKey = "proxySource"

/// The pinned source baked into this build (bumped at release time).
static let compiledSource = "git+https://github.com/kartikkabadi/opencode-go-proxy@v0.4.8"
static let compiledSource = "git+https://github.com/kartikkabadi/opencode-go-proxy@v0.4.10"

/// A defaults override wins over the compiled pin; an empty or missing
/// value falls back to `fallbackProxySource` (the compiled pin).
Expand Down Expand Up @@ -516,8 +516,8 @@ final class ProxyController {
}

private func childEnvironment() -> [String] {
// Menu bar apps launch without the shell PATH; give the child the same
// PATH shape as the launchd plist plus a stable HOME.
// Menu bar apps launch without the shell PATH; give the child a stable
// user-tool PATH and HOME.
let home = FileManager.default.homeDirectoryForCurrentUser.path
let processInfo = ProcessInfo.processInfo
var vars = processInfo.environment
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "opencode-go-proxy"
version = "0.4.10"
description = "Use your OpenCode Go subscription in Codex — local Responses-to-Chat-Completions bridge"
description = "Local single-user adapter for using OpenCode Go and Zen models with Codex"
readme = "README.md"
authors = [{ name = "Kartik Kabadi", email = "1kartikkabadi1@gmail.com" }]
license = "MIT"
Expand Down
Loading
Loading