From 7c0dd149d94fdb59dd4acbfc00a3bc2f7a06367b Mon Sep 17 00:00:00 2001 From: Renn F Date: Tue, 13 Oct 2026 21:54:18 +0200 Subject: [PATCH 1/2] test(agent): cover an injected agent handler end to end through the middleware --- .../guardcore/ktor/InjectedAgentWiringTest.kt | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt diff --git a/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt b/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt new file mode 100644 index 0000000..c85cb12 --- /dev/null +++ b/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt @@ -0,0 +1,90 @@ +package com.guardcore.ktor + +import com.guardcore.config.SecurityConfig +import com.guardcore.config.SecurityConfigBuilder +import com.guardcore.core.events.AgentTelemetryMember +import com.guardcore.protocols.AgentHandlerProtocol +import com.guardcore.protocols.RedisHandlerProtocol +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import kotlinx.coroutines.runBlocking + +class InjectedAgentWiringTest { + /** The guard-agent-jvm GuardAgentTelemetry shape: a facade protocol and a composite member. */ + private class RecordingTelemetry : AgentHandlerProtocol, AgentTelemetryMember { + var starts = 0 + var stops = 0 + val events = mutableListOf>() + val metrics = mutableListOf>() + + override suspend fun initializeRedis(redisHandler: RedisHandlerProtocol) {} + + override suspend fun initializeRedis(redisHandler: Any?) {} + + override suspend fun sendEvent(event: Map) { + events.add(event) + } + + override suspend fun sendMetric(metric: Map) { + metrics.add(metric) + } + + @Suppress("UNCHECKED_CAST") + override suspend fun sendEvent(event: Any?) { + (event as? Map)?.let { events.add(it) } + } + + @Suppress("UNCHECKED_CAST") + override suspend fun sendMetric(metric: Any?) { + (metric as? Map)?.let { metrics.add(it) } + } + + override suspend fun start() { + starts++ + } + + override suspend fun stop() { + stops++ + } + + override suspend fun flushBuffer() {} + + override suspend fun getDynamicRules(): Any? = null + + override suspend fun healthCheck(): Boolean = true + } + + private fun agentConfig(): SecurityConfig = + SecurityConfigBuilder() + .apply { + enableRedis = false + enableAgent = true + agentApiKey = "test-key" + } + .build() + + @Test + fun enableAgentWithoutAHandlerDegrades() { + val middleware = GuardCoreMiddleware(agentConfig(), null, null) + assertTrue(middleware.agentDegraded) + } + + @Test + fun injectedHandlerIsStartedReceivesEventsAndMetricsAndStops() = runBlocking { + val telemetry = RecordingTelemetry() + val middleware = GuardCoreMiddleware(agentConfig(), null, telemetry) + assertFalse(middleware.agentDegraded) + + middleware.initialize() + middleware.agentHandler!!.sendEvent(linkedMapOf("event_type" to "ip_banned")) + middleware.metricsCollector.sendMetric("response_time", 1.0) + assertEquals(1, telemetry.starts) + assertEquals(listOf("ip_banned"), telemetry.events.map { it["event_type"] }) + assertEquals(listOf("response_time"), telemetry.metrics.map { it["metric_type"] }) + + middleware.shutdown() + assertEquals(1, telemetry.stops) + } +} From 0d0c229d4732a43501e8efc6aa0ffe04b068b28a Mon Sep 17 00:00:00 2001 From: Renn F Date: Tue, 13 Oct 2026 22:12:49 +0200 Subject: [PATCH 2/2] test(agent): pin the engine to the agent telemetry fix and satisfy detekt --- .github/workflows/ci.yml | 2 +- .github/workflows/code-ql.yml | 2 +- .github/workflows/release.yml | 2 +- CHANGELOG.md | 1 + CONTRIBUTING.md | 2 +- docs/examples.md | 2 +- docs/installation.md | 4 ++-- settings.gradle.kts | 2 +- .../kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt | 6 +++--- 9 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcb9423..a8d8662 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ concurrency: env: # The engine ref ktor-guard pins (lockstep 4.3.3; settings.gradle.kts builds it from # source). Bump this and the settings comment together with a facade upgrade. - GUARD_CORE_JVM_REF: 2415a77b35f99dbaa96ad821b7ef4571992e18f4 + GUARD_CORE_JVM_REF: 9067b7b247d73790cc93b4cb433a1e973265a473 jobs: build: diff --git a/.github/workflows/code-ql.yml b/.github/workflows/code-ql.yml index 5b1b2e0..57cb838 100644 --- a/.github/workflows/code-ql.yml +++ b/.github/workflows/code-ql.yml @@ -11,7 +11,7 @@ permissions: {} env: # The engine ref ktor-guard pins (mirrors ci.yml; settings.gradle.kts builds the engine # from source, so the composite build needs the sibling checkout during analysis). - GUARD_CORE_JVM_REF: 2415a77b35f99dbaa96ad821b7ef4571992e18f4 + GUARD_CORE_JVM_REF: 9067b7b247d73790cc93b4cb433a1e973265a473 jobs: code-ql: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e5873d..630ddc7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ permissions: {} env: # The engine ref ktor-guard pins (lockstep 4.3.3; settings.gradle.kts builds it from # source). Bump this and the settings comment together with a facade upgrade. - GUARD_CORE_JVM_REF: 2415a77b35f99dbaa96ad821b7ef4571992e18f4 + GUARD_CORE_JVM_REF: 9067b7b247d73790cc93b4cb433a1e973265a473 jobs: pre-flight: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4056aa3..3a378eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project are documented in this file. The format foll ### Changed +- The pinned guard-core-jvm engine ref moves to 9067b7b, which fixes the agent telemetry wiring (Guard-Core/guard-core-jvm#48): an injected guard-agent-jvm handler was never added to the engine composite, so it was never started and received no events, and metrics travelled as events. A new `InjectedAgentWiringTest` covers the injected handler end to end (start, events, metrics, stop). - Dependencies: netty is pinned to 4.1.139.Final through `platform(io.netty:netty-bom)`. lettuce-core 6.8.2 declares netty 4.1.125, which carries twelve advisories fixed by 4.1.137 at the latest. The pin is declared here as well as in the guard-core-jvm facade, so this lockfile stays the same whichever engine revision the build resolves. All twelve netty osv-scanner suppressions are removed. - Two stale code comments that said the guard-agent-jvm artifact "ships in W7" now describe the injected `agentHandler` (`GuardCorePlugin.kt`, `GuardCoreMiddleware.kt`). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f3995d6..ac0efe1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ pinned ref: ```bash git clone https://github.com/Guard-Core/guard-core-jvm ../guard-core-jvm -git -C ../guard-core-jvm checkout 2415a77 +git -C ../guard-core-jvm checkout 9067b7b ./gradlew build # detekt + ktfmt check + tests ``` diff --git a/docs/examples.md b/docs/examples.md index 5653ada..cf9c514 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -8,7 +8,7 @@ for blocked requests. git clone https://github.com/Guard-Core/ktor-guard.git cd ktor-guard git clone https://github.com/Guard-Core/guard-core-jvm.git guard-core-jvm -git -C guard-core-jvm checkout 2415a77 +git -C guard-core-jvm checkout 9067b7b docker run -d -p 6379:6379 redis:7-alpine ./gradlew :examples:demo-ktor:run ``` diff --git a/docs/installation.md b/docs/installation.md index 2340363..c92bd9c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -24,7 +24,7 @@ packages stay `com.guardcore.*`. ## Engine dependency (includeBuild + dependency substitution) Consumers resolve the engine artifact `com.guard-core:guard-core` from Maven Central. This repository's own build pins the engine from source instead: CI and -local builds check out `Guard-Core/guard-core-jvm` at the pinned ref `2415a77` +local builds check out `Guard-Core/guard-core-jvm` at the pinned ref `9067b7b` as the sibling directory `./guard-core-jvm`, and `settings.gradle.kts` substitutes the declared coordinates with the included build's projects. The declared dependency coordinates stay `com.guard-core:guard-core:4.3.3` @@ -32,7 +32,7 @@ declared dependency coordinates stay `com.guard-core:guard-core:4.3.3` ```bash git clone https://github.com/Guard-Core/guard-core-jvm.git guard-core-jvm -git -C guard-core-jvm checkout 2415a77 +git -C guard-core-jvm checkout 9067b7b ./gradlew build ``` diff --git a/settings.gradle.kts b/settings.gradle.kts index abae260..f8615e5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -25,7 +25,7 @@ pluginManagement { // included build until the artifacts publish to Maven Central. // // Layout: the engine checkout sits as a sibling of this repo. CI checks it out -// with actions/checkout (repository: Guard-Core/guard-core-jvm, ref: 2415a77, +// with actions/checkout (repository: Guard-Core/guard-core-jvm, ref: 9067b7b, // path: guard-core-jvm); locally clone it with // git clone https://github.com/Guard-Core/guard-core-jvm ../guard-core-jvm // --------------------------------------------------------------------------- diff --git a/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt b/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt index c85cb12..c64ec28 100644 --- a/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt +++ b/src/test/kotlin/com/guardcore/ktor/InjectedAgentWiringTest.kt @@ -19,9 +19,9 @@ class InjectedAgentWiringTest { val events = mutableListOf>() val metrics = mutableListOf>() - override suspend fun initializeRedis(redisHandler: RedisHandlerProtocol) {} + override suspend fun initializeRedis(redisHandler: RedisHandlerProtocol) = Unit - override suspend fun initializeRedis(redisHandler: Any?) {} + override suspend fun initializeRedis(redisHandler: Any?) = Unit override suspend fun sendEvent(event: Map) { events.add(event) @@ -49,7 +49,7 @@ class InjectedAgentWiringTest { stops++ } - override suspend fun flushBuffer() {} + override suspend fun flushBuffer() = Unit override suspend fun getDynamicRules(): Any? = null