Skip to content

[OoP-8] Platform Host + Infra REST Surface (AuthZ, Tenant Resolver, Types Registry, CredStore) #4110

Description

@mattgarmon

Parent: OoP

Blocked by: OoP-1

Description

Give every shared service a network surface so the whole business tier (file-parser, simple-user-settings,
mini-chat, oagw) can go OoP. Two groups, by trust-coupling:

Embeds in each OoP pod (no REST endpoint needed):

  • AuthN Resolver — stateless JWT validation (JWKS cache only), zero network latency.

Stays in the Platform Host pod (trust-coupled — SecurityContext::anonymous() over the in-process RG boundary):

  • AuthZ Resolver and Tenant Resolver — AuthZ chains to TR→RG, and TR's rg-tr-plugin reads RG's DB.
    Embedding either in an OoP pod would require shared RG DB access — rejected. Exposed over REST instead.

Separate pods (no trust-coupling; see DESIGN § Platform Host Composition):

  • Types Registry — seeded from link-time inventory inside each binary, so an OoP gear's GTS types are
    absent from the Platform Host registry. OoP gears must register remotely at startup via the existing
    POST /types-registry/v1/entities route
    (no new write path), and post_init graph validation must work
    across the distributed set. No DB; heartbeat re-registration handles pod restarts.
  • CredStore — stateless, plugin-based secret lookups (no DB). Runs as a separate pod with REST endpoint.
    Needed by oagw for upstream auth. Alternative: embed CredStore directly in OoP pods (like AuthN Resolver)
    to avoid secrets in transit. Feasible because it is stateless; depends only on Types Registry for plugin discovery.

Without this phase, only gears with zero shared-service dependencies (e.g., file-parser) can go OoP.
With it, mini-chat, OAGW, and simple-user-settings become OoP-eligible.

The SecurityContext::anonymous() used internally by AuthZ→TR→RG stays within the Platform Host process
and is safe — it never crosses a network boundary.

Effort: Medium (Large only if the codegen from PR #4084 is unavailable and the four Rest*Clients must be hand-written; types-registry REST already exists. Only depends on OoP-1; can run in parallel with OoP-4–6)

Codegen note (PR #4084). The four Rest*Clients (8.2 / 8.4 / 8.6 / 8.7) can be generated by #4084's #[toolkit::rest_contract] once the existing SDK traits (AuthZResolverClient, TenantResolverClient, TypesRegistryClient, CredStoreClientV1) are annotated with per-method HTTP attributes — mechanical, but required. Hand-writing them is the fallback if the macro is unavailable. Note types-registry already exposes REST routes (register/list/get), so 8.5 is largely covered.
Design: DESIGN.md § Platform Host Composition

Tasks

AuthZ REST endpoint:

  • 8.1 Add REST endpoint for AuthZResolverClient::evaluate() in the Platform Host:
    • POST /authz-resolver/v1/evaluate — accepts EvaluationRequest, returns EvaluationResponse
    • Protected by secctx_middleware (OoP-1) — caller must present a valid JWT
    • Internally dispatches to the in-process AuthZResolverClient (which chains to TR→RG in-process)
  • 8.2 Implement RestAuthZResolverClient — REST client implementing the AuthZResolverClient SDK trait:
    • Resolves Platform Host AuthZ endpoint via DirectoryService
    • Uses attach_bearer_http (OoP-1) to propagate the caller's JWT on outbound calls
    • Registered in ClientHub so PolicyEnforcer works transparently

Tenant Resolver REST endpoint:

  • 8.3 Add REST endpoints for TenantResolverClient operations in the Platform Host:
    • Expose the full TenantResolverClient surface under /tenant-resolver/v1/... (e.g. GET /tenant-resolver/v1/root, GET /tenant-resolver/v1/hierarchy?tenant_id=...); the generated client covers all 6 trait methods
    • Protected by secctx_middleware (OoP-1)
    • Internally dispatches to the in-process TenantResolverClient
  • 8.4 Implement RestTenantResolverClient — REST client implementing the TenantResolverClient SDK trait:
    • Resolves Platform Host TR endpoint via DirectoryService
    • Uses attach_bearer_http (OoP-1) to propagate the caller's JWT
    • Registered in ClientHub so OAGW and other consumers work transparently

Types Registry REST:

  • 8.5 Wire OoP bootstrap to the existing types-registry REST routes (POST /types-registry/v1/entities register, plus list/get) — no new write path:
    • OoP gears register their schemas + instances against POST /types-registry/v1/entities at startup
    • Confirm post_init graph validation works across the now-distributed set of registered types; add read/query endpoints only if a concrete gap is found
  • 8.6 Implement RestTypesRegistryClient (SDK trait), registered in ClientHub; OoP bootstrap calls
    register at startup before serving.

CredStore REST:

  • 8.7 Add REST endpoint for secret retrieval. Implement
    RestCredStoreClientV1 registered in ClientHub.

account-management platform-plane migration:

  • 8.8 Migrate the genuine non-tenant for_gear_init path (gears/system/account-management/.../domain/system_actor.rs) off the nil-tenant SecurityContext shim onto PlatformSecurityContext (OoP-2). Tenant-bound am.system flows (for_bootstrap / for_provisioning_reaper / for_retention_sweep / for_user_groups_cascade) stay on the tenant plane via S2S client-credentials — unchanged.

Shared:

  • 8.9 Register AuthZ, TR, Types Registry, and CredStore REST endpoints in DirectoryService for discovery
  • 8.10 Tests:
    • OoP gear → REST AuthZ evaluate → in-process TR→RG → response; PolicyEnforcer parity
    • OoP gear → REST TR root/hierarchy → in-process RG → response; TenantResolverClient parity
    • OoP gear registers GTS types over REST at startup; another gear/oagw reads them; post_init validates
    • oagw as OoP pod: upstream provisioning + tenant resolution + CredStore secret retrieval via REST
    • for_gear_init global RG-type registration works under PlatformSecurityContext; tenant-bound flows unchanged

Acceptance Criteria

  • OoP gear resolves AuthZResolverClient, TenantResolverClient, TypesRegistryClient, and CredStoreClientV1 from ClientHub, calls them over REST, gets valid responses
  • PolicyEnforcer works identically whether AuthZ is in-process or REST-backed
  • An OoP gear's GTS types register with the central Types Registry over REST and are visible to other gears
  • oagw as OoP pod resolves tenant hierarchy, enforces authorization, and retrieves secrets via REST
  • mini-chat / simple-user-settings as OoP pods enforce authorization via the Platform Host AuthZ REST endpoint

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions