From 62ee9543f8ca13aa72f4a1bca5f034e8fbf5de0b Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sun, 16 Aug 2026 16:07:53 +0100 Subject: [PATCH 1/9] chore: setup pre-commit and initial lint fixes --- .pre-commit-config.yaml | 5 +++++ config/disabledAlgorithms.json | 8 ++++---- src/main/java/hbp/mip/configurations/OpenApiConfig.java | 2 +- src/main/java/hbp/mip/experiment/ExperimentAPI.java | 2 +- src/main/java/hbp/mip/user/UserDTO.java | 2 +- .../java/hbp/mip/utils/ControllerExceptionHandler.java | 2 +- src/main/java/hbp/mip/utils/CustomResourceLoader.java | 2 +- .../hbp/mip/utils/Exceptions/BadRequestException.java | 2 +- .../mip/utils/Exceptions/ExperimentNotFoundException.java | 2 +- .../hbp/mip/utils/Exceptions/InternalServerError.java | 2 +- src/main/java/hbp/mip/utils/Exceptions/NoContent.java | 2 +- .../hbp/mip/utils/Exceptions/UnauthorizedException.java | 2 +- 12 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e0d92dfdd..60dc5bee0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,3 +13,8 @@ repos: - id: pretty-format-json args: ["--autofix"] exclude: slack.json + +- repo: https://github.com/gitleaks/gitleaks + rev: v8.21.2 + hooks: + - id: gitleaks diff --git a/config/disabledAlgorithms.json b/config/disabledAlgorithms.json index 6fc4a5d46..01cb167b7 100644 --- a/config/disabledAlgorithms.json +++ b/config/disabledAlgorithms.json @@ -1,4 +1,4 @@ -[ - "THREE_C", - "KAPLAN_MEIER" -] \ No newline at end of file +[ + "THREE_C", + "KAPLAN_MEIER" +] diff --git a/src/main/java/hbp/mip/configurations/OpenApiConfig.java b/src/main/java/hbp/mip/configurations/OpenApiConfig.java index 0ee5264d3..9ecc8e290 100644 --- a/src/main/java/hbp/mip/configurations/OpenApiConfig.java +++ b/src/main/java/hbp/mip/configurations/OpenApiConfig.java @@ -15,4 +15,4 @@ public OpenAPI usersMicroserviceOpenAPI() { .info(new Info().title("Platform-backend API") .version("1.0")); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/experiment/ExperimentAPI.java b/src/main/java/hbp/mip/experiment/ExperimentAPI.java index faca46b36..a34561cd8 100644 --- a/src/main/java/hbp/mip/experiment/ExperimentAPI.java +++ b/src/main/java/hbp/mip/experiment/ExperimentAPI.java @@ -132,4 +132,4 @@ public ResponseEntity createTransientExperiment(Authentication au return new ResponseEntity<>(experimentResponse, HttpStatus.OK); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/user/UserDTO.java b/src/main/java/hbp/mip/user/UserDTO.java index 3b68be5cf..48a62b4ac 100644 --- a/src/main/java/hbp/mip/user/UserDTO.java +++ b/src/main/java/hbp/mip/user/UserDTO.java @@ -10,4 +10,4 @@ public UserDTO(UserDAO userDAO){ userDAO.getAgreeNDA() ); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/utils/ControllerExceptionHandler.java b/src/main/java/hbp/mip/utils/ControllerExceptionHandler.java index a86cfb492..1f284f6b8 100644 --- a/src/main/java/hbp/mip/utils/ControllerExceptionHandler.java +++ b/src/main/java/hbp/mip/utils/ControllerExceptionHandler.java @@ -27,7 +27,7 @@ public ResponseEntity handleExperimentNotFoundException(ExperimentNotFou return new ResponseEntity<>(message, HttpStatus.NOT_FOUND); } - + @ExceptionHandler(BadRequestException.class) public ResponseEntity handleBadRequestException(BadRequestException ex, WebRequest request) { ErrorMessage message = new ErrorMessage( diff --git a/src/main/java/hbp/mip/utils/CustomResourceLoader.java b/src/main/java/hbp/mip/utils/CustomResourceLoader.java index 89552146c..4fd0f5dd7 100644 --- a/src/main/java/hbp/mip/utils/CustomResourceLoader.java +++ b/src/main/java/hbp/mip/utils/CustomResourceLoader.java @@ -18,4 +18,4 @@ public void setResourceLoader(@NonNull ResourceLoader resourceLoader) { public Resource getResource(String resourceLocation) { return resourceLoader.getResource(resourceLocation); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/utils/Exceptions/BadRequestException.java b/src/main/java/hbp/mip/utils/Exceptions/BadRequestException.java index a83830665..cd3bfb4d1 100644 --- a/src/main/java/hbp/mip/utils/Exceptions/BadRequestException.java +++ b/src/main/java/hbp/mip/utils/Exceptions/BadRequestException.java @@ -5,4 +5,4 @@ public class BadRequestException extends RuntimeException { public BadRequestException(String msg) { super(msg); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java b/src/main/java/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java index 303735509..cfec9a6ed 100644 --- a/src/main/java/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java +++ b/src/main/java/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java @@ -5,4 +5,4 @@ public class ExperimentNotFoundException extends RuntimeException { public ExperimentNotFoundException(String msg) { super(msg); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/utils/Exceptions/InternalServerError.java b/src/main/java/hbp/mip/utils/Exceptions/InternalServerError.java index 31357164f..2439779b2 100644 --- a/src/main/java/hbp/mip/utils/Exceptions/InternalServerError.java +++ b/src/main/java/hbp/mip/utils/Exceptions/InternalServerError.java @@ -5,4 +5,4 @@ public class InternalServerError extends RuntimeException { public InternalServerError(String msg) { super(msg); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/utils/Exceptions/NoContent.java b/src/main/java/hbp/mip/utils/Exceptions/NoContent.java index 6ac31b899..66e2ba167 100644 --- a/src/main/java/hbp/mip/utils/Exceptions/NoContent.java +++ b/src/main/java/hbp/mip/utils/Exceptions/NoContent.java @@ -5,4 +5,4 @@ public class NoContent extends RuntimeException { public NoContent(String msg) { super(msg); } -} \ No newline at end of file +} diff --git a/src/main/java/hbp/mip/utils/Exceptions/UnauthorizedException.java b/src/main/java/hbp/mip/utils/Exceptions/UnauthorizedException.java index 1cbe3cf20..bb07f6f57 100644 --- a/src/main/java/hbp/mip/utils/Exceptions/UnauthorizedException.java +++ b/src/main/java/hbp/mip/utils/Exceptions/UnauthorizedException.java @@ -5,4 +5,4 @@ public class UnauthorizedException extends RuntimeException { public UnauthorizedException(String msg) { super(msg); } -} \ No newline at end of file +} From 570d0389ec708aa2ca8598d84dca6e9c155a4142 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sun, 16 Aug 2026 16:18:05 +0100 Subject: [PATCH 2/9] pre-commit-config negative testing --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60dc5bee0..3e4d5f7c9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,6 +10,7 @@ repos: - id: check-added-large-files - id: check-yaml - id: check-json + - id: check-xml - id: pretty-format-json args: ["--autofix"] exclude: slack.json From eb2b2e8cf1ac701004bb5ee2d1988c4d8a5eb719 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sun, 16 Aug 2026 17:20:43 +0100 Subject: [PATCH 3/9] pin pre-commit hook revisions to commit SHAs --- .pre-commit-config.yaml | 8 ++++++-- src/main/java/hbp/mip/utils/CustomResourceLoader.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e4d5f7c9..7d7ffe017 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c #v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -14,8 +14,12 @@ repos: - id: pretty-format-json args: ["--autofix"] exclude: slack.json + - id: check-xml + - id: detect-private-key + - id: check-case-conflict + - id: mixed-line-ending - repo: https://github.com/gitleaks/gitleaks - rev: v8.21.2 + rev: afc89f91c0795f9763920d40848d770e44341b06 #v8.21.2 hooks: - id: gitleaks diff --git a/src/main/java/hbp/mip/utils/CustomResourceLoader.java b/src/main/java/hbp/mip/utils/CustomResourceLoader.java index 4fd0f5dd7..6f6e536bc 100644 --- a/src/main/java/hbp/mip/utils/CustomResourceLoader.java +++ b/src/main/java/hbp/mip/utils/CustomResourceLoader.java @@ -18,4 +18,4 @@ public void setResourceLoader(@NonNull ResourceLoader resourceLoader) { public Resource getResource(String resourceLocation) { return resourceLoader.getResource(resourceLocation); } -} +} From 1a428d9d8ce98053134f7332b31431a90368a378 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sun, 16 Aug 2026 17:28:48 +0100 Subject: [PATCH 4/9] fix(docker): pin base images to digests and use JSON notation for HEALTHCHECK --- .github/workflows/sast.yml | 2 +- .github/workflows/secrets-scan.yml | 40 ++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 5 ++-- Dockerfile | 24 +++--------------- ci/sast_scan.py | 2 +- ci/setup-tools.sh | 17 +++++++++++++ ci/suppress_gitleaks.toml | 4 +++ pom.xml | 4 +-- 8 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/secrets-scan.yml create mode 100644 ci/suppress_gitleaks.toml diff --git a/.github/workflows/sast.yml b/.github/workflows/sast.yml index 786dbc816..6bedefeb3 100644 --- a/.github/workflows/sast.yml +++ b/.github/workflows/sast.yml @@ -16,7 +16,7 @@ jobs: env: SEMGREP_CONFIG_RULESETS: >- semgrep-rules/generic semgrep-rules/problem-based-packs semgrep-rules/bash semgrep-rules/java auto - semgrep-rules/yaml semgrep-rules/package_managers p/default + semgrep-rules/yaml semgrep-rules/package_managers p/default p/gitleaks OPENGREP_EXCLUDE: >- *.sarif ci/ Dockerfile* .pre-commit-config.yaml docs/** README.md AGENTS.md OPENGREP_SARIF_OUTPUT: sast-semgrep-app.sarif diff --git a/.github/workflows/secrets-scan.yml b/.github/workflows/secrets-scan.yml new file mode 100644 index 000000000..cd8bb5848 --- /dev/null +++ b/.github/workflows/secrets-scan.yml @@ -0,0 +1,40 @@ +name: Secret Scanning (gitleaks) + +on: + pull_request: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + security-events: write + +jobs: + gitleaks: + runs-on: ubuntu-latest + env: + GITLEAKS_SARIF_OUTPUT: gitleaks.sarif + + steps: + - name: Check out repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Install gitleaks + run: bash ci/setup-tools.sh --install-tool gitleaks + + - name: Install and run gitleaks + run: > + gitleaks dir . + --config ci/suppress_gitleaks.toml + --redact + --report-format sarif + --report-path "$GITLEAKS_SARIF_OUTPUT" + + - name: Upload SARIF to code scanning + if: always() + uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + with: + sarif_file: ${{ env.GITLEAKS_SARIF_OUTPUT }} + category: gitleaks diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7d7ffe017..3fd08481c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c #v6.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -10,7 +10,6 @@ repos: - id: check-added-large-files - id: check-yaml - id: check-json - - id: check-xml - id: pretty-format-json args: ["--autofix"] exclude: slack.json @@ -20,6 +19,6 @@ repos: - id: mixed-line-ending - repo: https://github.com/gitleaks/gitleaks - rev: afc89f91c0795f9763920d40848d770e44341b06 #v8.21.2 + rev: v8.30.0 hooks: - id: gitleaks diff --git a/Dockerfile b/Dockerfile index b08839aff..2cd21516f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ####################################################### # Build the spring boot maven project ####################################################### -FROM maven:3.9.11-amazoncorretto-21 AS mvn-build-env +FROM maven:3.9.11-amazoncorretto-21@sha256:82d98fbed447e3f7dfbf1089840a51bfaeb5651cb47a9c5820139d054db3dde1 AS mvn-build-env LABEL maintainer="Thanasis Karampatsis " ENV CODE_PATH="/opt/code" @@ -9,7 +9,6 @@ WORKDIR $CODE_PATH COPY pom.xml $CODE_PATH/ -# Pre-fetch dependencies first to improve build cache efficiency. RUN mvn -B -ntp dependency:go-offline COPY src/ $CODE_PATH/src @@ -19,17 +18,11 @@ RUN mvn -B -ntp clean package ####################################################### # Setup the running container ####################################################### -FROM amazoncorretto:21-alpine3.21 +FROM amazoncorretto:21-alpine3.21@sha256:392b286e53c7f4cd366bd2f752f509b7e24de9f414564bccd7d152a58214a8b6 -####################################################### -# Setting up timezone -####################################################### ENV TZ=Etc/GMT RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone -####################################################### -# Setting up environment -####################################################### ENV APP_CONFIG_TEMPLATE="/opt/config/application.tmpl" ENV APP_CONFIG_LOCATION="/opt/config/application.yml" ENV SPRING_CONFIG_LOCATION="file:/opt/config/application.yml" @@ -43,25 +36,14 @@ WORKDIR /opt RUN apk add --no-cache curl -####################################################### -# Install dockerize -####################################################### ENV DOCKERIZE_VERSION=v0.14.0 RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz - -####################################################### -# Prepare the spring boot application files -####################################################### COPY config/application.tmpl $APP_CONFIG_TEMPLATE COPY --from=mvn-build-env /opt/code/target/platform-backend.jar /usr/share/jars/ - -####################################################### -# Configuration for the backend config files -####################################################### ENV DISABLED_ALGORITHMS_CONFIG_PATH="/opt/platform/algorithms/disabledAlgorithms.json" COPY config/disabledAlgorithms.json $DISABLED_ALGORITHMS_CONFIG_PATH VOLUME /opt/platform/api @@ -73,4 +55,4 @@ RUN addgroup -S appgroup && adduser -S appuser -G appgroup \ USER appuser ENTRYPOINT ["sh", "-ec", "exec dockerize -template ${APP_CONFIG_TEMPLATE}:${APP_CONFIG_LOCATION} java --add-opens java.base/java.io=ALL-UNNAMED -Daeron.term.buffer.length -jar /usr/share/jars/platform-backend.jar"] EXPOSE 8080 -HEALTHCHECK --start-period=60s CMD curl --fail --silent --show-error http://localhost:8080/services/actuator/health | grep -q '"status":"UP"' +HEALTHCHECK --start-period=60s CMD ["sh", "-c", "curl --fail --silent --show-error http://localhost:8080/services/actuator/health | grep -q '\"status\":\"UP\"'"] diff --git a/ci/sast_scan.py b/ci/sast_scan.py index 5c40496d9..f127ae0db 100644 --- a/ci/sast_scan.py +++ b/ci/sast_scan.py @@ -19,7 +19,7 @@ SEMGREP_CONFIG_RULESETS = os.getenv( "SEMGREP_CONFIG_RULESETS", " semgrep-rules/generic semgrep-rules/problem-based-packs semgrep-rules/bash " - " semgrep-rules/java auto semgrep-rules/yaml semgrep-rules/package_managers p/default " + " semgrep-rules/java auto semgrep-rules/yaml semgrep-rules/package_managers p/default p/gitleaks " ).split() OPENGREP_EXCLUDE = os.getenv( "OPENGREP_EXCLUDE", diff --git a/ci/setup-tools.sh b/ci/setup-tools.sh index c24ca8de7..510453ee5 100644 --- a/ci/setup-tools.sh +++ b/ci/setup-tools.sh @@ -30,6 +30,10 @@ SEMGREP_RULES_DIR="semgrep-rules" HADOLINT_VERSION="${HADOLINT_VERSION:-v2.14.0}" HADOLINT_SHA256="${HADOLINT_SHA256:-6bf226944684f56c84dd014e8b979d27425c0148f61b3bd99bcc6f39e9dc5a47}" +# renovate: datasource=github-release-attachments depName=gitleaks/gitleaks +GITLEAKS_VERSION="${GITLEAKS_VERSION:-v8.30.1}" +GITLEAKS_SHA256="${GITLEAKS_SHA256:-551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb}" + # renovate: datasource=npm depName=@cyclonedx/cyclonedx-npm CYCLONEDX_NPM_VERSION="${CYCLONEDX_NPM_VERSION:-6.0.0}" @@ -128,6 +132,19 @@ if should_install "hadolint"; then echo "Hadolint installed OK" fi +# --- Gitleaks ----------------------------------------------------------- +if should_install "gitleaks"; then + echo "[setup-tools] Installing Gitleaks ${GITLEAKS_VERSION}" + GITLEAKS_TARBALL="gitleaks_${GITLEAKS_VERSION#v}_linux_x64.tar.gz" + download_and_verify \ + "https://github.com/gitleaks/gitleaks/releases/download/${GITLEAKS_VERSION}/${GITLEAKS_TARBALL}" \ + "${TMP_DIR}/${GITLEAKS_TARBALL}" \ + "${GITLEAKS_SHA256}" + sudo tar -xzf "${TMP_DIR}/${GITLEAKS_TARBALL}" -C /usr/local/bin gitleaks + gitleaks version + echo "Gitleaks installed OK" +fi + # --- SBOM generation ---------------------------------------------------- case "$SBOM_ECOSYSTEM" in maven) diff --git a/ci/suppress_gitleaks.toml b/ci/suppress_gitleaks.toml new file mode 100644 index 000000000..5673600f3 --- /dev/null +++ b/ci/suppress_gitleaks.toml @@ -0,0 +1,4 @@ +[allowlist] +paths = [ + '''AGENTS\.md''', +] diff --git a/pom.xml b/pom.xml index 69cfbf0a8..38c9bf80c 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 4.0.6 + 4.0.7 @@ -31,7 +31,7 @@ 2.6 10.9.1 2.21.5 - 3.1.4 + 3.1.5 From e25a3ba5eb1f53fe0640baa3942bda2695f20633 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Wed, 19 Aug 2026 11:39:52 +0100 Subject: [PATCH 5/9] chore(renovate): track DOCKERIZE_VERSION --- Dockerfile | 1 + renovate.json | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Dockerfile b/Dockerfile index 2cd21516f..8a87ddc6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,7 @@ WORKDIR /opt RUN apk add --no-cache curl +# renovate: datasource=github-releases depName=jwilder/dockerize ENV DOCKERIZE_VERSION=v0.14.0 RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ diff --git a/renovate.json b/renovate.json index 7094f757a..6a7b3e477 100644 --- a/renovate.json +++ b/renovate.json @@ -21,6 +21,16 @@ "matchStrings": [ "# renovate: datasource=(?[a-z-]+) depName=(?[^\\s]+)\\n\\s*python-version:\\s*'(?[0-9][0-9.]*)'" ] + }, + { + "customType": "regex", + "description": "Bump DOCKERIZE_VERSION pinned in Dockerfile", + "managerFilePatterns": [ + "/(^|/)Dockerfile[^/]*$/" + ], + "matchStrings": [ + "# renovate: datasource=(?[a-z-]+) depName=(?[^\\s]+)\\s*\\nENV DOCKERIZE_VERSION=(?v[0-9][0-9.]*)" + ] } ], "enabledManagers": [ @@ -48,6 +58,7 @@ "matchDatasources": [ "github-release-attachments", "github-tags", + "github-releases", "npm", "python-version" ], From dfaed46deae080973fe4a214e178c8e19f89227a Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sat, 29 Aug 2026 10:52:44 +0100 Subject: [PATCH 6/9] docs: fix outdated repo layout in README --- ci/README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ci/README.md b/ci/README.md index ca91b851e..eb8eb4aeb 100644 --- a/ci/README.md +++ b/ci/README.md @@ -25,20 +25,22 @@ Following the OWASP DevSecOps model, scanning is split into three independent pi ``` .github/ -├── workflows/ -│ ├── container-scan.yml # builds the image, scans the Dockerfile (SAST) and image (SCA) -│ ├── sca.yml # resolves deps, generates SBOM, scans it (SCA) -│ └── sast.yml # scans source code (SAST) -└── scripts/ - ├── setup-tools.sh # installs trivy, osv-scanner, opengrep, hadolint, semgrep-rules - ├── container_scan.py # orchestrator for container-scan.yml - ├── sca_scan.py # orchestrator for sca.yml - ├── sast_scan.py # orchestrator for sast.yml - ├── parse_sarif.py # shared: reads SARIF security-severity scores - ├── suppress_trivy.yaml # shared Trivy ignore file - └── suppress_osv_scanner.toml # shared OSV-Scanner ignore file +└── workflows/ + ├── container-scan.yml # builds the image, scans the Dockerfile (SAST) and image (SCA) + ├── sca.yml # resolves deps, generates SBOM, scans it (SCA) + ├── sast.yml # scans source code (SAST) + ├── publish_images.yml # publishes built images + └── ebrains.yml # EBRAINS-specific pipeline + +ci/ +├── setup-tools.sh # installs trivy, osv-scanner, opengrep, hadolint, semgrep-rules +├── container_scan.py # orchestrator for container-scan.yml +├── sca_scan.py # orchestrator for sca.yml +├── sast_scan.py # orchestrator for sast.yml +├── parse_sarif.py # shared: reads SARIF security-severity scores +├── suppress_trivy.yaml # shared Trivy ignore file +└── suppress_osv_scanner.toml # shared OSV-Scanner ignore file ``` - > **Note:** all three workflows trigger on `pull_request`, `workflow_dispatch`, and a weekly Monday 02:00 UTC schedule, and run independently in parallel. Each has its own gate and its own category in the GitHub Security tab. ## 2. Architecture From a159937fa5f64c85e3ab491364f7dd676a5b32b8 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sun, 30 Aug 2026 11:48:44 +0100 Subject: [PATCH 7/9] Bump Dockerize --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8a87ddc6d..f5fafe761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ WORKDIR /opt RUN apk add --no-cache curl # renovate: datasource=github-releases depName=jwilder/dockerize -ENV DOCKERIZE_VERSION=v0.14.0 +ENV DOCKERIZE_VERSION=v0.15.0 RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz From f4eb91df8ebf72da36789ee2b18e0b6e5c95c065 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Sun, 30 Aug 2026 14:12:00 +0100 Subject: [PATCH 8/9] chore(ci): align pipeline with blueprint (gate thresholds, maven resolve, codeql-action v4) --- .github/workflows/container-scan.yml | 8 ++++---- .github/workflows/sast.yml | 2 +- .github/workflows/sca.yml | 12 ++++++------ ci/container_scan.py | 13 ++++++------- ci/parse_sarif.py | 8 ++++++-- ci/sca_scan.py | 7 +++---- ci/setup-tools.sh | 4 +++- 7 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.github/workflows/container-scan.yml b/.github/workflows/container-scan.yml index c1341c184..9f9560872 100644 --- a/.github/workflows/container-scan.yml +++ b/.github/workflows/container-scan.yml @@ -57,7 +57,7 @@ jobs: - name: Upload Trivy SARIF to GitHub Security tab id: upload_trivy if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.TRIVY_SCA_SARIF_OUTPUT }} category: trivy-container-scanning @@ -65,7 +65,7 @@ jobs: - name: Upload OSV Scanner SARIF to GitHub Security tab id: upload_osv if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.OSV_SCA_SARIF_OUTPUT }} category: osv-scanner-container-scanning @@ -73,7 +73,7 @@ jobs: - name: Upload OpenGrep SARIF to GitHub Security tab id: upload_opengrep if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.OPENGREP_SAST_SARIF_OUTPUT }} category: opengrep-sast @@ -81,7 +81,7 @@ jobs: - name: Upload Hadolint SARIF to GitHub Security tab id: upload_hadolint if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.HADOLINT_SAST_SARIF_OUTPUT }} category: hadolint-sast diff --git a/.github/workflows/sast.yml b/.github/workflows/sast.yml index 6bedefeb3..68553e30e 100644 --- a/.github/workflows/sast.yml +++ b/.github/workflows/sast.yml @@ -40,7 +40,7 @@ jobs: - name: Upload Semgrep SARIF to GitHub Security tab id: upload_semgrep if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.OPENGREP_SARIF_OUTPUT }} category: semgrep-app diff --git a/.github/workflows/sca.yml b/.github/workflows/sca.yml index c57bf84a5..c10ec33c5 100644 --- a/.github/workflows/sca.yml +++ b/.github/workflows/sca.yml @@ -20,6 +20,9 @@ jobs: TRIVY_SARIF_OUTPUT: trivy-platform-backend.sarif OSV_SARIF_OUTPUT: osv-scanner-platform-backend.sarif SCA_MERGED_SARIF_OUTPUT: SCA-platform-backend-merged.sarif + # CVSS gate: fail at >= FAIL, warn between WARN and FAIL. + GATE_FAIL_THRESHOLD: "8.0" + GATE_WARN_THRESHOLD: "5.0" steps: - name: Check out repository @@ -38,10 +41,7 @@ jobs: key: ${{ runner.os }}-m2-v1-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2-v1- - - name: Resolve Maven dependencies - run: mvn dependency:resolve -q - - - name: Setup tools + - name: Setup tools and generate SBOM run: bash ci/setup-tools.sh --install-tool trivy,osv-scanner --sbom-ecosystem maven - name: Run SCA tools @@ -50,7 +50,7 @@ jobs: - name: Upload Trivy SARIF to GitHub Security tab id: upload_trivy if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.TRIVY_SARIF_OUTPUT }} category: trivy-app @@ -58,7 +58,7 @@ jobs: - name: Upload OSV Scanner SARIF to GitHub Security tab id: upload_osv if: always() - uses: github/codeql-action/upload-sarif@c35d1b164463ee62a100735382aaaa525c5d3496 #v2.25.6 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.2 with: sarif_file: ${{ env.OSV_SARIF_OUTPUT }} category: osv-scanner-app diff --git a/ci/container_scan.py b/ci/container_scan.py index e909dc013..d0cbf8b13 100644 --- a/ci/container_scan.py +++ b/ci/container_scan.py @@ -4,7 +4,7 @@ import logging import json import argparse -from parse_sarif import evaluate +from parse_sarif import evaluate, GATE_FAIL_THRESHOLD, GATE_WARN_THRESHOLD GREEN = '\033[92m' @@ -92,12 +92,12 @@ def handle_sca(): eval_result = evaluate(path) if eval_result.gate_failed: - tool_status[name] = "FAILED" # this tool found CVSS >= 8.0 + tool_status[name] = "FAILED" gate_failed = True elif eval_result.gate_warn: - tool_status[name] = "WARNING" # this tool found 5.0 <= CVSS < 8.0 + tool_status[name] = "WARNING" else: - tool_status[name] = "PASSED" # this tool found nothing >= 5.0 + tool_status[name] = "PASSED" # Print summary of results logger.info(f"\n{BOLD}========== SCA PIPELINE SUMMARY =========={RESET}") @@ -105,12 +105,11 @@ def handle_sca(): if status == "PASSED": logger.info(f"[{name}]: {GREEN}PASSED{RESET}") elif status == "WARNING": - logger.warning(f"[{name}]: {YELLOW}WARNING (findings between 5.0 and 8.0){RESET}") + logger.warning(f"[{name}]: {YELLOW}WARNING (findings between {GATE_WARN_THRESHOLD} and {GATE_FAIL_THRESHOLD}){RESET}") elif status == "ERROR": logger.error(f"[{name}]: {RED}ERROR (tool did not run correctly){RESET}") else: - logger.error(f"[{name}]: {RED}FAILED (CVSS >= 8.0 found){RESET}") - logger.info(f"{BOLD}=========================================={RESET}\n") + logger.error(f"[{name}]: {RED}FAILED (CVSS >= {GATE_FAIL_THRESHOLD} found){RESET}") # Exit with non-zero code if any tool failed the gate if gate_failed: diff --git a/ci/parse_sarif.py b/ci/parse_sarif.py index 5d35c9707..793a2e6ed 100644 --- a/ci/parse_sarif.py +++ b/ci/parse_sarif.py @@ -1,6 +1,10 @@ import json +import os from dataclasses import dataclass +GATE_FAIL_THRESHOLD = float(os.getenv("GATE_FAIL_THRESHOLD", "8.0")) +GATE_WARN_THRESHOLD = float(os.getenv("GATE_WARN_THRESHOLD", "5.0")) + @dataclass class EvaluationResult: gate_failed: bool @@ -34,6 +38,6 @@ def evaluate(sarif_paths): max_score = max(max_score, float(score)) return EvaluationResult( - gate_failed=max_score >= 8, - gate_warn=5 <= max_score < 8, + gate_failed=max_score >= GATE_FAIL_THRESHOLD, + gate_warn=GATE_WARN_THRESHOLD <= max_score < GATE_FAIL_THRESHOLD, ) diff --git a/ci/sca_scan.py b/ci/sca_scan.py index b3297d949..2c651ec74 100644 --- a/ci/sca_scan.py +++ b/ci/sca_scan.py @@ -3,7 +3,7 @@ import sys import logging import json -from parse_sarif import evaluate +from parse_sarif import evaluate, GATE_FAIL_THRESHOLD, GATE_WARN_THRESHOLD GREEN = '\033[92m' RED = '\033[91m' @@ -114,12 +114,11 @@ def main(): if status == "PASSED": logger.info(f"[{name}]: {GREEN}PASSED{RESET}") elif status == "WARNING": - logger.warning(f"[{name}]: {YELLOW}WARNING (findings between 5.0 and 8.0){RESET}") + logger.warning(f"[{name}]: {YELLOW}WARNING (findings between {GATE_WARN_THRESHOLD} and {GATE_FAIL_THRESHOLD}){RESET}") elif status == "ERROR": logger.error(f"[{name}]: {RED}ERROR (tool did not run correctly){RESET}") else: - logger.error(f"[{name}]: {RED}FAILED (CVSS >= 8.0 found){RESET}") - logger.info(f"{BOLD}=========================================={RESET}\n") + logger.error(f"[{name}]: {RED}FAILED (CVSS >= {GATE_FAIL_THRESHOLD} found){RESET}") # Exit with non-zero code if any tool failed the gate if gate_failed: diff --git a/ci/setup-tools.sh b/ci/setup-tools.sh index 510453ee5..e65fcf000 100644 --- a/ci/setup-tools.sh +++ b/ci/setup-tools.sh @@ -149,10 +149,12 @@ fi case "$SBOM_ECOSYSTEM" in maven) echo "Generating SBOM for Maven project" - mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -q + mvn -B -ntp dependency:resolve -q + mvn -B -ntp org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -q ;; npm) echo "Generating SBOM for NPM project" + npm ci npx --yes "@cyclonedx/cyclonedx-npm@${CYCLONEDX_NPM_VERSION}" --output-file target/bom.json ;; none) From 6ebbb54f87874dd76ffc528685f50cda7ef392c6 Mon Sep 17 00:00:00 2001 From: moghit-eou Date: Tue, 1 Sep 2026 13:15:17 +0100 Subject: [PATCH 9/9] chore(renovate): auto-bump pre-commit hooks and semgrep-rules ref - enable the pre-commit manager and switch hook revs to the - add a git-refs custom manager to track semgrep-rules develop head branch - add git-refs to the minimumReleaseAge cooldown list --- .github/workflows/sast.yml | 2 +- .pre-commit-config.yaml | 4 ++-- ci/sast_scan.py | 2 +- ci/setup-tools.sh | 2 +- renovate.json | 17 +++++++++++++++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/sast.yml b/.github/workflows/sast.yml index 68553e30e..40940c4a0 100644 --- a/.github/workflows/sast.yml +++ b/.github/workflows/sast.yml @@ -16,7 +16,7 @@ jobs: env: SEMGREP_CONFIG_RULESETS: >- semgrep-rules/generic semgrep-rules/problem-based-packs semgrep-rules/bash semgrep-rules/java auto - semgrep-rules/yaml semgrep-rules/package_managers p/default p/gitleaks + semgrep-rules/yaml semgrep-rules/package_managers p/default OPENGREP_EXCLUDE: >- *.sarif ci/ Dockerfile* .pre-commit-config.yaml docs/** README.md AGENTS.md OPENGREP_SARIF_OUTPUT: sast-semgrep-app.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3fd08481c..c2a0f044d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -19,6 +19,6 @@ repos: - id: mixed-line-ending - repo: https://github.com/gitleaks/gitleaks - rev: v8.30.0 + rev: 83d9cd684c87d95d656c1458ef04895a7f1cbd8e # frozen: v8.30.1 hooks: - id: gitleaks diff --git a/ci/sast_scan.py b/ci/sast_scan.py index f127ae0db..98e9d3586 100644 --- a/ci/sast_scan.py +++ b/ci/sast_scan.py @@ -19,7 +19,7 @@ SEMGREP_CONFIG_RULESETS = os.getenv( "SEMGREP_CONFIG_RULESETS", " semgrep-rules/generic semgrep-rules/problem-based-packs semgrep-rules/bash " - " semgrep-rules/java auto semgrep-rules/yaml semgrep-rules/package_managers p/default p/gitleaks " + " semgrep-rules/java auto semgrep-rules/yaml semgrep-rules/package_managers p/default" ).split() OPENGREP_EXCLUDE = os.getenv( "OPENGREP_EXCLUDE", diff --git a/ci/setup-tools.sh b/ci/setup-tools.sh index e65fcf000..bc3222978 100644 --- a/ci/setup-tools.sh +++ b/ci/setup-tools.sh @@ -22,7 +22,7 @@ OSV_SCANNER_SHA256="${OSV_SCANNER_SHA256:-15314940c10d26af9c6649f150b8a47c1262e8 OPENGREP_VERSION="${OPENGREP_VERSION:-v1.25.0}" OPENGREP_SHA256="${OPENGREP_SHA256:-9ac4aebb47ba3f7b0d8fc641ac8749cb6c2f253f616131a67d9631e00d4bea33}" -# renovate: datasource=github-tags depName=semgrep/semgrep-rules +# renovate: datasource=git-refs depName=https://github.com/semgrep/semgrep-rules SEMGREP_RULES_REF="${SEMGREP_RULES_REF:-40b8c63f75dc7c22c8a77482d73bfb864b146f7e}" SEMGREP_RULES_DIR="semgrep-rules" diff --git a/renovate.json b/renovate.json index 6a7b3e477..1af49b6fd 100644 --- a/renovate.json +++ b/renovate.json @@ -31,10 +31,22 @@ "matchStrings": [ "# renovate: datasource=(?[a-z-]+) depName=(?[^\\s]+)\\s*\\nENV DOCKERIZE_VERSION=(?v[0-9][0-9.]*)" ] + }, + { + "currentValueTemplate": "develop", + "customType": "regex", + "description": "Track a git branch head pinned as a commit SHA in CI setup scripts", + "managerFilePatterns": [ + "/(^|/)setup-tools\\.sh$/" + ], + "matchStrings": [ + "# renovate: datasource=(?git-refs) depName=(?[^\\s]+)\\n[A-Z_]+_REF=\"\\$\\{[A-Z_]+_REF:-(?[a-f0-9]{40})\\}\"" + ] } ], "enabledManagers": [ - "custom.regex" + "custom.regex", + "pre-commit" ], "extends": [ "config:recommended" @@ -60,7 +72,8 @@ "github-tags", "github-releases", "npm", - "python-version" + "python-version", + "git-refs" ], "minimumReleaseAge": "7 days" }