diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index e5c45b6d8c..79c34b8120 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 3732bd0aee..20c80dc7ae 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 9b4ba55c0e..513f62ef32 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 e2b4d6464f..5a0c7e4411 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 3761cc4d1d..9c254b6304 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 50a2b153d6..defd387817 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 fee0ca1212..955f444463 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 daf178b4fa..3a5cecbd23 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 8aebde941c..5c70e81d0a 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 3cd70bfa14..41d1263e59 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 ddae6a739b..1a07bf0b32 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 f8c57181d3..fc31322dc1 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 a3cc71f4ac..ac8541ba4f 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 bba00df106..d090f9d88e 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 9646ab80c0..54d3e36f60 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 b1bfa03d00..23d1c04104 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 12b5640e9a..ffb8ecbb2b 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 03c5f71f07..1540d6dbd5 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 2507ea074d..8ae6c470ed 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 @@ -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 @@ -230,7 +230,7 @@ org.flywaydb flyway-core - 13.8.1 + 13.9.0 test 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 a4bd35587f..31c16dbce2 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 05d0625cef..d55ab77fde 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 79865416ad..3fa419dbd2 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 0000000000..0025cbcc73 --- /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 cb1d55c65e..0de22d93f6 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 f6e66a1e4f..b5ea5f8072 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 f3b48bb3ea..b45d95743d 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 081d3c820d..68f1686657 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 0000000000..16f8409a20 --- /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 c1735550fd..63db1e5e9c 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 11b7a28eaa..fee9180873 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 @@ -113,7 +119,7 @@ org.flywaydb flyway-core - 13.8.1 + 13.9.0 test @@ -125,7 +131,7 @@ org.flywaydb flyway-mysql - 13.8.1 + 13.9.0 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 6a5698c614..f9d6099874 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 ccff9fc741..564aefb278 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 8a4329fba7..269220f6ee 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 66a7e3cf07..6e1160edc3 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 7b70cce997..0aa5c84519 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 c844831ae3..6cfdcd9e73 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 d331da7aa8..801378ed12 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 b48222a8bb..5ff30e2fc6 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 8c11b4b10a..c7e684efd1 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 a62c104291..bb64769b23 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 69e55fe074..3e0c9ab3fe 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 670a9788e3..12f8576362 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 b953c44a57..2b08d05781 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 3d4d1ad6fa..efccf2a34e 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 c4b78d998d..da9656e315 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 2fb5c6967b..b454fb51ee 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 809ac29b81..e7f58b0fa2 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 @@ -108,7 +113,7 @@ com.redis testcontainers-redis - 2.2.4 + 3.0.0 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 1280d5f0c7..ad629ceb0d 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/main/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupport.java b/services/platform/web-security/src/main/java/com/ulticode/websecurity/jwt/DelegationAssertionVerifierSupport.java index 7d5e1c2161..5f41b82928 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/RateLimitIT.java b/services/platform/web-security/src/test/java/com/ulticode/websecurity/RateLimitIT.java index 1fab4c0034..26b805162a 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/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 48247ee627..e3766ad0a4 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(); diff --git a/services/pom.xml b/services/pom.xml index d4ef0d60c1..7538cfb182 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,14 @@ 1.0.1 17 - 2.21.7 - 4.1.137.Final - 10.1.59 + 2.21.7 + 3.1.7 + 11.0.25 UTF-8 3.5.17 0.13.0 - 4.7.0 - 2.9.1 + 4.8.0 + 3.1.1 3.3.6 5.8.47 1.18.48 @@ -76,7 +76,7 @@ 4.12.0 - 0.26.2 + 0.26.3 0.50 diff --git a/services/search/pom.xml b/services/search/pom.xml index 43316014a6..1cbc6e90a0 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 @@ -90,12 +94,12 @@ com.meilisearch.sdk meilisearch-java - 0.21.0 + 0.22.1 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 aa731095bc..8c8ef1ee16 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 ae079c844e..817a8ba368 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 9364cbfa10..8432d91bf8 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 4d530797b8..5b36d4ea17 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 8db9d7710f..0291cf5b2c 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);