Skip to content

Connected client: ocx usage calls a missing local endpoint instead of showing hub usage #4205

Closed

Description

@lidge-jun

Client or integration

Other

Area

CLI

Summary

On a connected Windows client, ocx usage --range today --json fails with Error: not_found even though the hub has recorded this client's requests. The CLI calls the local machine listener's /api/usage, which is not an admitted route on that listener.

The user cannot answer “how much did this machine use?” without switching to hub administration and knowing the client's key ID. This is a read-path failure, not evidence that usage was lost.

Reproduction

  1. Connect a Windows installation to a working hub with ocx connect, selecting Codex and --management-transport relay.
  2. Have existing model traffic associated with the issued client key.
  3. Confirm ocx connect status --json says connected and the local listener's /healthz responds.
  4. Run ocx usage --range today --json.
  5. Compare the hub's authorized /api/usage?range=today&apiKeyId=<client-key-id> read with the local /api/usage?range=today read.

Observed: local CLI fails; local HTTP returns 404; the hub's filtered report returns 200 and positive measured usage. The filtered report is distinct from the hub-wide report. No additional billable requests were needed for this audit.

Version

Windows client 2.50.0; macOS hub 2.51.0 from dev 6d3ad12e3fbfd8423f1515a467db4d3349732886. The same routing structure is present in that inspected dev source.

Operating system

Windows 11 25H2 client; macOS 27.0 hub.

Provider and model

Not provider-specific.

Logs or error output

ocx usage --range today --json
Error: not_found

GET local /api/usage?range=today
404 {"error":"not_found","method":"GET","path":"/api/usage"}

GET hub /api/usage?range=today&apiKeyId=<redacted>
200; client filter applied; measured usage present

Screenshots and supporting files

Source anchors at the inspected commit:

Expected completion: a supported authenticated client-scoped CLI read, with explicit source/scope in JSON and human output; no silent substitution of old local totals; actionable authentication/offline errors. Do not solve this by exposing the whole hub's usage to a client credential or copying hub administrator credentials into clients. If the supported credential cannot read usage yet, report that specific requirement instead of not_found.

Redacted configuration

{"runtimeRole":"client","client":{"managementTransport":"relay","selectedClients":["codex"]}}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. Ingwannu commented on Sep 10, 2026

    @Ingwannu
    Owner

    The current source confirms the read-path mismatch: cli/observe.ts calls runtimeRequest('/api/usage...'), runtime-api.ts chooses the local live listener, and client/machine-listener.ts deliberately rejects that path. The relay route is a separate admitted surface, not an automatic alias for every management endpoint.

    I would keep the first fix role-aware: a connected client should use an explicitly authorized machine-scoped read (with source/scope included in the result), or return a precise “hub usage authorization required” outcome. Merely adding /api/usage to the machine allowlist or copying a hub admin credential would not establish safe scope. Filtering by a caller-supplied apiKeyId is not itself authorization; the hub must bind the allowed key to the admitted client identity.

    This does not imply lost usage or require replaying billable requests. Acceptance should compare client A versus client B visibility, unavailable/expired authorization, offline hub, and standalone local usage. No runtime settings or live reads were changed during this review.

  2. lidge-jun commented on Sep 10, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 69 / 80

    연결된 Windows 클라이언트에서 ocx usage --range today --json 이 not_found 로 실패합니다. CLI 는 로컬 machine listener 의 /api/usage 를 치는데, 그 리스너는 그 경로를 허용하지 않습니다. 허브에는 같은 클라이언트 키로 필터한 usage 가 있고, 사용량은 사라진 게 아니라 읽기 경로만 깨져 있습니다.

    현재 dev HEAD 6101140ff(2.51.0) 에서 src/cli/observe.ts 는 runtimeRequest(/api/usage…) 로 usage 를 가져옵니다. src/cli/runtime-api.ts 의 runtimeRequest 는 연결된 클라이언트면 로컬 live proxy(machine listener)로 갑니다. 그런데 src/client/machine-listener.ts machineRouteAllowed(~:45) 는 GET 으로 /api/machine/*·healthz 등만 허용하고, path.startsWith("/api/") 이면 false 를 돌려 /api/usage 는 404 입니다. 허브 쪽 src/server/management/logs-usage-routes.ts 에는 /api/usage 와 apiKeyId 필터가 이미 있습니다.

    그래서 “이 머신이 얼마나 썼나”를 보려면 관리자처럼 허브에 들어가 키 ID 를 알아야 합니다. 이건 connected-client 제품 경험의 실제 버그이고, 우선순위가 높은 이유입니다. 다만 클라이언트 자격으로 허브 전체 usage 를 열어 주면 안 됩니다. 반드시 자기 apiKeyId 로 스코프한 읽기만 허용해야 합니다.

    라인 - src/client/machine-listener.ts machineRouteAllowed ~:45 — /api/machine/* 만 허용; GET /api/usage 는 /api/ 접두로 false → 404
    라인 - src/cli/observe.ts usage 경로 ~:178 — runtimeRequest(/api/usage…) 가 connected 시 로컬 listener 로 감
    경로/심볼 - src/cli/runtime-api.ts runtimeRequest — 로컬 live proxy 우선; usage 전용 hub 프록시/필터 없음
    경로/심볼 - src/server/management/logs-usage-routes.ts /api/usage — 허브에는 apiKeyId 필터 읽기가 이미 존재

    메인테이너의 판단이 필요한 지점

    • machine listener 에 /api/usage 를 프록시로 추가할지, observe 가 connected 일 때 hub 로 직접(또는 management relay) 읽게 할지
    • 인증된 클라이언트 자격으로 hub-wide usage 노출을 절대 막을지(권장: 막고 apiKeyId 스코프만)
    • relay vs direct managementTransport 에서 같은 계약을 유지할지

    너의 추천
    인증된 클라이언트 스코프 usage 읽기를 넣으세요. 허브 /api/usage 를 클라이언트의 apiKeyId 로 필터해 돌려주고, hub-wide 집계는 클라이언트 자격에 절대 노출하지 마세요. machine listener 허용 목록에 무분별한 /api/* 를 열지 말고, usage 전용 안전한 경로(또는 observe→hub 스코프 호출)만 추가하세요.

    이 댓글은 grok-bot이 작성했습니다

  3. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    OwnerAuthor

    Resolved on dev by #4373, landed today as part of a 36-pull-request batch.

    src/cli/observe.ts routes to fetchHubUsage when connection.kind === "connected", and src/server/hub-usage.ts answers with source: "hub" and scope: "client" for the enrolled data key, so a connected client no longer calls the local machine listener's /api/usage.

    Verified against origin/dev at 72601a173 after the batch landed, rather than from the pull request description. Closing on that evidence; reopen if the behavior does not match on your setup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcliCLI, config inject, packaging flags

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions