ADORSYS-GIS / ADORSYS-GIS/lightbridge-opencode-toolbeit

[Epic]: Local-dev repo (Source) authentication for OpenCode

Offen
#64 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
epic
Vorherrschende Sprache
TypeScript
Sterne
4
Forks
0
Ø Merge
6 Std. 14 Min.
Gemergte PRs (30 T.)
26

Beschreibung

## Executive Summary

We want **local-dev OpenCode requests to be attributed and budgeted to the git repo the developer is working on** (its "Source"), because today only **CI** runs carry that repo-as-principal attribution (GitHub OIDC → `lightbridge-repo-auth` `/v1/resolve` → Source billing, ai-helm ADR-0047); a human running the OpenCode CLI bills to their *person* (`x-account-id = sub`), never to the repo. This epic exists to close that gap by giving local dev the **same** Source-attribution machinery CI already uses — no parallel model, no new JWKS.

## Strategic Intent

A developer authenticates once as themselves, and every gateway request from a given repo is billed and access-controlled as that repo's Source — exactly like CI — while the repo↔account binding stays operator-controlled and revocable.

## Problem Statement

- **Users/devs:** local-dev spend is not separable per repo; a developer's personal budget (free $50 / pro $200, ADR-0035) is consumed regardless of which repo/project the work belongs to.
- **Ops/business:** no per-repo cost attribution or RBAC for interactive (non-CI) usage; the CI Source model can't be reused because a human Keycloak token carries no repo dimension.
- **Security/compliance:** there is no operator-controlled, revocable binding of a *human's* interactive session to a repo/Source.

## Desired Outcome

Running the OpenCode CLI inside an enrolled repo, a developer's gateway requests are validated by Authorino and billed to the repo's **Source account** (`x-account-id = Source.account_id`, `x-billing-plan = Source.billing_plan`), through the existing rate-limit/budget path (ADR-0021/0035). Revoking a repo binding takes effect on the next request, not at token expiry.

## Scope (In / Out)

### In Scope
- A new OpenCode plugin `@vymalo/opencode-repo-auth` (git-remote → Source id, RFC 8693 token exchange to a Source-scoped `aud`, per-Source cache, `chat.headers` bearer injection).
- Extraction of a shared `@vymalo/opencode-auth-core` (OAuth flows incl. token exchange, `TokenRuntime`, cache, logging) and refactor of `@vymalo/opencode-oauth2` onto it.
- Keycloak `opencode-cli` client + human-subject token exchange to a Source audience (ai-helm ADR-0077).
- Additive human-subject→Source binding in `lightbridge-repo-auth` `/v1/resolve` (operator-claimed).
- Authorino external-plane `when` branch stamping Source descriptors (in `ai-helm-values`, values-repo-first).

### Out of Scope
- Self-serve Source claiming for humans (stays operator-claimed per ADR-0049).
- A lower `@vymalo/opencode-core` kit unifying logging/cache/config across all plugins (separate refactor).
- Monorepo sub-project Sources (one Source per repo in v1).
- Changing the CI path.

## Source of truth (links)

- Plugin ADR: `vymalo/opencode-oauth2` `docs/adr/0005-repo-auth-audience-scoped-token-exchange.md` (in-flight on branch `claude/kind-lichterman-d1671f`).
- Infra ADR: `ADORSYS-GIS/ai-helm` `docs/adr/0077-local-dev-repo-binding-via-human-token-exchange.md` (in-flight on branch `feat/local-dev-repo-auth`).
- Design: `vymalo/opencode-oauth2` `plans/git-auth.md`.
- Builds on ai-helm ADR-0047 (CI repo binding), ADR-0049 (operator-claimed Sources), ADR-0021/0035 (dual-plane + budget), ADR-0052 (sentinels), ADR-0009 (Keycloak token exchange).

## Stakeholders

Product Owner / Technical Lead / Delivery Owner / Security: @stephane-segning.

## Key Assumptions

- Keycloak (`camer-digital` realm) can mint a Source-scoped `aud` via token exchange (audience mapper or custom claim) — to be verified by the spike ticket.
- `/v1/resolve`'s binding logic is identity-agnostic and can take a human subject additively (validated in research).
- One Source per git repo is sufficient for v1.

## Constraints

- No new JWKS/issuer (platform trusts Keycloak + GitHub OIDC only).
- Binding must remain operator-controlled and revocable (ADR-0049).
- `ai-helm-values` AuthConfig change is **values-repo-first**: it must not merge before the Keycloak client + resolve extension exist, or it risks the gateway AuthConfig (ADR-0056).
- `@vymalo/opencode-repo-auth` and `@vymalo/opencode-oauth2` must not run on the same provider.

## Risks

| Risk | Prob | Impact | Mitigation |
|---|---|---|---|
| Keycloak can't carry an arbitrary Source URL in `aud` | Med | High | Spike first; fallback to a custom `source` claim resolve reads. |
| Exchange `aud` not preserved across refresh | Med | Low | Default to re-exchange from the offline root ("model b"). |
| Refactor regresses mature `oauth2` (~88% cov, 0 warn) | Med | Med | Extract behind `auth-core`, re-baseline thresholds, keep tests green. |
| Values-repo AuthConfig merged out of order | Low | High | Sequence tickets; values-repo-first gate. |

## Success metrics

| Metric | Current | Target | Source |
|---|---|---|---|
| Local-dev requests attributable to a repo Source | 0% | 100% for enrolled repos | Authorino `x-account-id` / gateway usage (ADR-0058/0070) |
| Repo-binding revocation lag | n/a (no binding) | ≤ next request | `/v1/resolve` behavior |
| New security-critical OAuth code duplicated | n/a | 0 (shared via `auth-core`) | code review |

## Child User Stories / Tickets

- [ ] vymalo/opencode-oauth2#65 — Story: local-dev requests bill to the repo (Source).
- [ ] vymalo/opencode-oauth2#66 — Extract `@vymalo/opencode-auth-core`.
- [ ] vymalo/opencode-oauth2#67 — Build `@vymalo/opencode-repo-auth`.
- [ ] ADORSYS-GIS/lightbridge-repo-auth#2 — Extend `/v1/resolve` for human→Source.
- [ ] ADORSYS-GIS/ai-helm#586 — Keycloak `opencode-cli` client + Source-audience token exchange (+ carrier/refresh spike).
- [ ] ADORSYS-GIS/ai-helm-values#300 — Authorino external-plane `when` branch (values-repo-first).

**Suggested sequence:** vymalo/opencode-oauth2#66 → vymalo/opencode-oauth2#67 (client side, parallel with infra); ADORSYS-GIS/lightbridge-repo-auth#2 + ADORSYS-GIS/ai-helm#586 (bindings + IdP) → ADORSYS-GIS/ai-helm-values#300 (Authorino branch, values-repo-first, lands last).

## Human accountable owner

@stephane-segning

## AI Usage Declaration

Research, Drafting, Ticket decomposition, Technical proposal. AI (Claude) researched the existing ai-helm/lightbridge-repo-auth system and drafted the ADRs, design doc, and this decomposition. AI output is not truth; the human owner verifies before acceptance.

## Human verification completed

- [ ] Intent checked against source of truth
- [ ] Scope reviewed
- [ ] Technical feasibility reviewed
- [ ] Risks reviewed
- [ ] No unverified AI claim remains
- [x] I am the accountable owner and accept responsibility for this epic.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.