CAMEL-24502: Least privilege for the sync workflows and pin the Maven wrapper downloads - #1930
Merged
Merged
Conversation
… wrapper downloads
The two scheduled workflows, automatic-sync-main.yml and generate-sbom-main.yml,
declared no permissions block, so their single job ran with the repository default
GITHUB_TOKEN grants. pr-build-main.yml and pr-doc-validation.yml already declare
`permissions: contents: read`, so this brings the remaining workflows in line.
Each workflow now declares `permissions: {}` at the top and every job opts in to
exactly what it needs. The job is also split in two:
- `build` (contents: read) checks out and builds apache/camel and then
camel-spring-boot, exactly as before, and uploads the regenerated changes as a
build artifact.
- `create-pull-request` (contents: write, pull-requests: write) checks out
camel-spring-boot, applies the artifact and calls
peter-evans/create-pull-request.
The regenerated tree is handed over as a `git diff --cached --binary` patch rather
than a copy of the working tree. A typical sync changes a handful of files out of
a repository of well over a hundred thousand, so a patch keeps the transfer small,
and unlike a file overlay it also carries deletions, which a regeneration can
produce when a component goes away. `git add --all -- ':!camel'` excludes the
nested apache/camel checkout, and .gitignore already excludes target directories.
The patch is applied with `git apply --3way` so that a main branch that moved
while the build was running is merged rather than silently dropped.
Every `uses:` reference in these two workflows is pinned to a full commit SHA with
the version kept as a trailing comment, so the resolved action code is reproducible
and reviewable. .github/dependabot.yml already has a github-actions ecosystem
entry, so the pins keep getting bumped.
maven-wrapper.properties gained distributionSha256Sum and wrapperSha256Sum, so
mvnw and mvnw.cmd verify what they download instead of trusting the URL. The two
values were computed from the artifacts at the exact URLs already in the file and
cross-checked against the .sha1 files published next to them on
repo.maven.apache.org; the distribution was additionally cross-checked against the
.sha512 published on archive.apache.org, and the wrapper jar sum matches the
maven-wrapper.jar already committed under .mvn/wrapper.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Croway
force-pushed
the
CAMEL-24502-ci-hardening
branch
from
September 2, 2026 13:12
366d26e to
cfac81c
Compare
davsclaus
approved these changes
Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements CAMEL-24502. Build infrastructure only, no shipped artifact is touched.
1. Least-privilege
permissions:on the two scheduled workflows.github/workflows/automatic-sync-main.ymland.github/workflows/generate-sbom-main.ymldeclared nopermissions:block, so their job ran with the repository defaultGITHUB_TOKENgrants.pr-build-main.ymlandpr-doc-validation.ymlalready declarepermissions: contents: read; this brings the remaining two workflows in line.Both now declare
permissions: {}at the workflow level, and each job opts in to exactly what it needs.2. Build split away from the PR-creation step
Previously one job checked out and fully built
apache/camel, then built camel-spring-boot, and then handed the write-capable token topeter-evans/create-pull-request— all in the same job. It is now two jobs:buildcontents: readapache/cameland camel-spring-boot, runs the same two./mvnwcommands as before, uploads the regenerated changes as an artifactcreate-pull-requestcontents: write,pull-requests: writecreate-pull-requestCron schedule, the
if: github.repository == 'apache/camel-spring-boot'guard, the./mvnwcommand lines, theautomatic-periodic-syncbranch name and the PR title/body text are all unchanged. Only the job structure and the grants change.Why a patch rather than a copy of the tree
The handover artifact is a
git diff --cached --binarypatch, not a copy of the working tree:Generation excludes the nested
apache/camelcheckout via the':!camel'pathspec;target/build output is already covered by.gitignore.The patch is applied with
git apply --3way. The two jobs check outmainat different times — potentially an hour or two apart, given theapache/camelbuild in between — so--3waymerges an advancedmaininstead of failing on context drift. A genuine conflict fails the step loudly rather than producing a half-applied tree.actions/download-artifact@v8verifies the artifact digest and errors on mismatch by default, so the handover between the two jobs is integrity-checked.I verified the generate/apply round trip locally on a scratch repository covering: modified file, added text file, added binary file, deleted file, a nested git checkout named
camel, gitignoredtarget/output, and an unrelated commit landing on the destination branch between generation and application. All four changes came through, the nested checkout and build output were excluded, and the deletion was staged correctly.Action pinning
Every
uses:in these two workflows is pinned to a full commit SHA with the version as a trailing comment. SHAs were resolved withgh api repos/<owner>/<repo>/git/ref/tags/<tag>; all five refs are of typecommit(no annotated tag objects needing dereferencing), so the pins are commits and not tag objects:Anyone can re-run the same
gh apicalls to confirm..github/dependabot.ymlalready has agithub-actionsecosystem entry, so the pins will keep being bumped and the trailing comment updated — no change needed there.3. Maven wrapper checksums
.mvn/wrapper/maven-wrapper.propertiesgaineddistributionSha256SumandwrapperSha256Sum, somvnw/mvnw.cmdverify what they download instead of trusting the URL. Both values were computed from the artifacts at the exact URLs already in the file:So each value is corroborated by a checksum file published by the ASF alongside the artifact, and the distribution by a second one on an independent host. The wrapper jar sha256 also matches the
.mvn/wrapper/maven-wrapper.jaralready committed in this repository byte for byte, so the new property agrees with what contributors already run.Verified locally:
./mvnw -vstill works with the existing wrapper cache (exit 0, Maven 3.9.11)../mvnw -vwith an isolatedMAVEN_USER_HOMEforces a fresh distribution download; it downloads, passesdistributionSha256Sumand starts Maven 3.9.11.wrapperSha256Sum:mvnwaborts with "Failed to validate Maven wrapper SHA-256".distributionSha256Sumand a clean wrapper home: the wrapper aborts with "Failed to validate Maven distribution SHA-256".Both properties are therefore actually enforced by the wrapper version in use (3.3.4), not just cosmetic.
Deferred
maven-wrapper.jarin favour ofdistributionType=script/ theonly-scriptwrapper. That changes how every contributor and every CI job bootstraps Maven and deserves its own PR and its own discussion, so it is intentionally not done here. WithwrapperSha256Sumin place, the committed jar is now checksum-verified on every run, which covers the immediate concern.pr-build-main.yml,pr-doc-validation.ymlanddepsreview.yamlstill use floating tags. They are out of scope for this ticket and none of them combines a third-party build with a write-capable token; happy to follow up in a separate PR if reviewers want repo-wide consistency.Validation
actionlint1.7.12 clean on both modified workflows..github/dependabot.ymlparse as YAML.Claude Code (Opus 5) on behalf of Federico Mariani