From 84adf3e14372f7f169c4ee7588337a5678008e63 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Thu, 1 Oct 2026 10:10:49 +0200 Subject: [PATCH 1/3] Replace Snyk scans with Trivy - trivy.yaml: PR gate on fixable HIGH/CRITICAL findings (was snyk.yaml with --severity-threshold=high --fail-on=upgradable), plus a job summary with all findings - scheduled-trivy.yaml: weekly code base scan, SARIF to Code scanning - scheduled-trivy-docker.yaml: weekly base image scan (OS packages, like Snyk's --exclude-app-vulns), SARIF to Code scanning - .github/trivy-lock.init.gradle: locks runtimeClasspath, so Trivy can read the Gradle dependencies - .trivyignore.yaml: empty ignore list (Trivy 0.74 needs the file to exist) - Remove .snyk. Its ignores were only meant to quiet Snyk until this move, so they are not carried over and Trivy reports those findings. Co-Authored-By: Claude Opus 5.5 --- .github/trivy-lock.init.gradle | 19 +++++ .github/workflows/scheduled-snyk.yaml | 69 ------------------- ...ocker.yaml => scheduled-trivy-docker.yaml} | 42 +++++------ .github/workflows/scheduled-trivy.yaml | 48 +++++++++++++ .github/workflows/snyk.yaml | 27 -------- .github/workflows/trivy.yaml | 50 ++++++++++++++ .snyk | 5 -- .trivyignore.yaml | 8 +++ 8 files changed, 146 insertions(+), 122 deletions(-) create mode 100644 .github/trivy-lock.init.gradle delete mode 100644 .github/workflows/scheduled-snyk.yaml rename .github/workflows/{scheduled-snyk-docker.yaml => scheduled-trivy-docker.yaml} (60%) create mode 100644 .github/workflows/scheduled-trivy.yaml delete mode 100644 .github/workflows/snyk.yaml create mode 100644 .github/workflows/trivy.yaml delete mode 100644 .snyk create mode 100644 .trivyignore.yaml diff --git a/.github/trivy-lock.init.gradle b/.github/trivy-lock.init.gradle new file mode 100644 index 00000000..cca5e61b --- /dev/null +++ b/.github/trivy-lock.init.gradle @@ -0,0 +1,19 @@ +// Writes a gradle.lockfile per project with only the classpath that ships, so Trivy scans what ships. +// It mirrors the old Snyk gate's --configuration-matching="^runtimeClasspath$". +// Usage: ./gradlew -I trivy-lock.init.gradle trivyLock --write-locks +// Android modules have no runtimeClasspath; pass -PtrivyConfigurations=releaseRuntimeClasspath (comma-separated). +allprojects { + def lockedNames = (findProperty('trivyConfigurations') ?: 'runtimeClasspath').toString().split(',')*.trim() + configurations.matching { it.name in lockedNames }.configureEach { + resolutionStrategy.activateDependencyLocking() + } + tasks.register('trivyLock') { + notCompatibleWithConfigurationCache('resolves configurations at execution time') + doLast { + if (!gradle.startParameter.writeDependencyLocks) { + throw new GradleException('Run trivyLock with --write-locks') + } + project.configurations.matching { it.name in lockedNames && it.canBeResolved }.each { it.resolve() } + } + } +} diff --git a/.github/workflows/scheduled-snyk.yaml b/.github/workflows/scheduled-snyk.yaml deleted file mode 100644 index 85407149..00000000 --- a/.github/workflows/scheduled-snyk.yaml +++ /dev/null @@ -1,69 +0,0 @@ -name: Snyk scheduled code base scan - -on: - schedule: - - cron: '0 2 * * 1' - workflow_dispatch: - -env: - MODULES: >- - [{ - 'name': 'kafka-connect-fitbit-source', - 'build_file': 'kafka-connect-fitbit-source/build.gradle.kts', - },{ - 'name': 'kafka-connect-oura-source', - 'build_file': 'kafka-connect-oura-source/build.gradle.kts', - },{ - 'name': 'kafka-connect-rest-source', - 'build_file': 'kafka-connect-rest-source/build.gradle.kts', - },{ - 'name': 'oura-library', - 'build_file': 'oura-library/build.gradle', - }] - -jobs: - prepare-matrix: - name: Prepare Matrix Output - runs-on: ubuntu-latest - permissions: {} - outputs: - modules: ${{ steps.step1.outputs.matrix }} - steps: - - name: Create Matrix Variable - id: step1 - run: echo "matrix=${{env.MODULES}}" >> $GITHUB_OUTPUT - - security: - needs: prepare-matrix - runs-on: ubuntu-latest - permissions: - contents: read - security-events: write - strategy: - matrix: - module: ${{ fromJson(needs.prepare-matrix.outputs.modules ) }} - - steps: - - uses: actions/checkout@v5 - - - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/gradle-8-jdk17@master - continue-on-error: true # To make sure that SARIF upload gets called - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - with: - args: >- - --file=${{ matrix.module.build_file }} - --configuration-matching='^runtimeClasspath$' - --fail-on=upgradable - --severity-threshold=high - --policy-path=.snyk - --org=radar-base - --sarif-file-output=snyk.sarif - - # Detected vulnerabilities will appear on Github in Security->Code_scanning_alerts tab - - name: Upload result to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: snyk.sarif - category: ${{ matrix.module.module }} diff --git a/.github/workflows/scheduled-snyk-docker.yaml b/.github/workflows/scheduled-trivy-docker.yaml similarity index 60% rename from .github/workflows/scheduled-snyk-docker.yaml rename to .github/workflows/scheduled-trivy-docker.yaml index 0794c27c..972e6bbc 100644 --- a/.github/workflows/scheduled-snyk-docker.yaml +++ b/.github/workflows/scheduled-trivy-docker.yaml @@ -1,4 +1,4 @@ -name: Snyk scheduled Docker base image scan +name: Trivy scheduled Docker base image scan on: schedule: @@ -45,32 +45,32 @@ jobs: security-events: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Lowercase image name run: | echo "DOCKER_IMAGE=${REGISTRY}/${REPOSITORY,,}/${{ matrix.image.name }}" >>${GITHUB_ENV} - - name: Run Snyk to check for vulnerabilities - continue-on-error: true # To make sure that SARIF upload gets called - uses: snyk/actions/docker@master - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + - uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 with: - image: ${{ env.DOCKER_IMAGE }} - args: >- - --file=${{ matrix.image.build_file }} - --fail-on=upgradable - --severity-threshold=high - --policy-path=.snyk - --exclude-app-vulns - --org=radar-base - --sarif-file-output=snyk.sarif + version: v0.74.0 + cache: true - # Detected vulnerabilities will appear on Github in Security->Code_scanning_alerts tab + # '--pkg-types os' only tests the base image, like Snyk's --exclude-app-vulns. + # Code base vulnerabilities are tested in scheduled-trivy.yaml. + - name: Run Trivy to check for vulnerabilities + run: >- + trivy image + --scanners vuln + --pkg-types os + --ignorefile .trivyignore.yaml + --format sarif + --output trivy.sarif + "${DOCKER_IMAGE}" + + # Detected vulnerabilities will appear on GitHub in Security -> Code scanning alerts - name: Upload result to GitHub Code Scanning - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: - sarif_file: snyk.sarif - category: ${{ matrix.image.name }} - + sarif_file: trivy.sarif + category: trivy-image-${{ matrix.image.name }} diff --git a/.github/workflows/scheduled-trivy.yaml b/.github/workflows/scheduled-trivy.yaml new file mode 100644 index 00000000..1f26b2eb --- /dev/null +++ b/.github/workflows/scheduled-trivy.yaml @@ -0,0 +1,48 @@ +name: Trivy scheduled code base scan + +on: + schedule: + - cron: '0 2 * * 1' + workflow_dispatch: + +jobs: + security: + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 + with: + distribution: temurin + java-version: 17 + + - uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 + + - name: Lock the runtime classpath for Trivy + run: ./gradlew -I .github/trivy-lock.init.gradle trivyLock --write-locks + + - uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 + with: + version: v0.74.0 + cache: true + + # All severities: Code scanning shows the severity, and low-rated findings often hide under-rated issues. + - name: Run Trivy to check for vulnerabilities + run: >- + trivy fs + --scanners vuln + --ignorefile .trivyignore.yaml + --format sarif + --output trivy.sarif + . + + # Detected vulnerabilities will appear on GitHub in Security -> Code scanning alerts + - name: Upload result to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + with: + sarif_file: trivy.sarif + category: trivy-dependencies diff --git a/.github/workflows/snyk.yaml b/.github/workflows/snyk.yaml deleted file mode 100644 index ba6c2c47..00000000 --- a/.github/workflows/snyk.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Snyk test on PR commits - -on: - pull_request: - branches: - - master - - dev - - release-* - -jobs: - security: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/gradle-8-jdk17@master - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - with: - args: >- - --all-projects - --configuration-matching="^runtimeClasspath$" - --severity-threshold=high - --fail-on=upgradable - --org=radar-base - --policy-path=.snyk diff --git a/.github/workflows/trivy.yaml b/.github/workflows/trivy.yaml new file mode 100644 index 00000000..1dcf3364 --- /dev/null +++ b/.github/workflows/trivy.yaml @@ -0,0 +1,50 @@ +name: Trivy dependency scan + +on: + pull_request: + branches: + - master + - dev + - release-* + +jobs: + security: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 + with: + distribution: temurin + java-version: 17 + + - uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0 + + # Trivy only sees Gradle dependencies through lockfiles. This locks just the shipped classpath. + - name: Lock the runtime classpath for Trivy + run: ./gradlew -I .github/trivy-lock.init.gradle trivyLock --write-locks + + - uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 + with: + version: v0.74.0 + cache: true + + # Every severity, also unfixed, so MEDIUM findings on shipped packages stay visible. + - name: List all findings + run: | + { + echo '### Trivy: all findings' + echo '```' + trivy fs --quiet --scanners vuln --ignorefile .trivyignore.yaml --format table . + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + - name: Fail on fixable HIGH/CRITICAL findings + run: >- + trivy fs + --scanners vuln + --severity HIGH,CRITICAL + --ignore-unfixed + --ignorefile .trivyignore.yaml + --exit-code 1 + . diff --git a/.snyk b/.snyk deleted file mode 100644 index 2b62034f..00000000 --- a/.snyk +++ /dev/null @@ -1,5 +0,0 @@ -# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. -version: v1.25.0 -# ignores vulnerabilities until expiry date; change duration by modifying expiry date -ignore: -patch: {} diff --git a/.trivyignore.yaml b/.trivyignore.yaml new file mode 100644 index 00000000..7d1a7225 --- /dev/null +++ b/.trivyignore.yaml @@ -0,0 +1,8 @@ +# Trivy ignore file (https://trivy.dev/latest/docs/configuration/filtering/#trivyignoreyaml). +# Every entry needs a reason and an expiry, for example: +# +# vulnerabilities: +# - id: CVE-2024-12345 +# statement: Not exploitable, because ... +# expired_at: 2027-01-01 +vulnerabilities: [] From baba30f028419833e67efb3cc1b404b6fdfc730d Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Thu, 1 Oct 2026 11:00:52 +0200 Subject: [PATCH 2/3] Lock only the dependency graph for Trivy Locking only needs the dependency graph, not the files. Resolving files fails in multi-module Android builds (radar-commons-android), and the lock script is kept the same in every RADAR-base repo. On this build the lockfile is unchanged. Co-Authored-By: Claude Opus 5.5 --- .github/trivy-lock.init.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/trivy-lock.init.gradle b/.github/trivy-lock.init.gradle index cca5e61b..bcc05019 100644 --- a/.github/trivy-lock.init.gradle +++ b/.github/trivy-lock.init.gradle @@ -13,7 +13,11 @@ allprojects { if (!gradle.startParameter.writeDependencyLocks) { throw new GradleException('Run trivyLock with --write-locks') } - project.configurations.matching { it.name in lockedNames && it.canBeResolved }.each { it.resolve() } + // Resolve only the dependency graph, which is all that locking needs. Resolving files (resolve()) + // fails in multi-module Android builds, where project dependencies offer several artifact variants. + project.configurations.matching { it.name in lockedNames && it.canBeResolved }.each { + it.incoming.resolutionResult.allComponents + } } } } From 07cbc503a3b193ac4a55ba44d601dee56aaea042 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Mon, 5 Oct 2026 15:12:44 +0200 Subject: [PATCH 3/3] Ignore Trivy findings that have no usable fix yet Ignore 7 HIGH findings until 2027-04-05, with the reason per entry: certifi and urllib3 1.26.x in the Python 2 helper script scripts/REDCAP-FITBIT-AUTH-AUTO (fixed only in urllib3 2.x / current certifi; not part of the image). The remaining findings are fixed by the security PR into dev. --- .trivyignore.yaml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.trivyignore.yaml b/.trivyignore.yaml index 7d1a7225..d6872d45 100644 --- a/.trivyignore.yaml +++ b/.trivyignore.yaml @@ -5,4 +5,32 @@ # - id: CVE-2024-12345 # statement: Not exploitable, because ... # expired_at: 2027-01-01 -vulnerabilities: [] +vulnerabilities: + - id: CVE-2023-37920 + statement: >- + certifi 2018.10.15 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05 + - id: CVE-2025-66418 + statement: >- + urllib3 1.26.20 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05 + - id: CVE-2025-66471 + statement: >- + urllib3 1.26.20 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05 + - id: CVE-2026-21441 + statement: >- + urllib3 1.26.20 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05 + - id: CVE-2026-44431 + statement: >- + urllib3 1.26.20 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05 + - id: CVE-2026-97687 + statement: >- + urllib3 1.26.20 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05 + - id: CVE-2026-97689 + statement: >- + urllib3 1.26.20 (HIGH) in scripts/REDCAP-FITBIT-AUTH-AUTO/requirements.txt, a helper script that isn't part of the shipped image: fixed only in urllib3 2.x / current certifi, which need a newer requests (and Python 3). + expired_at: 2027-04-05