diff --git a/.github/renovate.json b/.github/renovate.json index 3c91c383..35140430 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -3,8 +3,7 @@ "extends": [ "config:recommended", ":semanticCommits", - ":dependencyDashboard", - "helpers:pinGitHubActionDigests" + ":dependencyDashboard" ], "timezone": "UTC", "schedule": [ @@ -19,15 +18,15 @@ "osvVulnerabilityAlerts": false, "packageRules": [ { - "description": "The workflows pin every action to a commit SHA, so a floating tag cannot change what CI runs; keep those digests fresh in one PR.", + "description": "The workflows reference actions by their major tag (v7), so the tag itself is what moves and there is no digest to refresh; raise the major bumps in one PR.", "matchManagers": [ "github-actions" ], "groupName": "github actions", - "pinDigests": true + "pinDigests": false }, { - "description": "assembly/Dockerfile pins its base images by digest for the same reason, and a Temurin rebuild is what carries the base OS's security fixes in.", + "description": "assembly/Dockerfile pins its base images by digest, because an image tag is re-pushed in place and the released artifacts are built from it; a Temurin rebuild is what carries the base OS's security fixes in.", "matchManagers": [ "dockerfile" ], diff --git a/.github/workflows/central-publish.yml b/.github/workflows/central-publish.yml index 7fcab095..f5a0165a 100644 --- a/.github/workflows/central-publish.yml +++ b/.github/workflows/central-publish.yml @@ -62,7 +62,7 @@ jobs: fi echo "All required Maven Central secrets are present." - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Derive the reproducible-build timestamp # The pom declares no project.build.outputTimestamp on purpose, so that no @@ -80,7 +80,7 @@ jobs: echo "BUILD_OUTPUT_TIMESTAMP=${timestamp}" >> "$GITHUB_ENV" - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' @@ -88,8 +88,8 @@ jobs: # Creates a settings.xml server entry with id "central" whose # username/password come from the env vars below. server-id: central - server-username: MAVEN_CENTRAL_USERNAME - server-password: MAVEN_CENTRAL_PASSWORD + server-username-env-var: MAVEN_CENTRAL_USERNAME + server-password-env-var: MAVEN_CENTRAL_PASSWORD - name: Bootstrap CLAUDE.md enforcer rule # The custom enforcer rule is consumed as a plugin dependency by the diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b9dc5279..eb5df91f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -42,17 +42,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + uses: actions/checkout@v7 - name: Setup java - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: 25 distribution: 'temurin' # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@988661ebb5e81487b3fb31b2185d2856c0a10679 # v4 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@988661ebb5e81487b3fb31b2185d2856c0a10679 # v4 + uses: github/codeql-action/autobuild@v4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -80,6 +80,6 @@ jobs: - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@988661ebb5e81487b3fb31b2185d2856c0a10679 # v4 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 079494f3..45f42b2f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' @@ -31,7 +31,7 @@ jobs: - name: Run tests with JaCoCo run: mvn -B -ntp verify -Pcoverage --file pom.xml - name: Upload coverage reports - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@v7 with: name: jacoco-reports path: '**/target/site/jacoco/' diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5b1287f0..17ba866c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -35,10 +35,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' @@ -78,17 +78,17 @@ jobs: } >> "$GITHUB_OUTPUT" - name: Set up QEMU - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@v4 # A single-arch build first, loaded into the local daemon, so the image is # actually executed before anything is published. Buildx cannot --load a # multi-platform image, hence the two builds; the GHA layer cache makes the # later multi-arch build reuse this work for linux/amd64. - name: Build the image (linux/amd64) - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@v7 with: context: . file: assembly/Dockerfile @@ -122,7 +122,7 @@ jobs: # caught before the push rather than after — and, on the weekly run, while # there is still time to fix it rather than at the release. - name: Scan the image for vulnerabilities - uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0 + uses: aquasecurity/trivy-action@v0.36.0 with: image-ref: tools:ci format: table @@ -132,7 +132,7 @@ jobs: - name: Log in to GitHub Container Registry if: github.event_name == 'release' - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -143,7 +143,7 @@ jobs: # architectures the trimmed DuckDB driver still carries natives for. - name: Push the image to GHCR if: github.event_name == 'release' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@v7 with: context: . file: assembly/Dockerfile diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 1f204ba8..85a6110a 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 0c748312..f1ef4e12 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -25,7 +25,7 @@ jobs: packages: write steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Derive the reproducible-build timestamp # The pom declares no project.build.outputTimestamp on purpose, so that no @@ -43,7 +43,7 @@ jobs: echo "BUILD_OUTPUT_TIMESTAMP=${timestamp}" >> "$GITHUB_ENV" - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' diff --git a/.github/workflows/maven-windows.yml b/.github/workflows/maven-windows.yml index cdaa5772..51f11030 100644 --- a/.github/workflows/maven-windows.yml +++ b/.github/workflows/maven-windows.yml @@ -26,9 +26,9 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 28acac71..1ac72e6e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -35,9 +35,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' diff --git a/.github/workflows/pitest.yml b/.github/workflows/pitest.yml index cdae309a..99b256b7 100644 --- a/.github/workflows/pitest.yml +++ b/.github/workflows/pitest.yml @@ -23,9 +23,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' @@ -40,7 +40,7 @@ jobs: # bound to the `test` phase, so it still runs on every module. run: mvn -B -ntp install -Ppitest --file pom.xml - name: Upload mutation testing reports - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@v7 with: name: pitest-reports path: '**/target/pit-reports/' diff --git a/.github/workflows/spotbugs.yml b/.github/workflows/spotbugs.yml index 6a4967f2..d34ba630 100644 --- a/.github/workflows/spotbugs.yml +++ b/.github/workflows/spotbugs.yml @@ -29,9 +29,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/checkout@v7 - name: Set up JDK 25 - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + uses: actions/setup-java@v6 with: java-version: '25' distribution: 'temurin' @@ -66,11 +66,11 @@ jobs: # No category input: it would only apply to runs that have no # automationDetails.id of their own, and the step above gives every run # the per-module id that keeps the delivery's runs distinct. - uses: github/codeql-action/upload-sarif@988661ebb5e81487b3fb31b2185d2856c0a10679 # v4 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: target/sarif - name: Upload SpotBugs reports - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@v7 with: name: spotbugs-reports path: | diff --git a/AGENTS.md b/AGENTS.md index 57788079..b3e8cd86 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -831,13 +831,24 @@ across all ten, and a new workflow is expected to keep them: itself at 120 s has no business finishing an answer nobody is waiting for. Everywhere else it is `false` — a scheduled run is not superseded by a newer commit, and a publish interrupted half-way can leave a partial release behind. -- **Actions pinned to a commit SHA**, with the tag kept in a trailing comment - (`uses: actions/checkout@d23441aâ€Ļ # v6`). A tag is mutable, so an unpinned - action is a third party's ability to change what CI runs without a commit - here — and CI is what produces the released artifacts the supply-chain posture - of [ADR 0002](docs/adr/0002-security-policy-and-supply-chain-posture.md) rests - on. `assembly/Dockerfile` pins its `eclipse-temurin` base images by digest for - the same reason. Renovate refreshes both. +- **Actions referenced by their major tag alone** — `uses: actions/setup-java@v6`, + never a commit SHA and never `@v6.0.0`. The major tag is the one each action's + maintainers move, so a patch or a security fix inside an action reaches CI + without a commit here, and the workflow says in the line itself what it runs + rather than hiding it behind a digest. The trade is deliberate: a tag is + mutable, so this trusts each action's owner not to re-point it — see the + trade-off recorded in + [ADR 0005](docs/adr/0005-renovate-dependency-updates.md). + `aquasecurity/trivy-action` is the one action that cannot follow the rule: it + publishes no major tag at all — every one of its 75 tags is an exact `v0.x.y` + release — so `docker.yml` names `@v0.36.0` and Renovate bumps it like any other + dependency. +- **`assembly/Dockerfile` is the opposite case and stays pinned by digest.** An + image tag is re-pushed in place by whoever owns it, and those `eclipse-temurin` + base images end up *inside* the released artifacts, which is the part of the + supply-chain posture of + [ADR 0002](docs/adr/0002-security-policy-and-supply-chain-posture.md) that a + mutable base image would undo. Renovate keeps those digests fresh. ### Dependency updates @@ -860,9 +871,12 @@ configuration is `.github/renovate.json`: once already. - This project's own `io.github.adamw7:**` modules are **disabled**: they resolve inside the reactor at `${revision}`. -- `pinDigests` is on for the **github-actions** and **dockerfile** managers, so - the SHA pins above are refreshed rather than left to rot; the action bumps - arrive as one grouped PR. +- `pinDigests` is **off** for the **github-actions** manager and **on** for + **dockerfile**, matching the two conventions above: the workflows track major + tags, so there is no action digest to refresh, while the Dockerfile's base + images stay pinned and current. What Renovate still raises for actions is the + major move — `@v7` to `@v8` — as one grouped PR, and that is the one to read + release notes for. - A **major** bump of the Maven API artifacts or of Spring Boot needs dependency dashboard approval — a Maven 4 API is wired in on purpose while the build is pinned to 3.9.x, and the framework the MCP servers boot on deserves a review. diff --git a/CLAUDE.md b/CLAUDE.md index c148709f..39bcd970 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -236,9 +236,15 @@ the whole matrix passes: GHCR; `maven-publish.yml` (GitHub Packages); `central-publish.yml` (Maven Central). -Every workflow builds on JDK 25 (Temurin). Use clear, conventional commit -messages — the `git-commit` skill writes them with this repository's real module -scopes — keep changes focused, and add or update tests alongside the code. +Every workflow builds on JDK 25 (Temurin). Actions are referenced by their +**major tag alone** (`uses: actions/setup-java@v6`) — not a commit SHA, not +`@v6.0.0` — so an action's own patches reach CI without a commit here. +`aquasecurity/trivy-action` publishes no major tag and is the exception, at +`@v0.36.0`. `assembly/Dockerfile` still pins its base images by digest. + +Use clear, conventional commit messages — the `git-commit` skill writes them with +this repository's real module scopes — keep changes focused, and add or update +tests alongside the code. **Do not open a pull request unless explicitly asked.** ## Agent configuration diff --git a/docs/adr/0005-renovate-dependency-updates.md b/docs/adr/0005-renovate-dependency-updates.md index c66b3f88..050f2b07 100644 --- a/docs/adr/0005-renovate-dependency-updates.md +++ b/docs/adr/0005-renovate-dependency-updates.md @@ -74,6 +74,16 @@ repository's shape calls for: dashboard rather than arriving unannounced. - **This project's own `io.github.adamw7` modules disabled** — they resolve inside the reactor at `${revision}`, so there is no release for Renovate to raise. +- **`pinDigests` off for github-actions, on for dockerfile.** The workflows + reference each action by its major tag (`actions/setup-java@v6`), so the tag is + what moves and there is no digest for Renovate to refresh; what it raises is + the major bump, `@v6` to `@v7`, in the grouped actions pull request — the one + place release notes are worth reading. The Dockerfile is the opposite case and + stays pinned: an image tag is re-pushed in place by whoever owns it, and those + base images end up inside the released artifacts. + `aquasecurity/trivy-action` publishes no major tag at all — every one of its 75 + tags is an exact `v0.x.y` release — so it is referenced exactly and Renovate + raises its minor bumps like any other dependency. Validate a change to that file with `npx --package renovate renovate-config-validator` before committing it. @@ -93,3 +103,11 @@ Validate a change to that file with - Requires the Renovate App to be installed and configured on the repository. - Care is needed so Renovate and Dependabot do not both open a PR for the same security-driven bump; the role split in ADR 0002 exists to prevent that. +- Referencing actions by a major tag rather than a commit SHA means a tag that is + re-pointed — by a compromised account or by its owner — changes what CI runs + without a commit in this repository. That is accepted knowingly: it is what + lets an action's own patch and security releases reach CI unattended, the + actions in use are first-party GitHub and Docker ones plus Trivy, and the + artifacts a release actually ships are protected at the layer that survives + this — `assembly/Dockerfile`'s digest-pinned base images. Revisit it if an + action in use changes hands.