fix(ingestion): bump mcp-chassis to v0.7.1; label refused REST requests by route
CI / Lint / Test / Vet (pull_request) Successful in 54s
CI / Mirror to GitHub (pull_request) Skipped

1. Rejections are logged. chassis v0.2.0 refused without a log line, so
   since #149 an unknown REST caller got silent 401s. v0.7.1 writes
   `mcp auth rejected` (reason, remote, token fingerprint, path) and
   `mcp auth accepted` per authenticated request. Tested through
   buildMux.

2. Fallout: since chassis v0.7 (mcp-chassis#4) NewJWTValidator no longer
   fails on OIDC discovery; the issuer resolves lazily and a JWT gets
   503-and-retry until it does. #83's boot retry loop therefore never
   retried, and its tests failed. buildJWTValidator now builds once and
   logs an issuer still unresolved at boot. Behaviour change: a
   misconfigured issuer no longer exits the process; JWTs get 503, the
   static bearer keeps working. internal/startupretry is now unused.

3. Metrics: authenticated REST requests were already labelled by route
   (the REST mux sets Pattern on the same *http.Request the middleware
   reads). Requests refused by auth never reached the REST mux and were
   labelled path="/". labelRESTPattern now sets the REST route's pattern
   before auth; unmatched paths keep "/", so the label set stays bounded.

Closes #155

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 09:38:41 +02:00
co-authored by Claude Opus 5.5
parent 0bd0fbf03e
commit 474473c99f
8 changed files with 149 additions and 73 deletions
+8 -15
View File
@@ -32,7 +32,6 @@ import (
"github.com/mathiasbq/hyperguild/ingestion/internal/pipeline"
"github.com/mathiasbq/hyperguild/ingestion/internal/reranker"
"github.com/mathiasbq/hyperguild/ingestion/internal/search"
"github.com/mathiasbq/hyperguild/ingestion/internal/startupretry"
"github.com/mathiasbq/hyperguild/ingestion/internal/symlinkguard"
"github.com/mathiasbq/hyperguild/ingestion/internal/vectorstore"
"github.com/mathiasbq/hyperguild/ingestion/internal/watcher"
@@ -369,21 +368,15 @@ func main() {
// hyperguild#157: report a symlink that appears in the brain while running.
go symlinkguard.Watch(ctx, brainDir, symlinkScanInterval(os.Getenv), buildNotifier())
// Built before the watcher, the graph backfill and session ingestion, and
// retried rather than fatal (#83). Two separate reasons:
//
// - On a cold cluster boot this pod can beat dex to serving and gets a
// 502 from ingress. Nothing is misconfigured; it simply started first.
// Exiting there meant CrashLoopBackOff redoing the backfill on every
// attempt, with exponential backoff stretching the brain outage.
// - Constructing it first means a genuine config error (wrong issuer,
// bad audience) fails in seconds instead of after all that work.
//
// The budget stays bounded: retrying forever would turn a misconfiguration
// into a process that looks alive and never serves.
// Never fatal on an unreachable issuer (#83): on a cold cluster boot this
// pod can beat dex to serving and get a 502 from ingress, and exiting meant
// CrashLoopBackOff redoing the backfill. Since mcp-chassis v0.7 the
// validator resolves the issuer lazily and answers JWTs 503-and-retry until
// it does (hyperguild#155), so no boot retry is needed. A misconfigured
// issuer no longer exits the process: it is logged at boot and every JWT
// gets 503; the static bearer keeps working.
jwtValidator, err := buildJWTValidator(ctx, logger,
os.Getenv("DEX_ISSUER_URL"), os.Getenv("MCP_AUDIENCE"),
startupretry.Policy{Attempts: 8, Base: time.Second, Max: 30 * time.Second})
os.Getenv("DEX_ISSUER_URL"), os.Getenv("MCP_AUDIENCE"))
if err != nil {
logger.Error("build jwt validator", "err", err)
os.Exit(1)