Skip to content

Commit 3fa6443

Browse files
committed
fix(dashboard): make Docker restarts authenticate and report honestly
The restart request lost its Authorization header after a save because auth() skipped fullBridgeKey() whenever pendingBridgeKey was set, while the server reported the key as [REDACTED] and localStorage was only written after a successful restart. Use pendingBridgeKey directly. restartBridge() was also a silent no-op on an unsupervised linux process, so /admin/restart answered ok while the container kept running the old configuration. Resolve the restart mode explicitly, return restart_requested: false with the reason when the process cannot restart itself, keep the configuration marked dirty in that case, and tell the operator in the dashboard instead of polling for a restart that will never arrive. Both Compose files now set COMMANDCODE_BRIDGE_RESTART_MODE so the button works out of the box. Closes #4
1 parent 7cca36a commit 3fa6443

11 files changed

Lines changed: 145 additions & 52 deletions

README.ko.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,17 @@ curl -sS http://127.0.0.1:9992/v1/chat/completions \
111111

112112
### API 표면
113113

114-
| Method | Path | Behavior |
115-
| ------ | -------------------------------- | ------------------------------------------------------------------------------------------------- |
116-
| `GET` | `/health` | Public secret-free health/runtime summary. |
117-
| `GET` | `/dashboard` | 신뢰 network용 public read-only shell. |
118-
| `GET` | `/v1/models` | `BRIDGE_API_KEY` 설정 시 인증; available model 목록. |
119-
| `GET` | `/v1/models/:model` | 설정 시 인증; 단일 available model 조회. |
120-
| `POST` | `/v1/chat/completions` | 설정 시 인증; streaming/non-streaming chat. |
121-
| `GET` | `/admin/config` | 신뢰 network의 public redacted dashboard state. |
122-
| `GET` | `/admin/commandcode/credentials` | Public redacted diagnostics; `?refresh=true`는 billing refresh. |
123-
| `PUT` | `/admin/config` | 현재 `BRIDGE_API_KEY` 인증 필요. key 없는 runtime은 peer와 Host가 모두 loopback일 때만 bootstrap. |
124-
| `POST` | `/admin/restart` | 동일한 인증 규칙 적용. restart가 끝날 때까지 기존 key가 current key. |
114+
| Method | Path | Behavior |
115+
| ------ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
116+
| `GET` | `/health` | Public secret-free health/runtime summary. |
117+
| `GET` | `/dashboard` | 신뢰 network용 public read-only shell. |
118+
| `GET` | `/v1/models` | `BRIDGE_API_KEY` 설정 시 인증; available model 목록. |
119+
| `GET` | `/v1/models/:model` | 설정 시 인증; 단일 available model 조회. |
120+
| `POST` | `/v1/chat/completions` | 설정 시 인증; streaming/non-streaming chat. |
121+
| `GET` | `/admin/config` | 신뢰 network의 public redacted dashboard state. |
122+
| `GET` | `/admin/commandcode/credentials` | Public redacted diagnostics; `?refresh=true`는 billing refresh. |
123+
| `PUT` | `/admin/config` | 현재 `BRIDGE_API_KEY` 인증 필요. key 없는 runtime은 peer와 Host가 모두 loopback일 때만 bootstrap. |
124+
| `POST` | `/admin/restart` | 동일한 인증 규칙 적용. restart가 끝날 때까지 기존 key가 current key. supervise되지 않아 스스로 재시작할 수 없으면 `restart_requested: false`를 반환합니다. |
125125

126126
### Model metadata와 정확한 catalog
127127

@@ -212,6 +212,8 @@ curl -sS http://127.0.0.1:9992/v1/chat/completions \
212212

213213
브라우저에 key가 저장된 기존 사용자는 그대로 동작합니다. 새 브라우저에서는 저장·재시작 전에 **현재 Admin API Key**에 기존 key를 한 번 입력합니다. key 없는 runtime은 실제 loopback 연결이며 Host도 loopback인 경우에만 bootstrap할 수 있습니다.
214214

215+
Dashboard의 재시작 버튼은 process가 supervise되는 환경에서만 저장한 설정을 적용합니다. systemd는 자동으로 감지하고, restart 정책을 둔 Docker를 포함한 그 밖의 supervisor는 `COMMANDCODE_BRIDGE_RESTART_MODE=exit`가 필요하며 제공되는 두 Compose 파일에 모두 설정돼 있습니다. 설정이 없으면 bridge는 종료를 거부하고 `POST /admin/restart``restart_requested: false`를 반환하며, 저장한 설정은 service를 직접 재시작할 때까지 적용 대기 상태로 남습니다.
216+
215217
Credential 우선순위는 `COMMANDCODE_CREDENTIALS_FILE`, `COMMANDCODE_CREDENTIALS`/`COMMANDCODE_API_KEYS`, `COMMAND_CODE_API_KEY`/`COMMANDCODE_API_KEY`/`CMD_API_KEY`, CLI auth file 순입니다. 핵심 기본값은 `HOST=127.0.0.1`, `PORT=9992`, `COMMANDCODE_UPSTREAM_MODE=auto`, `COMMANDCODE_ROUTING_POLICY=daily_burn_priority`, `COMMANDCODE_MAX_IN_FLIGHT_PER_CREDENTIAL=4`, `COMMANDCODE_CLI_VERSION=1.53.0`, `COMMANDCODE_TIMEOUT_MS=600000`, `COMMANDCODE_RETRY_MAX_ATTEMPTS=5`, `COMMANDCODE_RETRY_BACKOFF_MS=250`, `COMMANDCODE_EMPTY_VISIBLE_RESPONSE_POLICY=error_on_length`입니다. 일시적 upstream 실패(429, 5xx, timeout)는 `COMMANDCODE_RETRY_MAX_ATTEMPTS`까지 지수 백오프로 재시도합니다. 401/402/403으로 실패한 키는 해당 요청에서 제외되고 다른 키를 우선하며, visible output이 나온 뒤에는 재시도하지 않습니다. `BRIDGE_API_KEY`는 설정 시 `/v1/*`를 보호하며 client는 Bearer 또는 `x-api-key`를 쓸 수 있습니다. `COMMANDCODE_UPSTREAM_MODE=auto`는 시작 시 Provider API를 프로브해 요금제가 허용하면(Provider $15/월 이상) 공식 API를 쓰고, `provider`는 공식 API를 강제하며, `alpha`는 모든 model을 legacy `/alpha/generate`로 강제합니다. `COMMANDCODE_ZDR=true`면 Provider API 요청에 `x-cmd-zdr: 1`(zero data retention)을 보냅니다. Credential JSON은 `chmod 600`으로 보호하십시오. Balance alert는 기본 off입니다. 선택적 `commandcode-router`는 여러 bridge host의 least-in-flight routing용입니다.
216218

217219
## 동작 방식

README.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,17 @@ curl -sS http://127.0.0.1:9992/v1/chat/completions \
111111

112112
### API surface
113113

114-
| Method | Path | Behavior |
115-
| ------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
116-
| `GET` | `/health` | Public, secret-free health and runtime summary. |
117-
| `GET` | `/dashboard` | Public read-only shell for trusted networks. |
118-
| `GET` | `/v1/models` | Authenticated when `BRIDGE_API_KEY` is configured; lists available models. |
119-
| `GET` | `/v1/models/:model` | Authenticated when configured; retrieves one available model. |
120-
| `POST` | `/v1/chat/completions` | Authenticated when configured; streaming or non-streaming chat. |
121-
| `GET` | `/admin/config` | Public redacted dashboard state on the trusted network. |
122-
| `GET` | `/admin/commandcode/credentials` | Public redacted diagnostics; `?refresh=true` refreshes billing. |
123-
| `PUT` | `/admin/config` | Requires the current `BRIDGE_API_KEY`; a keyless runtime may bootstrap only over a loopback peer and loopback Host. |
124-
| `POST` | `/admin/restart` | Uses the same authentication rule; the pre-restart key remains current until restart completes. |
114+
| Method | Path | Behavior |
115+
| ------ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
116+
| `GET` | `/health` | Public, secret-free health and runtime summary. |
117+
| `GET` | `/dashboard` | Public read-only shell for trusted networks. |
118+
| `GET` | `/v1/models` | Authenticated when `BRIDGE_API_KEY` is configured; lists available models. |
119+
| `GET` | `/v1/models/:model` | Authenticated when configured; retrieves one available model. |
120+
| `POST` | `/v1/chat/completions` | Authenticated when configured; streaming or non-streaming chat. |
121+
| `GET` | `/admin/config` | Public redacted dashboard state on the trusted network. |
122+
| `GET` | `/admin/commandcode/credentials` | Public redacted diagnostics; `?refresh=true` refreshes billing. |
123+
| `PUT` | `/admin/config` | Requires the current `BRIDGE_API_KEY`; a keyless runtime may bootstrap only over a loopback peer and loopback Host. |
124+
| `POST` | `/admin/restart` | Uses the same authentication rule; the pre-restart key remains current until restart completes. Answers `restart_requested: false` when the process is unsupervised and cannot restart itself. |
125125

126126
### Model metadata and exact catalog
127127

@@ -212,6 +212,8 @@ Upgrades from a persisted dashboard catalog preserve each current model's enable
212212

213213
Existing browsers with a saved key continue without interruption. On a fresh browser, enter the current key in **Current Admin API Key** before saving or restarting. A runtime with no key can bootstrap only from a real loopback connection whose Host is also loopback.
214214

215+
The dashboard restart button applies a saved configuration only where the process is supervised. systemd is detected automatically; every other supervisor, including Docker with a restart policy, needs `COMMANDCODE_BRIDGE_RESTART_MODE=exit`, which both shipped Compose files set. Without it the bridge refuses to exit, `POST /admin/restart` reports `restart_requested: false`, and the saved configuration stays pending until the service is restarted by hand.
216+
215217
Credential precedence is `COMMANDCODE_CREDENTIALS_FILE`, `COMMANDCODE_CREDENTIALS`/`COMMANDCODE_API_KEYS`, then `COMMAND_CODE_API_KEY`/`COMMANDCODE_API_KEY`/`CMD_API_KEY`, then CLI auth files. Core defaults are `HOST=127.0.0.1`, `PORT=9992`, `COMMANDCODE_UPSTREAM_MODE=auto`, `COMMANDCODE_ROUTING_POLICY=daily_burn_priority`, `COMMANDCODE_MAX_IN_FLIGHT_PER_CREDENTIAL=4`, `COMMANDCODE_CLI_VERSION=1.53.0`, `COMMANDCODE_TIMEOUT_MS=600000`, `COMMANDCODE_RETRY_MAX_ATTEMPTS=5`, `COMMANDCODE_RETRY_BACKOFF_MS=250`, and `COMMANDCODE_EMPTY_VISIBLE_RESPONSE_POLICY=error_on_length`. Transient upstream failures (429, 5xx, timeouts) are retried with exponential backoff up to `COMMANDCODE_RETRY_MAX_ATTEMPTS`; a credential that fails with 401/402/403 is skipped for the rest of the request while other keys are preferred, and retries stop once any visible output has been emitted. `BRIDGE_API_KEY` protects `/v1/*` when set; clients may use Bearer or `x-api-key`. `COMMANDCODE_UPSTREAM_MODE=auto` probes the Provider API at startup and uses it whenever the plan allows (the Provider plan at $15/mo or higher); `provider` forces the official API and `alpha` forces the legacy `/alpha/generate` path for every model. Set `COMMANDCODE_ZDR=true` to send `x-cmd-zdr: 1` (zero data retention) on Provider API requests. Protect credential JSON with `chmod 600`. Optional balance alerts are off. Optional `commandcode-router` is for least-in-flight routing across multiple bridge hosts.
216218

217219
## How it works

README.zh.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,17 @@ curl -sS http://127.0.0.1:9992/v1/chat/completions \
111111

112112
### API 表面
113113

114-
| Method | Path | Behavior |
115-
| ------ | -------------------------------- | ------------------------------------------------------------------------------------------ |
116-
| `GET` | `/health` | Public、secret-free health/runtime summary。 |
117-
| `GET` | `/dashboard` | 可信 network 的 public read-only shell。 |
118-
| `GET` | `/v1/models` | 配置 `BRIDGE_API_KEY` 时认证;列出 available model。 |
119-
| `GET` | `/v1/models/:model` | 配置时认证;查询一个 available model。 |
120-
| `POST` | `/v1/chat/completions` | 配置时认证;streaming/non-streaming chat。 |
121-
| `GET` | `/admin/config` | 可信 network 上的 public redacted dashboard state。 |
122-
| `GET` | `/admin/commandcode/credentials` | Public redacted diagnostics;`?refresh=true` 刷新 billing。 |
123-
| `PUT` | `/admin/config` | 需要当前 `BRIDGE_API_KEY`;无 key runtime 仅可在 peer 与 Host 都为 loopback 时 bootstrap。 |
124-
| `POST` | `/admin/restart` | 使用相同认证规则;restart 完成前旧 key 仍是 current key。 |
114+
| Method | Path | Behavior |
115+
| ------ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
116+
| `GET` | `/health` | Public、secret-free health/runtime summary。 |
117+
| `GET` | `/dashboard` | 可信 network 的 public read-only shell。 |
118+
| `GET` | `/v1/models` | 配置 `BRIDGE_API_KEY` 时认证;列出 available model。 |
119+
| `GET` | `/v1/models/:model` | 配置时认证;查询一个 available model。 |
120+
| `POST` | `/v1/chat/completions` | 配置时认证;streaming/non-streaming chat。 |
121+
| `GET` | `/admin/config` | 可信 network 上的 public redacted dashboard state。 |
122+
| `GET` | `/admin/commandcode/credentials` | Public redacted diagnostics;`?refresh=true` 刷新 billing。 |
123+
| `PUT` | `/admin/config` | 需要当前 `BRIDGE_API_KEY`;无 key runtime 仅可在 peer 与 Host 都为 loopback 时 bootstrap。 |
124+
| `POST` | `/admin/restart` | 使用相同认证规则;restart 完成前旧 key 仍是 current key。进程未被 supervise、无法自行重启时返回 `restart_requested: false` |
125125

126126
### Model metadata 与准确 catalog
127127

@@ -212,6 +212,8 @@ curl -sS http://127.0.0.1:9992/v1/chat/completions \
212212

213213
浏览器已保存 key 的现有用户可继续使用。新浏览器在保存或重启前,需要在 **当前管理员 API Key** 中输入一次现有 key。无 key runtime 仅在真实 loopback 连接且 Host 也是 loopback 时允许 bootstrap。
214214

215+
Dashboard 的重启按钮只有在进程被 supervise 时才能应用已保存的配置。systemd 会被自动检测;包括配置了 restart 策略的 Docker 在内的其他 supervisor 需要 `COMMANDCODE_BRIDGE_RESTART_MODE=exit`,随附的两个 Compose 文件均已设置。未设置时 bridge 拒绝退出,`POST /admin/restart` 返回 `restart_requested: false`,已保存的配置会保持待应用状态,直到手动重启服务。
216+
215217
Credential 优先级为 `COMMANDCODE_CREDENTIALS_FILE`、`COMMANDCODE_CREDENTIALS`/`COMMANDCODE_API_KEYS`、`COMMAND_CODE_API_KEY`/`COMMANDCODE_API_KEY`/`CMD_API_KEY`、CLI auth file。核心默认值:`HOST=127.0.0.1`、`PORT=9992`、`COMMANDCODE_UPSTREAM_MODE=auto`、`COMMANDCODE_ROUTING_POLICY=daily_burn_priority`、`COMMANDCODE_MAX_IN_FLIGHT_PER_CREDENTIAL=4`、`COMMANDCODE_CLI_VERSION=1.53.0`、`COMMANDCODE_TIMEOUT_MS=600000`、`COMMANDCODE_RETRY_MAX_ATTEMPTS=5`、`COMMANDCODE_RETRY_BACKOFF_MS=250`、`COMMANDCODE_EMPTY_VISIBLE_RESPONSE_POLICY=error_on_length`。对瞬时上游故障(429、5xx、超时)按指数退避重试,最多 `COMMANDCODE_RETRY_MAX_ATTEMPTS` 次;以 401/402/403 失败的凭据会在本次请求中被跳过并优先使用其他 key,一旦产生可见输出即停止重试。设置后 `BRIDGE_API_KEY` 保护 `/v1/*`;client 可使用 Bearer 或 `x-api-key`。`COMMANDCODE_UPSTREAM_MODE=auto` 在启动时探测 Provider API,套餐允许时(Provider $15/月或更高)使用官方 API;`provider` 强制官方 API;`alpha` 强制所有模型走 legacy `/alpha/generate`。设 `COMMANDCODE_ZDR=true` 会在 Provider API 请求中发送 `x-cmd-zdr: 1`(zero data retention)。用 `chmod 600` 保护 credential JSON。Balance alert 默认关闭。可选 `commandcode-router` 用于多个 bridge host 的 least-in-flight routing。
216218

217219
## 工作原理

docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ services:
88
environment:
99
HOST: 0.0.0.0
1010
PORT: 9992
11+
# The dashboard restart button exits the process; the restart policy above brings it back.
12+
# Without this the container is unsupervised and /admin/restart cannot take effect.
13+
COMMANDCODE_BRIDGE_RESTART_MODE: exit
1114
ports:
1215
- "127.0.0.1:9992:9992"
1316
healthcheck:

0 commit comments

Comments
 (0)