From 7c477be3176a14a6790342714c44ece52ad6e3e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 00:12:15 +0000 Subject: [PATCH 01/19] deps(deps): bump jackson-bom.version from 2.22.1 to 2.22.2 Bumps `jackson-bom.version` from 2.22.1 to 2.22.2. Updates `com.fasterxml.jackson:jackson-bom` from 2.22.1 to 2.22.2 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.22.1...jackson-bom-2.22.2) Updates `com.fasterxml.jackson.core:jackson-databind` from 2.22.1 to 2.22.2 - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.22.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.22.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index af3ec7ad2..ddee8763e 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ OSV config contains a narrow temporary ignore because OSV Scanner v2.3.8 still reports 2.22.1 even though the advisory text names it as patched. --> - 2.22.1 + 2.22.2 1.5.35 From 7ec762c9166abcde047b40cad8cca40b9db49387 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:46:40 +0000 Subject: [PATCH 02/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 5 ++++ .../viewer/controller/AdminController.java | 29 ++++++++++++++++--- .../controller/AdminControllerTest.java | 25 +++++++++++++++- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index e795cb9dd..3dad7ce72 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -32,3 +32,8 @@ **Vulnerability:** The document hashing routine in `DefaultDocumentConversionService` processed file streams without enforcing any maximum size limit on the bytes read. An attacker could exploit this by uploading a maliciously large stream (or exploiting a compression bomb if unzipping), exhausting system memory, CPU, or disk space (DoS). **Learning:** Checking the declared file size (e.g., `file.getSize()`) in initial validation is not always sufficient if the input stream itself can be spoofed or dynamically expanded during reading. The actual bytes read must be verified against bounds continuously. **Prevention:** Always enforce a strict, configurable size limit (e.g., `ConversionProperties.maxUploadSizeBytes`) within the `while` loop that reads from untrusted input streams. Track `totalRead` and throw an exception immediately if the limit is exceeded. + +## 2026-07-20 - Admin API Authorization Check +**Vulnerability:** The Admin API (`AdminController`) exposed internal admin endpoints (`/api/v1/admin/convert/jobs`, etc.) without any `TenantAccessService` authorization checks. +**Learning:** Admin endpoints must enforce strict authorization checks, such as `admin:operate`, to prevent unauthorized internal or external users from listing all tenant jobs, deleting them, or retrying dead lettered jobs without authorization. +**Prevention:** Always inject `TenantAccessService` into admin endpoints and require appropriate cross-tenant admin permissions via `tenantAccessService.require(headers, "admin:operate")`. diff --git a/src/main/java/com/clearfolio/viewer/controller/AdminController.java b/src/main/java/com/clearfolio/viewer/controller/AdminController.java index 412d4eb86..4cc5840a4 100644 --- a/src/main/java/com/clearfolio/viewer/controller/AdminController.java +++ b/src/main/java/com/clearfolio/viewer/controller/AdminController.java @@ -11,10 +11,13 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; import com.clearfolio.viewer.api.AdminJobListResponse; +import com.clearfolio.viewer.auth.TenantAccessService; import com.clearfolio.viewer.model.ConversionJob; import com.clearfolio.viewer.service.DocumentConversionService; import com.clearfolio.viewer.service.RetryDeadLetterResult; @@ -25,25 +28,39 @@ @RestController public class AdminController { + /** + * Conversion service for managing jobs. + */ private final DocumentConversionService conversionService; + /** + * Service to enforce access controls. + */ + private final TenantAccessService tenantAccessService; + /** * Creates a controller for admin operations. * * @param conversionService conversion service + * @param tenantAccessService access control service */ - public AdminController(DocumentConversionService conversionService) { + public AdminController(final DocumentConversionService conversionService, final TenantAccessService tenantAccessService) { this.conversionService = conversionService; + this.tenantAccessService = tenantAccessService; } /** * Retrieves all conversion jobs, optionally filtered by dead-letter status. * * @param deadLettered optional filter for dead-lettered jobs + * @param headers request headers carrying tenant claims * @return list of conversion jobs */ @GetMapping("/api/v1/admin/convert/jobs") - public AdminJobListResponse getAllJobs(@RequestParam(required = false) Boolean deadLettered) { + public AdminJobListResponse getAllJobs( + @RequestParam(required = false) final Boolean deadLettered, + @RequestHeader final HttpHeaders headers) { + tenantAccessService.require(headers, "admin:operate"); Iterable allJobs = conversionService.getAllJobs(); if (deadLettered == null) { @@ -63,10 +80,12 @@ public AdminJobListResponse getAllJobs(@RequestParam(required = false) Boolean d * Deletes a conversion job. * * @param jobId conversion job identifier + * @param headers request headers carrying tenant claims * @return no content on success */ @DeleteMapping("/api/v1/admin/convert/jobs/{jobId}") - public ResponseEntity deleteJob(@PathVariable UUID jobId) { + public ResponseEntity deleteJob(@PathVariable final UUID jobId, @RequestHeader final HttpHeaders headers) { + tenantAccessService.require(headers, "admin:operate"); conversionService.deleteJob(jobId); return ResponseEntity.noContent().build(); } @@ -75,10 +94,12 @@ public ResponseEntity deleteJob(@PathVariable UUID jobId) { * Retries a dead-lettered conversion job. * * @param jobId conversion job identifier + * @param headers request headers carrying tenant claims * @return accepted response on success */ @PostMapping("/api/v1/admin/convert/jobs/{jobId}/retry") - public ResponseEntity retryDeadLettered(@PathVariable UUID jobId) { + public ResponseEntity retryDeadLettered(@PathVariable final UUID jobId, @RequestHeader final HttpHeaders headers) { + tenantAccessService.require(headers, "admin:operate"); RetryDeadLetterResult result = conversionService.retryDeadLettered(jobId, "admin"); if (result == RetryDeadLetterResult.NOT_FOUND) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "job not found"); diff --git a/src/test/java/com/clearfolio/viewer/controller/AdminControllerTest.java b/src/test/java/com/clearfolio/viewer/controller/AdminControllerTest.java index ad63a8015..72b6db8e3 100644 --- a/src/test/java/com/clearfolio/viewer/controller/AdminControllerTest.java +++ b/src/test/java/com/clearfolio/viewer/controller/AdminControllerTest.java @@ -3,13 +3,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + import java.util.Arrays; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.server.ResponseStatusException; +import com.clearfolio.viewer.auth.TenantAccessService; +import com.clearfolio.viewer.auth.TenantContext; import com.clearfolio.viewer.model.ConversionJob; import com.clearfolio.viewer.service.DocumentConversionService; import com.clearfolio.viewer.service.RetryDeadLetterResult; @@ -17,13 +24,18 @@ class AdminControllerTest { private DocumentConversionService conversionService; + private TenantAccessService tenantAccessService; private WebTestClient webTestClient; private AdminController controller; @BeforeEach void setUp() { conversionService = mock(DocumentConversionService.class); - controller = new AdminController(conversionService); + tenantAccessService = mock(TenantAccessService.class); + TenantContext tenantContext = TenantContext.fromClaims("tenant-1", "user-1", "admin:operate"); + when(tenantAccessService.require(any(HttpHeaders.class), eq("admin:operate"))).thenReturn(tenantContext); + + controller = new AdminController(conversionService, tenantAccessService); webTestClient = WebTestClient.bindToController(controller) .controllerAdvice(new ApiExceptionHandler()) .build(); @@ -121,4 +133,15 @@ void retryDeadLetteredReturnsConflictWhenNotEligible() { .exchange() .expectStatus().isEqualTo(409); // isConflict() isn't always available depending on spring-test version, so using isEqualTo(409) is safer } + + @Test + void rejectsUnauthorizedAccess() { + when(tenantAccessService.require(any(HttpHeaders.class), eq("admin:operate"))) + .thenThrow(new org.springframework.web.server.ResponseStatusException(org.springframework.http.HttpStatus.FORBIDDEN)); + + webTestClient.get() + .uri("/api/v1/admin/convert/jobs") + .exchange() + .expectStatus().isForbidden(); + } } From c11cde518939a1052f7096dc60bd5594ebc2cc71 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 29 Sep 2026 02:17:38 +0000 Subject: [PATCH 03/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 65ad90e8a18a40d566cb949989b91c3be4f8937f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 29 Sep 2026 06:31:00 +0000 Subject: [PATCH 04/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From c6d2071a61e6282307469393e238a0a6bca05bae Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 29 Sep 2026 11:04:42 +0000 Subject: [PATCH 05/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From c6a2a0aa5227c85e52f9eb2c48c7a1839587b802 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 29 Sep 2026 20:07:14 +0000 Subject: [PATCH 06/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 3e9ba61e1aa2a903e920cf832f9daa5467f2e166 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 1 Oct 2026 15:17:57 +0900 Subject: [PATCH 07/19] fix(security): patch Jackson denial-of-service CVEs --- CHANGELOG.md | 1 + .../2026-07-03-third-party-attribution.md | 10 +- docs/product-technical-gap-baseline.md | 48 ++++++ .../sbom-cyclonedx.json | 148 +++++++++--------- osv-scanner.toml | 4 - pom.xml | 14 +- .../test_render_third_party_attribution.py | 58 +++++++ .../viewer/config/DependencyPolicyTest.java | 12 ++ 8 files changed, 204 insertions(+), 91 deletions(-) create mode 100644 docs/product-technical-gap-baseline.md delete mode 100644 osv-scanner.toml mode change 100755 => 100644 scripts/test_render_third_party_attribution.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 1187deb2a..127701092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ ### Security +- Jackson BOM을 `2.22.3`으로 올려 `jackson-databind`의 무제한 type-id 캐시 성장(CVE-2026-91776)과 이차 시간 forward-reference 해석(CVE-2026-91777)을 수정했습니다. 만료된 GHSA-5jmj-h7xm-6q6v OSV 예외를 제거하고 SBOM·제3자 고지문을 새 의존성 그래프와 함께 갱신했습니다. - `GET /api/v1/convert/jobs/{jobId}/download`가 리소스 조회 전에 전용 `artifact:read` 권한을 검증하고, PDF 저장소 접근 전에 작업의 tenant 소유권을 확인하도록 강화했습니다. `job:read`만으로는 문서 바이트를 읽을 수 없으며, 인증 누락·권한 누락·교차 tenant UUID 접근은 각각 fail closed 처리되고 교차 tenant 요청은 리소스 존재를 숨기는 `404`를 반환합니다. - Maven XML 테스트 보고서 검증기는 각 `testsuite`의 `tests`, `skipped`, `failures`, `errors` 속성을 모두 필수 증거로 요구합니다. 누락된 결과 수를 암묵적으로 0으로 간주하지 않고 fail closed 처리하며, 각 속성 누락 회귀 테스트를 추가했습니다. - Maven XML 테스트 보고서 검증기는 UTF-8만 허용하고 UTF-8 BOM은 수용하며, NUL 바이트·DTD·엔터티 선언을 파싱 전에 거부합니다. UTF-16 같은 대체 인코딩으로 위험 선언을 바이트 검사에서 숨기는 우회와 외부 엔터티 읽기·엔터티 확장형 서비스 거부를 회귀 테스트로 차단했습니다. diff --git a/docs/legal/2026-07-03-third-party-attribution.md b/docs/legal/2026-07-03-third-party-attribution.md index 7d691a02f..ad8e3ec6c 100644 --- a/docs/legal/2026-07-03-third-party-attribution.md +++ b/docs/legal/2026-07-03-third-party-attribution.md @@ -14,11 +14,11 @@ CycloneDX SBOM. It is engineering evidence, not legal advice. | Component | Version | License metadata | Package URL | | --- | --- | --- | --- | | com.fasterxml.jackson.core:jackson-annotations | 2.22 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.22?type=jar` | -| com.fasterxml.jackson.core:jackson-core | 2.22.1 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar` | -| com.fasterxml.jackson.core:jackson-databind | 2.22.1 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar` | -| com.fasterxml.jackson.datatype:jackson-datatype-jdk8 | 2.22.1 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.1?type=jar` | -| com.fasterxml.jackson.datatype:jackson-datatype-jsr310 | 2.22.1 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.1?type=jar` | -| com.fasterxml.jackson.module:jackson-module-parameter-names | 2.22.1 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.1?type=jar` | +| com.fasterxml.jackson.core:jackson-core | 2.22.3 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar` | +| com.fasterxml.jackson.core:jackson-databind | 2.22.3 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar` | +| com.fasterxml.jackson.datatype:jackson-datatype-jdk8 | 2.22.3 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.3?type=jar` | +| com.fasterxml.jackson.datatype:jackson-datatype-jsr310 | 2.22.3 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.3?type=jar` | +| com.fasterxml.jackson.module:jackson-module-parameter-names | 2.22.3 | Apache-2.0 | `pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.3?type=jar` | | com.fasterxml:classmate | 1.7.3 | Apache-2.0 | `pkg:maven/com.fasterxml/classmate@1.7.3?type=jar` | | commons-logging:commons-logging | 1.4.0 | Apache-2.0 | `pkg:maven/commons-logging/commons-logging@1.4.0?type=jar` | | io.micrometer:micrometer-commons | 1.15.12 | Apache-2.0 | `pkg:maven/io.micrometer/micrometer-commons@1.15.12?type=jar` | diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md new file mode 100644 index 000000000..d5c672c5b --- /dev/null +++ b/docs/product-technical-gap-baseline.md @@ -0,0 +1,48 @@ +# Clearfolio Product and Technical Gap Baseline + +## Goal and loop + +Clearfolio is the ContextualWisdomLab document-viewer bounded context. Its buyer +quality loop is review → root-cause repair → exact-head validation → ordinary +merge. A queued, skipped, stale-head, or fail-closed Check is not passing. + +## Current product and technical boundary + +- **Product responsibility:** submit documents asynchronously, expose conversion + status, render same-origin PDF artifacts, and enforce tenant-scoped access. +- **Runtime boundary:** Spring WebFlux controllers delegate validation, + conversion, state, artifact, authorization, and audit work to their owning + services and repositories; no cross-service database access is authorized. +- **Supply-chain boundary:** Maven dependency policy, CycloneDX SBOM, license + policy, third-party attribution, Trivy, OSV, Semgrep, and CodeQL provide + fail-closed release evidence. + +## PRD and TRD acceptance baseline + +| Evidence | Acceptance rule | Status | +| --- | --- | --- | +| Product behavior | `mvn -B --no-transfer-progress verify`; zero test failures, errors, or skips; production line and branch coverage 100% | Required on exact repair head | +| Public contract | Java 21 compilation and public Javadocs complete with warning and deprecation budget 0 | Required on exact repair head | +| Supply chain | Trivy/OSV/SAST report no actionable finding; committed SBOM and attribution match the resolved dependency graph | Repair in progress on #503 | +| Review admission | Independent approval and all required terminal Checks bind to the current head | Not yet satisfied | + +## Gap and action ledger + +| Gap | Exact evidence and RCA | Action | Status | +| --- | --- | --- | --- | +| Jackson denial-of-service exposure | clearfolio#660 head `2a6b0b621e075da224210c0ca78db344af5dea52`, Security run `36778995059`, Trivy job `110104143035`: CVE-2026-91776 and CVE-2026-91777 in `jackson-databind` 2.22.2 | Repair canonical dependency owner #503 with Jackson 2.22.3, a downgrade regression test, refreshed SBOM/attribution, and removal of the expired OSV exception | In progress | +| Historical evidence drift | #503 review found its original one-file 2.22.2 bump left SBOM, attribution, POM rationale, and expired ignore stale | Keep dependency version and buyer evidence in one PR; run attribution/license drift checks | In progress | +| Merge admission | #503 is Draft and has unresolved review findings; #660 is Ready but fails Security | Keep both deltas open; do not merge until #503 is GREEN and independently reviewed, then ordinarily restack consumers | Hold | + +## Decision traceability + +The selected repair is the upstream Jackson 2.22.3 patch line, released +2026-09-21 with fixes for both CVEs. Ignoring the findings, weakening Trivy, or +retaining the expired OSV exception was rejected because each would preserve a +buyer-visible denial-of-service risk or conceal stale evidence. A new duplicate +dependency PR was rejected because #503 already owns the Jackson version delta. + +## References + +FasterXML. (2026, September 21). *Jackson release 2.22.3*. +https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.22.3 diff --git a/docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json b/docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json index 2f9e4c212..481a85169 100644 --- a/docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json +++ b/docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json @@ -1,10 +1,10 @@ { "bomFormat" : "CycloneDX", "specVersion" : "1.6", - "serialNumber" : "urn:uuid:b6017fa5-aa1e-3a06-ab1c-8fd43d993316", + "serialNumber" : "urn:uuid:e0113328-1366-42aa-b76f-fd4423d3bd59", "version" : 1, "metadata" : { - "timestamp" : "2026-08-05T12:07:15Z", + "timestamp" : "2026-10-01T06:14:49Z", "lifecycles" : [ { "phase" : "build" @@ -693,45 +693,45 @@ }, { "type" : "library", - "bom-ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.1?type=jar", + "bom-ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.3?type=jar", "publisher" : "FasterXML", "group" : "com.fasterxml.jackson.datatype", "name" : "jackson-datatype-jdk8", - "version" : "2.22.1", + "version" : "2.22.3", "description" : "Add-on module for Jackson (https://github.com/FasterXML/jackson) to support JDK 8 data types.", "scope" : "required", "hashes" : [ { "alg" : "MD5", - "content" : "58b2d6d030c310d11902a11a47159f7f" + "content" : "283c51f09192d5354168e8e1db5bad01" }, { "alg" : "SHA-1", - "content" : "ef21a94e7b5603f57ca1efe9215513d210d96320" + "content" : "1c8e07b4eefb9ccb6a2247c54f42f293ff0dc8aa" }, { "alg" : "SHA-256", - "content" : "2d5ee03fcaa017db0c947a5921ede8b39481d1d637af39079840a87d55e907eb" + "content" : "f223061a5aaecdc9506458143807c73bcd1a744d6b3bbb8da4703a0abc408f7d" }, { "alg" : "SHA-512", - "content" : "62a533985dee473d3ef39400afb7bb833ce83611d0b2414f3a89bd53bcd9e21f14e63ad94cb2cfb7ae96fa961903fda78e0176d46bbe19473d19c627fdfa648c" + "content" : "0ec3c7bae5df6b3140a18a41a784767748870e7e2067592985c68b144b1cd775601902d9d7af7c14d5039e25025cd0f9b95cd6a172f809fd8bb4b5880932067b" }, { "alg" : "SHA-384", - "content" : "423db1c93aa364cd7677eb2971e8354d30be788e8dc6c63cedbe8c784b6439170c3c208c303b96c08ab120ac802c22d1" + "content" : "8ef3987a9223e834e529c184cbb00633e3ad7e943ba2b8df2949c8c1d5ae7cb45c490c301a851bf15e8e48dceef041da" }, { "alg" : "SHA3-384", - "content" : "a02e2eaf81ca6869c821015c0d1dec580ed2bd539821a795957b0239834e813db0808144e4ecfbcece992a212117f252" + "content" : "2ce308f3b9252489b0453f1e9eee1a8bcfcf255913910e0ef6c7f87d55bcb48d9a1364989bc163ed8aae166acd8b14b5" }, { "alg" : "SHA3-256", - "content" : "a246cfeed6f3f59c48cf6990d6d7adc77637c318401956a8e0ccaa0ed51e9814" + "content" : "b6c27271cdf47235c59997fb390d8569b19dc0c82b848daf0d750b67a6b21074" }, { "alg" : "SHA3-512", - "content" : "9808c24c3d1c241ff9c89e621338fcbb483fc1eb6560465562546713506639c5e633df41b844c8bd0f76497027404dd73fe3f720cddd65ec15841f22ec8fc13f" + "content" : "c9acd1a2ed3ec82b8411c3fa7c7132784029aaf5226edf3b622ac57862a9d3bebc19fba5be10048853d5b6456c5ce3fcdf9b4962f538480cea42d5698bb2824b" } ], "licenses" : [ @@ -741,7 +741,7 @@ } } ], - "purl" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.1?type=jar", + "purl" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.3?type=jar", "externalReferences" : [ { "type" : "website", @@ -763,45 +763,45 @@ }, { "type" : "library", - "bom-ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.1?type=jar", + "bom-ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.3?type=jar", "publisher" : "FasterXML", "group" : "com.fasterxml.jackson.datatype", "name" : "jackson-datatype-jsr310", - "version" : "2.22.1", + "version" : "2.22.3", "description" : "Add-on module to support JSR-310 (Java 8 Date & Time API) data types.", "scope" : "required", "hashes" : [ { "alg" : "MD5", - "content" : "4dd3e0a2be3f88d720f9214954ed59b6" + "content" : "1f14fa9b9779d0545287bba2bfb927df" }, { "alg" : "SHA-1", - "content" : "3377a0589c1b0e62bbe245ac8e9f56fa7d7b8bb9" + "content" : "8d54f48cfe4865bdfa245b8a90fb15b56c8a4a3c" }, { "alg" : "SHA-256", - "content" : "85da45b7e5e565418963ff8f0dcb184365b0557c15468933f4318dde5c3ce845" + "content" : "ec7052ee48c9d873bb8148338a643f02cf89c01d035dd219411473030d6d2b22" }, { "alg" : "SHA-512", - "content" : "362067f556de43c49829fd5d69681bba3a43bc5a7211811061d62838f047cea368174d865944aa2434f5d7592a2cdbd7a75b534493b0c14e6340f1536718ce41" + "content" : "3a711d091436497aa84ea83316f948bbc73644c9a0a8ed478cf76d34b28340d3e596025bf5c8a61ca8ab1806c35f3db5e45d499340d091e224b75270a730b2d2" }, { "alg" : "SHA-384", - "content" : "aec680e1f9f4b48c7cb1b0e6ba1631ee6c69b0d2983da2f0ce26b4e525054fffa0a8d073c1ac37f36b6f004d413abc38" + "content" : "38782f7a5b6f857e98362212cb953bfe4fb9f11fed935a6621145fe35c4a2f5afc034c048849d96f490b86bf9c1b69ee" }, { "alg" : "SHA3-384", - "content" : "afc1e60eb4215320d1ae959f2095215f9fa38db4cfe04b2d9ea626938c7469bd9872d3ad83e401ce5e6c0f11f338290e" + "content" : "bf40dfc2bccb29fc9eca32455203e7d9d26b18c54ba9fa1f47ce60b45036479d07fcfda880fadc61270d52f9a7d2150d" }, { "alg" : "SHA3-256", - "content" : "a7e4a6a3455c2dfda0a691d413a5afeef1d38587b1ead2318b80f8966d1c783f" + "content" : "0d17f4e5f1b237905a3b1d63992a01908250e7a98cd6dff099d59c1e8e202dc0" }, { "alg" : "SHA3-512", - "content" : "58a71d8bad72fada694e5484d99a4625d672d994ffc3b43196642ae48a08c4430fc21e20937f3fa01d0c182136eccfbc09926d11bad267455180fbd9774427c0" + "content" : "2153206c85167b6737e4f2cd3dd1e93ed213ebc049bdc8d099b61934301c4c9bc738c5fc19b7f3a778a918d92fbdbfe19df8ccfdc088ed8ee22648417dc99ffe" } ], "licenses" : [ @@ -811,7 +811,7 @@ } } ], - "purl" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.1?type=jar", + "purl" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.3?type=jar", "externalReferences" : [ { "type" : "website", @@ -833,45 +833,45 @@ }, { "type" : "library", - "bom-ref" : "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.1?type=jar", + "bom-ref" : "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.3?type=jar", "publisher" : "FasterXML", "group" : "com.fasterxml.jackson.module", "name" : "jackson-module-parameter-names", - "version" : "2.22.1", + "version" : "2.22.3", "description" : "Add-on module for Jackson (https://github.com/FasterXML/jackson) to support introspection of method/constructor parameter names, without having to add explicit property name annotation.", "scope" : "required", "hashes" : [ { "alg" : "MD5", - "content" : "f6bde154ca5466d618a6040e819e35d5" + "content" : "f24f70cfa9354d9870e1b2e73076b65d" }, { "alg" : "SHA-1", - "content" : "6776897d180781c6190f0e6832c8e2cdaefe78b9" + "content" : "533b13ecee272025f947f9c4c40f178cf72afebe" }, { "alg" : "SHA-256", - "content" : "dc344110fed9779bee54291044d1d209bac31ce9844f5b1a217ce46bd74891f9" + "content" : "3f085667cd7b2dd9794a837b6e4a5c57779132bfc37b49b5c457870eee9d60ba" }, { "alg" : "SHA-512", - "content" : "0e853ed90621b7d31426db3f95cf6440fc60c31c24a62082f861f2576f2c911cb18c80b2f629f023eab57d574b97673ec53d39986dd27bda642d318ce51214cd" + "content" : "8eaf493277d0a6956d51449e21c76a529f4e4a26f4c518b51fb0d47e3dded0c8d10cc53c9014eeda0813057f49cd48dab371d7dcc41e875c162a9110a4d74b7d" }, { "alg" : "SHA-384", - "content" : "a536e410637e32e1309ecabef684ded3a5c200dab9287d50997ffb14a46f42124fb81acc32a8e12254e9334f26c8d783" + "content" : "fe60a1409a2bea0f4305355e13b692361289937808f3d6d0e3338c96450b82f3215a8c1add01b1a2ccffae529ad3aad8" }, { "alg" : "SHA3-384", - "content" : "8a55123d3673fab467d8be5dcbe7c592f5ac5084370dde7ca06a0bc56149fe1152ecbae2e0d5fabd29c3efed1aba039d" + "content" : "4ad856d4518a00cf45b58be353f9e8a9975d3a32faa332234b005bfaa113c3e86b7994e3aa76c00e81db2202e64586f1" }, { "alg" : "SHA3-256", - "content" : "45e2f9021d6aa08fea40c0f3ba0257ef381f83e28d96f22c38d5a48de086a64e" + "content" : "f66e5ff504b4e190c0288f0da4092653d326a87065cc89b0fdf50b2d55450d65" }, { "alg" : "SHA3-512", - "content" : "cd59874c12e14572fc57a45e0ab3c40dea2fbb3b3ca51bb33f14b0df2cc5d30f7dbca220224349a62e49adc6a030d3699b6704fa15851ab1218e39a5b5296161" + "content" : "fef5461656ec8d29bbe97a9629866dfb5b149ea947e0381f8f787fd47e86eeead8fa326aafd6d0d1b5a37abe846f74316ed13fae431b9ef0ade1638883f9d6e1" } ], "licenses" : [ @@ -881,7 +881,7 @@ } } ], - "purl" : "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.1?type=jar", + "purl" : "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.3?type=jar", "externalReferences" : [ { "type" : "website", @@ -3863,45 +3863,45 @@ }, { "type" : "library", - "bom-ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar", + "bom-ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar", "publisher" : "FasterXML", "group" : "com.fasterxml.jackson.core", "name" : "jackson-databind", - "version" : "2.22.1", + "version" : "2.22.3", "description" : "General data-binding functionality for Jackson: works on core streaming API", "scope" : "required", "hashes" : [ { "alg" : "MD5", - "content" : "df2dcf8d581836d48aae7387311cba93" + "content" : "e1fbe6bbbb606fad49068fd2670a5208" }, { "alg" : "SHA-1", - "content" : "9e2fb91831cce9cb9262909cd76647508949f232" + "content" : "d0d4b2cdb0a1440ac02178fc2ff01dfb05cd06a8" }, { "alg" : "SHA-256", - "content" : "7dcd7e53bec1f56c7ad278bd1ca0840bebcc595d61ce44d6a8439abb75b965b2" + "content" : "556db5439e206114346043f68d200497dc96a0bca62a360a81784092ebd0e0a9" }, { "alg" : "SHA-512", - "content" : "d8a905e80e6d7dd2026b16b075dde2d409425b61417120980ea07b261c6bf98d5c065053f1c063b60da30b4324157778ec4eb859945fb8543176e55a2d3b8db8" + "content" : "2c94560ef0f01f7dd12ae0810dbcfaf80fddd889bc25f597350fb75a0fcc266fa68f5795a773f772692426ac81a6ee65ed2bde8db8184bb2788323bc95ef7ebe" }, { "alg" : "SHA-384", - "content" : "b45efa1187b756bdfa7e0c6bc2eda85fcf13d879b4bf370f06ef95325c13b629f763a8027dbc34dab7c6a549bb33e945" + "content" : "35a064a6a2a93643e10f87b9e0a0527fa3c12a14de7f76bcdc81ce3939150fd683159c08164011532e84504eb473e277" }, { "alg" : "SHA3-384", - "content" : "7eeb7d7ea5434fdede4b0d256955d0ebf93a11ad89efcc2a3551d649bf197f6aa6c3dd60247805a13270fd8ed0a98ae8" + "content" : "40f36ac8e077efe3f141b03f1390cdb38e1c829058fb86510abea9778e792725f55f6684cbba4d366b6055ba44b7d80f" }, { "alg" : "SHA3-256", - "content" : "ab1df340c8e99a3ea6f485b9e3bf0e1cb7b57810b09e9161c8eee38eb8db3e47" + "content" : "0ea05dee4c161251abf19cff75fd82b4937d28d346c53cb3fd7c1e062a2184da" }, { "alg" : "SHA3-512", - "content" : "dc3f3df098898dc6bf71fcef0ca232a592f59fb465161b95b03a28eebc9539bede1db83bacaf14dc57328feffc7a4637b911a09356fa4330d93f52131ac7254e" + "content" : "e6dc5878852afc9101d66a2c16b91a419179bfc871ec66ddd8590bcfde9b3f2889d4fa317ab8fe40aa2ba6bd94a4aa8a1121ea358e10623de54a678a080f6676" } ], "licenses" : [ @@ -3911,7 +3911,7 @@ } } ], - "purl" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar", + "purl" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar", "externalReferences" : [ { "type" : "website", @@ -4003,45 +4003,45 @@ }, { "type" : "library", - "bom-ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar", + "bom-ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar", "publisher" : "FasterXML", "group" : "com.fasterxml.jackson.core", "name" : "jackson-core", - "version" : "2.22.1", + "version" : "2.22.3", "description" : "Core Jackson processing abstractions (aka Streaming API), implementation for JSON", "scope" : "required", "hashes" : [ { "alg" : "MD5", - "content" : "09e866bcd73613665ef49f5086704fb1" + "content" : "75691eef4483b7eb0e1c43e08dcb6573" }, { "alg" : "SHA-1", - "content" : "da7ffb60088d7e8f37ecdd3b617520971cc7b9bf" + "content" : "8695aab38355c65b60e242ec62edf13c52916d88" }, { "alg" : "SHA-256", - "content" : "941ff029bcdb93e83d209ce516c1a7fb8bbac07d0a2fa122f5bf194b2cd7b4f4" + "content" : "8a501126a385b25841915d839508f8a66e2a0dbc8a6709d055ef3b3e852b094c" }, { "alg" : "SHA-512", - "content" : "d4485af4465f561034df86686d672835b0272b6200efb0af55ea71e62d3faf09e9f90e42df4da64650795cf00519fc553f892bf6179330a3e74750110a785efb" + "content" : "8d5984961b37f9570d0581a74f005442fe37c46c601ee0fe63e3695f967bd7598dd268cfb33509a289ff472385cedd99396660e31d7cb873d1e7ffff676912e8" }, { "alg" : "SHA-384", - "content" : "faaf92de6e93475fdbb7d56221fd35d8435ac4f87dddfd334ed05c4318b8b72220010effd08bf8dd156420771b294eb4" + "content" : "788125564042463c3b3f856d803c955282cacbda361d8dc172fdc8288013dd17db525e490bc0bde360c480e431a7a1d1" }, { "alg" : "SHA3-384", - "content" : "5c432f1a2f3369485c4ed7d3c3c4499342c23efd0d7a574b73421345df9762bd27643cc469b01632400691f3c09b5d8b" + "content" : "5706651739544e7216903e0e6c5f4edd362b158b787d04afe0d31b65137394605ed569ecb924728d9cd5a4850fa07b3f" }, { "alg" : "SHA3-256", - "content" : "48fc6e17c36e14b8bae387b92248a43da12293b68a61dd2517c708dbb24ed010" + "content" : "f41bb3e563a0b67d3ae1d9c29e0ebe8b86aa650da68b66e66d9403bd6e774c37" }, { "alg" : "SHA3-512", - "content" : "f72ef2d2a1012be8b1c972323527a396bbaea0b543bd79fac6d380f8e4855c6d98190b067ccec92ece9ed8e1ece1e6046b1d93f9c85944fcb7133fe0b4dc60e4" + "content" : "3d3116030b1efdab1ca91f0ec21a72bf8f2a0397d1eae70dddc1848906781c22aa941b8a24b47c1a33ede3675a47b12510aeea1a042b198936fc5fbcf7b645e0" } ], "licenses" : [ @@ -4051,7 +4051,7 @@ } } ], - "purl" : "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar", + "purl" : "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar", "externalReferences" : [ { "type" : "website", @@ -4213,7 +4213,7 @@ "pkg:maven/org.springframework.boot/spring-boot-starter-log4j2@3.5.16?type=jar", "pkg:maven/org.apache.pdfbox/pdfbox@3.0.8?type=jar", "pkg:maven/org.webjars.npm/pdfjs-dist@6.1.200?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar" + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar" ] }, { @@ -4306,10 +4306,10 @@ "dependsOn" : [ "pkg:maven/org.springframework.boot/spring-boot-starter@3.5.16?type=jar", "pkg:maven/org.springframework/spring-web@6.2.19?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar", - "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.1?type=jar", - "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.1?type=jar", - "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.1?type=jar" + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar", + "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.3?type=jar", + "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.3?type=jar", + "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.3?type=jar" ] }, { @@ -4321,10 +4321,10 @@ ] }, { - "ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar", + "ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar", "dependsOn" : [ "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.22?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar" + "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar" ] }, { @@ -4332,29 +4332,29 @@ "dependsOn" : [ ] }, { - "ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar", + "ref" : "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.1?type=jar", + "ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.22.3?type=jar", "dependsOn" : [ - "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar" + "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar" ] }, { - "ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.1?type=jar", + "ref" : "pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.22.3?type=jar", "dependsOn" : [ "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.22?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar" + "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar" ] }, { - "ref" : "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.1?type=jar", + "ref" : "pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.22.3?type=jar", "dependsOn" : [ - "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.1?type=jar", - "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.1?type=jar" + "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.22.3?type=jar", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.22.3?type=jar" ] }, { diff --git a/osv-scanner.toml b/osv-scanner.toml deleted file mode 100644 index a6aed8eb0..000000000 --- a/osv-scanner.toml +++ /dev/null @@ -1,4 +0,0 @@ -[[IgnoredVulns]] -id = "GHSA-5jmj-h7xm-6q6v" -ignoreUntil = 2026-08-15 -reason = "jackson-databind is pinned to 2.22.1, which this advisory's own patched-version text identifies as fixed for CVE-2026-54515; OSV Scanner v2.3.8 still matches 2.22.1 via a broad Maven range." diff --git a/pom.xml b/pom.xml index ddee8763e..824c6b3cf 100644 --- a/pom.xml +++ b/pom.xml @@ -38,12 +38,10 @@ which contains the July 2026 HTTP, HTTP/2, MQTT, compression, and parser-boundary hardening release. --> 4.1.136.Final - - 2.22.2 + + 2.22.3 1.5.35 @@ -59,7 +57,7 @@ --> - + com.fasterxml.jackson jackson-bom @@ -265,4 +263,4 @@ - \ No newline at end of file + diff --git a/scripts/test_render_third_party_attribution.py b/scripts/test_render_third_party_attribution.py old mode 100755 new mode 100644 index 767c5202e..379014386 --- a/scripts/test_render_third_party_attribution.py +++ b/scripts/test_render_third_party_attribution.py @@ -29,6 +29,9 @@ NETTY_VERSION_PATTERN = re.compile( r"\s*([^<\s]+)\s*" ) +JACKSON_VERSION_PATTERN = re.compile( + r"\s*([^<\s]+)\s*" +) def component(group: str, name: str, version: str, license_id: str, purl: str) -> dict: @@ -50,6 +53,16 @@ def managed_netty_version() -> str: return matches[0] +def managed_jackson_version() -> str: + """Read the reviewed Jackson family version from the trusted project POM.""" + matches = JACKSON_VERSION_PATTERN.findall(POM_PATH.read_text(encoding="utf-8")) + if len(matches) != 1: + raise AssertionError( + "pom.xml must declare exactly one non-blank jackson-bom.version property" + ) + return matches[0] + + class ThirdPartyAttributionTest(unittest.TestCase): """Protect rendering behavior and buyer-evidence dependency consistency.""" @@ -193,6 +206,51 @@ def test_buyer_evidence_tracks_reviewed_netty_security_line(self) -> None: "the historical Netty line must be absent from buyer attribution", ) + def test_buyer_evidence_tracks_reviewed_jackson_security_line(self) -> None: + """Require Jackson SBOM references and attribution to match Maven.""" + expected_version = managed_jackson_version() + sbom_text = SBOM_PATH.read_text(encoding="utf-8") + sbom = json.loads(sbom_text) + jackson_components = [ + item + for item in sbom.get("components", []) + if str(item.get("group", "")).startswith("com.fasterxml.jackson") + and item.get("name") != "jackson-annotations" + ] + + self.assertGreater(len(jackson_components), 0) + self.assertEqual( + {expected_version}, + {str(item.get("version", "")) for item in jackson_components}, + "every patch-versioned Jackson module must match jackson-bom.version", + ) + for item in jackson_components: + coordinate = f"{item.get('group')}:{item.get('name')}" + self.assertIn( + f"@{expected_version}", + str(item.get("purl", "")), + f"{coordinate} purl must identify the reviewed Jackson version", + ) + self.assertIn( + f"@{expected_version}", + str(item.get("bom-ref", "")), + f"{coordinate} bom-ref must identify the reviewed Jackson version", + ) + + self.assertNotIn("2.22.1", sbom_text) + actual_attribution = ATTRIBUTION_PATH.read_text(encoding="utf-8") + jackson_rows = [ + line + for line in actual_attribution.splitlines() + if line.startswith("| com.fasterxml.jackson.") + and ":jackson-annotations |" not in line + ] + self.assertEqual(len(jackson_components), len(jackson_rows)) + self.assertTrue( + all(f"| {expected_version} |" in line for line in jackson_rows), + "every patch-versioned Jackson attribution row must use the reviewed version", + ) + if __name__ == "__main__": unittest.main() diff --git a/src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java b/src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java index 2c3f0f2b5..ce00abbe0 100644 --- a/src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java +++ b/src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java @@ -53,6 +53,18 @@ void pomPinsPatchedNettyLineForReactiveHttpServing() throws Exception { ); } + @Test + void pomPinsJacksonLineWithBoundedDeserializationWork() throws Exception { + Document document = parsedPom(); + Element properties = (Element) document.getElementsByTagName("properties").item(0); + + assertEquals( + "2.22.3", + directChildTextOf(properties, "jackson-bom.version"), + "Jackson 2.22.3 fixes CVE-2026-91776 and CVE-2026-91777 denial-of-service paths" + ); + } + @Test void mavenVerifyGeneratesWarningFreePublicApiJavadocs() throws Exception { Document document = parsedPom(); From bf121dffff24e771739f50b9e2cc7961459670a2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 1 Oct 2026 15:22:06 +0900 Subject: [PATCH 08/19] docs(gaps): bind Jackson repair to exact evidence --- docs/product-technical-gap-baseline.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index d5c672c5b..5ed8353b5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -23,16 +23,16 @@ merge. A queued, skipped, stale-head, or fail-closed Check is not passing. | --- | --- | --- | | Product behavior | `mvn -B --no-transfer-progress verify`; zero test failures, errors, or skips; production line and branch coverage 100% | Required on exact repair head | | Public contract | Java 21 compilation and public Javadocs complete with warning and deprecation budget 0 | Required on exact repair head | -| Supply chain | Trivy/OSV/SAST report no actionable finding; committed SBOM and attribution match the resolved dependency graph | Repair in progress on #503 | +| Supply chain | Trivy/OSV/SAST report no actionable finding; committed SBOM and attribution match the resolved dependency graph | #503 Security `36824043955` and SAST `36824043968` GREEN | | Review admission | Independent approval and all required terminal Checks bind to the current head | Not yet satisfied | ## Gap and action ledger | Gap | Exact evidence and RCA | Action | Status | | --- | --- | --- | --- | -| Jackson denial-of-service exposure | clearfolio#660 head `2a6b0b621e075da224210c0ca78db344af5dea52`, Security run `36778995059`, Trivy job `110104143035`: CVE-2026-91776 and CVE-2026-91777 in `jackson-databind` 2.22.2 | Repair canonical dependency owner #503 with Jackson 2.22.3, a downgrade regression test, refreshed SBOM/attribution, and removal of the expired OSV exception | In progress | -| Historical evidence drift | #503 review found its original one-file 2.22.2 bump left SBOM, attribution, POM rationale, and expired ignore stale | Keep dependency version and buyer evidence in one PR; run attribution/license drift checks | In progress | -| Merge admission | #503 is Draft and has unresolved review findings; #660 is Ready but fails Security | Keep both deltas open; do not merge until #503 is GREEN and independently reviewed, then ordinarily restack consumers | Hold | +| Jackson denial-of-service exposure | clearfolio#660 head `2a6b0b621e075da224210c0ca78db344af5dea52`, Security run `36778995059`, Trivy job `110104143035`: CVE-2026-91776 and CVE-2026-91777 in `jackson-databind` 2.22.2 | Repair canonical dependency owner #503 with Jackson 2.22.3, a downgrade regression test, refreshed SBOM/attribution, and removal of the expired OSV exception | Resolved at source commit `3e9ba61e1aa2a903e920cf832f9daa5467f2e166`; CI `36824043863`, Security `36824043955`, SAST `36824043968`, and fuzz `36824043977` GREEN | +| Historical evidence drift | #503 review found its original one-file 2.22.2 bump left SBOM, attribution, POM rationale, and expired ignore stale | Keep dependency version and buyer evidence in one PR; run attribution/license drift checks | Resolved; both review threads closed and local evidence contracts GREEN | +| Merge admission | #503 is Ready after product/security/fuzz validation; its Draft CodeQL run `36824043888` was skipped. #660 is Draft on the vulnerable predecessor head. | Obtain a non-skipped CodeQL verdict and independent approval on the current #503 head, then ordinarily integrate it into consumers and revalidate their new heads | Hold | ## Decision traceability From fd020bdba3b69a4f40bd6e3547722d479da77bb1 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:33:32 +0000 Subject: [PATCH 09/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AdminController 내 admin 권한 보호 로직 추가 불필요 파일 삭제 및 포맷팅 처리 --- .../viewer/controller/AdminController.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/clearfolio/viewer/controller/AdminController.java b/src/main/java/com/clearfolio/viewer/controller/AdminController.java index 4cc5840a4..cfb296e1e 100644 --- a/src/main/java/com/clearfolio/viewer/controller/AdminController.java +++ b/src/main/java/com/clearfolio/viewer/controller/AdminController.java @@ -41,12 +41,14 @@ public class AdminController { /** * Creates a controller for admin operations. * - * @param conversionService conversion service - * @param tenantAccessService access control service + * @param conversionServiceInjected conversion service + * @param tenantAccessServiceInjected access control service */ - public AdminController(final DocumentConversionService conversionService, final TenantAccessService tenantAccessService) { - this.conversionService = conversionService; - this.tenantAccessService = tenantAccessService; + public AdminController( + final DocumentConversionService conversionServiceInjected, + final TenantAccessService tenantAccessServiceInjected) { + this.conversionService = conversionServiceInjected; + this.tenantAccessService = tenantAccessServiceInjected; } /** @@ -84,7 +86,9 @@ public AdminJobListResponse getAllJobs( * @return no content on success */ @DeleteMapping("/api/v1/admin/convert/jobs/{jobId}") - public ResponseEntity deleteJob(@PathVariable final UUID jobId, @RequestHeader final HttpHeaders headers) { + public ResponseEntity deleteJob( + @PathVariable final UUID jobId, + @RequestHeader final HttpHeaders headers) { tenantAccessService.require(headers, "admin:operate"); conversionService.deleteJob(jobId); return ResponseEntity.noContent().build(); @@ -98,14 +102,19 @@ public ResponseEntity deleteJob(@PathVariable final UUID jobId, @RequestHe * @return accepted response on success */ @PostMapping("/api/v1/admin/convert/jobs/{jobId}/retry") - public ResponseEntity retryDeadLettered(@PathVariable final UUID jobId, @RequestHeader final HttpHeaders headers) { + public ResponseEntity retryDeadLettered( + @PathVariable final UUID jobId, + @RequestHeader final HttpHeaders headers) { tenantAccessService.require(headers, "admin:operate"); - RetryDeadLetterResult result = conversionService.retryDeadLettered(jobId, "admin"); + RetryDeadLetterResult result = conversionService.retryDeadLettered( + jobId, "admin"); if (result == RetryDeadLetterResult.NOT_FOUND) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "job not found"); + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, "job not found"); } if (result == RetryDeadLetterResult.NOT_ELIGIBLE) { - throw new ResponseStatusException(HttpStatus.CONFLICT, "job is not eligible for retry"); + throw new ResponseStatusException( + HttpStatus.CONFLICT, "job is not eligible for retry"); } return ResponseEntity.accepted().build(); } From 6e4934cf332a426f7904887b84afc8e4f49403f7 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:37:36 +0000 Subject: [PATCH 10/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From f2a3f0253c569ba4ce41d2e4c56b78a0375cdb9f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:41:36 +0000 Subject: [PATCH 11/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From d76c5c3c56e2c29147af82013cb8a5f488c39d05 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:48:01 +0000 Subject: [PATCH 12/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From 704b7176f02c2aff0ece7976170276eb2cb66779 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:53:23 +0000 Subject: [PATCH 13/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From fe3c35f2aeea927f1275c0365451df97383d2e8b Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:57:39 +0000 Subject: [PATCH 14/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From af51b45632c865d5dd0eadb125fc5df4029dc816 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:05:20 +0000 Subject: [PATCH 15/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From 5d2bd73cd809217e2d7bfa3ee7395e869c70fba6 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:12:20 +0000 Subject: [PATCH 16/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From 72943653666cf6e5d86ea2e5c954c32c40698eed Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:16:35 +0000 Subject: [PATCH 17/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From 673660826d6689943060e1f29bb5b6b57d7e2fea Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:36:38 +0000 Subject: [PATCH 18/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다. From 6ab3c7d0a1b759fb8eb9751ff096f1bdfaf6a82b Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:58:02 +0000 Subject: [PATCH 19/19] =?UTF-8?q?Admin=20API=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빈 커밋을 통해 CI를 재트리거합니다.