From 5727f0ffc5f4b63ca67726a59199295a73a2b518 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 10 Oct 2026 08:05:05 +0000 Subject: [PATCH 1/4] build(deps): bump the all-maven group in /services with 6 updates Bumps the all-maven group in /services with 6 updates: | Package | From | To | | --- | --- | --- | | [com.github.siom79.japicmp:japicmp-maven-plugin](https://github.com/siom79/japicmp) | `0.26.2` | `0.26.3` | | [com.redis:testcontainers-redis](https://github.com/redis-field-engineering/testcontainers-redis) | `2.2.4` | `3.0.0` | | org.redisson:redisson-spring-boot-starter | `4.7.0` | `4.8.0` | | [com.meilisearch.sdk:meilisearch-java](https://github.com/meilisearch/meilisearch-java) | `0.21.0` | `0.22.1` | | org.flywaydb:flyway-core | `13.8.1` | `13.9.0` | | org.flywaydb:flyway-mysql | `13.8.1` | `13.9.0` | Updates `com.github.siom79.japicmp:japicmp-maven-plugin` from 0.26.2 to 0.26.3 - [Release notes](https://github.com/siom79/japicmp/releases) - [Changelog](https://github.com/siom79/japicmp/blob/master/release.py) - [Commits](https://github.com/siom79/japicmp/compare/japicmp-base-0.26.2...japicmp-base-0.26.3) Updates `com.redis:testcontainers-redis` from 2.2.4 to 3.0.0 - [Release notes](https://github.com/redis-field-engineering/testcontainers-redis/releases) - [Commits](https://github.com/redis-field-engineering/testcontainers-redis/compare/v2.2.4...v3.0.0) Updates `org.redisson:redisson-spring-boot-starter` from 4.7.0 to 4.8.0 Updates `com.meilisearch.sdk:meilisearch-java` from 0.21.0 to 0.22.1 - [Release notes](https://github.com/meilisearch/meilisearch-java/releases) - [Commits](https://github.com/meilisearch/meilisearch-java/compare/v0.21.0...v0.22.1) Updates `org.flywaydb:flyway-core` from 13.8.1 to 13.9.0 Updates `org.flywaydb:flyway-mysql` from 13.8.1 to 13.9.0 --- updated-dependencies: - dependency-name: com.github.siom79.japicmp:japicmp-maven-plugin dependency-version: 0.26.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all-maven - dependency-name: com.redis:testcontainers-redis dependency-version: 3.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: all-maven - dependency-name: org.redisson:redisson-spring-boot-starter dependency-version: 4.8.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-maven - dependency-name: com.meilisearch.sdk:meilisearch-java dependency-version: 0.22.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-maven - dependency-name: org.flywaydb:flyway-core dependency-version: 13.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-maven - dependency-name: org.flywaydb:flyway-mysql dependency-version: 13.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-maven ... Signed-off-by: dependabot[bot] --- services/app/app-web/pom.xml | 6 +++--- services/core/pom.xml | 4 ++-- services/platform/web-security/pom.xml | 2 +- services/pom.xml | 4 ++-- services/search/pom.xml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/app/app-web/pom.xml b/services/app/app-web/pom.xml index 2507ea074..e7852a8b2 100644 --- a/services/app/app-web/pom.xml +++ b/services/app/app-web/pom.xml @@ -91,7 +91,7 @@ com.meilisearch.sdk meilisearch-java - 0.21.0 + 0.22.1 com.ulticode @@ -230,7 +230,7 @@ org.flywaydb flyway-core - 13.8.1 + 13.9.0 test 4.12.0 - 0.26.2 + 0.26.3 0.50 diff --git a/services/search/pom.xml b/services/search/pom.xml index 43316014a..dc359bdd6 100644 --- a/services/search/pom.xml +++ b/services/search/pom.xml @@ -90,7 +90,7 @@ com.meilisearch.sdk meilisearch-java - 0.21.0 + 0.22.1 From 0a4462959b263ced2e96f295ae5f8fab0263a227 Mon Sep 17 00:00:00 2001 From: DavidHLP Date: Sat, 10 Oct 2026 22:09:47 -0700 Subject: [PATCH 2/4] fix(deps): migrate backend to patched Spring Boot baseline --- docs/OPERATIONS.md | 4 ++ scripts/test/observability-contract.sh | 10 +++ scripts/test/supply-chain-contract.sh | 2 +- services/admin/pom.xml | 20 ++++-- .../admin/src/main/resources/application.yml | 22 ++++--- .../ulticode/BackendAdminApplicationTest.java | 13 ++-- .../BackendAdminDatasourceContextIT.java | 7 +- .../admin/config/AdminCacheConfigTest.java | 2 +- .../AdminRouteAuthorizationContractTest.java | 2 +- .../AdminAccountControllerTest.java | 4 +- .../AdminContestControllerTest.java | 4 +- .../AdminProblemListControllerTest.java | 4 +- .../AdminSettingsControllerTest.java | 4 +- .../AdminSubmissionControllerTest.java | 4 +- .../controller/AdminTagControllerTest.java | 4 +- .../controller/AuditControllerFormatTest.java | 4 +- .../admin/outbox/AuditSinkTransactionIT.java | 7 +- .../modules/backup/BackupRepositoryIT.java | 7 +- services/app/app-web/pom.xml | 22 +++++-- .../src/main/resources/application.yml | 22 ++++--- .../ulticode/BackendAppApplicationTest.java | 4 +- .../app/config/AppCacheConfigTest.java | 2 +- .../app/config/AppRedisRoleConfigTest.java | 4 +- .../app/dubbo/DubboBoot4LocalRoundTripIT.java | 64 +++++++++++++++++++ .../app/dubbo/boot4fixture/LocalEchoPort.java | 6 ++ .../dubbo/boot4fixture/LocalEchoService.java | 15 +++++ .../ContestAdministrationWiringIT.java | 10 +-- .../ProblemListAdministrationWiringIT.java | 10 +-- .../AppRouteAuthorizationContractTest.java | 2 +- .../userprofile/ProfileWriteProviderIT.java | 12 ++-- .../ContestPublicControllerTest.java | 4 +- .../ContestAdjudicationWiringIT.java | 10 +-- .../controller/ModerationControllerTest.java | 4 +- .../controller/ProblemControllerTest.java | 4 +- .../src/test/resources/application.yml | 4 +- services/app/modules/contest/pom.xml | 2 +- services/app/modules/moderation/pom.xml | 2 +- services/app/modules/problem/pom.xml | 2 +- services/auth/pom.xml | 21 +++++- .../security/oauth/GithubOAuthClient.java | 2 +- .../security/oauth/GoogleOAuthClient.java | 2 +- .../security/oauth/OAuthAuthorizationUrl.java | 22 +++++++ .../auth/src/main/resources/application.yml | 17 +++-- .../ulticode/BackendAuthApplicationTest.java | 4 +- .../error/AuthWebExceptionHandlerTest.java | 4 +- .../AuthSecurityConfigContractTest.java | 2 +- .../oauth/OAuthAuthorizationUrlTest.java | 23 +++++++ .../auth/src/test/resources/application.yml | 7 +- services/core/pom.xml | 12 +++- .../com/ulticode/core/CoreApplication.java | 12 ++-- .../core/CoreOwnerBootConfigurations.java | 4 +- .../CoreOwnerDataSourceConfiguration.java | 2 +- .../core/src/main/resources/application.yml | 3 + .../core/CoreEnabledOwnerJourneyIT.java | 2 +- services/judge-runtime/pom.xml | 2 +- services/judge/pom.xml | 4 +- .../judge/src/main/resources/application.yml | 22 ++++--- services/notification/pom.xml | 12 ++-- .../src/main/resources/application.yml | 20 ++++-- ...icationRouteAuthorizationContractTest.java | 2 +- services/platform/integration-inbox/pom.xml | 4 +- services/platform/observability/pom.xml | 6 +- .../config/OtlpSecurityAutoConfiguration.java | 11 ++-- .../OtlpSecurityAutoConfigurationTest.java | 25 +++++++- services/platform/storage/pom.xml | 2 +- services/platform/web-security/pom.xml | 15 +++-- .../config/WebSecurityAutoConfiguration.java | 4 +- .../com/ulticode/websecurity/RateLimitIT.java | 8 +-- services/pom.xml | 8 +-- services/search/pom.xml | 10 ++- .../search/src/main/resources/application.yml | 22 ++++--- services/submission/pom.xml | 6 +- .../src/main/resources/application.yml | 15 +++-- .../BackendSubmissionApplicationTest.java | 2 +- ...ternalDelegationAssertionVerifierTest.java | 23 +++---- 75 files changed, 480 insertions(+), 211 deletions(-) create mode 100644 services/app/app-web/src/test/java/com/ulticode/app/dubbo/DubboBoot4LocalRoundTripIT.java create mode 100644 services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoPort.java create mode 100644 services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoService.java create mode 100644 services/auth/src/main/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrl.java create mode 100644 services/auth/src/test/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrlTest.java diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index e5c45b6d8..79c34b812 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -28,6 +28,8 @@ Trivy JSON reports are uploaded per candidate even when scanning fails; a failed Runtime images retain pinned base-image digests and apply `apk upgrade --no-cache` for Alpine security updates. Both Verify and Publish bypass cache only for the final `runtime` (backend) or `production` (frontend) stage, so cached upgrade layers cannot retain newly vulnerable packages; builder caches remain enabled. Backend dependencies use Spring Boot's BOM with narrowly scoped security overrides; verify final dependency resolution and image scan results before release. +Backend services retain Java 17 and use the Spring Boot 4 BOM for Spring Framework 7 and Tomcat 11. Existing JSON wire and persisted payload contracts remain on the documented `spring-boot-jackson2` compatibility module, selected by `spring.http.converters.preferred-json-mapper=jackson2`; Jackson 2 security overrides use `jackson-2-bom.version`, not the Jackson 3 BOM property. Do not mix Spring Framework 7 into a Boot 3 parent or retain a Tomcat 10 override under Boot 4. Dependency upgrades must pass owner-context, serialization, security and RPC checks as well as all nine image scans; reverting code must not rewrite application data or applied migrations. + `host-deploy` 在任何 migration、Redis ACL materialization、Judge sandbox provisioning 或 Compose mutation 前检查: - approved source commit; @@ -322,6 +324,8 @@ backup、restore-drill、prune 使用同一 fenced database lease(`admin:owner 可选的 `docker/docker-compose.observability.yml` 提供 loopback-only、digest-pinned 的 OpenTelemetry Collector、Prometheus、Alertmanager、Grafana、Tempo 和 Loki。HTTP Owner 暴露 metrics;无 HTTP 的 Judge/Search worker 通过 Micrometer OTLP 输出。日志携带 trace/span 关联,Grafana 可从 Loki 跳转 Tempo。 +Boot 4 tracing binds OTLP export settings under `management.opentelemetry.tracing.export.otlp`; the existing `MANAGEMENT_OTLP_TRACING_ENDPOINT` and `MANAGEMENT_OTLP_AUTHORIZATION` environment inputs remain unchanged. The shared observability module enables the tracing integration and validates the effective endpoint/header pair before export: a configured authorization header requires HTTPS. OTLP metrics configuration and the opt-in Collector overlays remain separate from tracing. + 生产 telemetry receiver、存储、保留周期、通知 webhook、阈值调优和真实流量 SLO 由外部运维平台负责;仓库 overlay 默认不启动,也不公开 management endpoint 或 secret。 ### 关键指标 diff --git a/scripts/test/observability-contract.sh b/scripts/test/observability-contract.sh index 3732bd0ae..20c80dc7a 100755 --- a/scripts/test/observability-contract.sh +++ b/scripts/test/observability-contract.sh @@ -93,6 +93,16 @@ for service in services: raise SystemExit(f"{path}: sampling default must be between 0 and 1") if "Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:}" not in text: raise SystemExit(f"{path}: OTLP authorization header mapping is missing") + if service in ("notification", "search", "judge"): + metrics = re.search( + r"^ otlp:\n metrics:\n export:\n" + r" enabled: \$\{MANAGEMENT_OTLP_METRICS_ENABLED:false\}\n" + r" url: \$\{MANAGEMENT_OTLP_METRICS_ENDPOINT:http://localhost:4318/v1/metrics\}\n" + r" step: \$\{MANAGEMENT_OTLP_METRICS_STEP:30s\}$", + text, re.MULTILINE, + ) + if metrics is None: + raise SystemExit(f"{path}: OTLP metrics must retain management.otlp.metrics.export bindings") PY printf 'owner OTLP sampling and authorization bindings: PASS\n' contains .github/services-matrix.json '"artifact": "backend-search-exec.jar"' diff --git a/scripts/test/supply-chain-contract.sh b/scripts/test/supply-chain-contract.sh index 9b4ba55c0..513f62ef3 100755 --- a/scripts/test/supply-chain-contract.sh +++ b/scripts/test/supply-chain-contract.sh @@ -165,7 +165,7 @@ python3 "$ROOT_DIR/scripts/test/promote-release-contract.py" contains .github/workflows/_docker.yml 'load: true' contains .github/workflows/_docker.yml 'TRIVY_IMAGE_SRC: docker' contains .github/workflows/_docker.yml 'name: trivy-verify-${{ matrix.service.name }}' -contains services/pom.xml '2.21.7' +contains services/pom.xml '2.21.7' contains .github/workflows/docker-publish.yml 'sbom: true' for entry in '_docker.yml:verify' 'docker-publish.yml:publish'; do diff --git a/services/admin/pom.xml b/services/admin/pom.xml index e2b4d6464..5a0c7e441 100644 --- a/services/admin/pom.xml +++ b/services/admin/pom.xml @@ -75,7 +75,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -154,7 +154,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -172,12 +172,12 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test - org.springframework.security - spring-security-test + org.springframework.boot + spring-boot-starter-security-test test @@ -196,6 +196,16 @@ mysql test + + org.springframework.boot + spring-boot-resttestclient + test + + + org.springframework.boot + spring-boot-restclient + test + diff --git a/services/admin/src/main/resources/application.yml b/services/admin/src/main/resources/application.yml index 3761cc4d1..9c254b630 100644 --- a/services/admin/src/main/resources/application.yml +++ b/services/admin/src/main/resources/application.yml @@ -3,6 +3,9 @@ server: shutdown: graceful spring: + http: + converters: + preferred-json-mapper: jackson2 application: name: backend-admin servlet: @@ -13,9 +16,10 @@ spring: timeout-per-shutdown-phase: ${SPRING_LIFECYCLE_TIMEOUT_PER_SHUTDOWN_PHASE:45s} autoconfigure: exclude: - - org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration - - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration - - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration + - org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration + - org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration + - org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration + - org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: ${ADMIN_DB_URL:jdbc:mysql://${ADMIN_DB_HOST}:${ADMIN_DB_PORT}/${ADMIN_DB_NAME}?useUnicode=true&characterEncoding=UTF-8&characterSetResults=utf8mb4&connectionCollation=utf8mb4_unicode_ci&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&sslMode=${ADMIN_DB_SSL_MODE:REQUIRED}} @@ -119,12 +123,14 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s security: internal-delegation: diff --git a/services/admin/src/test/java/com/ulticode/BackendAdminApplicationTest.java b/services/admin/src/test/java/com/ulticode/BackendAdminApplicationTest.java index 50a2b153d..defd38781 100644 --- a/services/admin/src/test/java/com/ulticode/BackendAdminApplicationTest.java +++ b/services/admin/src/test/java/com/ulticode/BackendAdminApplicationTest.java @@ -7,7 +7,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; +import org.springframework.boot.resttestclient.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -20,17 +21,19 @@ * infrastructure that is not available in a plain unit test.

*/ @Disabled("Requires Redis/MySQL infrastructure — convert to Testcontainers IT (P7-RELOCATE-ADMIN-001)") +@AutoConfigureTestRestTemplate @SpringBootTest( classes = BackendAdminApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "spring.main.allow-bean-definition-overriding=true", "spring.autoconfigure.exclude=" - + "org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration," - + "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration," - + "org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration," + + "org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration," + + "org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration," + + "org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration," + "org.redisson.spring.starter.RedissonAutoConfigurationV2," - + "org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration," + "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration," + "com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapAutoConfiguration", "spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver", diff --git a/services/admin/src/test/java/com/ulticode/admin/BackendAdminDatasourceContextIT.java b/services/admin/src/test/java/com/ulticode/admin/BackendAdminDatasourceContextIT.java index fee0ca121..955f44446 100644 --- a/services/admin/src/test/java/com/ulticode/admin/BackendAdminDatasourceContextIT.java +++ b/services/admin/src/test/java/com/ulticode/admin/BackendAdminDatasourceContextIT.java @@ -22,9 +22,10 @@ import org.testcontainers.junit.jupiter.Testcontainers; @SpringBootTest(classes = BackendAdminApplication.class, properties = "spring.autoconfigure.exclude=" - + "org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration," - + "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration," - + "org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration," + + "org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration," + + "org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration," + "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration," + "com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapAutoConfiguration") @Testcontainers diff --git a/services/admin/src/test/java/com/ulticode/admin/config/AdminCacheConfigTest.java b/services/admin/src/test/java/com/ulticode/admin/config/AdminCacheConfigTest.java index daf178b4f..3a5cecbd2 100644 --- a/services/admin/src/test/java/com/ulticode/admin/config/AdminCacheConfigTest.java +++ b/services/admin/src/test/java/com/ulticode/admin/config/AdminCacheConfigTest.java @@ -35,7 +35,7 @@ void cacheClearEvictsThroughScan() { when(connectionFactory.getConnection()).thenReturn(connection); when(connection.keyCommands()).thenReturn(keyCommands); AtomicReference scan = new AtomicReference<>(); - when(connection.scan(any(ScanOptions.class))).thenAnswer(call -> { + when(keyCommands.scan(any(ScanOptions.class))).thenAnswer(call -> { scan.set(call.getArgument(0)); throw new IllegalStateException("scan reached"); }); diff --git a/services/admin/src/test/java/com/ulticode/admin/security/AdminRouteAuthorizationContractTest.java b/services/admin/src/test/java/com/ulticode/admin/security/AdminRouteAuthorizationContractTest.java index 8aebde941..5c70e81d0 100644 --- a/services/admin/src/test/java/com/ulticode/admin/security/AdminRouteAuthorizationContractTest.java +++ b/services/admin/src/test/java/com/ulticode/admin/security/AdminRouteAuthorizationContractTest.java @@ -7,7 +7,7 @@ import com.ulticode.websecurity.jwt.AccessTokenVerifier; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminAccountControllerTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminAccountControllerTest.java index 3cd70bfa1..41d1263e5 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminAccountControllerTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminAccountControllerTest.java @@ -17,8 +17,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminContestControllerTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminContestControllerTest.java index ddae6a739..1a07bf0b3 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminContestControllerTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminContestControllerTest.java @@ -11,8 +11,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminProblemListControllerTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminProblemListControllerTest.java index f8c57181d..fc31322dc 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminProblemListControllerTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminProblemListControllerTest.java @@ -14,8 +14,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSettingsControllerTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSettingsControllerTest.java index a3cc71f4a..ac8541ba4 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSettingsControllerTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSettingsControllerTest.java @@ -15,8 +15,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSubmissionControllerTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSubmissionControllerTest.java index bba00df10..d090f9d88 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSubmissionControllerTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminSubmissionControllerTest.java @@ -13,8 +13,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminTagControllerTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminTagControllerTest.java index 9646ab80c..54d3e36f6 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminTagControllerTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AdminTagControllerTest.java @@ -11,8 +11,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AuditControllerFormatTest.java b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AuditControllerFormatTest.java index b1bfa03d0..23d1c0410 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/controller/AuditControllerFormatTest.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/controller/AuditControllerFormatTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.context.ContextConfiguration; diff --git a/services/admin/src/test/java/com/ulticode/modules/admin/outbox/AuditSinkTransactionIT.java b/services/admin/src/test/java/com/ulticode/modules/admin/outbox/AuditSinkTransactionIT.java index 12b5640e9..ffb8ecbb2 100644 --- a/services/admin/src/test/java/com/ulticode/modules/admin/outbox/AuditSinkTransactionIT.java +++ b/services/admin/src/test/java/com/ulticode/modules/admin/outbox/AuditSinkTransactionIT.java @@ -24,9 +24,10 @@ import org.testcontainers.junit.jupiter.Testcontainers; @SpringBootTest(properties = "spring.autoconfigure.exclude=" - + "org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration," - + "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration," - + "org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration," + + "org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration," + + "org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration," + "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration," + "com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapAutoConfiguration") @Testcontainers diff --git a/services/admin/src/test/java/com/ulticode/modules/backup/BackupRepositoryIT.java b/services/admin/src/test/java/com/ulticode/modules/backup/BackupRepositoryIT.java index 03c5f71f0..1540d6dbd 100644 --- a/services/admin/src/test/java/com/ulticode/modules/backup/BackupRepositoryIT.java +++ b/services/admin/src/test/java/com/ulticode/modules/backup/BackupRepositoryIT.java @@ -40,9 +40,10 @@ * MyBatis-Plus {@link BackupMapper} against a real MySQL 8.0 container. */ @SpringBootTest(properties = "spring.autoconfigure.exclude=" - + "org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration," - + "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration," - + "org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration," + + "org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration," + + "org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration," + + "org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration," + "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration," + "com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapAutoConfiguration") @Testcontainers diff --git a/services/app/app-web/pom.xml b/services/app/app-web/pom.xml index 2507ea074..15164cbe8 100644 --- a/services/app/app-web/pom.xml +++ b/services/app/app-web/pom.xml @@ -101,7 +101,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -114,7 +114,7 @@ org.springframework.boot - spring-boot-starter-aop + spring-boot-starter-aspectj @@ -128,7 +128,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -202,12 +202,12 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test - org.springframework.security - spring-security-test + org.springframework.boot + spring-boot-starter-security-test test @@ -256,6 +256,16 @@ org.springframework.boot spring-boot-starter-websocket + + org.springframework.boot + spring-boot-resttestclient + test + + + org.springframework.boot + spring-boot-restclient + test + diff --git a/services/app/app-web/src/main/resources/application.yml b/services/app/app-web/src/main/resources/application.yml index 248ffe611..01ed5e594 100644 --- a/services/app/app-web/src/main/resources/application.yml +++ b/services/app/app-web/src/main/resources/application.yml @@ -3,6 +3,9 @@ server: shutdown: graceful spring: + http: + converters: + preferred-json-mapper: jackson2 application: name: backend-app servlet: @@ -13,9 +16,10 @@ spring: timeout-per-shutdown-phase: ${SPRING_LIFECYCLE_TIMEOUT_PER_SHUTDOWN_PHASE:45s} autoconfigure: exclude: - - org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration - - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration - - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration + - org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration + - org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration + - org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration + - org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration # P7-MIGRATE-PROBLEM-001: enable datasource for problem domain datasource: driver-class-name: com.mysql.cj.jdbc.Driver @@ -152,12 +156,14 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s security: internal-delegation: diff --git a/services/app/app-web/src/test/java/com/ulticode/BackendAppApplicationTest.java b/services/app/app-web/src/test/java/com/ulticode/BackendAppApplicationTest.java index 0fd3c9069..c3d48b1a2 100644 --- a/services/app/app-web/src/test/java/com/ulticode/BackendAppApplicationTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/BackendAppApplicationTest.java @@ -22,8 +22,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; import org.springframework.test.context.bean.override.mockito.MockitoBean; -import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.resttestclient.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; @@ -33,6 +34,7 @@ /** * P1-INFRA-005: verify the app service shell boots and exposes health. */ +@AutoConfigureTestRestTemplate @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("test") class BackendAppApplicationTest { diff --git a/services/app/app-web/src/test/java/com/ulticode/app/config/AppCacheConfigTest.java b/services/app/app-web/src/test/java/com/ulticode/app/config/AppCacheConfigTest.java index 6509f5f9d..c3ddb0c0e 100644 --- a/services/app/app-web/src/test/java/com/ulticode/app/config/AppCacheConfigTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/app/config/AppCacheConfigTest.java @@ -36,7 +36,7 @@ void cacheClearEvictsThroughScan() { when(connectionFactory.getConnection()).thenReturn(connection); when(connection.keyCommands()).thenReturn(keyCommands); AtomicReference scan = new AtomicReference<>(); - when(connection.scan(any(ScanOptions.class))).thenAnswer(call -> { + when(keyCommands.scan(any(ScanOptions.class))).thenAnswer(call -> { scan.set(call.getArgument(0)); throw new IllegalStateException("scan reached"); }); diff --git a/services/app/app-web/src/test/java/com/ulticode/app/config/AppRedisRoleConfigTest.java b/services/app/app-web/src/test/java/com/ulticode/app/config/AppRedisRoleConfigTest.java index ffa73644e..51670240c 100644 --- a/services/app/app-web/src/test/java/com/ulticode/app/config/AppRedisRoleConfigTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/app/config/AppRedisRoleConfigTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -12,7 +12,7 @@ class AppRedisRoleConfigTest { private final ApplicationContextRunner runner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - RedisAutoConfiguration.class, + DataRedisAutoConfiguration.class, AppRedisRoleConfig.class)); @Test diff --git a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/DubboBoot4LocalRoundTripIT.java b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/DubboBoot4LocalRoundTripIT.java new file mode 100644 index 000000000..d8b8b7891 --- /dev/null +++ b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/DubboBoot4LocalRoundTripIT.java @@ -0,0 +1,64 @@ +package com.ulticode.app.dubbo; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ulticode.app.dubbo.boot4fixture.LocalEchoPort; +import com.ulticode.app.dubbo.boot4fixture.LocalEchoService; +import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; + +@SpringBootTest( + classes = DubboBoot4LocalRoundTripIT.TestApplication.class, + properties = { + "dubbo.application.name=boot4-dubbo-local-roundtrip-test", + "dubbo.application.qos-enable=false", + "dubbo.registry.address=N/A", + "dubbo.protocol.port=-1" + }) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +class DubboBoot4LocalRoundTripIT { + + @Autowired + private EchoClient client; + + @Test + @Timeout(15) + void bootAutoConfigurationWiresLocalServiceReferenceWithoutRegistry() { + assertThat(client.echo("boot4")).isEqualTo("echo:boot4"); + } + + @SpringBootConfiguration(proxyBeanMethods = false) + @EnableDubbo(scanBasePackageClasses = LocalEchoService.class) + @ImportAutoConfiguration(DubboAutoConfiguration.class) + @Import(ClientConfiguration.class) + static class TestApplication { + } + + static class EchoClient { + + @DubboReference(interfaceClass = LocalEchoPort.class, scope = "local", check = false, retries = 0) + private LocalEchoPort echoPort; + + String echo(String value) { + return echoPort.echo(value); + } + } + + static class ClientConfiguration { + + @Bean + EchoClient echoClient() { + return new EchoClient(); + } + } +} diff --git a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoPort.java b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoPort.java new file mode 100644 index 000000000..9e62d97e9 --- /dev/null +++ b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoPort.java @@ -0,0 +1,6 @@ +package com.ulticode.app.dubbo.boot4fixture; + +public interface LocalEchoPort { + + String echo(String value); +} diff --git a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoService.java b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoService.java new file mode 100644 index 000000000..380fbcee1 --- /dev/null +++ b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/boot4fixture/LocalEchoService.java @@ -0,0 +1,15 @@ +package com.ulticode.app.dubbo.boot4fixture; + +import org.apache.dubbo.config.annotation.DubboService; + +@DubboService( + interfaceClass = LocalEchoPort.class, + scope = "local", + register = false) +public class LocalEchoService implements LocalEchoPort { + + @Override + public String echo(String value) { + return "echo:" + value; + } +} diff --git a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ContestAdministrationWiringIT.java b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ContestAdministrationWiringIT.java index 28ed5b326..a70a5c256 100644 --- a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ContestAdministrationWiringIT.java +++ b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ContestAdministrationWiringIT.java @@ -39,10 +39,10 @@ import org.junit.jupiter.api.Test; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -69,7 +69,7 @@ DataSourceTransactionManagerAutoConfiguration.class, TransactionAutoConfiguration.class, MybatisPlusAutoConfiguration.class, - JacksonAutoConfiguration.class + Jackson2AutoConfiguration.class }, properties = { "spring.flyway.enabled=false", diff --git a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ProblemListAdministrationWiringIT.java b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ProblemListAdministrationWiringIT.java index 9d5f133db..fb550d827 100644 --- a/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ProblemListAdministrationWiringIT.java +++ b/services/app/app-web/src/test/java/com/ulticode/app/dubbo/provider/ProblemListAdministrationWiringIT.java @@ -30,10 +30,10 @@ import java.util.UUID; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.junit.jupiter.api.BeforeEach; @@ -59,7 +59,7 @@ DataSourceTransactionManagerAutoConfiguration.class, TransactionAutoConfiguration.class, MybatisPlusAutoConfiguration.class, - JacksonAutoConfiguration.class + Jackson2AutoConfiguration.class }, properties = { "spring.flyway.enabled=false", diff --git a/services/app/app-web/src/test/java/com/ulticode/app/security/AppRouteAuthorizationContractTest.java b/services/app/app-web/src/test/java/com/ulticode/app/security/AppRouteAuthorizationContractTest.java index fb3b2b599..5f8164dfc 100644 --- a/services/app/app-web/src/test/java/com/ulticode/app/security/AppRouteAuthorizationContractTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/app/security/AppRouteAuthorizationContractTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; diff --git a/services/app/app-web/src/test/java/com/ulticode/app/userprofile/ProfileWriteProviderIT.java b/services/app/app-web/src/test/java/com/ulticode/app/userprofile/ProfileWriteProviderIT.java index 05c3d202e..fcffcc711 100644 --- a/services/app/app-web/src/test/java/com/ulticode/app/userprofile/ProfileWriteProviderIT.java +++ b/services/app/app-web/src/test/java/com/ulticode/app/userprofile/ProfileWriteProviderIT.java @@ -44,11 +44,11 @@ import org.junit.jupiter.api.Test; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration; +import org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.DynamicPropertyRegistry; @@ -85,7 +85,7 @@ TransactionAutoConfiguration.class, JdbcTemplateAutoConfiguration.class, MybatisPlusAutoConfiguration.class, - JacksonAutoConfiguration.class + Jackson2AutoConfiguration.class }, properties = { "spring.flyway.enabled=false", diff --git a/services/app/app-web/src/test/java/com/ulticode/modules/contest/controller/ContestPublicControllerTest.java b/services/app/app-web/src/test/java/com/ulticode/modules/contest/controller/ContestPublicControllerTest.java index 8002c3ca2..d2185df03 100644 --- a/services/app/app-web/src/test/java/com/ulticode/modules/contest/controller/ContestPublicControllerTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/modules/contest/controller/ContestPublicControllerTest.java @@ -15,8 +15,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; diff --git a/services/app/app-web/src/test/java/com/ulticode/modules/contest/integration/ContestAdjudicationWiringIT.java b/services/app/app-web/src/test/java/com/ulticode/modules/contest/integration/ContestAdjudicationWiringIT.java index cade00052..1837cf7c1 100644 --- a/services/app/app-web/src/test/java/com/ulticode/modules/contest/integration/ContestAdjudicationWiringIT.java +++ b/services/app/app-web/src/test/java/com/ulticode/modules/contest/integration/ContestAdjudicationWiringIT.java @@ -22,10 +22,10 @@ import org.junit.jupiter.api.Test; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -77,7 +77,7 @@ DataSourceTransactionManagerAutoConfiguration.class, TransactionAutoConfiguration.class, MybatisPlusAutoConfiguration.class, - JacksonAutoConfiguration.class, + Jackson2AutoConfiguration.class, ScoringStrategyResolver.class, ScoreStrategy.class, IcpcStrategy.class, diff --git a/services/app/app-web/src/test/java/com/ulticode/modules/moderation/controller/ModerationControllerTest.java b/services/app/app-web/src/test/java/com/ulticode/modules/moderation/controller/ModerationControllerTest.java index 87194835c..751278279 100644 --- a/services/app/app-web/src/test/java/com/ulticode/modules/moderation/controller/ModerationControllerTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/modules/moderation/controller/ModerationControllerTest.java @@ -14,8 +14,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; diff --git a/services/app/app-web/src/test/java/com/ulticode/modules/problem/controller/ProblemControllerTest.java b/services/app/app-web/src/test/java/com/ulticode/modules/problem/controller/ProblemControllerTest.java index d030e5948..1dedcf5fa 100644 --- a/services/app/app-web/src/test/java/com/ulticode/modules/problem/controller/ProblemControllerTest.java +++ b/services/app/app-web/src/test/java/com/ulticode/modules/problem/controller/ProblemControllerTest.java @@ -11,8 +11,8 @@ import org.junit.jupiter.api.Nested; 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.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; diff --git a/services/app/app-web/src/test/resources/application.yml b/services/app/app-web/src/test/resources/application.yml index a4c1ce338..2a2e56e35 100644 --- a/services/app/app-web/src/test/resources/application.yml +++ b/services/app/app-web/src/test/resources/application.yml @@ -6,8 +6,8 @@ spring: active: test autoconfigure: exclude: - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration - - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration + - org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration + - org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration - org.redisson.spring.starter.RedissonAutoConfigurationV2 - org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration diff --git a/services/app/modules/contest/pom.xml b/services/app/modules/contest/pom.xml index 6edace681..03e0b4a76 100644 --- a/services/app/modules/contest/pom.xml +++ b/services/app/modules/contest/pom.xml @@ -49,7 +49,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/app/modules/moderation/pom.xml b/services/app/modules/moderation/pom.xml index af347ab08..7955c0c9d 100644 --- a/services/app/modules/moderation/pom.xml +++ b/services/app/modules/moderation/pom.xml @@ -35,7 +35,7 @@
org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/app/modules/problem/pom.xml b/services/app/modules/problem/pom.xml index 83dedec99..2dfdad529 100644 --- a/services/app/modules/problem/pom.xml +++ b/services/app/modules/problem/pom.xml @@ -50,7 +50,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/auth/pom.xml b/services/auth/pom.xml index a4bd35587..31c16dbce 100644 --- a/services/auth/pom.xml +++ b/services/auth/pom.xml @@ -55,7 +55,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -81,7 +81,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -165,7 +165,22 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic + test + + + org.springframework.boot + spring-boot-starter-security-test + test + + + org.springframework.boot + spring-boot-resttestclient + test + + + org.springframework.boot + spring-boot-restclient test diff --git a/services/auth/src/main/java/com/ulticode/auth/security/oauth/GithubOAuthClient.java b/services/auth/src/main/java/com/ulticode/auth/security/oauth/GithubOAuthClient.java index 05d0625ce..d55ab77fd 100644 --- a/services/auth/src/main/java/com/ulticode/auth/security/oauth/GithubOAuthClient.java +++ b/services/auth/src/main/java/com/ulticode/auth/security/oauth/GithubOAuthClient.java @@ -37,7 +37,7 @@ public String getProviderName() { @Override public String buildAuthorizationUrl(String state, String redirectUri) { OAuthProperties.OAuthProvider config = oauthProperties.getGithub(); - return UriComponentsBuilder.fromHttpUrl(config.getAuthorizeUrl()) + return OAuthAuthorizationUrl.fromTrustedHttpUrl(config.getAuthorizeUrl()) .queryParam("client_id", config.getClientId()) .queryParam("redirect_uri", redirectUri) .queryParam("scope", config.getScopes()) diff --git a/services/auth/src/main/java/com/ulticode/auth/security/oauth/GoogleOAuthClient.java b/services/auth/src/main/java/com/ulticode/auth/security/oauth/GoogleOAuthClient.java index 79865416a..3fa419dbd 100644 --- a/services/auth/src/main/java/com/ulticode/auth/security/oauth/GoogleOAuthClient.java +++ b/services/auth/src/main/java/com/ulticode/auth/security/oauth/GoogleOAuthClient.java @@ -37,7 +37,7 @@ public String getProviderName() { @Override public String buildAuthorizationUrl(String state, String redirectUri) { OAuthProperties.OAuthProvider config = oauthProperties.getGoogle(); - return UriComponentsBuilder.fromHttpUrl(config.getAuthorizeUrl()) + return OAuthAuthorizationUrl.fromTrustedHttpUrl(config.getAuthorizeUrl()) .queryParam("client_id", config.getClientId()) .queryParam("redirect_uri", redirectUri) .queryParam("response_type", "code") diff --git a/services/auth/src/main/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrl.java b/services/auth/src/main/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrl.java new file mode 100644 index 000000000..0025cbcc7 --- /dev/null +++ b/services/auth/src/main/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrl.java @@ -0,0 +1,22 @@ +package com.ulticode.auth.security.oauth; + +import java.net.URI; + +import org.springframework.web.util.UriComponentsBuilder; + +/** Validates trusted provider authorization endpoints before URI construction. */ +final class OAuthAuthorizationUrl { + + private OAuthAuthorizationUrl() { + } + + static UriComponentsBuilder fromTrustedHttpUrl(String value) { + URI endpoint = URI.create(value); + String scheme = endpoint.getScheme(); + if (!endpoint.isAbsolute() || endpoint.getHost() == null + || !("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme))) { + throw new IllegalArgumentException("OAuth authorization URL must be an absolute HTTP(S) URL"); + } + return UriComponentsBuilder.fromUriString(value); + } +} diff --git a/services/auth/src/main/resources/application.yml b/services/auth/src/main/resources/application.yml index cb1d55c65..0de22d93f 100644 --- a/services/auth/src/main/resources/application.yml +++ b/services/auth/src/main/resources/application.yml @@ -13,6 +13,9 @@ cors: allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:9002,http://localhost:9003} spring: + http: + converters: + preferred-json-mapper: jackson2 application: name: backend-auth lifecycle: @@ -49,7 +52,7 @@ spring: max-idle: 8 min-idle: 0 - jackson: + jackson2: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai flyway: @@ -188,12 +191,14 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s security: internal-delegation: # Base64-encoded X509 public key; Auth never receives Admin private material. diff --git a/services/auth/src/test/java/com/ulticode/BackendAuthApplicationTest.java b/services/auth/src/test/java/com/ulticode/BackendAuthApplicationTest.java index f6e66a1e4..b5ea5f807 100644 --- a/services/auth/src/test/java/com/ulticode/BackendAuthApplicationTest.java +++ b/services/auth/src/test/java/com/ulticode/BackendAuthApplicationTest.java @@ -6,7 +6,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; +import org.springframework.boot.resttestclient.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -15,6 +16,7 @@ * P1-INFRA-005: verify the populated auth service boots and exposes health. */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureTestRestTemplate class BackendAuthApplicationTest { @LocalServerPort diff --git a/services/auth/src/test/java/com/ulticode/auth/error/AuthWebExceptionHandlerTest.java b/services/auth/src/test/java/com/ulticode/auth/error/AuthWebExceptionHandlerTest.java index f3b48bb3e..b45d95743 100644 --- a/services/auth/src/test/java/com/ulticode/auth/error/AuthWebExceptionHandlerTest.java +++ b/services/auth/src/test/java/com/ulticode/auth/error/AuthWebExceptionHandlerTest.java @@ -67,7 +67,7 @@ void omitsRetryAfterWhenRateLimitMessageHasNoValidSeconds() { ResponseEntity> response = handler.handleBusinessException(exception); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.TOO_MANY_REQUESTS); - assertThat(response.getHeaders()).doesNotContainKey(HttpHeaders.RETRY_AFTER); + assertThat(response.getHeaders().containsHeader(HttpHeaders.RETRY_AFTER)).isFalse(); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getCode()).isEqualTo(42900); } @@ -83,7 +83,7 @@ void preservesAuthErrorCodesAndStatuses(AuthErrorCode errorCode, HttpStatus stat ResponseEntity> response = handler.handleAuthBusinessException(exception); assertThat(response.getStatusCode()).isEqualTo(status); - assertThat(response.getHeaders()).doesNotContainKey(HttpHeaders.RETRY_AFTER); + assertThat(response.getHeaders().containsHeader(HttpHeaders.RETRY_AFTER)).isFalse(); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getCode()).isEqualTo(errorCode.code()); assertThat(response.getBody().getMessage()).isEqualTo(errorCode.message()); diff --git a/services/auth/src/test/java/com/ulticode/auth/security/AuthSecurityConfigContractTest.java b/services/auth/src/test/java/com/ulticode/auth/security/AuthSecurityConfigContractTest.java index 081d3c820..68f168665 100644 --- a/services/auth/src/test/java/com/ulticode/auth/security/AuthSecurityConfigContractTest.java +++ b/services/auth/src/test/java/com/ulticode/auth/security/AuthSecurityConfigContractTest.java @@ -3,7 +3,7 @@ import com.ulticode.auth.security.jwt.AuthAccessTokenVerifier; import com.ulticode.auth.security.jwt.AuthJwtFilterConfiguration; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.context.annotation.Import; import org.springframework.web.bind.annotation.GetMapping; diff --git a/services/auth/src/test/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrlTest.java b/services/auth/src/test/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrlTest.java new file mode 100644 index 000000000..16f8409a2 --- /dev/null +++ b/services/auth/src/test/java/com/ulticode/auth/security/oauth/OAuthAuthorizationUrlTest.java @@ -0,0 +1,23 @@ +package com.ulticode.auth.security.oauth; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class OAuthAuthorizationUrlTest { + + @Test + void preservesConfiguredHttpAuthorizationEndpointAndQuery() { + String endpoint = "https://provider.example/oauth/authorize?prompt=consent"; + + assertThat(OAuthAuthorizationUrl.fromTrustedHttpUrl(endpoint).build().toUriString()) + .isEqualTo(endpoint); + } + + @Test + void rejectsNonHttpProviderEndpoints() { + assertThatIllegalArgumentException() + .isThrownBy(() -> OAuthAuthorizationUrl.fromTrustedHttpUrl("ftp://provider.example/authorize")); + } +} diff --git a/services/auth/src/test/resources/application.yml b/services/auth/src/test/resources/application.yml index c1735550f..63db1e5e9 100644 --- a/services/auth/src/test/resources/application.yml +++ b/services/auth/src/test/resources/application.yml @@ -25,11 +25,12 @@ spring: enabled: false autoconfigure: exclude: - - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration + - org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration - org.redisson.spring.starter.RedissonAutoConfigurationV2 - org.redisson.spring.starter.RedissonAutoConfigurationV4 - - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration - - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration + - org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration + - org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration + - org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration mail: host: localhost port: 1025 diff --git a/services/core/pom.xml b/services/core/pom.xml index 11b7a28ea..ea6c5b236 100644 --- a/services/core/pom.xml +++ b/services/core/pom.xml @@ -43,7 +43,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -70,11 +70,17 @@ com.ulticode backend-search ${service.version.search} + + + org.springframework.boot + spring-boot-grpc-server + + org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -87,7 +93,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/core/src/main/java/com/ulticode/core/CoreApplication.java b/services/core/src/main/java/com/ulticode/core/CoreApplication.java index 6a5698c61..f9d609987 100644 --- a/services/core/src/main/java/com/ulticode/core/CoreApplication.java +++ b/services/core/src/main/java/com/ulticode/core/CoreApplication.java @@ -9,10 +9,10 @@ import org.springframework.context.annotation.FilterType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.DataRedisRepositoriesAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootConfiguration @@ -21,8 +21,8 @@ exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, - RedisAutoConfiguration.class, - RedisRepositoriesAutoConfiguration.class, + DataRedisAutoConfiguration.class, + DataRedisRepositoriesAutoConfiguration.class, MybatisPlusAutoConfiguration.class, RedissonAutoConfigurationV2.class, RedissonAutoConfigurationV4.class diff --git a/services/core/src/main/java/com/ulticode/core/CoreOwnerBootConfigurations.java b/services/core/src/main/java/com/ulticode/core/CoreOwnerBootConfigurations.java index ccff9fc74..564aefb27 100644 --- a/services/core/src/main/java/com/ulticode/core/CoreOwnerBootConfigurations.java +++ b/services/core/src/main/java/com/ulticode/core/CoreOwnerBootConfigurations.java @@ -157,8 +157,8 @@ static class Notification { @EnableAutoConfiguration( excludeName = "org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration", exclude = { - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class, - org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration.class, + org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration.class, + org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration.class, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration.class }) @ComponentScan({"com.ulticode.search", "com.ulticode.common"}) diff --git a/services/core/src/main/java/com/ulticode/core/CoreOwnerDataSourceConfiguration.java b/services/core/src/main/java/com/ulticode/core/CoreOwnerDataSourceConfiguration.java index 8a4329fba..269220f6e 100644 --- a/services/core/src/main/java/com/ulticode/core/CoreOwnerDataSourceConfiguration.java +++ b/services/core/src/main/java/com/ulticode/core/CoreOwnerDataSourceConfiguration.java @@ -4,7 +4,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.jdbc.autoconfigure.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/services/core/src/main/resources/application.yml b/services/core/src/main/resources/application.yml index 66a7e3cf0..6e1160edc 100644 --- a/services/core/src/main/resources/application.yml +++ b/services/core/src/main/resources/application.yml @@ -1,4 +1,7 @@ spring: + http: + converters: + preferred-json-mapper: jackson2 application: name: ${CORE_APPLICATION_NAME:ulticode-core} main: diff --git a/services/core/src/test/java/com/ulticode/core/CoreEnabledOwnerJourneyIT.java b/services/core/src/test/java/com/ulticode/core/CoreEnabledOwnerJourneyIT.java index 7b70cce99..0aa5c8451 100644 --- a/services/core/src/test/java/com/ulticode/core/CoreEnabledOwnerJourneyIT.java +++ b/services/core/src/test/java/com/ulticode/core/CoreEnabledOwnerJourneyIT.java @@ -257,7 +257,7 @@ private static void startOwnerContexts(KeyPair delegationKeyPair) { .withProperty("spring.main.lazy-initialization", "true") .withProperty("ulticode.app.inbox.enabled", "false") .withProperty("spring.autoconfigure.exclude", - "org.springframework.boot.actuate.autoconfigure.metrics.SystemMetricsAutoConfiguration"); + "org.springframework.boot.micrometer.metrics.autoconfigure.system.SystemMetricsAutoConfiguration"); ownerContexts = new CoreOwnerContextManager(new CoreModuleRegistry(), environment, true, 60_000L); ownerContexts.startOwnerModules(); awaitOwnerStartup(); diff --git a/services/judge-runtime/pom.xml b/services/judge-runtime/pom.xml index c844831ae..6cfdcd9e7 100644 --- a/services/judge-runtime/pom.xml +++ b/services/judge-runtime/pom.xml @@ -75,7 +75,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/judge/pom.xml b/services/judge/pom.xml index d331da7aa..801378ed1 100644 --- a/services/judge/pom.xml +++ b/services/judge/pom.xml @@ -52,7 +52,7 @@ org.springframework.boot - spring-boot-starter + spring-boot-starter-classic org.springframework.boot @@ -111,7 +111,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/judge/src/main/resources/application.yml b/services/judge/src/main/resources/application.yml index b48222a8b..5ff30e2fc 100644 --- a/services/judge/src/main/resources/application.yml +++ b/services/judge/src/main/resources/application.yml @@ -13,12 +13,13 @@ spring: web-application-type: none autoconfigure: exclude: - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + - org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration - org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration - com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration - - org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration - - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration - - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration + - org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration + - org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration + - org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration + - org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration data: redis: url: ${JUDGE_REDIS_URL:redis://${REDIS_USERNAME:}:${REDIS_PASSWORD:}@${REDIS_HOST:localhost}:${REDIS_PORT:26379}/${REDIS_DB:0}} @@ -99,12 +100,15 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s + otlp: metrics: export: enabled: ${MANAGEMENT_OTLP_METRICS_ENABLED:false} diff --git a/services/notification/pom.xml b/services/notification/pom.xml index 8c11b4b10..c7e684efd 100644 --- a/services/notification/pom.xml +++ b/services/notification/pom.xml @@ -62,7 +62,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -88,7 +88,7 @@ org.springframework.boot - spring-boot-starter-aop + spring-boot-starter-aspectj org.springframework.boot @@ -104,7 +104,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -153,12 +153,12 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test - org.springframework.security - spring-security-test + org.springframework.boot + spring-boot-starter-security-test test diff --git a/services/notification/src/main/resources/application.yml b/services/notification/src/main/resources/application.yml index a62c10429..bb64769b2 100644 --- a/services/notification/src/main/resources/application.yml +++ b/services/notification/src/main/resources/application.yml @@ -3,14 +3,17 @@ server: shutdown: graceful spring: + http: + converters: + preferred-json-mapper: jackson2 application: name: backend-notification lifecycle: timeout-per-shutdown-phase: ${SPRING_LIFECYCLE_TIMEOUT_PER_SHUTDOWN_PHASE:45s} autoconfigure: exclude: - - org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration - - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration + - org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration + - org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: ${NOTIFICATION_DB_URL:jdbc:mysql://${NOTIFICATION_DB_HOST}:${NOTIFICATION_DB_PORT}/${NOTIFICATION_DB_NAME}?useUnicode=true&characterEncoding=UTF-8&characterSetResults=utf8mb4&connectionCollation=utf8mb4_unicode_ci&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&sslMode=${NOTIFICATION_DB_SSL_MODE:REQUIRED}&useAffectedRows=true} @@ -168,12 +171,15 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s + otlp: metrics: export: enabled: ${MANAGEMENT_OTLP_METRICS_ENABLED:false} diff --git a/services/notification/src/test/java/com/ulticode/notification/security/NotificationRouteAuthorizationContractTest.java b/services/notification/src/test/java/com/ulticode/notification/security/NotificationRouteAuthorizationContractTest.java index 69e55fe07..3e0c9ab3f 100644 --- a/services/notification/src/test/java/com/ulticode/notification/security/NotificationRouteAuthorizationContractTest.java +++ b/services/notification/src/test/java/com/ulticode/notification/security/NotificationRouteAuthorizationContractTest.java @@ -7,7 +7,7 @@ import com.ulticode.websecurity.jwt.AccessTokenVerifier; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; diff --git a/services/platform/integration-inbox/pom.xml b/services/platform/integration-inbox/pom.xml index 670a9788e..12f857636 100644 --- a/services/platform/integration-inbox/pom.xml +++ b/services/platform/integration-inbox/pom.xml @@ -21,7 +21,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -39,7 +39,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/platform/observability/pom.xml b/services/platform/observability/pom.xml index b953c44a5..2b08d0578 100644 --- a/services/platform/observability/pom.xml +++ b/services/platform/observability/pom.xml @@ -20,7 +20,11 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-opentelemetry + + + org.springframework.boot + spring-boot-starter-test-classic test diff --git a/services/platform/observability/src/main/java/com/ulticode/observability/config/OtlpSecurityAutoConfiguration.java b/services/platform/observability/src/main/java/com/ulticode/observability/config/OtlpSecurityAutoConfiguration.java index 3d4d1ad6f..efccf2a34 100644 --- a/services/platform/observability/src/main/java/com/ulticode/observability/config/OtlpSecurityAutoConfiguration.java +++ b/services/platform/observability/src/main/java/com/ulticode/observability/config/OtlpSecurityAutoConfiguration.java @@ -12,8 +12,9 @@ public class OtlpSecurityAutoConfiguration { @Bean OtlpEndpointSecurityPolicy otlpEndpointSecurityPolicy(Environment environment) { - String endpoint = environment.getProperty("management.otlp.tracing.endpoint"); - String authorization = environment.getProperty("management.otlp.tracing.headers.Authorization"); + String endpoint = environment.getProperty("management.opentelemetry.tracing.export.otlp.endpoint"); + String authorization = environment.getProperty( + "management.opentelemetry.tracing.export.otlp.headers.Authorization"); return OtlpEndpointSecurityPolicy.validate(endpoint, authorization); } @@ -25,17 +26,17 @@ static OtlpEndpointSecurityPolicy validate(String endpoint, String authorization } if (endpoint == null || endpoint.isBlank()) { throw new IllegalStateException( - "management.otlp.tracing.endpoint is required when authorization is configured"); + "management.opentelemetry.tracing.export.otlp.endpoint is required when authorization is configured"); } try { URI uri = URI.create(endpoint.trim()); if (!"https".equalsIgnoreCase(uri.getScheme())) { throw new IllegalStateException( - "management.otlp.tracing.endpoint must use https when authorization is configured"); + "management.opentelemetry.tracing.export.otlp.endpoint must use https when authorization is configured"); } } catch (IllegalArgumentException exception) { throw new IllegalStateException( - "management.otlp.tracing.endpoint is not a valid URI", exception); + "management.opentelemetry.tracing.export.otlp.endpoint is not a valid URI", exception); } return new OtlpEndpointSecurityPolicy(); } diff --git a/services/platform/observability/src/test/java/com/ulticode/observability/config/OtlpSecurityAutoConfigurationTest.java b/services/platform/observability/src/test/java/com/ulticode/observability/config/OtlpSecurityAutoConfigurationTest.java index c4b78d998..da9656e31 100644 --- a/services/platform/observability/src/test/java/com/ulticode/observability/config/OtlpSecurityAutoConfigurationTest.java +++ b/services/platform/observability/src/test/java/com/ulticode/observability/config/OtlpSecurityAutoConfigurationTest.java @@ -1,8 +1,11 @@ package com.ulticode.observability.config; import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingProperties; import org.springframework.mock.env.MockEnvironment; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -33,12 +36,30 @@ void httpsEndpointIsAllowedWhenAuthorizationIsConfigured() { @Test void autoConfigurationReadsResolvedProperties() { MockEnvironment environment = new MockEnvironment() - .withProperty("management.otlp.tracing.endpoint", "http://collector.example/v1/traces") - .withProperty("management.otlp.tracing.headers.Authorization", "Bearer secret"); + .withProperty("management.opentelemetry.tracing.export.otlp.endpoint", + "http://collector.example/v1/traces") + .withProperty("management.opentelemetry.tracing.export.otlp.headers.Authorization", + "Bearer secret"); assertThatThrownBy(() -> new OtlpSecurityAutoConfiguration() .otlpEndpointSecurityPolicy(environment)) .isInstanceOf(IllegalStateException.class) .hasMessageContaining("must use https"); } + + @Test + void boot4TracingPropertiesBindFromTheManagedOtlpPrefix() { + MockEnvironment environment = new MockEnvironment() + .withProperty("management.opentelemetry.tracing.export.otlp.endpoint", + "https://collector.example/v1/traces") + .withProperty("management.opentelemetry.tracing.export.otlp.headers.Authorization", + "Bearer secret"); + + OtlpTracingProperties properties = Binder.get(environment) + .bind("management.opentelemetry.tracing.export.otlp", OtlpTracingProperties.class) + .get(); + + assertThat(properties.getEndpoint()).isEqualTo("https://collector.example/v1/traces"); + assertThat(properties.getHeaders()).containsEntry("Authorization", "Bearer secret"); + } } diff --git a/services/platform/storage/pom.xml b/services/platform/storage/pom.xml index 2fb5c6967..b454fb51e 100644 --- a/services/platform/storage/pom.xml +++ b/services/platform/storage/pom.xml @@ -42,7 +42,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/platform/web-security/pom.xml b/services/platform/web-security/pom.xml index 809ac29b8..18ee18e20 100644 --- a/services/platform/web-security/pom.xml +++ b/services/platform/web-security/pom.xml @@ -34,13 +34,13 @@ org.springframework.boot - spring-boot-starter-aop + spring-boot-starter-aspectj org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -70,6 +70,11 @@ spring-boot-starter-data-redis + + org.springframework.boot + spring-boot-jackson2 + + org.projectlombok @@ -80,12 +85,12 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test - org.springframework.security - spring-security-test + org.springframework.boot + spring-boot-starter-security-test test diff --git a/services/platform/web-security/src/main/java/com/ulticode/websecurity/config/WebSecurityAutoConfiguration.java b/services/platform/web-security/src/main/java/com/ulticode/websecurity/config/WebSecurityAutoConfiguration.java index 1280d5f0c..ad629ceb0 100644 --- a/services/platform/web-security/src/main/java/com/ulticode/websecurity/config/WebSecurityAutoConfiguration.java +++ b/services/platform/web-security/src/main/java/com/ulticode/websecurity/config/WebSecurityAutoConfiguration.java @@ -7,7 +7,7 @@ import com.ulticode.websecurity.util.ClientIpResolver; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -20,7 +20,7 @@ * adapter and {@code SecurityFilterChain}. */ @AutoConfiguration -@AutoConfigureAfter(RedisAutoConfiguration.class) +@AutoConfigureAfter(DataRedisAutoConfiguration.class) public class WebSecurityAutoConfiguration { @Bean diff --git a/services/platform/web-security/src/test/java/com/ulticode/websecurity/RateLimitIT.java b/services/platform/web-security/src/test/java/com/ulticode/websecurity/RateLimitIT.java index 1fab4c003..26b805162 100644 --- a/services/platform/web-security/src/test/java/com/ulticode/websecurity/RateLimitIT.java +++ b/services/platform/web-security/src/test/java/com/ulticode/websecurity/RateLimitIT.java @@ -16,9 +16,9 @@ import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration; +import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -55,7 +55,7 @@ * retry seconds, and Retry-After header. */ @SpringBootTest(classes = RateLimitIT.TestConfig.class) -@ImportAutoConfiguration({RedisAutoConfiguration.class, WebMvcAutoConfiguration.class, +@ImportAutoConfiguration({DataRedisAutoConfiguration.class, WebMvcAutoConfiguration.class, WebSecurityAutoConfiguration.class}) @AutoConfigureMockMvc(addFilters = false) @Testcontainers diff --git a/services/pom.xml b/services/pom.xml index d4ef0d60c..b55590df5 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.5.16 + 4.1.1 com.ulticode @@ -61,14 +61,12 @@ 1.0.1 17 - 2.21.7 - 4.1.137.Final - 10.1.59 + 2.21.7 UTF-8 3.5.17 0.13.0 4.7.0 - 2.9.1 + 3.1.1 3.3.6 5.8.47 1.18.48 diff --git a/services/search/pom.xml b/services/search/pom.xml index 43316014a..2bf44d6c6 100644 --- a/services/search/pom.xml +++ b/services/search/pom.xml @@ -47,7 +47,7 @@ (judge worker precedent: web-application-type=none). --> org.springframework.boot - spring-boot-starter + spring-boot-starter-classic org.springframework.boot @@ -79,7 +79,11 @@ org.springframework.boot - spring-boot-starter-json + spring-boot-starter-jackson + + + org.springframework.boot + spring-boot-jackson2 com.fasterxml.jackson.datatype @@ -95,7 +99,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/search/src/main/resources/application.yml b/services/search/src/main/resources/application.yml index aa731095b..8c8ef1ee1 100644 --- a/services/search/src/main/resources/application.yml +++ b/services/search/src/main/resources/application.yml @@ -13,12 +13,13 @@ spring: web-application-type: none autoconfigure: exclude: - - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration + - org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration - org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration - com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration - - org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration - - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration - - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration + - org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration + - org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration + - org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration + - org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration data: redis: url: ${SEARCH_REDIS_URL:redis://${REDIS_USERNAME:}:${REDIS_PASSWORD:}@${REDIS_HOST:localhost}:${REDIS_PORT:26379}/${REDIS_DB:0}} @@ -76,12 +77,15 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s + otlp: metrics: export: enabled: ${MANAGEMENT_OTLP_METRICS_ENABLED:false} diff --git a/services/submission/pom.xml b/services/submission/pom.xml index ae079c844..817a8ba36 100644 --- a/services/submission/pom.xml +++ b/services/submission/pom.xml @@ -38,7 +38,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc org.springframework.boot @@ -74,7 +74,7 @@ com.baomidou - mybatis-plus-spring-boot3-starter + mybatis-plus-spring-boot4-starter ${mybatis-plus.version} @@ -129,7 +129,7 @@ org.springframework.boot - spring-boot-starter-test + spring-boot-starter-test-classic test diff --git a/services/submission/src/main/resources/application.yml b/services/submission/src/main/resources/application.yml index 9364cbfa1..8432d91bf 100644 --- a/services/submission/src/main/resources/application.yml +++ b/services/submission/src/main/resources/application.yml @@ -3,6 +3,9 @@ server: shutdown: graceful spring: + http: + converters: + preferred-json-mapper: jackson2 application: name: backend-submission lifecycle: @@ -75,12 +78,14 @@ management: tracing: sampling: probability: ${MANAGEMENT_TRACING_SAMPLING_PROBABILITY:1.0} - otlp: + opentelemetry: tracing: - endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} - headers: - Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} - timeout: 5s + export: + otlp: + endpoint: ${MANAGEMENT_OTLP_TRACING_ENDPOINT:http://localhost:4318/v1/traces} + headers: + Authorization: ${MANAGEMENT_OTLP_AUTHORIZATION:} + timeout: 5s metrics: export: enabled: ${MANAGEMENT_OTLP_METRICS_ENABLED:false} diff --git a/services/submission/src/test/java/com/ulticode/submission/BackendSubmissionApplicationTest.java b/services/submission/src/test/java/com/ulticode/submission/BackendSubmissionApplicationTest.java index 4d530797b..5b36d4ea1 100644 --- a/services/submission/src/test/java/com/ulticode/submission/BackendSubmissionApplicationTest.java +++ b/services/submission/src/test/java/com/ulticode/submission/BackendSubmissionApplicationTest.java @@ -23,7 +23,7 @@ "spring.autoconfigure.exclude=" + "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration," + "com.alibaba.cloud.dubbo.bootstrap.DubboBootstrapAutoConfiguration," - + "org.springframework.boot.actuate.autoconfigure.metrics.SystemMetricsAutoConfiguration", + + "org.springframework.boot.micrometer.metrics.autoconfigure.system.SystemMetricsAutoConfiguration", "SUBMISSION_DB_HOST=localhost", "SUBMISSION_DB_PORT=1", "SUBMISSION_DB_NAME=none", diff --git a/services/submission/src/test/java/com/ulticode/submission/security/InternalDelegationAssertionVerifierTest.java b/services/submission/src/test/java/com/ulticode/submission/security/InternalDelegationAssertionVerifierTest.java index 8db9d7710..0291cf5b2 100644 --- a/services/submission/src/test/java/com/ulticode/submission/security/InternalDelegationAssertionVerifierTest.java +++ b/services/submission/src/test/java/com/ulticode/submission/security/InternalDelegationAssertionVerifierTest.java @@ -12,7 +12,6 @@ import java.security.KeyPairGenerator; import java.time.Clock; import java.time.Instant; -import java.time.ZoneOffset; import java.util.Base64; import java.util.Date; import java.util.UUID; @@ -24,7 +23,7 @@ class InternalDelegationAssertionVerifierTest { private static final String KEY_ID = "admin-delegation-v1"; private static final String ACTOR_ID = "admin-1"; private static final String AUDIENCE = "backend-submission"; - private static final Instant NOW = Instant.now(); + private Instant now; private KeyPair keyPair; private InternalDelegationAssertionVerifier verifier; @@ -32,13 +31,15 @@ class InternalDelegationAssertionVerifierTest { @BeforeEach void setUp() throws Exception { keyPair = rsaKeyPair(); + Clock clock = Clock.systemUTC(); + now = clock.instant(); verifier = new InternalDelegationAssertionVerifier( encode(keyPair.getPublic()), KEY_ID, DelegationAssertionContract.ISSUER, AUDIENCE, (audience, jti, ttl) -> true, - Clock.systemUTC()); + clock); } @AfterEach @@ -49,32 +50,32 @@ void tearDown() { @Test void acceptsFreshAssertionBoundToAdminActorAndOwnerAudience() { - putAssertion(ACTOR_ID, NOW.plusSeconds(20), AUDIENCE, false); + putAssertion(ACTOR_ID, now.plusSeconds(20), AUDIENCE, false); assertThat(verifier.isTrusted(actor("ADMIN", ACTOR_ID))).isTrue(); } @Test void rejectsWrongAudienceExpiredBootstrapAndNonAdminAssertions() { - putAssertion(ACTOR_ID, NOW.plusSeconds(20), "backend-app", false); + putAssertion(ACTOR_ID, now.plusSeconds(20), "backend-app", false); assertThat(verifier.isTrusted(actor("ADMIN", ACTOR_ID))).isFalse(); - putAssertion(ACTOR_ID, NOW.minusSeconds(1), AUDIENCE, false); + putAssertion(ACTOR_ID, now.minusSeconds(1), AUDIENCE, false); assertThat(verifier.isTrusted(actor("ADMIN", ACTOR_ID))).isFalse(); - putAssertion(ACTOR_ID, NOW.plusSeconds(20), AUDIENCE, true); + putAssertion(ACTOR_ID, now.plusSeconds(20), AUDIENCE, true); assertThat(verifier.isTrusted(actor("ADMIN", ACTOR_ID))).isFalse(); - putAssertion(ACTOR_ID, NOW.plusSeconds(20), AUDIENCE, false); + putAssertion(ACTOR_ID, now.plusSeconds(20), AUDIENCE, false); assertThat(verifier.isTrusted(actor("USER", ACTOR_ID))).isFalse(); } @Test void rejectsLongLivedAndNonSelfDelegation() { - putAssertion(ACTOR_ID, NOW.plusSeconds(120), AUDIENCE, false); + putAssertion(ACTOR_ID, now.plusSeconds(120), AUDIENCE, false); assertThat(verifier.isTrusted(actor("ADMIN", ACTOR_ID))).isFalse(); - putAssertion(ACTOR_ID, NOW.plusSeconds(20), AUDIENCE, false); + putAssertion(ACTOR_ID, now.plusSeconds(20), AUDIENCE, false); assertThat(verifier.isTrusted( new ActorDelegation("ADMIN", ACTOR_ID, "different-delegator", "test"))).isFalse(); } @@ -92,7 +93,7 @@ private void putAssertion(String subject, Instant expiresAt, String audience, bo .claim(DelegationAssertionContract.ACTOR_TYPE_CLAIM, "ADMIN") .issuer(DelegationAssertionContract.ISSUER) .audience().add(audience).and() - .issuedAt(Date.from(NOW)) + .issuedAt(Date.from(now)) .expiration(Date.from(expiresAt)); if (bootstrap) { builder.claim(DelegationAssertionContract.BOOTSTRAP_CLAIM, true); From 20b912eb31f669f9f1234ede3c82ca2273688526 Mon Sep 17 00:00:00 2001 From: DavidHLP Date: Sat, 10 Oct 2026 22:15:50 -0700 Subject: [PATCH 3/4] fix(deps): pin patched Tomcat and Jackson dependencies --- services/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/pom.xml b/services/pom.xml index b55590df5..770561c18 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -62,6 +62,8 @@ 17 2.21.7 + 3.1.7 + 11.0.25 UTF-8 3.5.17 0.13.0 From 70df4fb4ff678e663c3f4bdfe72fff299020780e Mon Sep 17 00:00:00 2001 From: DavidHLP Date: Sat, 10 Oct 2026 22:41:04 -0700 Subject: [PATCH 4/4] fix(security): use injected clock for delegation JWT parsing --- .../jwt/DelegationAssertionVerifierSupport.java | 1 + .../DelegationAssertionVerifierSupportTest.java | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/services/platform/web-security/src/main/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupport.java b/services/platform/web-security/src/main/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupport.java index 7d5e1c216..5f41b8292 100644 --- a/services/platform/web-security/src/main/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupport.java +++ b/services/platform/web-security/src/main/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupport.java @@ -41,6 +41,7 @@ public static Claims verify( } Jws signed = Jwts.parser() + .clock(() -> Date.from(clock.instant())) .verifyWith(publicKey) .requireIssuer(expectedIssuer) .requireAudience(expectedAudience) diff --git a/services/platform/web-security/src/test/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupportTest.java b/services/platform/web-security/src/test/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupportTest.java index 48247ee62..e3766ad0a 100644 --- a/services/platform/web-security/src/test/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupportTest.java +++ b/services/platform/web-security/src/test/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupportTest.java @@ -11,7 +11,6 @@ import java.time.Clock; import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.UUID; import org.junit.jupiter.api.Test; @@ -19,7 +18,7 @@ class DelegationAssertionVerifierSupportTest { private static final String KEY_ID = "admin-delegation-v1"; - private static final Instant NOW = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private static final Instant NOW = Instant.parse("2020-01-01T00:00:00Z"); @Test void validatesRs256HeaderAndBoundClaims() throws Exception { @@ -38,6 +37,18 @@ void validatesRs256HeaderAndBoundClaims() throws Exception { assertThat(claims.getId()).isNotBlank(); } + @Test + void rejectsExpiredAssertionUsingSuppliedClock() throws Exception { + KeyPair keyPair = rsaKeyPair(); + String assertion = assertion(keyPair, KEY_ID, NOW.plusSeconds(30), NOW); + + assertThatThrownBy(() -> DelegationAssertionVerifierSupport.verify( + assertion, keyPair.getPublic(), KEY_ID, + DelegationAssertionContract.ISSUER, "backend-app", + Clock.fixed(NOW.plusSeconds(31), ZoneOffset.UTC))) + .isInstanceOf(io.jsonwebtoken.ExpiredJwtException.class); + } + @Test void rejectsWrongKidFutureIssuedAtAndExcessiveLifetime() throws Exception { KeyPair keyPair = rsaKeyPair();