From 4415291c5fb9767e43036b34227fc30baa1a73c3 Mon Sep 17 00:00:00 2001 From: Renn F Date: Tue, 13 Oct 2026 21:54:18 +0200 Subject: [PATCH 1/2] feat(agent): inject an AgentHandlerProtocol bean into GuardMiddleware --- CHANGELOG.md | 1 + README.md | 26 ++++ .../com/guardcore/spring/GuardMiddleware.kt | 81 ++++++++-- .../spring/GuardSecurityAutoConfiguration.kt | 9 +- .../guardcore/spring/GuardAgentWiringTest.kt | 142 ++++++++++++++++++ 5 files changed, 247 insertions(+), 12 deletions(-) create mode 100644 src/test/kotlin/com/guardcore/spring/GuardAgentWiringTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 4444267..2d20422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Changed +- Telemetry agent support: an `AgentHandlerProtocol` bean (for example guard-agent-jvm's `GuardAgentTelemetry`) is now injected into `GuardMiddleware` by the auto-configuration, adopted into the engine composite on initialization, and stopped through the new `GuardMiddleware.shutdown()` when the context closes. Before this, `guard.enable-agent=true` always degraded with a "W7 artifact" message, because the middleware had no way to receive a handler. The degrade path now only applies when no handler bean is registered. - 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. The four netty osv-scanner suppressions are removed; the Spring Boot test-scope suppressions stay. ## [1.0.0] - 2026-10-13 diff --git a/README.md b/README.md index 7f4e040..dc928e3 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,32 @@ Rate limiting, IP banning, and behavioral tracking run through the facade manage Redis 6+ (`guard.redis-url`). The test suite uses the live `localhost:6379` (CI wires a redis service container); redis-backed tests skip when no server answers. +## Telemetry agent + +The adapter never builds the agent itself. Register a guard-agent-jvm handler as an `AgentHandlerProtocol` bean and set `guard.enable-agent=true` (with `guard.agent-api-key`, which the engine config requires when the agent is enabled). The auto-configuration hands the bean to `GuardMiddleware`, which starts it on initialization and stops it, flushing its buffer, when the application context closes: + +```kotlin +import com.guardcore.agent.GuardAgent +import com.guardcore.agent.GuardAgentTelemetry +import com.guardcore.agent.defaultConfig +import com.guardcore.protocols.AgentHandlerProtocol +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class GuardAgentConfig { + @Bean + fun guardAgentTelemetry(): AgentHandlerProtocol { + val cfg = defaultConfig() + cfg.apiKey = "YOUR_API_KEY" + cfg.projectId = "YOUR_PROJECT_ID" + return GuardAgentTelemetry(GuardAgent.create(cfg)) + } +} +``` + +With `guard.enable-agent=true` and no such bean, the middleware degrades like the reference adapter: it logs the missing handler and continues without agent functionality (or fails startup when `guard.agent-strict=true`). + ## Example `examples/demo-boot` is a runnable Boot app with guarded + open routes and the README run diff --git a/src/main/kotlin/com/guardcore/spring/GuardMiddleware.kt b/src/main/kotlin/com/guardcore/spring/GuardMiddleware.kt index a7289f6..4c0d98b 100644 --- a/src/main/kotlin/com/guardcore/spring/GuardMiddleware.kt +++ b/src/main/kotlin/com/guardcore/spring/GuardMiddleware.kt @@ -7,6 +7,7 @@ import com.guardcore.core.bypass.BypassContext import com.guardcore.core.bypass.BypassHandler import com.guardcore.core.checks.ChecksFactory import com.guardcore.core.checks.SecurityCheckPipeline +import com.guardcore.core.events.CompositeAgentHandler import com.guardcore.core.events.MetricsCollector import com.guardcore.core.events.SecurityEventBus import com.guardcore.core.initialization.HandlerInitializer @@ -22,6 +23,7 @@ import com.guardcore.errors.GuardRedisError import com.guardcore.handlers.BehaviorRule import com.guardcore.handlers.CloudManager import com.guardcore.handlers.CorsHandler +import com.guardcore.handlers.HandlerAgentSink import com.guardcore.handlers.RateLimitManager import com.guardcore.handlers.RedisManager import com.guardcore.handlers.SecurityHeadersManager @@ -33,6 +35,7 @@ import com.guardcore.protocols.GuardResponse import com.guardcore.protocols.GuardResponseFactory import com.guardcore.protocols.MiddlewareEventBusProtocol import com.guardcore.protocols.MiddlewareResponseFactoryProtocol +import com.guardcore.protocols.RedisHandlerProtocol import com.guardcore.util.IpExtraction import com.guardcore.util.LoggingUtils import java.util.logging.Logger @@ -55,6 +58,8 @@ public class GuardMiddleware( override val config: SecurityConfig, servletResponseFactory: ServletGuardResponseFactory = ServletGuardResponseFactory(), decorator: BaseSecurityDecorator? = null, + /** An externally supplied agent handler (guard-agent-jvm); null when none is registered. */ + public val injectedAgentHandler: AgentHandlerProtocol? = null, ) : GuardMiddlewareProtocol { override val logger: Logger = LoggingUtils.setupCustomLogging(config.customLogFile, config.logFormat.pythonName) @@ -84,9 +89,9 @@ public class GuardMiddleware( /** Python `redis_handler` (middleware.py:66-70): Lettuce via the facade manager. */ public val redisHandler: RedisManager? = if (config.enableRedis) RedisManager(config) else null - private var agentHandlerField: AgentHandlerProtocol? = null + private var agentHandlerField: AgentHandlerProtocol? = injectedAgentHandler - /** Python `agent_handler` (middleware.py:72-93); guard-agent-jvm ships at W7. */ + /** Python `agent_handler` (middleware.py:72-93): the injected handler, then the composite. */ override val agentHandler: AgentHandlerProtocol? get() = agentHandlerField @@ -105,11 +110,13 @@ public class GuardMiddleware( get() = plainResponseFactory /** Python `event_bus` (middleware.py:99). */ - override var eventBus: MiddlewareEventBusProtocol = SecurityEventBus(null, config, geoIpHandler) + override var eventBus: MiddlewareEventBusProtocol = + SecurityEventBus(injectedAgentHandler as? HandlerAgentSink, config, geoIpHandler) private set /** Python `metrics_collector` (middleware.py:102). */ - public var metricsCollector: MetricsCollector = MetricsCollector(null, config) + public var metricsCollector: MetricsCollector = + MetricsCollector(injectedAgentHandler as? HandlerAgentSink, config) private set /** Python `handler_initializer` (middleware.py:104-111). */ @@ -117,7 +124,7 @@ public class GuardMiddleware( HandlerInitializer( config = config, redisHandler = redisHandler, - agentHandler = null, + agentHandler = injectedAgentHandler, geoIpHandler = geoIpHandler, rateLimitHandler = rateLimitHandler, guardDecorator = guardDecoratorField, @@ -174,12 +181,13 @@ public class GuardMiddleware( BypassContext(config, logger, eventBus, routeResolver, errorResponseFactory, validator), ) behavioralProcessor = buildBehavioralProcessor() - if (config.enableAgent) { - // guard-agent-jvm lands at W7; mirror the AgentPackageNotInstalledError degrade path - // (middleware.py:83-93) until then. + if (config.enableAgent && injectedAgentHandler == null) { + // The adapter never builds the agent itself: an AgentHandlerProtocol bean is the only agent + // source. Mirror the reference AgentPackageNotInstalledError degrade path + // (middleware.py:83-93). onAgentInitFailed( - "Agent enabled but guard-agent-jvm is not available in this build yet " + - "(W7 artifact); continuing without agent functionality", + "Agent enabled but no agent handler was provided. Register a guard-agent-jvm " + + "AgentHandlerProtocol bean (GuardAgentTelemetry), or disable enable_agent.", null, ) } @@ -265,7 +273,11 @@ public class GuardMiddleware( handlerInitializer.initializeRedisHandlers() handlerInitializer.initializeAgentIntegrations() - if (handlerInitializer.compositeHandler != null) { + val composite = handlerInitializer.compositeHandler + if (composite != null) { + // Python initialize() lines 719-726: adopt the composite as the agent handler and rebuild + // the event bus + metrics collector around it, then the event-dependent contexts. + agentHandlerField = CompositeAgentProtocol(composite) eventBus = handlerInitializer.buildEventBus(geoIpHandler = geoIpHandler) metricsCollector = handlerInitializer.buildMetricsCollector() rebuildEventDependentContexts() @@ -423,4 +435,51 @@ public class GuardMiddleware( logger.severe(message) logger.warning("Continuing without agent functionality") } + + /** + * Python `shutdown_agent_integrations` on application shutdown: stops the composite, which stops + * the injected agent and flushes its buffer. Spring calls it as the bean's inferred destroy + * method. + */ + public fun shutdown() { + kotlinx.coroutines.runBlocking { handlerInitializer.shutdownAgentIntegrations() } + } + + /** + * The composite handler as the agent protocol (python passes the composite as agent_handler; the + * HandlerInitializer builds the same adapter shape over the composite). + */ + private class CompositeAgentProtocol( + private val composite: CompositeAgentHandler, + ) : AgentHandlerProtocol { + override suspend fun initializeRedis(redisHandler: RedisHandlerProtocol) { + composite.initializeRedis(redisHandler) + } + + override suspend fun sendEvent(event: Any?) { + @Suppress("UNCHECKED_CAST") + composite.sendEvent((event as? Map) ?: linkedMapOf()) + } + + override suspend fun sendMetric(metric: Any?) { + @Suppress("UNCHECKED_CAST") + composite.sendMetric((metric as? Map) ?: linkedMapOf()) + } + + override suspend fun start() { + composite.start() + } + + override suspend fun stop() { + composite.stop() + } + + override suspend fun flushBuffer() { + composite.flushBuffer() + } + + override suspend fun getDynamicRules(): Any? = composite.getDynamicRules() + + override suspend fun healthCheck(): Boolean = composite.healthCheck() + } } diff --git a/src/main/kotlin/com/guardcore/spring/GuardSecurityAutoConfiguration.kt b/src/main/kotlin/com/guardcore/spring/GuardSecurityAutoConfiguration.kt index b54c012..fff0312 100644 --- a/src/main/kotlin/com/guardcore/spring/GuardSecurityAutoConfiguration.kt +++ b/src/main/kotlin/com/guardcore/spring/GuardSecurityAutoConfiguration.kt @@ -2,6 +2,7 @@ package com.guardcore.spring import com.guardcore.config.SecurityConfig import com.guardcore.config.SecurityConfigBuilder +import com.guardcore.protocols.AgentHandlerProtocol import jakarta.servlet.DispatcherType import jakarta.servlet.http.HttpServletRequest import org.springframework.beans.factory.ObjectProvider @@ -60,7 +61,13 @@ public open class GuardSecurityAutoConfiguration { public open fun guardMiddleware( config: SecurityConfig, decorator: SpringGuardDecorator, - ): GuardMiddleware = GuardMiddleware(config, decorator = decorator) + agentHandler: ObjectProvider, + ): GuardMiddleware = + GuardMiddleware( + config, + decorator = decorator, + injectedAgentHandler = agentHandler.ifAvailable, + ) @Bean public open fun guardAnnotationConfigurator( diff --git a/src/test/kotlin/com/guardcore/spring/GuardAgentWiringTest.kt b/src/test/kotlin/com/guardcore/spring/GuardAgentWiringTest.kt new file mode 100644 index 0000000..c9c7ee9 --- /dev/null +++ b/src/test/kotlin/com/guardcore/spring/GuardAgentWiringTest.kt @@ -0,0 +1,142 @@ +package com.guardcore.spring + +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 kotlinx.coroutines.runBlocking +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.test.context.TestPropertySource +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +/** The guard-agent-jvm GuardAgentTelemetry shape: a facade protocol and a composite member. */ +public class RecordingTelemetry : AgentHandlerProtocol, AgentTelemetryMember { + public var starts: Int = 0 + public var stops: Int = 0 + public val events: MutableList> = mutableListOf() + public val metrics: MutableList> = 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 +} + +public class GuardAgentWiringTest { + private fun agentConfig(): SecurityConfig = + SecurityConfigBuilder() + .apply { + enableRedis = false + enableAgent = true + agentApiKey = "test-key" + } + .build() + + @Test + public fun `enable_agent without a registered handler degrades`() { + val middleware = GuardMiddleware(agentConfig()) + assertThat(middleware.agentDegraded).isTrue() + assertThat(middleware.agentHandler).isNull() + } + + @Test + public fun `an injected handler is started, receives events and metrics, and stops on shutdown`() { + val telemetry = RecordingTelemetry() + val middleware = GuardMiddleware(agentConfig(), injectedAgentHandler = telemetry) + assertThat(middleware.agentDegraded).isFalse() + assertThat(middleware.agentHandler).isSameAs(telemetry) + + runBlocking { + middleware.initialize() + middleware.agentHandler!!.sendEvent(linkedMapOf("event_type" to "ip_banned")) + middleware.metricsCollector.sendMetric("response_time", 1.0) + } + assertThat(telemetry.starts).isEqualTo(1) + assertThat(telemetry.events.map { it["event_type"] }).containsExactly("ip_banned") + assertThat(telemetry.metrics.map { it["metric_type"] }).containsExactly("response_time") + + middleware.shutdown() + assertThat(telemetry.stops).isEqualTo(1) + } +} + +@TestConfiguration +public open class AgentBeanConfig { + @Bean public open fun recordingTelemetry(): RecordingTelemetry = RecordingTelemetry() +} + +@SpringBootTest( + classes = [GuardTestApp::class, AgentBeanConfig::class], + webEnvironment = SpringBootTest.WebEnvironment.MOCK, +) +@AutoConfigureMockMvc +@TestPropertySource( + properties = + [ + "guard.enable-redis=false", + "guard.enable-agent=true", + "guard.agent-api-key=test-key", + "guard.blocked-user-agents[0]=BadBot", + ], +) +public class GuardAgentBeanIntegrationTest { + @Autowired public lateinit var mockMvc: MockMvc + + @Autowired public lateinit var middleware: GuardMiddleware + + @Autowired public lateinit var telemetry: RecordingTelemetry + + @Test + public fun `a registered AgentHandlerProtocol bean receives the events of blocked requests`() { + mockMvc + .perform(get("/api/echo").header("User-Agent", "BadBot/1.0")) + .andExpect(status().isForbidden) + + assertThat(middleware.injectedAgentHandler).isSameAs(telemetry) + assertThat(middleware.agentDegraded).isFalse() + assertThat(telemetry.starts).isEqualTo(1) + assertThat(telemetry.events.map { it["event_type"] as? String }).anyMatch { + !it.isNullOrBlank() + } + } +} From 0d9f5033a17625e6c08fd9105948bf2cb33a12d1 Mon Sep 17 00:00:00 2001 From: Renn F Date: Tue, 13 Oct 2026 22:12:50 +0200 Subject: [PATCH 2/2] chore(engine): pin guard-core-jvm to the agent telemetry fix --- .github/workflows/ci.yml | 6 +++--- .github/workflows/code-ql.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- CHANGELOG.md | 2 +- CONTRIBUTING.md | 2 +- README.md | 4 ++-- docs/examples.md | 2 +- docs/installation.md | 4 ++-- examples/demo-boot/README.md | 4 ++-- examples/demo-boot/settings.gradle.kts | 4 ++-- settings.gradle.kts | 4 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 541ffcf..2adebc8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,15 +25,15 @@ jobs: with: persist-credentials: false - # The engine dependency: guard-core-jvm pinned at 2415a77 (full SHA for the + # The engine dependency: guard-core-jvm pinned at 9067b7b (full SHA for the # actions/checkout fetch), checked # out as the sibling directory ./guard-core-jvm and substituted for the # declared com.guardcore:guard-core coordinates by settings.gradle.kts. - - name: Checkout engine (guard-core-jvm @ 2415a77) + - name: Checkout engine (guard-core-jvm @ 9067b7b) uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: Guard-Core/guard-core-jvm - ref: 2415a77b35f99dbaa96ad821b7ef4571992e18f4 + ref: 9067b7b247d73790cc93b4cb433a1e973265a473 path: guard-core-jvm persist-credentials: false diff --git a/.github/workflows/code-ql.yml b/.github/workflows/code-ql.yml index 4aba816..5876c5e 100644 --- a/.github/workflows/code-ql.yml +++ b/.github/workflows/code-ql.yml @@ -23,11 +23,11 @@ jobs: # The engine dependency: the composite includeBuild needs the pinned # guard-core-jvm checkout next to the repository (same as ci.yml). - - name: Checkout engine (guard-core-jvm @ 2415a77) + - name: Checkout engine (guard-core-jvm @ 9067b7b) uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: Guard-Core/guard-core-jvm - ref: 2415a77b35f99dbaa96ad821b7ef4571992e18f4 + ref: 9067b7b247d73790cc93b4cb433a1e973265a473 path: guard-core-jvm persist-credentials: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43ea084..65df299 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -72,11 +72,11 @@ jobs: persist-credentials: false # Same engine checkout as ci.yml (the composite default for tests). - - name: Checkout engine (guard-core-jvm @ 2415a77) + - name: Checkout engine (guard-core-jvm @ 9067b7b) uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: Guard-Core/guard-core-jvm - ref: 2415a77b35f99dbaa96ad821b7ef4571992e18f4 + ref: 9067b7b247d73790cc93b4cb433a1e973265a473 path: guard-core-jvm persist-credentials: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d20422..3c65406 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Changed -- Telemetry agent support: an `AgentHandlerProtocol` bean (for example guard-agent-jvm's `GuardAgentTelemetry`) is now injected into `GuardMiddleware` by the auto-configuration, adopted into the engine composite on initialization, and stopped through the new `GuardMiddleware.shutdown()` when the context closes. Before this, `guard.enable-agent=true` always degraded with a "W7 artifact" message, because the middleware had no way to receive a handler. The degrade path now only applies when no handler bean is registered. +- Telemetry agent support: an `AgentHandlerProtocol` bean (for example guard-agent-jvm's `GuardAgentTelemetry`) is now injected into `GuardMiddleware` by the auto-configuration, adopted into the engine composite on initialization, and stopped through the new `GuardMiddleware.shutdown()` when the context closes. Before this, `guard.enable-agent=true` always degraded with a "W7 artifact" message, because the middleware had no way to receive a handler. The degrade path now only applies when no handler bean is registered. The pinned guard-core-jvm engine ref moves to 9067b7b, whose agent telemetry wiring fix (Guard-Core/guard-core-jvm#48) the handler needs to receive anything. - 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. The four netty osv-scanner suppressions are removed; the Spring Boot test-scope suppressions stay. ## [1.0.0] - 2026-10-13 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b95184..4716f79 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ side in the same directory) at the 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 (redis-backed tests skip when redis is down) ``` diff --git a/README.md b/README.md index dc928e3..8b8de2a 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ logs the same "eager init not honored" warning as fastapi-guard. The engine artifact `com.guard-core:guard-core` (groupId is the Central Portal namespace; Kotlin packages stay `com.guardcore.*`) is on Maven Central for consumers. 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` as the sibling directory `./guard-core-jvm`, and `settings.gradle.kts` +pinned ref `9067b7b` as the sibling directory `./guard-core-jvm`, and `settings.gradle.kts` substitutes the declared coordinates `com.guard-core:guard-core:4.3.3` / `com.guard-core:guard-core-engine:4.3.3` with the included build's projects (the Gradle analog of the Rust path+version pattern). The declared dependency coordinates stay @@ -152,7 +152,7 @@ Local checkout: ```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/docs/examples.md b/docs/examples.md index 4cfab1d..38529d9 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -7,7 +7,7 @@ routes, live Redis-backed rate limiting, and per-route decorator configs. git clone https://github.com/Guard-Core/spring-boot-guard.git cd spring-boot-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-boot:bootRun ``` diff --git a/docs/installation.md b/docs/installation.md index 0c2e851..2e34e0b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -23,7 +23,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 `com.guard-core:guard-core:4.3.3` / `com.guard-core:guard-core-engine:4.3.3` with the included build's projects. @@ -32,7 +32,7 @@ The 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/examples/demo-boot/README.md b/examples/demo-boot/README.md index 1156b24..e629036 100644 --- a/examples/demo-boot/README.md +++ b/examples/demo-boot/README.md @@ -21,12 +21,12 @@ engine's `SecurityConfig` field names). Prerequisites: -1. Clone Guard-Core/guard-core-jvm at the pinned ref `2415a77` next to this repository +1. Clone Guard-Core/guard-core-jvm at the pinned ref `9067b7b` next to this repository (the engine builds from source via includeBuild until the artifacts publish): ```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 ``` 2. A Redis on `localhost:6379` (rate limiting), or set `guard.enable-redis: false` in diff --git a/examples/demo-boot/settings.gradle.kts b/examples/demo-boot/settings.gradle.kts index 6c94d77..26cb92d 100644 --- a/examples/demo-boot/settings.gradle.kts +++ b/examples/demo-boot/settings.gradle.kts @@ -15,7 +15,7 @@ rootProject.name = "demo-boot" // The adapter and the engine are consumed from source until both publish: // the adapter repo sits two levels up and the engine at the pinned ref -// 2415a77 sits next to it (the same includeBuild convention as the adapter). +// 9067b7b sits next to it (the same includeBuild convention as the adapter). includeBuild("../../") { dependencySubstitution { substitute(module("com.guardcore:spring-boot-guard")).using(project(":")) @@ -35,7 +35,7 @@ val engineDir: File = run { ) roots.firstOrNull { it.resolve("settings.gradle.kts").isFile } ?: throw GradleException( - "Clone Guard-Core/guard-core-jvm at the pinned ref 2415a77 next to the " + + "Clone Guard-Core/guard-core-jvm at the pinned ref 9067b7b next to the " + "spring-boot-guard repository first (or point -PguardCoreJvmDir / " + "GUARD_CORE_JVM_DIR at an existing checkout). Searched: " + roots.joinToString(", ") { it.path }, diff --git a/settings.gradle.kts b/settings.gradle.kts index e84bb38..e25135a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,7 +13,7 @@ pluginManagement { // GUARD_CORE_USE_COMPOSITE (environment variable): // unset / "1" / "true" -> composite ON (default). The engine is built from // source via includeBuild + dependency substitution: CI (and local builds) -// check out Guard-Core/guard-core-jvm at the PINNED REF 2415a77 as the +// check out Guard-Core/guard-core-jvm at the PINNED REF 9067b7b as the // sibling directory ./guard-core-jvm, and the block below substitutes the // declared coordinates com.guard-core:guard-core / // com.guard-core:guard-core-engine with the included build's projects. @@ -63,7 +63,7 @@ if (useComposite) { roots.firstOrNull { it.resolve("settings.gradle.kts").isFile } ?: throw GradleException( "The guard-core-jvm engine checkout was not found. Clone Guard-Core/guard-core-jvm " + - "at the pinned ref 2415a77 next to this repository (or point -PguardCoreJvmDir / " + + "at the pinned ref 9067b7b next to this repository (or point -PguardCoreJvmDir / " + "GUARD_CORE_JVM_DIR at an existing checkout). Searched: " + roots.joinToString(", ") { it.path }, )