Skip to content

feat(config): implement configuration management subsystem#60

Merged
cuioss-oliver merged 21 commits into
mainfrom
feature/implement-configuration-management
Jul 13, 2026
Merged

feat(config): implement configuration management subsystem#60
cuioss-oliver merged 21 commits into
mainfrom
feature/implement-configuration-management

Conversation

@cuioss-oliver

@cuioss-oliver cuioss-oliver commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements the configuration-management subsystem described in
doc/plan/02-configuration-management.adoc: JSON Schemas for gateway.yaml and
endpoints/*.yaml, the load → resolve → validate pipeline, an immutable config
model, topology/route resolution into an immutable RouteTable, fail-fast CDI
wiring, and the associated unit and integration tests. Two aspects are folded in:
three-level retry / HTTP-304 not_modified override plumbing (global
upstream_defaults → endpoint upstream_defaults → per-route upstream), and
the cui-java-parent / cui-http doc version bumps.

Changes

Config loading & resolution (api-sheriff/src/main/java/de/cuioss/sheriff/api/config/)

  • load/ConfigLoader.java, EnvSecretResolver.java, ConfigError.java,
    ConfigLoadException.java — YAML/properties loading with ${ENV_VAR} secret
    resolution.
  • model/* — immutable config records (GatewayConfig, RouteConfig,
    OidcConfig, UpstreamConfig, UpstreamDefaultsConfig, resolved-topology
    types, etc.).
  • topology/TopologyResolver.java, EndpointEnablementResolver.java and
    RouteTableBuilder.java — resolve endpoints/routes into an immutable
    RouteTable.
  • validation/ConfigValidator.java + rule/ValidationRule.java — rule-based
    validation.
  • quarkus/ConfigProducer.java — fail-fast CDI wiring (aggregates all
    violations, refuses to start on any error).
  • ConfigLogMessages.javaLogRecord catalogue.

Schemas & resources

  • src/main/resources/schema/gateway.schema.json, endpoint.schema.json
    allow-list-first (additionalProperties: false) schemas including the
    upstream_defaults retry / not-modified blocks.
  • src/main/resources/application.properties.

Security hardening (finalize security-audit)

  • model/OidcConfig.java — redacting toString() overrides on OidcConfig
    and its nested Session record so resolved clientSecret / encryptionKey
    / previousKey values are not leaked via logs, exception messages, or
    debugger views.

Tests — unit tests for loader, env-secret resolver, model contract,
topology/enablement resolvers, validator, proxy route, and fail-fast producer;
plus integration-tests/.../ConfigLoadedIntegrationIT.java and config fixtures.

Docs & build

  • doc/configuration.adoc, doc/LogMessages.adoc, doc/adr/0005-module-structure.adoc,
    doc/plan/* (Plan 02 delivered; cui-http:2.1-SNAPSHOT2.1 references).
  • pom.xml / api-sheriff/pom.xmlcui-java-parent bump and module deps.

Test Plan

  • test -pl api-sheriff -am green (unit tests, incl. config subsystem)
  • Full CI quality gate + integration-tests (validated by CI on this PR)

Related Issues

None — plan sourced from doc/plan/02-configuration-management.adoc.


Generated by plan-finalize skill

Summary by CodeRabbit

  • New Features
    • Added file-based configuration loading for gateway.yaml, endpoints/*.yaml, and topology.properties, including ${ENV_VAR} substitution and TOPOLOGY_*/ENDPOINT_* overrides.
    • Proxy routing is now driven by a generated route table with longest-prefix matching, method/host/header constraints, and per-route upstream defaults.
  • Bug Fixes
    • Invalid configuration now fails fast at startup with aggregated, actionable error details.
    • Unmatched requests return 404.
  • Documentation
    • Updated configuration and schema docs for the new validation and upstream_defaults behavior.

cuioss-oliver and others added 15 commits July 13, 2026 12:15
…endencies

Bump the parent POM to 1.5.1 and add the YAML/JSON-Schema config parsing
and validation dependencies required by the configuration-management feature
(deliverable 1).

Co-Authored-By: Claude <noreply@anthropic.com>
… tests

Introduce the immutable Java record hierarchy under
de.cuioss.sheriff.api.config.model (GatewayConfig, EndpointConfig with
id/enabled/allowedMethods, the HttpMethod enum excluding TRACE/CONNECT, and
the supporting gateway/route/upstream records) as the framework-agnostic
binding target for the YAML loader, plus the ConfigModelContractTest
value-object contract suite covering equals/hashCode/toString, builder
equivalence, null-normalization, defensive copying, mandatory-field
enforcement, and the enum contracts (deliverable 3).

Co-Authored-By: Claude <noreply@anthropic.com>
Align multi-line record-component continuation lines and normalize import
ordering in the configuration model records and ConfigModelContractTest as
enforced by the pre-commit spotless profile.

Co-Authored-By: Claude <noreply@anthropic.com>
Add the draft 2020-12 JSON Schemas that mirror the configuration reference
field-for-field and reject unknown keys at every object level
(additionalProperties:false), forming the structural-validation contract the
YAML loader enforces at boot (deliverable 2).

Co-Authored-By: Claude <noreply@anthropic.com>
Add the framework-agnostic boot loader under de.cuioss.sheriff.api.config.load:
ConfigLoader reads gateway.yaml and endpoints/*.yaml (sorted), validates each
document against the D2 JSON Schemas via networknt, resolves ${ENV_VAR} secret
references through EnvSecretResolver, and binds the valid trees to the immutable
D3 model records with Jackson (snake_case mapping, case-insensitive enums, and a
custom deserializer flattening the nested upstream_defaults block). Every schema,
secret, and binding problem is aggregated with file + JSON-pointer context and
raised together as ConfigLoadException — never failing on the first. Includes
ConfigError, ConfigLoadException, the loader/resolver unit tests, and valid /
invalid configuration fixtures (deliverable 4).

The endpoint-enablement, topology-alias, cross-cutting validation, and
route-table steps of the full boot sequence are layered on by later deliverables.

Co-Authored-By: Claude <noreply@anthropic.com>
Add the framework-agnostic boot-pipeline resolvers under
de.cuioss.sheriff.api.config.topology: EndpointEnablementResolver computes each
endpoint's effective enabled state (ENDPOINT_<ID>_ENABLED environment override
over the file default) and drops disabled endpoints, and TopologyResolver
resolves the topology aliases referenced by the surviving enabled endpoints
(TOPOLOGY_<ALIAS> override over topology.properties), validates each URL, and
decomposes it once into the immutable ResolvedUpstream (scheme/host/port/basePath,
ADR-0004). Adds the ResolvedTopology / ResolvedUpstream model records and the
resolver unit tests. A missing or malformed alias referenced by an enabled
endpoint is a boot failure; disabled endpoints are exempt from alias resolution
(deliverable 5).

Co-Authored-By: Claude <noreply@anthropic.com>
…nd tests

Co-Authored-By: Claude <noreply@anthropic.com>
…hods, retry/not-modified

Co-Authored-By: Claude <noreply@anthropic.com>
…OADED LogRecords

Co-Authored-By: Claude <noreply@anthropic.com>
…figuration

The proxy edge now sources each route's upstream from the RouteTable assembled by the configuration subsystem instead of a static ProxyConfiguration bean, which is deleted. ProxyRouteTest and the @QuarkusTest boot config are rewired: the shared testboot config gains a /proxy endpoint whose UPSTREAM topology alias resolves to the MockWebServer port.

Produce the immutable GatewayConfig and RouteTable records under the @singleton pseudo-scope: ArC cannot build a client proxy for a normal scope (@ApplicationScoped) over a final record type, which failed every @QuarkusTest container at boot once test-compile went green.

Co-Authored-By: Claude <noreply@anthropic.com>
Replace the removed SHERIFF_PROXY_* env with a mounted sheriff-config directory (SHERIFF_CONFIG_DIR): gateway.yaml, endpoints/httpbin.yaml and topology.properties assemble the RouteTable whose UPSTREAM alias resolves to the go-httpbin echo backend. The benchmark overlay repoints the target via the TOPOLOGY_UPSTREAM alias override rather than a proxy env var.

Add ConfigLoadedIntegrationIT (the mounted /proxy route forwards, unmatched paths deny by default, container boots healthy) and verify-invalid-config-fails.sh, a negative check that an invalid mounted config makes the container fail fast with a non-zero exit.

Co-Authored-By: Claude <noreply@anthropic.com>
…g LogMessages

Document the two bundled JSON Schemas (gateway/endpoint, Draft 2020-12, additionalProperties:false) and the upstream_defaults retry / not-modified toggles with their three-level wholesale-replace inheritance, matching RouteTableBuilder. Existing endpoint id/enabled/allowed_methods sections are left untouched.

Catalogue the config LogRecords in doc/LogMessages.adoc — ApiSheriff-002 CONFIG_LOADED (INFO), ApiSheriff-200 CONFIG_VALIDATION_FAILED and ApiSheriff-201 CONFIG_STARTUP_ABORTED (ERROR) — matching ConfigLogMessages.

Co-Authored-By: Claude <noreply@anthropic.com>
cui-http 2.1 is released: update every doc/plan cui-http:2.1-SNAPSHOT reference to cui-http:2.1 and drop the snapshot-risk caveats that no longer apply (token-sheriff stays 1.0.0-SNAPSHOT). Relocate the delivered Plan 02 spec out of doc/plan/ into the plan workspace and sweep all 5 link:02-configuration-management.adoc references across 4 files to plain-text 'Plan 02 (delivered)' notes, so no dangling link survives.

Co-Authored-By: Claude <noreply@anthropic.com>
OpenRewrite pre-commit normalizations for the config subsystem: canonical import ordering in ConfigProducer, an import-group blank line in three config tests, and broadened throws Exception on the ConfigProducer/ConfigFailFast test methods. Committed so the quality gate is idempotent on these files.

Co-Authored-By: Claude <noreply@anthropic.com>
Security-audit hardening: OidcConfig and its nested Session record used the
default Java-record toString(), which printed the resolved clientSecret,
encryptionKey, and previousKey verbatim. ConfigLoader substitutes ${ENV_VAR}
references with real secret values before binding, so an unredacted toString()
would leak them into any log line, exception message, or debugger view.
Added redacting toString() overrides that preserve presence without exposing
the values.

Co-Authored-By: Claude <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @cuioss-oliver, your pull request is larger than the review limit of 150000 diff characters

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The pull request adds a file-based configuration subsystem with immutable models, YAML/schema loading, environment secret resolution, topology and route resolution, semantic validation, Quarkus startup wiring, and route-table-driven proxy forwarding. It also updates integration fixtures, documentation, dependency management, native-image resources, and tests.

Configuration contracts and loading

Layer / File(s) Summary
Immutable configuration model contracts
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/*
Adds immutable records and enums for gateway, endpoint, route, security, upstream, topology, and resolved-route configuration.
Schema-backed configuration loading
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/*, api-sheriff/src/main/resources/schema/*
Loads gateway and endpoint YAML files, validates them against bundled schemas, resolves environment placeholders, applies defaults, and aggregates load errors.
Topology and semantic validation
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/*, api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/*
Resolves endpoint enablement and topology aliases, decomposes upstream URLs, and applies ordered cross-cutting validation rules.
Route table materialization
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/RouteTableBuilder.java, api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteTable.java
Builds longest-prefix-first routes, resolves inherited settings, rejects overlapping same-prefix routes, and supports prefix lookup.

Startup and integration

Layer / File(s) Summary
Startup assembly and proxy integration
api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/*, api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/*
Eagerly loads, validates, and caches configuration during startup, aborting on errors; proxy forwarding now uses assembled route tables and resolved upstreams.
Integration fixtures and end-to-end checks
integration-tests/*, api-sheriff/src/test/resources/config/*
Adds mounted configuration fixtures, topology aliases, invalid-configuration checks, and integration coverage for forwarding, unmatched paths, and health status.
Documentation and build metadata
doc/*, pom.xml, api-sheriff/pom.xml, api-sheriff/src/main/resources/application.properties
Documents schemas, upstream defaults, and log messages while adding YAML/JSON Schema dependencies, updating managed versions, and packaging schemas for native images.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: implementing the configuration management subsystem.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request implements the complete configuration management subsystem for the API Sheriff gateway, introducing JSON schemas for global and endpoint configurations, an immutable configuration model, and a robust boot-time loading and validation pipeline. The interim proxy edge has been updated to dynamically source its routes and upstreams from the assembled RouteTable. Review feedback identifies several key areas for improvement: refining path prefix matching in RouteTable to prevent incorrect partial matches, updating header disjointness checks in RouteTableBuilder to respect the present attribute, trimming resolved topology URLs in TopologyResolver to prevent parsing failures, and ensuring timeout values are strictly positive during validation in ConfigValidator.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteTable.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/ProxyRoute.java (1)

92-113: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add a per-request timeout to the upstream HttpRequest.

The HttpClient sets only connectTimeout(10s). Once connected, httpClient.send() (line 164) blocks the virtual thread indefinitely if the upstream hangs or sends data slowly. No server-side read timeout is configured in application.properties either, so a slow upstream will hold both the virtual thread and the client connection with no upper bound.

⏱️ Proposed fix: add per-request timeout
     HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(target));
+    builder.timeout(Duration.ofSeconds(30));
     request.headers().forEach(header -> {

If you prefer a single configurable value, inject it via @ConfigProperty:

+    `@ConfigProperty`(name = "sheriff.proxy.upstream-timeout-seconds", defaultValue = "30")
+    int upstreamTimeoutSeconds;
+
     // in buildUpstreamRequest:
     HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(target));
-    // no timeout
+    builder.timeout(Duration.ofSeconds(upstreamTimeoutSeconds));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/ProxyRoute.java`
around lines 92 - 113, Update the upstream request creation in ProxyRoute so
each HttpRequest used by httpClient.send() has a bounded per-request timeout,
covering response waits after connection and slow upstreams. Use the existing
Duration/configuration approach, and preserve the current client connection
timeout and request behavior.
🧹 Nitpick comments (4)
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/OidcConfig.java (1)

175-184: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Csrf is the only nested record without @Builder.

All other nested records in OidcConfig (Logout, Session, Refresh, StepUp) are annotated with @Builder, but Csrf is not. If this is intentional (e.g., Csrf is always constructed inline), consider documenting why. Otherwise, adding @Builder keeps the pattern consistent and allows builder-based construction in config loading or tests.

♻️ Optional: add `@Builder` to Csrf for consistency
+@Builder
 public record Csrf(List<String> trustedOrigins) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/OidcConfig.java`
around lines 175 - 184, Add Lombok `@Builder` to the OidcConfig.Csrf record,
preserving its existing compact canonical constructor and trustedOrigins
normalization. Keep the annotation consistent with the other nested records
without changing construction behavior.
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/ConfigValidator.java (1)

167-181: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider including the route ID in the error path for method membership violations.

validateWholeSecondTimeouts (line 200) uses "/endpoint/routes/%s/upstream/%s".formatted(route.id(), field) for precise error localization, but validateMethodMembership uses the generic "/endpoint/routes" for all violations. Adding the route ID would make debugging easier when multiple routes in the same endpoint have method violations.

♻️ Optional refactor for error path consistency
-                       errors.add(new ConfigError(endpointFile(endpoint), "/endpoint/routes",
+                       errors.add(new ConfigError(endpointFile(endpoint), "/endpoint/routes/%s".formatted(route.id()),
                                "route '%s' matches method %s outside the effective allowed_methods"
                                        .formatted(route.id(), method)));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/ConfigValidator.java`
around lines 167 - 181, Update validateMethodMembership so each method
membership ConfigError uses a route-specific path containing route.id(),
consistent with the precise route paths used by validateWholeSecondTimeouts;
keep the existing endpoint file and message content unchanged.
api-sheriff/src/main/resources/schema/endpoint.schema.json (1)

136-161: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add minimum constraints to integer fields in the schema.

Several integer fields accept negative values through schema validation: connect_timeout_ms, read_timeout_ms, max_attempts, failures, reset_ms, and the security-filter limits (max_header_count, max_header_value_length, max_query_params, max_param_value_length, max_body_bytes). While the semantic ConfigValidator layer may catch these, schema-level constraints provide earlier, pointer-annotated error messages and serve as defense-in-depth.

♻️ Proposed additions for the upstream and security-filter integer fields
                   "path": { "type": "string" },
-                  "connect_timeout_ms": { "type": "integer" },
-                  "read_timeout_ms": { "type": "integer" },
+                  "connect_timeout_ms": { "type": "integer", "minimum": 0 },
+                  "read_timeout_ms": { "type": "integer", "minimum": 0 },
                   "retry": {
                     "type": "object",
                     "additionalProperties": false,
                     "properties": {
                       "enabled": { "type": "boolean" },
-                      "max_attempts": { "type": "integer" },
+                      "max_attempts": { "type": "integer", "minimum": 0 },
                       "idempotent_only": { "type": "boolean" }
                     }
                   },
@@ circuit_breaker @@
                     "properties": {
-                      "failures": { "type": "integer" },
-                      "reset_ms": { "type": "integer" }
+                      "failures": { "type": "integer", "minimum": 0 },
+                      "reset_ms": { "type": "integer", "minimum": 0 }
                     }
@@ security_filter @@
-                  "max_header_count": { "type": "integer" },
-                  "max_header_value_length": { "type": "integer" },
-                  "max_query_params": { "type": "integer" },
-                  "max_param_value_length": { "type": "integer" },
-                  "max_body_bytes": { "type": "integer" },
+                  "max_header_count": { "type": "integer", "minimum": 0 },
+                  "max_header_value_length": { "type": "integer", "minimum": 0 },
+                  "max_query_params": { "type": "integer", "minimum": 0 },
+                  "max_param_value_length": { "type": "integer", "minimum": 0 },
+                  "max_body_bytes": { "type": "integer", "minimum": 0 },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-sheriff/src/main/resources/schema/endpoint.schema.json` around lines 136
- 161, Add non-negative minimum constraints to the integer properties
connect_timeout_ms, read_timeout_ms, retry.max_attempts,
circuit_breaker.failures, circuit_breaker.reset_ms, and the security-filter
limits max_header_count, max_header_value_length, max_query_params,
max_param_value_length, and max_body_bytes in endpoint.schema.json, while
preserving their existing integer types and structure.
api-sheriff/src/test/java/de/cuioss/sheriff/api/config/RouteTableBuilderTest.java (1)

103-196: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for header-based disjointness.

The headersDistinguish method in RouteTableBuilder (lines 164-175) has non-trivial nested-loop logic (case-insensitive name matching, Optional value comparison) that is currently untested. The existing disjointness tests only cover method-based overlap. Consider adding tests for:

  • Two same-prefix routes with the same header name but different values → should be accepted (distinguished).
  • Two same-prefix routes with the same header name and same value → should be rejected (not distinguished).
🧪 Suggested test additions
         `@Test`
+        `@DisplayName`("Should accept same-prefix routes distinguished by header value")
+        void shouldAcceptSamePrefixRoutesDistinguishedByHeader() {
+            MatchConfig matchA = MatchConfig.builder().pathPrefix("/x").methods(List.of(HttpMethod.GET))
+                    .headers(List.of(new MatchConfig.HeaderMatcher("X-Mode", Optional.of("read")))).build();
+            MatchConfig matchB = MatchConfig.builder().pathPrefix("/x").methods(List.of(HttpMethod.GET))
+                    .headers(List.of(new MatchConfig.HeaderMatcher("X-Mode", Optional.of("write")))).build();
+            EndpointConfig endpoint = endpoint("orders", "ORDERS")
+                    .routes(List.of(RouteConfig.builder().id("reader").match(matchA).build(),
+                            RouteConfig.builder().id("writer").match(matchB).build()))
+                    .build();
+
+            RouteTable table = builder.build(gateway().build(), List.of(endpoint), topologyWith("ORDERS"));
+
+            assertEquals(2, table.routes().size(), "header-distinguished same-prefix routes should both survive");
+        }
+
+        `@Test`
+        `@DisplayName`("Should reject same-prefix routes not distinguished by same header value")
+        void shouldRejectSamePrefixRoutesNotDistinguishedByHeader() {
+            MatchConfig matchA = MatchConfig.builder().pathPrefix("/x").methods(List.of(HttpMethod.GET))
+                    .headers(List.of(new MatchConfig.HeaderMatcher("X-Mode", Optional.of("read")))).build();
+            MatchConfig matchB = MatchConfig.builder().pathPrefix("/x").methods(List.of(HttpMethod.GET))
+                    .headers(List.of(new MatchConfig.HeaderMatcher("X-Mode", Optional.of("read")))).build();
+            EndpointConfig endpoint = endpoint("orders", "ORDERS")
+                    .routes(List.of(RouteConfig.builder().id("first").match(matchA).build(),
+                            RouteConfig.builder().id("second").match(matchB).build()))
+                    .build();
+
+            assertThrows(RouteTableBuilder.RouteTableException.class,
+                    () -> builder.build(gateway().build(), List.of(endpoint), topologyWith("ORDERS")));
+        }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@api-sheriff/src/test/java/de/cuioss/sheriff/api/config/RouteTableBuilderTest.java`
around lines 103 - 196, Add tests in the MergeOrderDisjointness test group for
header-based route disjointness, exercising RouteTableBuilder.headersDistinguish
through builder.build. Verify same-prefix routes with the same header name but
different values are accepted, and same-prefix routes with the same header name
and identical values throw RouteTableBuilder.RouteTableException, using the
existing route and endpoint test helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteTable.java`:
- Around line 59-62: Update RouteTable.lookup to normalize the incoming path or
route prefix using the same trailing-slash convention as route registration
before applying startsWith. Ensure configured prefixes such as /api/ and lookup
paths such as /api resolve consistently, while preserving the existing null
validation and first-match behavior.

In `@api-sheriff/src/main/resources/schema/gateway.schema.json`:
- Around line 58-65: Add a required declaration to the mtls schema object so
enabled must be present whenever mtls is configured. Keep client_ca optional and
preserve the existing property types and additionalProperties restriction.
- Around line 134-142: Update the jwks.source enum in the gateway schema to
remove the unsupported "inline" value, keeping only sources representable by
IssuerConfig.Jwks; preserve the existing source, url, and file property
definitions.

---

Outside diff comments:
In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/ProxyRoute.java`:
- Around line 92-113: Update the upstream request creation in ProxyRoute so each
HttpRequest used by httpClient.send() has a bounded per-request timeout,
covering response waits after connection and slow upstreams. Use the existing
Duration/configuration approach, and preserve the current client connection
timeout and request behavior.

---

Nitpick comments:
In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/OidcConfig.java`:
- Around line 175-184: Add Lombok `@Builder` to the OidcConfig.Csrf record,
preserving its existing compact canonical constructor and trustedOrigins
normalization. Keep the annotation consistent with the other nested records
without changing construction behavior.

In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/ConfigValidator.java`:
- Around line 167-181: Update validateMethodMembership so each method membership
ConfigError uses a route-specific path containing route.id(), consistent with
the precise route paths used by validateWholeSecondTimeouts; keep the existing
endpoint file and message content unchanged.

In `@api-sheriff/src/main/resources/schema/endpoint.schema.json`:
- Around line 136-161: Add non-negative minimum constraints to the integer
properties connect_timeout_ms, read_timeout_ms, retry.max_attempts,
circuit_breaker.failures, circuit_breaker.reset_ms, and the security-filter
limits max_header_count, max_header_value_length, max_query_params,
max_param_value_length, and max_body_bytes in endpoint.schema.json, while
preserving their existing integer types and structure.

In
`@api-sheriff/src/test/java/de/cuioss/sheriff/api/config/RouteTableBuilderTest.java`:
- Around line 103-196: Add tests in the MergeOrderDisjointness test group for
header-based route disjointness, exercising RouteTableBuilder.headersDistinguish
through builder.build. Verify same-prefix routes with the same header name but
different values are accepted, and same-prefix routes with the same header name
and identical values throw RouteTableBuilder.RouteTableException, using the
existing route and endpoint test helpers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: cuioss/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c869bf1-f909-4ff9-bc34-cc1a1844c435

📥 Commits

Reviewing files that changed from the base of the PR and between 3db4a99 and 1527be4.

📒 Files selected for processing (82)
  • api-sheriff/pom.xml
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/ConfigLogMessages.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/RouteTableBuilder.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/ConfigError.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/ConfigLoadException.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/ConfigLoader.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/EnvSecretResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/AuthConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/EndpointConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ForwardConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ForwardedConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/GatewayConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/HttpMethod.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/IssuerConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/MatchConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/Metadata.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/OidcConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/Protocol.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RateLimitConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedRoute.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedTopology.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedUpstream.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteTable.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityDefaultsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityFilterConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityHeadersConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/TlsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/TokenValidationConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/UpstreamConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/UpstreamDefaultsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/EndpointEnablementResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/TopologyResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/ConfigValidator.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/rule/ValidationRule.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/rule/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/ProxyConfiguration.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/ProxyRoute.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/package-info.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/quarkus/ConfigProducer.java
  • api-sheriff/src/main/resources/application.properties
  • api-sheriff/src/main/resources/schema/endpoint.schema.json
  • api-sheriff/src/main/resources/schema/gateway.schema.json
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/RouteTableBuilderTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/load/ConfigLoaderTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/load/EnvSecretResolverTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/model/ConfigModelContractTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/topology/EndpointEnablementResolverTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/topology/TopologyResolverTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/validation/ConfigValidatorTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/validation/rule/ValidationRuleTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/gateway/proxy/ProxyRouteTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/quarkus/ConfigFailFastTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/quarkus/ConfigProducerTest.java
  • api-sheriff/src/test/resources/application.properties
  • api-sheriff/src/test/resources/config/broken/gateway.yaml
  • api-sheriff/src/test/resources/config/invalid/unknown-key.yaml
  • api-sheriff/src/test/resources/config/testboot/endpoints/proxy.yaml
  • api-sheriff/src/test/resources/config/testboot/gateway.yaml
  • api-sheriff/src/test/resources/config/testboot/topology.properties
  • api-sheriff/src/test/resources/config/valid/gateway.yaml
  • api-sheriff/src/test/resources/config/valid/topology.properties
  • doc/LogMessages.adoc
  • doc/adr/0005-module-structure.adoc
  • doc/configuration.adoc
  • doc/plan/01-base-implementation.adoc
  • doc/plan/02-configuration-management.adoc
  • doc/plan/03-request-pipeline.adoc
  • doc/plan/README.adoc
  • integration-tests/docker-compose.benchmark.yml
  • integration-tests/docker-compose.yml
  • integration-tests/scripts/verify-invalid-config-fails.sh
  • integration-tests/src/main/docker/sheriff-config/endpoints/httpbin.yaml
  • integration-tests/src/main/docker/sheriff-config/gateway.yaml
  • integration-tests/src/main/docker/sheriff-config/topology.properties
  • integration-tests/src/test/java/de/cuioss/sheriff/api/integration/ConfigLoadedIntegrationIT.java
  • pom.xml
💤 Files with no reviewable changes (2)
  • doc/plan/02-configuration-management.adoc
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/gateway/proxy/ProxyConfiguration.java

Comment thread api-sheriff/src/main/resources/schema/gateway.schema.json
Comment thread api-sheriff/src/main/resources/schema/gateway.schema.json
cuioss-oliver and others added 6 commits July 13, 2026 19:08
The native Quarkus app failed to boot because the file-based config
subsystem relied on three JVM-only behaviors:

- Bundled JSON schemas (schema/*.json) were excluded from the native
  image, so ConfigLoader.getResourceAsStream returned null.
- The immutable config model records lacked reflection registration,
  so native Jackson databind into them failed.
- ObjectMapper.findAndAddModules() discovers the Jdk8 module via the
  ServiceLoader, which does not resolve in a native image, leaving
  Optional-typed record components unbindable.

Add schema/*.json to quarkus.native.resources.includes, consolidate
reflection registration of the Jackson-bound config records, nested
records, and enums in one ConfigModelReflection holder, and register
the Jdk8 module explicitly. No config semantics change.

Verified: native integration-tests suite boots and passes (10 ITs);
api-sheriff JVM module tests pass (131).

Co-Authored-By: Claude <noreply@anthropic.com>
headersDistinguish called HeaderMatcher.value() separately for the
isPresent() guard and the get() access, so static dataflow analysis could
not prove the value was present at the get() call (Sonar java:S3655,
new-code reliability rating C). Bind each header value to a local Optional
so the presence check and the access target the same instance. No behavior
change.

Co-Authored-By: Claude <noreply@anthropic.com>
… S2789)

Co-Authored-By: Claude <noreply@anthropic.com>
…ss, url trim, timeout validation, mtls schema)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
The three near-identical rejects* topology tests are consolidated into one
@ParameterizedTest over the malformed-input scenarios, clearing Sonar S5976
("replace these 3 tests with a single parameterized one"). Each scenario keeps
a descriptive display name; assertions are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/UpstreamConfig.java (1)

81-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding @Builder to NotModified for consistency.

Retry and CircuitBreaker carry @Builder, but NotModified does not. The test at RouteTableBuilderTest.java line 96 constructs it directly with new UpstreamConfig.NotModified(...), which works fine. Adding @Builder would keep the pattern uniform across all nested records, though for a single-field record the direct constructor is arguably simpler.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/UpstreamConfig.java`
around lines 81 - 98, Update the nested UpstreamConfig.NotModified record to
include the same `@Builder` annotation used by Retry and CircuitBreaker, while
preserving its canonical constructor and enabled normalization behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/UpstreamConfig.java`:
- Around line 81-98: Update the nested UpstreamConfig.NotModified record to
include the same `@Builder` annotation used by Retry and CircuitBreaker, while
preserving its canonical constructor and enabled normalization behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: cuioss/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0bfe1a14-4815-4969-92ca-2f33ea1f6176

📥 Commits

Reviewing files that changed from the base of the PR and between 5f0dc48 and 89bddf1.

📒 Files selected for processing (28)
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/RouteTableBuilder.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/ConfigLoader.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/EnvSecretResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/AuthConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/EndpointConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ForwardedConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/GatewayConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/IssuerConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/MatchConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/Metadata.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/OidcConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RateLimitConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedRoute.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedUpstream.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteTable.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityDefaultsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityFilterConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityHeadersConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/TlsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/UpstreamConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/EndpointEnablementResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/TopologyResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/ConfigValidator.java
  • api-sheriff/src/main/resources/schema/gateway.schema.json
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/RouteTableBuilderTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/topology/TopologyResolverTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/validation/ConfigValidatorTest.java
🚧 Files skipped from review as they are similar to previous changes (26)
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityDefaultsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RateLimitConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/AuthConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/Metadata.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityHeadersConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/RouteTable.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/EnvSecretResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ForwardedConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/TlsConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedUpstream.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/EndpointEnablementResolver.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/EndpointConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/GatewayConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/MatchConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/IssuerConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/ResolvedRoute.java
  • api-sheriff/src/main/resources/schema/gateway.schema.json
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/OidcConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/validation/ConfigValidator.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/topology/TopologyResolverTest.java
  • api-sheriff/src/test/java/de/cuioss/sheriff/api/config/validation/ConfigValidatorTest.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/RouteTableBuilder.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/model/SecurityFilterConfig.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/load/ConfigLoader.java
  • api-sheriff/src/main/java/de/cuioss/sheriff/api/config/topology/TopologyResolver.java

@cuioss-oliver cuioss-oliver added this pull request to the merge queue Jul 13, 2026
Merged via the queue into main with commit 6fcbc4b Jul 13, 2026
25 checks passed
@cuioss-oliver cuioss-oliver deleted the feature/implement-configuration-management branch July 13, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant