Skip to content

[Ticket]: Build @vymalo/opencode-repo-auth plugin (git remote → Source token exchange) #67

Description

@stephane-segning

Type: Feature

Summary

We need to build @vymalo/opencode-repo-auth — the OpenCode plugin that scopes a developer's gateway requests to their repo's Source via audience-scoped token exchange — because that is the client half of epic #64.

Expected result:

A published plugin that, on an enrolled repo, injects a Source-scoped bearer so Authorino bills the request to the repo's Source.

Intent

Give local dev the repo-as-principal attribution CI has, reusing auth-core.

Source of truth (links)

Expected Behavior

  • Resolve git origin → normalized remote (strip user:pass@, normalize scp/https, handle worktrees & missing remote).
  • Read the Source id from the repo's opencode.json (options.meta.repoAuth.sourceId).
  • TokenRuntime.ensure(human) (device-code/auth-code, offline_access) → exchange(humanToken, audience = <base>/sources/src-XXX).
  • Cache the Source-scoped token per Source (hash(sourceId), OS cache dir, 0o600, atomic rename). Short TTL → re-exchange from the offline root on expiry ("model b").
  • chat.headers injects Authorization: Bearer <source-token> on the gateway provider only (guard by managed provider id), after any user-bearer.
  • Honor the config-object handshake (stamp provider.options.headers.Authorization at config-time for models-info). Ordering: repo-auth → models-info → ratelimit.

Acceptance Criteria

  • Given an enrolled repo + logged-in dev, when a request runs, then the gateway provider carries the Source-scoped bearer (verified against a Keycloak stub).
  • Given no sourceId, then the plugin no-ops on that provider (no crash).
  • Given a worktree checkout, then remote resolution still yields the repo's Source (not the worktree path).
  • Not active on the same provider as @vymalo/opencode-oauth2 (documented + guarded).
  • Published-shaped (slim ., ./lib), on the shared version line, docs in docs/, CHANGELOG.md entry.
  • Pre-push gate green.

Out of Scope

auth-core extraction (separate ticket); resolve-by-remote (deferred); monorepo sub-project Sources.

Technical Context

Depends on the auth-core ticket. Mirror the per-package layout; new cache namespace opencode-repo-auth. Sibling reference service: ADORSYS-GIS/lightbridge-repo-auth.

Risks

Exchange aud/refresh semantics (see spike). Mitigate with re-exchange default. Leaking repo URL to non-gateway providers — mitigate with the managed-provider guard.

Test Plan

Unit (remote normalization incl. worktree, cache keying, exchange), integration against a Keycloak stub, manual end-to-end against the gateway.

Verification evidence

To be filled: tests + a live run showing the Source bearer on the gateway provider only.

Human accountable owner

@stephane-segning

AI Usage Declaration

Drafting the ticket, Proposing implementation, Generating code, Generating tests. Verified by owner.

Human verification completed

  • I understood the intent
  • I checked the source of truth
  • I reviewed all AI-generated code
  • I verified the tests
  • I am the accountable owner and accept responsibility for this ticket.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ticketAI Governance issue type

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions