LearnNewsExamplesServices
Frontmatter
id10770
titleHealthcheck observability: providers.auth block (symmetric to providers.embedding)
stateClosed
labels
enhancementaiarchitecture
assigneesneo-opus-4-7
createdAtMay 5, 2026, 8:26 PM
updatedAtMay 7, 2026, 7:03 PM
githubUrlhttps://github.com/neomjs/neo/issues/10770
authorneo-opus-4-7
commentsCount1
parentIssue10721
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 6, 2026, 10:11 AM

Healthcheck observability: providers.auth block (symmetric to providers.embedding)

Closedenhancementaiarchitecture
neo-opus-4-7
neo-opus-4-7 commented on May 5, 2026, 8:26 PM

Context

Follow-up to #10727 (auth proxy-identity) + #10723 (embedding provider observability). Surfaced during cross-family review of PR #10768 by @neo-opus-4-7 (review comment).

The Memory Core healthcheck currently surfaces three observability blocks: database.topology (#10127), identity (#10176), and (post-merge of PR #10767) providers.embedding (#10723). These let operators verify topology + identity + embedding-provider configuration empirically without inspecting logs or re-running config through node -e.

The auth dimension is currently NOT observable in healthcheck. With #10727 introducing auth.trustProxyIdentity (proxy-identity injection path), operators have two distinct auth paths (OIDC vs proxy-header) plus a single-tenant fallthrough — and no surfaced way to verify which path is active at boot.

The Problem

A misconfiguration like NEO_AUTH_TRUST_PROXY_IDENTITY=true set without a fronting proxy actually being deployed is undetectable from outside the MC server until requests start failing in non-obvious ways. Symmetric observability (already established for embedding-provider in #10723) closes this gap for the auth dimension.

The Architectural Reality

  • ai/mcp/server/memory-core/services/HealthService.mjs — currently exposes buildIdentityBlock (#10176), buildTopologyBlock (#10127), and buildEmbeddingProviderBlock (#10723, in PR #10767). All are module-scope pure projections with isolated unit-test coverage.
  • aiConfig.auth.{host, port, realm, issuerUrl, clientId, clientSecret, trustProxyIdentity} — the auth-config fields the new block reads
  • Server.mjs#buildRequestContext — propagates source: 'oidc' | 'proxy-header' into RequestContext; the healthcheck block reports the configured path-availability, not per-request observed source-tag (that's separate post-runtime observability)

The Fix

Add buildAuthProviderBlock(cfg) module-scope pure projection function to HealthService.mjs, wired into the healthcheck payload as providers.auth. Reports:

"providers": {
    "embedding": { "...as today..." },
    "auth": {
        "configured": "oidc" | "proxy-header" | "unconfigured",
        "oidc": {
            "issuerUrl": "...",
            "host": "...",
            "configured": true | false
        },
        "proxyHeader": {
            "trusted": true | false,
            "headersChecked": ["x-preferred-username", "x-auth-request-preferred-username"]
        }
    }
}

Field semantics:

  • configured: which path is primary'oidc' if aiConfig.auth.host and aiConfig.auth.issuerUrl are populated; 'proxy-header' if those are unset AND trustProxyIdentity=true; 'unconfigured' otherwise (single-tenant fallthrough — local dev only).
  • oidc: detailed OIDC config visibility (does NOT expose clientSecret)
  • proxyHeader: trust state + which headers are read

Acceptance Criteria

  • buildAuthProviderBlock(cfg) added to HealthService.mjs as module-scope pure projection
  • providers.auth block wired into healthcheck payload (alongside providers.embedding)
  • Unit tests cover all 4 configurations: OIDC-only, proxy-header-only, both-configured (OIDC wins per precedence), unconfigured (single-tenant fallthrough)
  • No clientSecret value leaks into the healthcheck output (security-relevant — secret should not be in observability surface)
  • learn/agentos/SharedDeployment.md updated to document the new observability surface (similar shape to the providers.embedding documentation in PR #10767)

Contract Ledger (T3)

Per parent epic #10721 AC2 (Contract Completeness Gate). Matrix added 2026-05-06 in response to @neo-gpt's hand-back (suggested row encoded verbatim with minor editorial adjustments).

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
providers.auth healthcheck payload #10770, #10721 AC2 + AC6, #10727 / PR #10768 auth substrate, PR #10785 401 gate, SharedDeployment.md ## Authentication section Report configured auth posture as 'oidc', 'proxy-header', or 'unconfigured'. Expose non-secret OIDC readiness fields (host, issuerUrl, realm, configured: bool) and proxy-header trust + canonical header list (x-preferred-username, x-auth-request-preferred-username). OIDC wins when both OIDC + proxy identity are configured (matches Server.mjs#buildRequestContext runtime precedence). Never expose clientSecret (verified by JSON.stringify probe in tests). 'unconfigured' reports explicit local-dev / single-tenant fallthrough. Missing proxy headers in 'proxy-header' mode remain a runtime 401 (PR #10785), not a healthcheck failure — healthcheck shows configured posture, runtime gate fires when prerequisite absent. Partial OIDC (e.g. host without issuerUrl) projects to 'unconfigured'. learn/agentos/SharedDeployment.md ## Healthcheck Verification subsection extended with providers.auth JSON sample + auth diagnostic-fields explanation. MemoryCore.md healthcheck response shape unchanged (extension is additive). test/playwright/unit/ai/mcp/server/memory-core/services/HealthService.spec.mjs covering 6 cases: OIDC-only, proxy-only, both-configured (OIDC wins), unconfigured fallthrough, clientSecret non-leak guard (JSON.stringify probe + property check), partial OIDC fallthrough. Targeted run: npx playwright test test/playwright/unit/ai/mcp/server/memory-core/services/HealthService.spec.mjs --reporter=line. Live healthcheck verification via the healthcheck MCP tool against a configured local Keycloak (operator-side L3, out of unit-test scope).

Out of Scope

  • Per-request source-tag audit (separate post-runtime observability concern)
  • Healthcheck-driven auth-misconfiguration auto-recovery (operator-territory)
  • Full OIDC-issuer-reachability check (network probe; out of scope for static config projection)

Related

  • Adjacent shipped: PR #10767 (providers.embedding precedent), PR #10768 (auth proxy-identity injection — the substrate this observability covers), PR #10769 (auth docs), PR #10785 (401 gate)
  • Pattern precedents: #10176 (buildIdentityBlock), #10127 (buildTopologyBlock), #10723 (buildEmbeddingProviderBlock), #10724 (buildSummaryProviderBlock)
  • Parent epic: #10721 (Shared deployment MVP completeness gaps) — this is post-trial-readiness polish, not blocking
  • Sibling parallel-track: #10773 (providers.neoEmbedding SQLite-side symmetric block — same pattern applied to the SQLite-side embedding selector)

Origin Session ID: 23b9cbcd-4938-4a46-b21a-0d48dd12e7e7

Retrieval Hint: query_raw_memories(query="healthcheck providers auth observability OIDC trustProxyIdentity proxy-header symmetric embedding 10727 10723 10768")

tobiu closed this issue on May 6, 2026, 10:11 AM
tobiu referenced in commit 5b67a7e - "feat(memory-core): surface active auth provider in healthcheck (#10770) (#10798) on May 6, 2026, 10:11 AM
tobiu referenced in commit 5e320f6 - "docs(agentos): polish cookbook Section 7 healthcheck JSON sample (#10800) (#10811) on May 6, 2026, 11:48 AM