From 71c57ea647fbc376d1207f11d851c09504c9c02d Mon Sep 17 00:00:00 2001 From: bitkyc08-arch Date: Tue, 25 Aug 2026 10:37:05 +0900 Subject: [PATCH 1/4] release: v2.32.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f73ed2d0e5..063ecfe73e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitkyc08/opencodex", - "version": "2.32.0", + "version": "2.32.1", "description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code", "type": "module", "main": "./bin/package-main.mjs", From ec51e42d745d2645bcb22cb67855fa053ba1778e Mon Sep 17 00:00:00 2001 From: bitkyc08-arch Date: Tue, 25 Aug 2026 20:25:22 +0900 Subject: [PATCH 2/4] release: v2.33.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 063ecfe73e..6f8499ffbf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitkyc08/opencodex", - "version": "2.32.1", + "version": "2.33.0", "description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code", "type": "module", "main": "./bin/package-main.mjs", From aaa9eaf37058965373dc42d1ca344e987950b6b6 Mon Sep 17 00:00:00 2001 From: JUN Date: Wed, 2 Sep 2026 18:43:29 +0900 Subject: [PATCH 3/4] fix(release): pass the bump job's permissions through the reusable-workflow call (#3262) Both v2.40.0 release dispatches (33615174183 preview, 33615177849 main) died at startup_failure: a workflow_call cannot grant its callee more than the calling job holds, and dev-version-bump.yml's job declares contents+pull- requests write. #3129 wired the call but never dispatched a release, so this is its first live run. The caller job now declares exactly the callee's two permissions; no other job in release.yml gains anything. Co-authored-by: jun (cherry picked from commit 7ce0ba51834740d7b4d5ec4793f6572d84624409) --- .github/workflows/release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 458bb67e0a..261aece1d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,6 +67,14 @@ jobs: bump-dev-version: needs: publish if: ${{ inputs.dry-run != true }} + # A reusable-workflow CALL cannot grant the callee more than the calling job holds, + # and GitHub refuses the whole run at startup when the called workflow's own job + # declares permissions the caller did not pass down ("startup_failure", runs + # 33615174183 / 33615177849 — the first dispatches since #3129 wired this call). + # The callee's job declares exactly these two; nothing else in this file gains them. + permissions: + contents: write + pull-requests: write uses: ./.github/workflows/dev-version-bump.yml with: released-version: v${{ inputs.version }} From 332061470f02488923d0950109126a62ff7e78b7 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Thu, 3 Sep 2026 14:52:36 +0900 Subject: [PATCH 4/4] fix(auth): reject spoofed Tailscale identity on ingress --- .../src/content/docs/fr/guides/remote-hub.md | 3 +- .../src/content/docs/guides/remote-hub.md | 19 ++++---- .../src/content/docs/ja/guides/remote-hub.md | 3 +- .../src/content/docs/ko/guides/remote-hub.md | 3 +- .../docs/reference/configuration/server.md | 8 ++-- .../src/content/docs/ru/guides/remote-hub.md | 3 +- .../src/content/docs/tr/guides/remote-hub.md | 3 +- .../content/docs/zh-cn/guides/remote-hub.md | 3 +- .../content/docs/zh-tw/guides/remote-hub.md | 3 +- src/server/index.ts | 7 +-- structure/05_gui-and-management-api.md | 13 +++--- tests/server-management-auth.test.ts | 43 ++----------------- 12 files changed, 32 insertions(+), 79 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/remote-hub.md b/docs-site/src/content/docs/fr/guides/remote-hub.md index 71b52ad422..0e7d7064aa 100644 --- a/docs-site/src/content/docs/fr/guides/remote-hub.md +++ b/docs-site/src/content/docs/fr/guides/remote-hub.md @@ -17,7 +17,7 @@ ocx sync La clé client est écrite dans le fichier privé `service-api-token`, jamais dans `config.json`. En mode connecté, l’usage provient du hub et est filtré par `apiKeyId`; après déconnexion, il provient du stockage local. Il n’existe aucune réplication entre les deux. -Le jeton admin permet la gestion ordinaire mais ne peut jamais créer une session de consentement. Les actions de consentement exigent une `gui-session`, une Origin correspondante et un jeton CSRF. `Tailscale-User-Login` n’est fiable que sur l’entrée de gestion dédiée; renseignez les identités exactes dans `remoteGui.allowedTailscaleUsers`. +Le jeton admin permet la gestion ordinaire mais ne peut jamais créer une session de consentement. Les actions de consentement exigent une `gui-session`, une Origin correspondante et un jeton CSRF. L’entrée TCP loopback ne fait pas confiance à `Tailscale-User-Login`; les sessions distantes utilisent l’association à usage unique. ## Service et Tailscale Serve @@ -27,7 +27,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ``` diff --git a/docs-site/src/content/docs/guides/remote-hub.md b/docs-site/src/content/docs/guides/remote-hub.md index 16ef574ab1..a384f2e43d 100644 --- a/docs-site/src/content/docs/guides/remote-hub.md +++ b/docs-site/src/content/docs/guides/remote-hub.md @@ -21,9 +21,9 @@ public-internet surface and is outside this deployment model. - A raw management admin token can perform ordinary administration, but it cannot mint a browser session or authorize consent-bearing actions such as starring the repository. Those actions require a server-issued `gui-session`, matching browser origin, and CSRF token. -- `Tailscale-User-Login` is trusted only on the separately bound management ingress. The same header - on the public listener is ignored. `remoteGui.allowedTailscaleUsers` controls session issuance; it - does not create a new general-purpose principal. +- `Tailscale-User-Login` is not trusted on the loopback TCP management ingress. Any local process can + connect to that socket and forge proxy headers, so remote browser sessions use the one-use pairing + flow instead. ## Roles and direct data flow @@ -77,7 +77,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' # Generate/read this in a protected operator shell or secret manager. # It is a data-admission token, not a provider credential. @@ -113,9 +112,9 @@ tailscale serve --bg --https=443 http://127.0.0.1:10101 tailscale serve status ``` -Set `hub.managementPublicOrigin` to the exact HTTPS origin shown by Serve. Add the operator's exact -Tailscale login to `remoteGui.allowedTailscaleUsers`; an empty list means no remote identity can mint -a session. Verify both directions: +Set `hub.managementPublicOrigin` to the exact HTTPS origin shown by Serve. The loopback backend does +not accept Tailscale identity headers as authentication; establish the browser session with the +single-use pairing flow. Verify both directions: ```bash # Negative: the loopback-only port must not be reachable through the node's tailnet address. @@ -125,9 +124,8 @@ curl --fail --connect-timeout 3 http://100.64.0.10:10101/ && echo "unexpected ex curl --fail --silent --show-error https://hub-name.tailnet-name.ts.net/ >/dev/null ``` -The positive browser test must use a real signed-in Tailscale session; a bare `curl` may not carry the -identity headers needed for automatic session issuance. Pairing remains the fallback when the HTTPS -frontend cannot provide trustworthy Tailscale identity. +The positive browser test verifies transport reachability only. Complete the one-use pairing flow to +create a remote browser session. ### Operator-owned ts.net certificate proxy @@ -231,7 +229,6 @@ docker compose run --rm hub bun run src/cli/index.ts config set runtimeRole hub docker compose run --rm hub bun run src/cli/index.ts config set hostname 0.0.0.0 docker compose run --rm hub bun run src/cli/index.ts config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' docker compose run --rm hub bun run src/cli/index.ts config set hub.managementIngress '{"enabled":true,"port":10101}' -docker compose run --rm hub bun run src/cli/index.ts config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' docker compose up -d ``` diff --git a/docs-site/src/content/docs/ja/guides/remote-hub.md b/docs-site/src/content/docs/ja/guides/remote-hub.md index cc441e1956..cecd019dcb 100644 --- a/docs-site/src/content/docs/ja/guides/remote-hub.md +++ b/docs-site/src/content/docs/ja/guides/remote-hub.md @@ -17,7 +17,7 @@ ocx sync 発行されたキーは所有者だけが読める `service-api-token` に保存され、`config.json` には入りません。接続中の使用量は hub 側で同じ `apiKeyId` に絞り込まれ、切断後はローカル保存分を表示します。両者はミラーリングされません。 -管理トークンは通常の管理だけに使え、同意セッションを作ることは永久にできません。同意操作にはサーバー発行の `gui-session`、一致する Origin、CSRF が必要です。`Tailscale-User-Login` は専用管理リスナーでのみ信頼し、許可する ID を `remoteGui.allowedTailscaleUsers` に正確に設定します。 +管理トークンは通常の管理だけに使え、同意セッションを作ることは永久にできません。同意操作にはサーバー発行の `gui-session`、一致する Origin、CSRF が必要です。Loopback TCP 管理入口は `Tailscale-User-Login` を信頼せず、リモートブラウザーセッションには一度限りのペアリングを使います。 ## サービスと Tailscale Serve @@ -27,7 +27,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ``` diff --git a/docs-site/src/content/docs/ko/guides/remote-hub.md b/docs-site/src/content/docs/ko/guides/remote-hub.md index 970a52cb1f..70a5c2ead3 100644 --- a/docs-site/src/content/docs/ko/guides/remote-hub.md +++ b/docs-site/src/content/docs/ko/guides/remote-hub.md @@ -28,7 +28,7 @@ ocx sync - 프로바이더/OAuth 인증 정보는 허브 밖으로 복사하지 마세요. - 데이터 키는 `service-api-token` 또는 `OCX_API_TOKEN_FILE`로 전달하며 관리 권한이 없습니다. - 관리자 토큰은 일반 관리 작업만 할 수 있습니다. 브라우저 동의 세션을 만들거나 저장소 Star 같은 동의 작업을 승인할 수는 없습니다. 그런 작업에는 서버가 발급한 `gui-session`, 일치하는 Origin, CSRF 토큰이 필요합니다. -- `Tailscale-User-Login`은 별도 관리 리스너에서만 신뢰합니다. 공개 리스너의 같은 헤더는 무시합니다. `remoteGui.allowedTailscaleUsers`에는 허용할 로그인 ID를 정확히 적으세요. +- 루프백 TCP 관리 리스너는 `Tailscale-User-Login`을 신뢰하지 않습니다. 원격 브라우저 세션은 일회용 pairing으로 생성합니다. ## systemd 또는 launchd @@ -38,7 +38,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ocx service status diff --git a/docs-site/src/content/docs/reference/configuration/server.md b/docs-site/src/content/docs/reference/configuration/server.md index 1a82eb82cd..d1fa9222fa 100644 --- a/docs-site/src/content/docs/reference/configuration/server.md +++ b/docs-site/src/content/docs/reference/configuration/server.md @@ -275,10 +275,8 @@ intended account and workload. | --- | --- | --- | --- | | `hub.managementPublicOrigin` | string | unset | The canonical browser-reachable management origin a hub advertises, for example the HTTPS origin Tailscale Serve prints. It is what `/readyz` reports as `managementUrl` while `runtimeRole` is `hub`; with it unset the hub falls back to whatever origin each request arrived on, so a client behind a different frontend can be handed an address it cannot reach. | | `hub.managementIngress` | `{enabled:false}` or `{enabled:true, port}` | `{enabled:false}` | An extra management-only listener for a local HTTPS frontend. The hostname is not configurable: when enabled the socket always binds `127.0.0.1`, and only GUI, session-bootstrap, and management API routes are admitted. Data-plane routes are rejected before dispatch. | -| `remoteGui.allowedTailscaleUsers` | string[] | `[]` (empty — nobody) | Exact Tailscale login identities allowed to be issued an automatic remote GUI session. The `Tailscale-User-Login` header is trusted **only** on the separate management ingress; an empty list means no remote identity can mint a session, which is the safe default rather than an oversight. Identities are compared exactly, so a typo silently denies access. | +| `remoteGui.allowedTailscaleUsers` | string[] | `[]` | Retained for configuration compatibility. The loopback TCP management ingress does not trust `Tailscale-User-Login`, because local callers can forge proxy headers; remote browser sessions use one-use pairing instead. | | `remoteGui.allowInsecureHttp` | boolean | unset | **Retired — has no effect.** It once permitted a one-time pairing exchange over non-loopback plaintext HTTP. A pairing grant now crosses loopback or authenticated HTTPS only. The key is still parsed so an existing `config.json` keeps loading (the schema is strict, and dropping the key outright would make an older config fail to load entirely); a persisted `true` is reported once and then ignored. Remove it from your config. | -A hub that is reachable from a browser needs `hub.managementPublicOrigin` and at least one entry -in `remoteGui.allowedTailscaleUsers`. Setting the origin without the user list produces a hub that -advertises itself correctly and then refuses every session; setting the user list without the -origin produces sessions pointed at whichever origin the request happened to use. +A hub that is reachable from a browser needs `hub.managementPublicOrigin`; remote browser sessions +are established through the one-use pairing flow. diff --git a/docs-site/src/content/docs/ru/guides/remote-hub.md b/docs-site/src/content/docs/ru/guides/remote-hub.md index e225d2564e..a2befd37b7 100644 --- a/docs-site/src/content/docs/ru/guides/remote-hub.md +++ b/docs-site/src/content/docs/ru/guides/remote-hub.md @@ -17,7 +17,7 @@ ocx sync Ключ клиента записывается в защищённый `service-api-token`, а не в `config.json`. При подключении статистика читается с hub и фильтруется по `apiKeyId`; после отключения используется локальное хранилище. Зеркалирования нет. -Admin token разрешает обычное управление, но никогда не создаёт consent session. Для действий с согласием нужны `gui-session`, совпадающий Origin и CSRF. Заголовок `Tailscale-User-Login` доверен только отдельному management ingress; точные логины задаются в `remoteGui.allowedTailscaleUsers`. +Admin token разрешает обычное управление, но никогда не создаёт consent session. Для действий с согласием нужны `gui-session`, совпадающий Origin и CSRF. Loopback TCP ingress не доверяет `Tailscale-User-Login`; удалённая browser session создаётся через одноразовое pairing. ## Сервис и Tailscale Serve @@ -27,7 +27,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ``` diff --git a/docs-site/src/content/docs/tr/guides/remote-hub.md b/docs-site/src/content/docs/tr/guides/remote-hub.md index ab19f9f06f..c3533462e1 100644 --- a/docs-site/src/content/docs/tr/guides/remote-hub.md +++ b/docs-site/src/content/docs/tr/guides/remote-hub.md @@ -17,7 +17,7 @@ ocx sync İstemci anahtarı yalnızca sahibinin okuyabildiği `service-api-token` dosyasına yazılır, `config.json` içine yazılmaz. Bağlı kullanım hub deposundan aynı `apiKeyId` ile filtrelenir; bağlantı kesilince yerel depo kullanılır. İki depo birbirini yansıtmaz. -Admin token sıradan yönetim yapabilir ancak hiçbir zaman onay oturumu oluşturamaz. Onay işlemleri sunucu tarafından verilen `gui-session`, eşleşen Origin ve CSRF ister. `Tailscale-User-Login` yalnızca ayrı yönetim girişinde güvenilirdir; tam kimlikleri `remoteGui.allowedTailscaleUsers` içinde belirtin. +Admin token sıradan yönetim yapabilir ancak hiçbir zaman onay oturumu oluşturamaz. Onay işlemleri sunucu tarafından verilen `gui-session`, eşleşen Origin ve CSRF ister. Loopback TCP girişi `Tailscale-User-Login` başlığına güvenmez; uzak tarayıcı oturumları tek kullanımlık eşleştirme ile oluşturulur. ## Servis ve Tailscale Serve @@ -27,7 +27,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ``` diff --git a/docs-site/src/content/docs/zh-cn/guides/remote-hub.md b/docs-site/src/content/docs/zh-cn/guides/remote-hub.md index f9179e8df9..26b74df2f6 100644 --- a/docs-site/src/content/docs/zh-cn/guides/remote-hub.md +++ b/docs-site/src/content/docs/zh-cn/guides/remote-hub.md @@ -17,7 +17,7 @@ ocx sync 客户端密钥写入仅所有者可读的 `service-api-token`,绝不会写入 `config.json`。连接期间,使用记录来自 hub 并按稳定的 `apiKeyId` 过滤;断开后显示本地记录。两者不会镜像。 -Admin token 只能执行普通管理,永远不能创建用户同意会话。用户同意操作必须使用服务器签发的 `gui-session`、匹配的 Origin 和 CSRF。`Tailscale-User-Login` 只在独立管理入口可信;请在 `remoteGui.allowedTailscaleUsers` 中填写准确登录名。 +Admin token 只能执行普通管理,永远不能创建用户同意会话。用户同意操作必须使用服务器签发的 `gui-session`、匹配的 Origin 和 CSRF。Loopback TCP 管理入口不信任 `Tailscale-User-Login`;远程浏览器会话使用一次性配对建立。 ## systemd/launchd 与 Tailscale Serve @@ -27,7 +27,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ``` diff --git a/docs-site/src/content/docs/zh-tw/guides/remote-hub.md b/docs-site/src/content/docs/zh-tw/guides/remote-hub.md index 3c05e6f100..616c602e03 100644 --- a/docs-site/src/content/docs/zh-tw/guides/remote-hub.md +++ b/docs-site/src/content/docs/zh-tw/guides/remote-hub.md @@ -17,7 +17,7 @@ ocx sync 用戶端金鑰會寫入只有擁有者可讀的 `service-api-token`,絕不寫入 `config.json`。連線期間,用量來自 hub 並依穩定的 `apiKeyId` 篩選;中斷後則顯示本機記錄。兩者不會互相鏡像。 -Admin token 只能執行一般管理,永遠不能建立使用者同意工作階段。同意操作必須使用伺服器簽發的 `gui-session`、相符的 Origin 與 CSRF。`Tailscale-User-Login` 只在獨立管理入口可信;請在 `remoteGui.allowedTailscaleUsers` 填入完整且正確的登入名稱。 +Admin token 只能執行一般管理,永遠不能建立使用者同意工作階段。同意操作必須使用伺服器簽發的 `gui-session`、相符的 Origin 與 CSRF。Loopback TCP 管理入口不信任 `Tailscale-User-Login`;遠端瀏覽器工作階段使用一次性配對建立。 ## systemd/launchd 與 Tailscale Serve @@ -27,7 +27,6 @@ ocx config set hostname 100.64.0.10 ocx config set hub.managementPublicOrigin '"https://hub-name.tailnet-name.ts.net"' ocx config set corsAllowOrigins '["http://localhost:10100"]' ocx config set hub.managementIngress '{"enabled":true,"port":10101}' -ocx config set remoteGui.allowedTailscaleUsers '["operator@example.com"]' export OPENCODEX_API_AUTH_TOKEN="$(openssl rand -hex 32)" ocx service install ``` diff --git a/src/server/index.ts b/src/server/index.ts index eab0ba1d7f..5f166e3881 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -763,7 +763,8 @@ export function startServer(port?: number, deps: StartServerDeps = {}): Server { }), httpConfig, state, { trustedTailscaleIngress: true, now })).toBeNull(); }); - test("the live listener trusts Tailscale identity only on hub management ingress", async () => { + test("the live management listener does not trust caller-supplied Tailscale identity", async () => { const managementPort = await findAvailablePort(0, "127.0.0.1"); const publicPort = await findAvailablePort(0, "127.0.0.1", { reservedPort: managementPort }); const config = hubConfig(); @@ -994,44 +994,9 @@ describe("management and data-plane credential separation", () => { const spoofedPublic = await fetch(new URL("/opencodex-session", server.url), { headers }); expect(spoofedPublic.status).toBe(401); - const wrongUser = await fetch(`http://127.0.0.1:${managementPort}/opencodex-session`, { - headers: { ...headers, "Tailscale-User-Login": "mallory@example.test" }, - }); - expect(wrongUser.status).toBe(401); - - const issued = await fetch(`http://127.0.0.1:${managementPort}/opencodex-session`, { headers }); - expect(issued.status).toBe(200); - const html = await issued.text(); - const token = /name="opencodex-session-token" content="([^"]+)"/.exec(html)?.[1]; - expect(token).toBeDefined(); - const sessionHeaders = { - Host: "hub.example.test", - Origin: "https://hub.example.test", - "x-opencodex-api-key": token!, - "x-opencodex-gui-origin": "https://hub.example.test", - }; - const management = await fetch(`http://127.0.0.1:${managementPort}/api/config`, { - headers: sessionHeaders, - }); - expect(management.status).toBe(200); - - // Connected GUI status/restart polling stays authenticated without widening the ingress: - // raw liveness remains absent, while its bounded management counterpart is available. - const rawHealth = await fetch(`http://127.0.0.1:${managementPort}/healthz`, { - headers: sessionHeaders, - }); - expect(rawHealth.status).toBe(404); - const managementHealth = await fetch(`http://127.0.0.1:${managementPort}/api/system/health`, { - headers: sessionHeaders, - }); - expect(managementHealth.status).toBe(200); - expect(await managementHealth.json()).toMatchObject({ - status: "ok", - service: "opencodex", - version: expect.any(String), - uptime: expect.any(Number), - pid: process.pid, - }); + const forgedIdentity = await fetch(`http://127.0.0.1:${managementPort}/opencodex-session`, { headers }); + expect(forgedIdentity.status).toBe(401); + expect(state.sessions.size).toBe(0); const adminConsent = await fetch(`http://127.0.0.1:${managementPort}/api/github/star`, { method: "POST",