ADORSYS-GIS / ADORSYS-GIS/lightbridge-opencode-toolbeit
[Epic]: Local-dev repo (Source) authentication for OpenCode
- 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
Bewertung
Dieses Issue wurde noch nicht bewertet.