From 2331cbf0a7d2edfeed9310d11f99bcd25a6b4165 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Wed, 10 Jun 2026 09:59:34 +0200 Subject: [PATCH 01/13] Publish SNAPSHOT artifacts during PR builder execution --- .github/workflows/build.yml | 6 +++ CLAUDE.md | 89 +++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 CLAUDE.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d48f197a1..35c3dcccd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,3 +25,9 @@ jobs: uses: gradle/gradle-build-action@v2.4.2 with: arguments: build jacocoTestReport jacocoTestCoverageVerification + + - name: Publish SNAPSHOT artifacts + if: github.event_name == 'pull_request' + uses: gradle/gradle-build-action@v2.4.2 + with: + arguments: publishToSonatype -PmavenRepoUsername=${{ secrets.MAVEN_USERNAME }} -PmavenRepoPassword=${{ secrets.MAVEN_PASSWORD }} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..efff0dfc9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,89 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build & Test Commands + +```bash +# Full build (default task) +./gradlew build + +# Build with coverage reports (used in CI) +./gradlew build jacocoTestReport jacocoTestCoverageVerification + +# Run all tests +./gradlew test + +# Run tests for a specific module +./gradlew :symphony-bdk-core:test + +# Run a single test class or method +./gradlew :symphony-bdk-core:test --tests "com.symphony.bdk.core.service.MessageServiceTest" +./gradlew :symphony-bdk-core:test --tests "com.symphony.bdk.core.service.MessageServiceTest.shouldSendMessage" + +# Publish to local Maven repository +./gradlew publishToMavenLocal + +# OWASP dependency vulnerability check (requires NVD_API_KEY env var for reasonable speed) +./gradlew dependencyCheck + +# Check for dependency updates +./gradlew dependencyUpdates +``` + +## Module Architecture + +The project is a multi-module Gradle build. All modules import the `symphony-bdk-bom` platform for dependency version alignment. + +### Core modules + +| Module | Role | +|--------|------| +| `symphony-bdk-bom` | Bill of Materials — version constraints for all dependencies | +| `symphony-bdk-config` | Loads and parses `bdk-config.yaml` into `BdkConfig` | +| `symphony-bdk-core` | Entry point, services, auth, datafeed loop, activity framework | +| `symphony-bdk-extension-api` | SPI for third-party BDK extensions | + +### Abstraction layers with multiple implementations + +| API module | Implementations | +|------------|-----------------| +| `symphony-bdk-http:symphony-bdk-http-api` | `symphony-bdk-http-jersey2`, `symphony-bdk-http-webclient` | +| `symphony-bdk-template:symphony-bdk-template-api` | `symphony-bdk-template-freemarker`, `symphony-bdk-template-handlebars` | + +### Spring Boot integration + +`symphony-bdk-spring:symphony-bdk-core-spring-boot-starter` and `symphony-bdk-app-spring-boot-starter` wrap the core in auto-configured Spring beans. These do not change core behaviour — they only wire configuration and lifecycle. + +### Test utilities + +`symphony-bdk-test:symphony-bdk-test-jupiter` provides JUnit 5 extensions; `symphony-bdk-test-spring-boot` wraps them for Spring context tests. + +## symphony-bdk-core Internals + +`SymphonyBdk` is the user-facing entry point. It is built via `SymphonyBdkBuilder` and owns a `ServiceFactory` that instantiates all services lazily. + +Key sub-packages: + +- **`auth`** — session authentication and JWT token management (`AuthSession`, `BotAuthenticator`, `OboAuthenticator`) +- **`service`** — one service class per Symphony API domain (`MessageService`, `StreamService`, `UserService`, `DatafeedService`, etc.) +- **`activity`** — activity framework: `ActivityRegistry` dispatches `DatafeedEvent`s to registered `AbstractActivity` handlers (command, form reply, room events) +- **`retry`** — Resilience4j-backed retry decorators applied to all HTTP calls +- **`client`** — HTTP client load-balancing and exception translation + +OBO (On-Behalf-Of) flows are surfaced through `OboServices` / `OboService`, which mirror the main services but authenticate with a delegated session. + +## Build Conventions (`buildSrc/`) + +Four Groovy convention plugins used by sub-modules: + +- `bdk.java-common-conventions` — Java 17, UTF-8, JaCoCo, JUnit Platform, sources+javadoc jars, BOM platform import +- `bdk.java-library-conventions` — extends common + `java-library` plugin (used by all published libs) +- `bdk.java-publish-conventions` — `maven-publish` + `signing`; signing is **only required for release versions** (`isReleaseVersion = !version.endsWith('SNAPSHOT')`) +- `bdk.java-codegen-conventions` — OpenAPI Generator (Jersey2, Java 8 date library) reading `src/main/resources/api.yaml`; generated sources land in `build/generated/openapi` + +## Publishing + +Snapshots are published to Sonatype OSSRH via the `publishToSonatype` Gradle task (nexus-publish-plugin). This task is automatically triggered in CI on every PR build. Releases use `publishToSonatype closeAndReleaseStagingRepository` and are triggered by a GitHub Release event. + +Credentials are passed as Gradle properties: `-PmavenRepoUsername` and `-PmavenRepoPassword`. From a350e4bb4a0faedf79bb83df3b5cb9b14f86ab31 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Wed, 10 Jun 2026 10:20:11 +0200 Subject: [PATCH 02/13] Update Gradle wrapper validation to use gradle/actions/wrapper-validation@v4 The old gradle/wrapper-validation-action is deprecated and was causing CI failures. --- .github/workflows/gradle-wrapper-validation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 611ae04b8..332400905 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -9,4 +9,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 + - uses: gradle/actions/wrapper-validation@v4 From 21f422e448c73e02e57fb247bfa3007354b04c79 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Wed, 10 Jun 2026 10:54:28 +0200 Subject: [PATCH 03/13] Fix SNAPSHOT repository URL for Sonatype Central Portal --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 547a5dbd3..c8edbbc9e 100644 --- a/build.gradle +++ b/build.gradle @@ -49,7 +49,7 @@ nexusPublishing { username = project.ext.mavenRepoUsername password = project.ext.mavenRepoPassword nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) - snapshotRepositoryUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/content/repositories/snapshots/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) } } } From 7c38d22fea74817a6e1929652648840114e53310 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Wed, 10 Jun 2026 17:03:40 +0200 Subject: [PATCH 04/13] Do not try to publish snapshot in case of a fork PR --- .github/workflows/build.yml | 2 +- AGENTS.md | 152 ++++++++++++++++++++++++++++++++++++ CLAUDE.md | 63 +++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 AGENTS.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 35c3dcccd..d233dc0da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: arguments: build jacocoTestReport jacocoTestCoverageVerification - name: Publish SNAPSHOT artifacts - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' && secrets.MAVEN_USERNAME != '' && secrets.MAVEN_PASSWORD != '' uses: gradle/gradle-build-action@v2.4.2 with: arguments: publishToSonatype -PmavenRepoUsername=${{ secrets.MAVEN_USERNAME }} -PmavenRepoPassword=${{ secrets.MAVEN_PASSWORD }} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..2cb03ee50 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,152 @@ +# AGENTS.md + +This file provides guidance to AI Coding Assistants when working with code in this repository. + +## Build & Test Commands + +```bash +# Full build (default task) +./gradlew build + +# Build with coverage reports (used in CI) +./gradlew build jacocoTestReport jacocoTestCoverageVerification + +# Run all tests +./gradlew test + +# Run tests for a specific module +./gradlew :symphony-bdk-core:test + +# Run a single test class or method +./gradlew :symphony-bdk-core:test --tests "com.symphony.bdk.core.service.MessageServiceTest" +./gradlew :symphony-bdk-core:test --tests "com.symphony.bdk.core.service.MessageServiceTest.shouldSendMessage" + +# Publish to local Maven repository +./gradlew publishToMavenLocal + +# OWASP dependency vulnerability check (requires NVD_API_KEY env var for reasonable speed) +./gradlew dependencyCheck + +# Check for dependency updates +./gradlew dependencyUpdates +``` + +## Module Architecture + +The project is a multi-module Gradle build. All modules import the `symphony-bdk-bom` platform for dependency version alignment. + +### Core modules + +| Module | Role | +|--------|------| +| `symphony-bdk-bom` | Bill of Materials — version constraints for all dependencies | +| `symphony-bdk-config` | Loads and parses `bdk-config.yaml` into `BdkConfig` | +| `symphony-bdk-core` | Entry point, services, auth, datafeed loop, activity framework | +| `symphony-bdk-extension-api` | SPI for third-party BDK extensions | + +### Abstraction layers with multiple implementations + +| API module | Implementations | +|------------|-----------------| +| `symphony-bdk-http:symphony-bdk-http-api` | `symphony-bdk-http-jersey2`, `symphony-bdk-http-webclient` | +| `symphony-bdk-template:symphony-bdk-template-api` | `symphony-bdk-template-freemarker`, `symphony-bdk-template-handlebars` | + +### Spring Boot integration + +`symphony-bdk-spring:symphony-bdk-core-spring-boot-starter` and `symphony-bdk-app-spring-boot-starter` wrap the core in auto-configured Spring beans. These do not change core behaviour — they only wire configuration and lifecycle. + +### Test utilities + +`symphony-bdk-test:symphony-bdk-test-jupiter` provides JUnit 5 extensions; `symphony-bdk-test-spring-boot` wraps them for Spring context tests. + +## symphony-bdk-core Internals + +`SymphonyBdk` is the user-facing entry point. It is built via `SymphonyBdkBuilder` and owns a `ServiceFactory` that instantiates all services lazily. + +Key sub-packages: + +- **`auth`** — session authentication and JWT token management (`AuthSession`, `BotAuthenticator`, `OboAuthenticator`) +- **`service`** — one service class per Symphony API domain (`MessageService`, `StreamService`, `UserService`, `DatafeedService`, etc.) +- **`activity`** — activity framework: `ActivityRegistry` dispatches `DatafeedEvent`s to registered `AbstractActivity` handlers (command, form reply, room events) +- **`retry`** — Resilience4j-backed retry decorators applied to all HTTP calls +- **`client`** — HTTP client load-balancing and exception translation + +OBO (On-Behalf-Of) flows are surfaced through `OboServices` / `OboService`, which mirror the main services but authenticate with a delegated session. + +## Build Conventions (`buildSrc/`) + +Four Groovy convention plugins used by sub-modules: + +- `bdk.java-common-conventions` — Java 17, UTF-8, JaCoCo, JUnit Platform, sources+javadoc jars, BOM platform import +- `bdk.java-library-conventions` — extends common + `java-library` plugin (used by all published libs) +- `bdk.java-publish-conventions` — `maven-publish` + `signing`; signing is **only required for release versions** (`isReleaseVersion = !version.endsWith('SNAPSHOT')`) +- `bdk.java-codegen-conventions` — OpenAPI Generator (Jersey2, Java 8 date library) reading `src/main/resources/api.yaml`; generated sources land in `build/generated/openapi` + +## Publishing + +Snapshots are published to Sonatype OSSRH via the `publishToSonatype` Gradle task (nexus-publish-plugin). This task is automatically triggered in CI on every PR build. Releases use `publishToSonatype closeAndReleaseStagingRepository` and are triggered by a GitHub Release event. + +Credentials are passed as Gradle properties: `-PmavenRepoUsername` and `-PmavenRepoPassword`. + +# context-mode — MANDATORY routing rules + +You have context-mode MCP tools available. These rules are NOT optional — they protect your context window from flooding. A single unrouted command can dump 56 KB into context and waste the entire session. + +## BLOCKED commands — do NOT attempt these + +### curl / wget — BLOCKED +Any Bash command containing `curl` or `wget` is intercepted and replaced with an error message. Do NOT retry. +Instead use: +- `ctx_fetch_and_index(url, source)` to fetch and index web pages +- `ctx_execute(language: "javascript", code: "const r = await fetch(...)")` to run HTTP calls in sandbox + +### Inline HTTP — BLOCKED +Any Bash command containing `fetch('http`, `requests.get(`, `requests.post(`, `http.get(`, or `http.request(` is intercepted and replaced with an error message. Do NOT retry with Bash. +Instead use: +- `ctx_execute(language, code)` to run HTTP calls in sandbox — only stdout enters context + +### WebFetch — BLOCKED +WebFetch calls are denied entirely. The URL is extracted and you are told to use `ctx_fetch_and_index` instead. +Instead use: +- `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` to query the indexed content + +## REDIRECTED tools — use sandbox equivalents + +### Bash (>20 lines output) +Bash is ONLY for: `git`, `mkdir`, `rm`, `mv`, `cd`, `ls`, `npm install`, `pip install`, and other short-output commands. +For everything else, use: +- `ctx_batch_execute(commands, queries)` — run multiple commands + search in ONE call +- `ctx_execute(language: "shell", code: "...")` — run in sandbox, only stdout enters context + +### Read (for analysis) +If you are reading a file to **Edit** it → Read is correct (Edit needs content in context). +If you are reading to **analyze, explore, or summarize** → use `ctx_execute_file(path, language, code)` instead. Only your printed summary enters context. The raw file content stays in the sandbox. + +### Grep (large results) +Grep results can flood context. Use `ctx_execute(language: "shell", code: "grep ...")` to run searches in sandbox. Only your printed summary enters context. + +## Tool selection hierarchy + +1. **GATHER**: `ctx_batch_execute(commands, queries)` — Primary tool. Runs all commands, auto-indexes output, returns search results. ONE call replaces 30+ individual calls. +2. **FOLLOW-UP**: `ctx_search(queries: ["q1", "q2", ...])` — Query indexed content. Pass ALL questions as array in ONE call. +3. **PROCESSING**: `ctx_execute(language, code)` | `ctx_execute_file(path, language, code)` — Sandbox execution. Only stdout enters context. +4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — Fetch, chunk, index, query. Raw HTML never enters context. +5. **INDEX**: `ctx_index(content, source)` — Store content in FTS5 knowledge base for later search. + +## Subagent routing + +When spawning subagents (Agent/Task tool), the routing block is automatically injected into their prompt. Bash-type subagents are upgraded to general-purpose so they have access to MCP tools. You do NOT need to manually instruct subagents about context-mode. + +## Output constraints + +- Keep responses under 500 words. +- Write artifacts (code, configs, PRDs) to FILES — never return them as inline text. Return only: file path + 1-line description. +- When indexing content, use descriptive source labels so others can `ctx_search(source: "label")` later. + +## ctx commands + +| Command | Action | +|---------|--------| +| `ctx stats` | Call the `ctx_stats` MCP tool and display the full output verbatim | +| `ctx doctor` | Call the `ctx_doctor` MCP tool, run the returned shell command, display as checklist | +| `ctx upgrade` | Call the `ctx_upgrade` MCP tool, run the returned shell command, display as checklist | diff --git a/CLAUDE.md b/CLAUDE.md index efff0dfc9..04eeeb34f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,3 +87,66 @@ Four Groovy convention plugins used by sub-modules: Snapshots are published to Sonatype OSSRH via the `publishToSonatype` Gradle task (nexus-publish-plugin). This task is automatically triggered in CI on every PR build. Releases use `publishToSonatype closeAndReleaseStagingRepository` and are triggered by a GitHub Release event. Credentials are passed as Gradle properties: `-PmavenRepoUsername` and `-PmavenRepoPassword`. + +# context-mode — MANDATORY routing rules + +You have context-mode MCP tools available. These rules are NOT optional — they protect your context window from flooding. A single unrouted command can dump 56 KB into context and waste the entire session. + +## BLOCKED commands — do NOT attempt these + +### curl / wget — BLOCKED +Any Bash command containing `curl` or `wget` is intercepted and replaced with an error message. Do NOT retry. +Instead use: +- `ctx_fetch_and_index(url, source)` to fetch and index web pages +- `ctx_execute(language: "javascript", code: "const r = await fetch(...)")` to run HTTP calls in sandbox + +### Inline HTTP — BLOCKED +Any Bash command containing `fetch('http`, `requests.get(`, `requests.post(`, `http.get(`, or `http.request(` is intercepted and replaced with an error message. Do NOT retry with Bash. +Instead use: +- `ctx_execute(language, code)` to run HTTP calls in sandbox — only stdout enters context + +### WebFetch — BLOCKED +WebFetch calls are denied entirely. The URL is extracted and you are told to use `ctx_fetch_and_index` instead. +Instead use: +- `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` to query the indexed content + +## REDIRECTED tools — use sandbox equivalents + +### Bash (>20 lines output) +Bash is ONLY for: `git`, `mkdir`, `rm`, `mv`, `cd`, `ls`, `npm install`, `pip install`, and other short-output commands. +For everything else, use: +- `ctx_batch_execute(commands, queries)` — run multiple commands + search in ONE call +- `ctx_execute(language: "shell", code: "...")` — run in sandbox, only stdout enters context + +### Read (for analysis) +If you are reading a file to **Edit** it → Read is correct (Edit needs content in context). +If you are reading to **analyze, explore, or summarize** → use `ctx_execute_file(path, language, code)` instead. Only your printed summary enters context. The raw file content stays in the sandbox. + +### Grep (large results) +Grep results can flood context. Use `ctx_execute(language: "shell", code: "grep ...")` to run searches in sandbox. Only your printed summary enters context. + +## Tool selection hierarchy + +1. **GATHER**: `ctx_batch_execute(commands, queries)` — Primary tool. Runs all commands, auto-indexes output, returns search results. ONE call replaces 30+ individual calls. +2. **FOLLOW-UP**: `ctx_search(queries: ["q1", "q2", ...])` — Query indexed content. Pass ALL questions as array in ONE call. +3. **PROCESSING**: `ctx_execute(language, code)` | `ctx_execute_file(path, language, code)` — Sandbox execution. Only stdout enters context. +4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — Fetch, chunk, index, query. Raw HTML never enters context. +5. **INDEX**: `ctx_index(content, source)` — Store content in FTS5 knowledge base for later search. + +## Subagent routing + +When spawning subagents (Agent/Task tool), the routing block is automatically injected into their prompt. Bash-type subagents are upgraded to general-purpose so they have access to MCP tools. You do NOT need to manually instruct subagents about context-mode. + +## Output constraints + +- Keep responses under 500 words. +- Write artifacts (code, configs, PRDs) to FILES — never return them as inline text. Return only: file path + 1-line description. +- When indexing content, use descriptive source labels so others can `ctx_search(source: "label")` later. + +## ctx commands + +| Command | Action | +|---------|--------| +| `ctx stats` | Call the `ctx_stats` MCP tool and display the full output verbatim | +| `ctx doctor` | Call the `ctx_doctor` MCP tool, run the returned shell command, display as checklist | +| `ctx upgrade` | Call the `ctx_upgrade` MCP tool, run the returned shell command, display as checklist | From 240b9660c9b9ad21f4a6546868b045c104d14b6e Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Wed, 10 Jun 2026 17:15:40 +0200 Subject: [PATCH 05/13] Restart PR Builder --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d233dc0da..9cd96bd31 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,3 +31,4 @@ jobs: uses: gradle/gradle-build-action@v2.4.2 with: arguments: publishToSonatype -PmavenRepoUsername=${{ secrets.MAVEN_USERNAME }} -PmavenRepoPassword=${{ secrets.MAVEN_PASSWORD }} + From 82aa285ee610d465e2cb3d6a08ea4f5cf03625f8 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Wed, 10 Jun 2026 17:26:40 +0200 Subject: [PATCH 06/13] Cache OWASP Dependency Check database in CI --- .github/workflows/cve-scanning-gradle.yml | 7 +++++++ build.gradle | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cve-scanning-gradle.yml b/.github/workflows/cve-scanning-gradle.yml index 4687e704f..4dc47ad4f 100644 --- a/.github/workflows/cve-scanning-gradle.yml +++ b/.github/workflows/cve-scanning-gradle.yml @@ -24,6 +24,13 @@ jobs: uses: gradle/actions/setup-gradle@v3 with: cache-read-only: ${{ github.ref != 'refs/heads/main' }} + - name: Cache OWASP Dependency Check Database + uses: actions/cache@v4 + with: + path: ~/.gradle/dependency-check-data + key: ${{ runner.os }}-owasp-db-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-owasp-db- - name: Build with Gradle # The build action is not strictly necessary as dependencyCheckAggregate will build the project # but it's good practice to have it as a separate step to catch build errors earlier. diff --git a/build.gradle b/build.gradle index c8edbbc9e..48618be98 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ dependencyCheck { failBuildOnCVSS=5 suppressionFile="./allow-list.xml" data { - directory = "${buildDir}/dependency-check-data" + directory = "${System.getProperty('user.home')}/.gradle/dependency-check-data" } nvd { apiKey = System.getenv("NVD_API_KEY") ?: (project.findProperty("dependencyCheck.nvd.apiKey") ?: "") From 3e73308948206134dbaabdcc18ec0b93cef3d724 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Mon, 15 Jun 2026 15:57:42 +0200 Subject: [PATCH 07/13] Suppress new Netty and Spring CVEs pending upstream fixes CVE-2026-42582 (Netty 4.1.134.Final) and CVE-2026-41840/41841/41842/41843/41850/41851 (Spring Framework 6.2.18 via spring-boot-dependencies:3.5.14) have no fixed release yet. Suppressed temporarily to unblock CI; a follow-up PR will bump the dependencies once fixed versions are available. --- allow-list.xml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/allow-list.xml b/allow-list.xml index bce70d1e4..48914109c 100644 --- a/allow-list.xml +++ b/allow-list.xml @@ -39,4 +39,26 @@ GHSA-7rx3-28cr-v5wh GHSA-442j-39wm-28r2 + + + ^pkg:maven/io\.netty/.*@.*$ + CVE-2026-42582 + + + + ^pkg:maven/org\.springframework/.*@.*$ + CVE-2026-41840 + CVE-2026-41841 + CVE-2026-41842 + CVE-2026-41843 + CVE-2026-41850 + CVE-2026-41851 + From c1892929b844ee4f480f25d84f646eaba113f999 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Mon, 15 Jun 2026 16:36:42 +0200 Subject: [PATCH 08/13] Upgrade to Spring Boot 3.5.15 to fix Netty and Spring CVEs 3.5.15 ships Netty 4.1.135.Final (fixes CVE-2026-42582 and 18 additional Netty CVEs) and Spring Framework 6.2.19 (fixes CVE-2026-41840 through CVE-2026-41851). Also ships Tomcat 10.1.55 so the explicit overrides for Netty and Tomcat are no longer needed. Reverts the CVE suppressions added in the previous commit. --- allow-list.xml | 22 ---------------------- symphony-bdk-bom/build.gradle | 9 +-------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/allow-list.xml b/allow-list.xml index 48914109c..bce70d1e4 100644 --- a/allow-list.xml +++ b/allow-list.xml @@ -39,26 +39,4 @@ GHSA-7rx3-28cr-v5wh GHSA-442j-39wm-28r2 - - - ^pkg:maven/io\.netty/.*@.*$ - CVE-2026-42582 - - - - ^pkg:maven/org\.springframework/.*@.*$ - CVE-2026-41840 - CVE-2026-41841 - CVE-2026-41842 - CVE-2026-41843 - CVE-2026-41850 - CVE-2026-41851 - diff --git a/symphony-bdk-bom/build.gradle b/symphony-bdk-bom/build.gradle index aeb823a76..c2d454eec 100644 --- a/symphony-bdk-bom/build.gradle +++ b/symphony-bdk-bom/build.gradle @@ -16,15 +16,13 @@ repositories { dependencies { // import Spring Boot's BOM - api platform('org.springframework.boot:spring-boot-dependencies:3.5.14') + api platform('org.springframework.boot:spring-boot-dependencies:3.5.15') // import Jackson's BOM api platform('com.fasterxml.jackson:jackson-bom:2.18.2') // import Jersey's BOM api platform('org.glassfish.jersey:jersey-bom:3.1.9') // import Log4j's BOM api platform('org.apache.logging.log4j:log4j-bom:2.26.0') - // override Netty (Spring Boot 3.5.14 ships 4.1.132 which is still vulnerable to CVE-2026-41417) - api platform('io.netty:netty-bom:4.1.134.Final') // define all our dependencies versions constraints { @@ -45,11 +43,6 @@ dependencies { // External dependencies - // override Tomcat (Spring Boot 3.5.14 ships 10.1.54 which is vulnerable to multiple CVEs) - api 'org.apache.tomcat.embed:tomcat-embed-core:10.1.55' - api 'org.apache.tomcat.embed:tomcat-embed-el:10.1.55' - api 'org.apache.tomcat.embed:tomcat-embed-websocket:10.1.55' - api 'org.apiguardian:apiguardian-api:1.1.2' api 'org.slf4j:slf4j-api:2.0.9' From f962e7238c91251c540d58a04674480ef77a7739 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Tue, 16 Jun 2026 11:02:38 +0200 Subject: [PATCH 09/13] Suppress CVE-2026-42582 for Netty pending upstream fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Netty 4.1.135.Final is the last 4.1.x release and Spring Boot 3.5.15 is the last 3.5.x release — no patched version is available upstream. --- allow-list.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/allow-list.xml b/allow-list.xml index bce70d1e4..54c564d08 100644 --- a/allow-list.xml +++ b/allow-list.xml @@ -23,6 +23,15 @@ ^pkg:maven/org\.jetbrains\.kotlin/kotlin-stdlib(-jdk7|-jdk8|-common)?@.*$ CVE-2020-29582 + + + ^pkg:maven/io\.netty/netty.*@.*$ + CVE-2026-42582 + Date: Tue, 16 Jun 2026 11:41:25 +0200 Subject: [PATCH 10/13] Improving CVE Scan exec time --- .github/workflows/cve-scanning-gradle.yml | 8 +------- build.gradle | 15 ++++++++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cve-scanning-gradle.yml b/.github/workflows/cve-scanning-gradle.yml index 4dc47ad4f..42cf4e14c 100644 --- a/.github/workflows/cve-scanning-gradle.yml +++ b/.github/workflows/cve-scanning-gradle.yml @@ -31,13 +31,7 @@ jobs: key: ${{ runner.os }}-owasp-db-${{ github.run_id }} restore-keys: | ${{ runner.os }}-owasp-db- - - name: Build with Gradle - # The build action is not strictly necessary as dependencyCheckAggregate will build the project - # but it's good practice to have it as a separate step to catch build errors earlier. - run: ./gradlew build --no-daemon - name: CVEs - # Using --no-daemon is a good practice in CI environments - # It prevents potential conflicts or statefulness between job runs. env: NVD_API_KEY: ${{ secrets.NVD_API_KEY }} - run: ./gradlew dependencyCheckAggregate --no-daemon -PdependencyCheck.nvd.apiKey=${{ secrets.NVD_API_KEY }} + run: ./gradlew dependencyCheckAggregate --no-daemon diff --git a/build.gradle b/build.gradle index 48618be98..8ffa07ae6 100644 --- a/build.gradle +++ b/build.gradle @@ -61,11 +61,12 @@ repositories { dependencyCheck { failBuildOnCVSS=5 suppressionFile="./allow-list.xml" - data { - directory = "${System.getProperty('user.home')}/.gradle/dependency-check-data" - } - nvd { - apiKey = System.getenv("NVD_API_KEY") ?: (project.findProperty("dependencyCheck.nvd.apiKey") ?: "") - delay = apiKey ? 2000 : 16000 - } + data.directory = "${System.getProperty('user.home')}/.gradle/dependency-check-data" + + nvd.apiKey = System.getenv("NVD_API_KEY") ?: (project.findProperty("dependencyCheck.nvd.apiKey") ?: "") + nvd.delay = System.getenv("NVD_API_KEY") ? 1000 : 16000 + + analyzers.assemblyEnabled = false + analyzers.retirejs.enabled = false + analyzers.nodeAudit.enabled = false } From 69dae87c3561139e746fedc88b1514bccd43cc87 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Tue, 16 Jun 2026 15:25:34 +0200 Subject: [PATCH 11/13] Fix GitHub Actions workflow: secrets context not allowed in if conditions Move secrets to job-level env vars and use env context in the conditional expression to check whether Sonatype credentials are available before publishing snapshot artifacts. --- .github/workflows/build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9cd96bd31..50606e1cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,10 @@ jobs: runs-on: ubuntu-latest + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + steps: - uses: actions/checkout@v4 @@ -27,7 +31,7 @@ jobs: arguments: build jacocoTestReport jacocoTestCoverageVerification - name: Publish SNAPSHOT artifacts - if: github.event_name == 'pull_request' && secrets.MAVEN_USERNAME != '' && secrets.MAVEN_PASSWORD != '' + if: github.event_name == 'pull_request' && env.MAVEN_USERNAME != '' uses: gradle/gradle-build-action@v2.4.2 with: arguments: publishToSonatype -PmavenRepoUsername=${{ secrets.MAVEN_USERNAME }} -PmavenRepoPassword=${{ secrets.MAVEN_PASSWORD }} From 87e5f1d72fc25502291f1acff0587d5de5d846a8 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Tue, 16 Jun 2026 15:52:37 +0200 Subject: [PATCH 12/13] Publish PR-specific SNAPSHOT versions in PR builder Sets the artifact version to PR-{number}-SNAPSHOT on PR builds so each PR publishes an independently addressable SNAPSHOT. Reports the published version in the GitHub Actions step summary. --- .github/workflows/build.yml | 14 +++++++++++++- build.gradle | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50606e1cc..c56822868 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,10 @@ jobs: distribution: 'temurin' java-version: '17' + - name: Compute PR SNAPSHOT version + if: github.event_name == 'pull_request' + run: echo "SNAPSHOT_VERSION=PR-${{ github.event.pull_request.number }}-SNAPSHOT" >> $GITHUB_ENV + - name: Build with Gradle uses: gradle/gradle-build-action@v2.4.2 with: @@ -34,5 +38,13 @@ jobs: if: github.event_name == 'pull_request' && env.MAVEN_USERNAME != '' uses: gradle/gradle-build-action@v2.4.2 with: - arguments: publishToSonatype -PmavenRepoUsername=${{ secrets.MAVEN_USERNAME }} -PmavenRepoPassword=${{ secrets.MAVEN_PASSWORD }} + arguments: publishToSonatype -PprojectVersion=${{ env.SNAPSHOT_VERSION }} -PmavenRepoUsername=${{ secrets.MAVEN_USERNAME }} -PmavenRepoPassword=${{ secrets.MAVEN_PASSWORD }} + - name: Report published SNAPSHOT + if: github.event_name == 'pull_request' && env.MAVEN_USERNAME != '' + run: | + echo "## SNAPSHOT Published" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version:** \`${SNAPSHOT_VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Repository: \`https://central.sonatype.com/repository/maven-snapshots/\`" >> $GITHUB_STEP_SUMMARY diff --git a/build.gradle b/build.gradle index 8ffa07ae6..34dd94f51 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id "org.owasp.dependencycheck" version "12.2.2" } -ext.projectVersion = '3.3.0-SNAPSHOT' +ext.projectVersion = project.properties['projectVersion'] ?: '3.3.0-SNAPSHOT' ext.isReleaseVersion = !ext.projectVersion.endsWith('SNAPSHOT') ext.mavenRepoUrl = project.properties['mavenRepoUrl'] ?: 'https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/' From 4e9d26059bc71cc547d99772a8028076b89dc0c5 Mon Sep 17 00:00:00 2001 From: Thibault Pensec Date: Tue, 16 Jun 2026 16:06:07 +0200 Subject: [PATCH 13/13] Report published SNAPSHOT as PR comment instead of step summary --- .github/workflows/build.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c56822868..2952486ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,9 +42,10 @@ jobs: - name: Report published SNAPSHOT if: github.event_name == 'pull_request' && env.MAVEN_USERNAME != '' + env: + GH_TOKEN: ${{ github.token }} run: | - echo "## SNAPSHOT Published" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Version:** \`${SNAPSHOT_VERSION}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "Repository: \`https://central.sonatype.com/repository/maven-snapshots/\`" >> $GITHUB_STEP_SUMMARY + BODY="**SNAPSHOT published:** \`${SNAPSHOT_VERSION}\` + Repository: https://central.sonatype.com/repository/maven-snapshots/" + gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "${BODY}" --edit-last \ + || gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "${BODY}"