Skip to content

Triage: Count harness-carried model auth in surface config and admin onboarding #814

Description

@time-attack

Tracking the change proposed in #128 (by @haramiya).

We're moving this from a code PR to a tracked issue under CONTRIBUTING.md: feature ideas belong in adrs/ as a short human-written note and bugs as an issue, and we implement the underlying code from our side. Capturing the original proposal here so it isn't lost.

Original PR: #128
Reported by: @haramiya


Bug

Running HARNESS=claude on a Claude subscription (CLAUDE_CODE_OAUTH_TOKEN from claude setup-token, no ANTHROPIC_API_KEY) serves turns fine, but the deployment tells everyone it isn't set up:

  • /v1/surface-config reports modelProviderConfigured: false, so the portal 503s non-admins and bounces admins to onboarding (Route the first admin to onboarding instead of a 403 web UI #29's gate).
  • The admin onboarding view says Needs a key / "claude-opus-5 cannot run until its Anthropic key is configured" — while the assistant answers happily underneath.

Root cause: both read only the model credential store, which counts anthropic/openai/openrouter API keys (env or admin-managed) and knows nothing about auth the harness carries itself. #67 and #109 both hit this and proposed fixes at different layers.

Fix

harnessCarriedModelAuth(config) in src/config.ts names the provider a harness authenticates on its own:

  • claudeanthropic when CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_AUTH_TOKEN is in claudeProcessEnv
  • codexopenai when CODEX_ACCESS_TOKEN is in codexProcessEnv
  • otherwise undefined (env API keys are already counted through the credential store's fallback, so they aren't double-counted here)

Wired as an optional ServerDeps.harnessCarriedModelAuth and surfaced at the two places that were lying:

  • Surface gate: getSurfaceConfig ORs it into modelProviderConfigured. Unlike making modelProviderAvailabilityFor unconditionally report claude as available (adr: smaller fix for the keyless-harness model gate #109's noted downside), a claude deployment with no token anywhere still reports unconfigured and keeps the onboarding gate.
  • Admin API: GET /v1/admin/model-providers gains a sibling harnessAuth: { harnessId, provider } field. The credential-store providers statuses are deliberately untouched — anthropic keeps reporting absent when no key is stored, because those keys feed pi-transport calls and adding/deleting them is independent of harness OAuth. Old admin UI against new core ignores the extra field; new UI against old core sees no harnessAuth and behaves exactly as before (blue-green safe).
  • Admin onboarding view: the model-provider step shows Ready when the base model's provider is store-configured or harness-authenticated, with the summary "claude-opus-5 · authenticated by the claude harness — no API key needed." Stored-key summaries keep precedence; the key form stays usable for feeding pi-transport.

Screenshots

Admin → Onboarding, HARNESS=claude with only CLAUDE_CODE_OAUTH_TOKEN:

Before After
before after

Rendered against the admin page served with realistic stubbed API fixtures (the machine's only dev-instance Slack slot was held by another live instance, so this wasn't exercised on a booted stack; the same states are covered by the tests below).

Tests

  • test/model-credential-route.test.ts: claude harness + OAuth token → modelProviderConfigured: true, harnessAuth: { harnessId: "claude", provider: "anthropic" }, and the anthropic status still { configured: false, source: "absent" }; claude harness with no token → still unconfigured, no harnessAuth field. start() now derives the dep from the test config the same way src/index.ts does.
  • plugins/admin/test/onboarding-view.test.ts: runs the real loadOnboarding() (vm-extracted from index.html) against stubbed endpoints — harness auth alone → Ready badge + harness summary; no harness auth → Needs a key; stored admin key + harness auth → Ready with the stored-key summary.

Verification

  • test/model-credential-route.test.ts 13/13, test/external-slack-participants.test.ts + test/admin-resources.test.ts 20/20, plugins/admin onboarding suite 7/7
  • tsc --noEmit (root and plugins/admin), eslint ., prettier --check — clean (lint:ox has a pre-existing missing-native-binding failure locally; CI covers it)
  • Independent fresh-context adversarial review of the diff — findings resolved before merge

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


If we ship a fix or feature from this, credit @haramiya as co-author.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions