Skip to content
Open
Show file tree
Hide file tree
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
16 changes: 14 additions & 2 deletions .plan/project-architecture/api-sheriff/enriched.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"Asset-serving hot path is deliberately virtual-thread-blocking (pipeline dispatched via virtualThreadExecutor; event-loop hop only for the write) and security guards re-resolve per request (root toRealPath TOCTOU check in DirectoryAssetSource) \u2014 decline review-bot suggestions to wrap in vertx.executeBlocking or to cache the resolved root, both recur and both are by-design.",
"Verify review-bot claims that a Vert.x API does not exist against the green build before acting: gemini-code-assist repeatedly asserted compilation errors for real Vert.x methods (e.g. HttpServerResponse.ended()) on edge-relay code, and the project consistently accepts these as false positives when the whole-tree build and native ITs are green."
],
"insights": [],
"insights": [
"NeutralTlsConfigSource runs at a single ordinal above 300 so its projected quarkus.* TLS policy keys reliably outrank application.properties defaults, but it never emits quarkus.tls.key-store.* \u2014 key material stays deployment-bound. TlsServerCustomizer then binds min_version/cipher_suites/alpn onto the terminated HTTPS listener and fails closed at boot on an unsupported value; ManagementPlainHttpAudit (StartupEvent, WARN ApiSheriff-115) is the runtime tripwire for the one legitimate plain-HTTP management path, naming both downgrade routes."
],
"internal_dependencies": [],
"key_dependencies": [
"io.quarkus:quarkus-resteasy-jackson",
Expand All @@ -27,6 +29,15 @@
},
"de.cuioss.sheriff.api.quarkus": {
"description": "CDI wiring: ApiSheriffProducer exposing application-scoped beans to the Quarkus container."
},
"de.cuioss.sheriff.gateway.config": {
"description": "Config sourcing and route-table assembly. NeutralTlsConfigSource is a SmallRye ConfigSource at a single ordinal above 300 that projects neutral gateway.yaml TLS POLICY keys into the quarkus.* namespace; it deliberately never writes quarkus.tls.key-store.*, so the management interface cannot silently inherit HTTPS from the default TLS registry bucket."
},
"de.cuioss.sheriff.gateway.config.model": {
"description": "Neutral configuration model records (GatewayConfig, RouteConfig, TlsConfig, SecurityHeadersConfig, etc.), including ManagementConfig \u2014 the neutral, policy-only management block (tls.enabled). It declares no port: ports stay deployment-bound, and a stray management.port is refused in-schema with a message naming quarkus.management.port / QUARKUS_MANAGEMENT_PORT."
},
"de.cuioss.sheriff.gateway.tls": {
"description": "Terminated-HTTPS listener security: SNI front listener, mTLS customizer, and TlsServerCustomizer, which binds the neutral gateway.yaml tls policy (min_version, cipher_suites, alpn) onto the terminated HTTPS listener \u2014 these keys had no production consumer before this plan, so the declared TLS floor and cipher allowlist were not in force; all three now fail closed at boot with an actionable message on an unsupported value. ManagementPlainHttpAudit is a StartupEvent observer that emits WARN ApiSheriff-115 when the management interface resolves to plain HTTP, naming both downgrade routes (the gateway.yaml key and the QUARKUS_MANAGEMENT_TLS_CONFIGURATION_NAME override)."
}
},
"purpose": "runtime",
Expand Down Expand Up @@ -174,6 +185,7 @@
"tips": [
"When deleting or moving a Java package's contents, package-info.java is a sibling that is easy to miss in consumer/deletion sweeps (caught here by the outline Q-Gate). Always include package-info.java in the deletion deliverable when a package is being emptied or removed.",
"api-sheriff source uses Java unnamed variables ('_' in catch and lambda params, e.g. catch (IOException _), _ -> vertx.createHttpClient()) across edge/forward/asset packages. Unnamed variables (JEP 456) require compiler release >= 22. Keep maven.compiler.release at the project Java level (25); a stale or lowered -source below 22 fails compilation with 'unnamed variables are not supported in -source 21 (use -source 22 or higher)'.",
"JaCoCo enforces a 0.80 branch-coverage floor on api-sheriff and fails fast, which masks coverage failures in later modules (integration-tests was hidden behind it). When a coverage check fails here, establish provenance first with a baseline check against origin/main before treating it as branch-introduced - the 0.78 breach seen in plan benchmark-health-target was inherited debt from main, not new."
"JaCoCo enforces a 0.80 branch-coverage floor on api-sheriff and fails fast, which masks coverage failures in later modules (integration-tests was hidden behind it). When a coverage check fails here, establish provenance first with a baseline check against origin/main before treating it as branch-introduced - the 0.78 breach seen in plan benchmark-health-target was inherited debt from main, not new.",
"TLS-related config keys fall into three classes per doc/adr/0025-*: POLICY (neutral, gateway.yaml \u2014 min_version, cipher_suites, alpn, management.tls.enabled), DEPLOYMENT-BOUND (ports and trust material, environment-supplied), and BUILD-TIME (fixed at image build). Never add a new POLICY key that also carries a port or key-store path \u2014 that would re-introduce the pre-plan gap where a declared knob had no production consumer, or silently make the management interface inherit HTTPS from the default TLS registry bucket."
]
}
8 changes: 8 additions & 0 deletions api-sheriff/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@
<properties>
<quarkus.native.container-build>true</quarkus.native.container-build>
<quarkus.native.enabled>true</quarkus.native.enabled>
<!-- Build-time GraalVM knob: enables SSL support in the native image. It is fixed when
the image is built, so it is deliberately OUTSIDE the neutral runtime configuration
surface — gateway.yaml is read at startup and could never make this key take effect.
Bound here rather than in application.properties so it lives with the other
build-time native properties and is active exactly when it has meaning. See ADR-0025
for the boundary rule separating build-time knobs, deployment-bound ports/trust
material, and gateway.yaml-owned TLS policy. -->
<quarkus.ssl.native>true</quarkus.ssl.native>
</properties>
</profile>
</profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,29 @@ public static final class WARN {
.identifier(102)
.template("trusted_proxies entry '%s' covers a very broad address range (prefix /%s) — review whether such broad proxy trust is intended")
.build();

/**
* The management interface resolved to plain HTTP at startup.
* <p>
* This reports the <em>observed effective state</em>, not a declared intention: the audit
* inspects what the management listener actually resolved to, so the warning cannot drift
* away from reality when the activation route changes. The management interface has exactly
* one port, so the downgrade takes health and metrics in their entirety — there is no
* simultaneous HTTPS listener, and every consumer probing that port over HTTPS breaks.
* <p>
* It is a {@code WARN} and never a boot refusal: a plain-HTTP management port behind a
* trusted network boundary is a legitimate deployment, and blocking it would be wrong. The
* template names the port only; it must never carry certificate paths or bucket contents.
* <p>
* The remedy names <em>both</em> doors onto the downgrade, because the audit observes the
* effective state and cannot tell which one was used: the neutral {@code gateway.yaml} key and
* the deployment environment variable land on the same Quarkus key (ADR-0025).
*/
public static final LogRecord MANAGEMENT_PLAIN_HTTP = LogRecordModel.builder()
.prefix(PREFIX)
.identifier(115)
.template("Management interface is serving PLAIN HTTP on port %s — health and metrics are unencrypted and every HTTPS consumer of that port will fail. Expose it only behind a trusted boundary; restore the HTTPS default by setting management.tls.enabled back to true in gateway.yaml, or by removing a QUARKUS_MANAGEMENT_TLS_CONFIGURATION_NAME override supplied by the deployment")
.build();
}

/**
Expand Down
Loading
Loading