Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions docs/adr/0026-ecosystem-admin-web-sso-and-keyvault.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# ADR-0026: Ecosystem admin-web architecture — Keyverse SSO and Keyvault

- **Status:** Accepted
- **Date:** 2026-09-02
- **Scope:** cross-repository admin-web architecture for `noema`, `contextual-orchestrator`, and `keyverse`

## Context

The owner asked for admin web UIs across three repositories
(`noema`, `contextual-orchestrator`, `keyverse`) and for mutual
integration so `keyverse` — currently a Keycloak-fronting central Identity
Provider — can also be used as a Keyvault (secrets/credential management,
analogous to Azure Key Vault or HashiCorp Vault), later expanded by the
owner to two further Keyverse capabilities: service-to-service ABAC/RBAC,
and a "login credential store" for service-account/machine credentials.
Comment on lines +9 to +15

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Keyverse admin direction remains contradictory

The plan includes a Keyverse admin web, while the master context permits configuration-as-code and Admin REST only. Reconcile these durable decisions.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


Direct repository research (cloned fresh, not assumed) found:

- **`contextual-orchestrator`** already runs a real, serving `/admin`
operator console (`admin.py`, inline stdlib HTML/JS, eight Figma-grounded
screens) with no per-model LLM timeout control — the exact gap
`docs/product-goal-directive.md` §8 already names. An `admin_ui/`
React+Storybook scaffold exists but is confirmed (by direct inspection,
matching that repo's own planning ADR 0036, superseded) to be the
unmodified Vite demo output — no admin-web work in flight there. This
was the readiest of the three repos: it already had a serving console,
an established KV/audit pattern (`credentials.py`, `model_group`
family), and an explicit product requirement to build against.
- **`keyverse`** had no encrypted secrets store (`kv_store.py`'s
`idp_config_entries` is its own internal, unencrypted config — never a
generic secrets product surface) and no frontend of any kind. PR #103
(open, Draft) already implements most of the requested service
ABAC/RBAC capability (`authorization_plane.py`, `org_authorization.py`,
ADRs 0010–0012) but is not currently mergeable.
Comment on lines +31 to +34

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Cross-repository references are ambiguous

The ADR calls Keyverse work PR #103 instead of ContextualWisdomLab/keyverse#103. These references do not link from this repository.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- **`noema`** is a Cloudflare Worker OIDC/credential-exchange broker with
only `/health`, `/ready`, `/exchange` and Durable-Object-only internal
state — no admin-readable HTTP surface exists to build a console on top
of today. The least ready of the three.

Per this repo's own scoping guidance for genuinely multi-week product
work, the correct first iteration is the smallest real, honestly-scoped
slice per repo — not three parallel half-built admin webs.

## Decision

1. **Keyverse is the shared SSO provider for every admin web in this
ecosystem.** It is already the org's central IdP; admins authenticate
to each product's admin console via Keyverse OIDC rather than a
per-repo local admin credential. This is itself the "상호 연계"
(mutual integration) the owner asked for, independent of the Keyvault
question. **Design only in this iteration** — `contextual-orchestrator`'s
`/admin` still uses its existing shared-bearer-token session model
(`/admin/session`); wiring Keyverse OIDC in is the next concrete step
for that console, tracked as an explicit open item rather than
silently deferred.
2. **Each repo's admin web stays a thin frontend over that repo's own
backend API**, not a shared cross-repo frontend package — there is no
second consumer of shared UI primitives yet (matching
`contextual-orchestrator`'s own ADR 0033 reasoning for why Storybook/
component tooling stays deferred there specifically).
3. **Keyverse's Keyvault is a bounded context separate from its IdP
identity/config modules**, sharing only the KV storage *pattern*
(Protocol + in-memory/SQLite backends) already proven in that repo,
not any shared table. `contextual-orchestrator`'s existing
`CredentialBackend` Protocol (pluggable backends, KV-not-env
discipline) is the natural adapter target for a future
`KeyverseCredentialBackend` — the motivating first consumer, not
implemented in this pass. Full reasoning: `keyverse` ADR-0014.
4. **Service ABAC/RBAC is not rebuilt here.** Keycloak's built-in
Authorization Services (UMA 2.0) exist but are unconfigured in this
deployment and do not natively cover the hierarchical org-path
inheritance CWL's Orgmetra-owned org tree requires; PR #103 already
implements that hierarchy. Recommendation: reconcile and land PR #103
rather than duplicate it. Full reasoning: `keyverse` ADR-0015.
5. **"Login credential store" is Keyvault plus per-service
Anti-Corruption Layers, not a fourth Keyverse module.** Centralizing
secret *storage* in Keyverse while each consuming service keeps its
own credential-taxonomy knowledge (via its own Protocol adapter, e.g.
`contextual-orchestrator`'s `CredentialBackend`) avoids growing
Keyverse into a service that must change whenever any consumer's
credential schema changes. Full reasoning: `keyverse` ADR-0016.
6. **The first implemented slice is `contextual-orchestrator`'s per-model
LLM timeout admin surface** (view/set/clear/restore, units, priority/
inheritance, validation, audit history, API contract — the exact §8
requirement), extending the existing `/admin` console in place per its
own ADR 0033/0042. `keyverse`'s Keyvault (write/read/delete/list APIs,
encryption at rest via Fernet, audit logging) is implemented alongside
it as the second slice, since it was independently ready and directly
answers the Keyvault half of the owner's request. `noema` gets no code
change this iteration — it has no admin-relevant state to expose yet;
the honest next step there is deciding what operational state (OIDC
exchange health/rate, App-token issuance evidence) is worth exposing
before building a console around it.

## Consequences

- No repo gained a half-built parallel admin frontend; each shipped
either a real, tested slice or an explicit, evidenced "not yet, and
here is why" record.
- Cross-repo SSO and the Keyvault-as-credential-backend consolidation are
both real, next, concretely-scoped follow-ups — not vague future work —
recorded here and in the two repos' own ADRs so the next iteration does
not have to re-derive this research.
- `keyverse` PR #103 (service authorization) is now more clearly the
blocking dependency for capability #2 of the owner's three-capability
Keyverse request; this ADR does not change its status, only records
that a competing implementation was deliberately not built.

## Rejected alternatives

- **Build out `admin_ui/` (React+Storybook) for `contextual-orchestrator`
instead of extending `admin.py`.** Rejected: contradicts that repo's own
operative ADR 0033, and no revisit trigger from that ADR is met by this
work.
- **Build a from-scratch policy engine for Keyverse service ABAC/RBAC.**
Rejected: PR #103 already implements the actual (hierarchical,
org-path-aware) requirement; a second implementation would duplicate
~2,000 lines of already-written, already-tested domain logic.
- **Centralize per-service credential semantics inside Keyverse.**
Rejected: violates this org's minimal-Shared-Kernel/Anti-Corruption-Layer
DDD convention and would couple Keyverse's deploy cadence to every
consuming service's credential taxonomy.
- **Force a code change into all three repos this iteration regardless of
readiness.** Rejected per this org's own genuinely-multi-week scoping
guidance: `noema` had no admin-relevant surface to build against yet,
and forcing one would have meant fabricating state or shipping a
console with nothing real to show.

## Update — 2026-09-03: `contextual-orchestrator#1010` closed, not merged

Decision item 6 above named `contextual-orchestrator#1010` (per-model LLM
timeout admin surface) as this iteration's first implemented slice. That PR
was subsequently **closed unmerged by the repo owner the same day** (2026-09-02,
`closed_at` 05:10:46Z — after this ADR PR was opened at 03:40:12Z), on a
categorical objection independent of this ADR's design: "the current manual
timeout-setting semantics must not become production authority," plus four
distinct unresolved correctness findings in the PR's live-enforcement wiring
(local queue path ignores the override, passthrough/tool requests bypass it,
failed persistence can leave the live timeout mutated, and admin-refresh races
can misreport/stale audit state). A subsequent repair-policy recheck (recorded
on the PR and in `docs/product-technical-gap-baseline.md`) confirmed this
closure is valid under the org's repair-not-close policy's "explicit user
instruction" ground, and that the PR's delta is preserved (not orphaned) on
its own closed branch for selective future reuse once a research-/standard-backed
timeout allocator exists to host it — not revived as-is.

**This ADR's own architecture decisions (1–5) are unaffected** — they concern
the SSO/Keyvault/ABAC-RBAC/credential-store shape, not the timeout-surface
implementation. Only decision item 6's specific claim that the timeout slice
was "implemented" is now stale. `keyverse#129` (Keyvault, this iteration's
second slice) is unaffected by this and remains open. Left as an update rather
than rewriting the original decision record, so the historical reasoning
trail (what was true when each decision was made) stays intact.

## References

- `contextual-orchestrator` planning ADR 0033 (admin console UI tooling
boundary), 0036 (superseded React/Storybook proposal), 0042 (per-model
timeout admin surface — this iteration's `contextual-orchestrator`
slice, subsequently closed unmerged; see Update above).
- `keyverse` ADR-0014 (Keyvault bounded context), ADR-0015 (service
authorization plane), ADR-0016 (login credential store).
- `docs/product-technical-gap-baseline.md`, 2026-09-02 entry (repair-policy
recheck of `contextual-orchestrator#1010`'s closure).
- `docs/product-goal-directive.md` §8 (LLM/orchestration; the per-model
timeout admin requirement this ADR's first slice attempted to close).
Loading