Repository navigation
[WP12] CI/CD supply-chain & gating: unpinned actions, auto-merge without in-repo build gate, dead branch guard #180
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Labels
github_actionsPull requests that update GitHub Actions codePull requests that update GitHub Actions codestatus: on-holdWe can't start working on this issue yetWe can't start working on this issue yettype: enhancementNew feature or requestNew feature or request
Description
此內容由 AI 產生(specification-mapper 全庫審查 2026-07-16)。
Work package WP12 · findings: DEP-02, TEST-01, COR-02 · worst severity: medium
From the 2026-07-16 whole-codebase review (branch jakarta, modules mapper/ + starter/). Each finding below is CONFIRMED by independent adversarial verification. File paths and line numbers reflect the review snapshot and may drift — treat them as starting points, not exact coordinates.
DEP-02 — Third-party actions pinned to mutable tags — including madhead/semver-utils@latest — in a workflow that wields a repo-write App token and auto-merges its own PRs
- Category / severity: dependencies / medium · effort S · confidence high
- Location:
.github/workflows/bump-spring.yml:42 - Evidence: bump-spring.yml:42 uses
madhead/semver-utils@latest(a moving tag dependabot cannot pin or update); the same workflow gives third-partypeter-evans/create-pull-request@v8(line 76) a GitHub App token with contents+pull-requests write and then auto-merges the resulting PR (line 91). Other third-party actions across workflows (shihyuho/go-jenkins-trigger@v2 receiving JENKINS_PAT, wagoid/commitlint-github-action@v6, mukunku/[email protected], WyriHaximus/github-action-next-semvers@v1) are all tag-pinned, not SHA-pinned. - Failure scenario: A compromised or force-retagged release of any of these actions executes immediately in this repo's CI (the
@latestone on the very next daily run) with access to the App token or Jenkins PAT — enough to push a branch, open a bump PR carrying arbitrary changes, and let the existing auto-merge flow land it on the release branch. - Suggested fix: Pin all third-party actions to full commit SHAs (dependabot's github-actions lane keeps SHA pins updated), and at minimum replace
@latestwith a fixed release; keep first-partyactions/*on major tags if preferred. - Verification: [CONFIRMED] Traced .github/workflows/bump-spring.yml directly. Line 42 uses
madhead/semver-utils@latest— a mutable moving tag, unpinnable/unupdatable by dependabot. Line 70 mints an App token (job-level permissions contents:write + pull-requests:write, lines 51-53). Line 76 passes that token to third-partypeter-evans/create-pull-request@v8(a mutable major tag), and line 91 runsgh pr merge --squash --autowith the same App token, auto-merging the bot's own PR. So the described supply-chain surface exists exactly as claimed: a compromised or force-retagged release of any third-party action here runs in this repo's daily CI, the@latestone on the very next scheduled run, and the cr…
TEST-01 — Dependency-bump PRs are auto-merged while the only in-repo PR-triggered check is commitlint — build/test gating depends entirely on out-of-repo Jenkins branch protection
- Category / severity: testing / medium · effort S · confidence low
- Location:
.github/workflows/bump-spring.yml:91 - Evidence: bump-spring.yml:89-93 runs
gh pr merge --squash --autoon every Spring bump PR. No GitHub Actions workflow compiles or tests the code (workflows are commitlint, label-issues, release-please, site-build, bump-*; commitlint.yml is the only pull_request-triggered one). Compile/test lives only in the Jenkins multibranch pipeline (Jenkinsfile), and nothing in the repo shows Jenkins is a required status check for auto-merge. - Failure scenario: If the Jenkins PR status is not a required check (or Jenkins is down/not discovering bot branches), a Spring Boot patch that breaks compilation or tests merges to the jakarta release branch automatically the day it is published, and release-please then proposes a release from a broken tree.
- Suggested fix: Verify branch protection marks the Jenkins build as a required status check for jakarta; alternatively add a minimal
mvn verifyGitHub Actions workflow on pull_request so the gate is visible and enforced in-repo. - Verification: [CONFIRMED] Every in-repo claim traced and verified. bump-spring.yml:89-91 runs
gh pr merge --squash --autoon each created Spring bump PR. Among the 6 workflows, only commitlint.yml triggers on pull_request open/synchronize and it merely lints commit messages/PR title (no build). site-build.yml's pull_request trigger istypes: [closed]and only builds the Hugo site (npm ci + hugo), never the Java code. Compile/test exist solely in Jenkinsfile (make compile / make test / matrix). So no in-repo GitHub Actions check compiles or tests the code before auto-merge — accurate as described. The failure (broken bump auto-merging to jakarta) is genuinely conditional on out-of-repo branch protectio…
COR-02 — Jenkins failure notification is gated on BRANCH_NAME == 'main', which is never true on the active jakarta branch
- Category / severity: correctness / medium · effort S · confidence high
- Location:
Jenkinsfile:157 - Evidence: Jenkinsfile:157 wraps the slackSend failure alert in
if (env.BRANCH_NAME == 'main' ...), but this Jenkinsfile lives on (and builds) thejakartabranch — every workflow in .github/workflows targetsbranches: [jakarta]and release-please releases from jakarta, so for builds of this line BRANCH_NAME is 'jakarta' (or a PR/bot branch) and the condition is unreachable. - Failure scenario: The Unit Tests or the Java 17/21 x Boot 3.0-3.4 Matrix Tests stage fails on the jakarta release line and nobody is notified; breakage sits unnoticed until the next manual look at Jenkins or until a release build fails.
- Suggested fix: Change the guard to the branch this line actually releases from (e.g.
env.BRANCH_NAME == 'jakarta') or compare against the multibranch project's primary branch instead of a hardcoded name. - Verification: [CONFIRMED] Traced Jenkinsfile:155-157 — the
failurepost block wrapsslackSendinif (env.BRANCH_NAME == 'main' && ...). Verified the branch context:git branch --show-currentisjakarta, and there is NOorigin/mainororigin/masterremote branch (checkedgit branch -r; onlyorigin/jakartaand jakarta-derived bot/release-please branches exist). All active GitHub workflows target jakarta: commitlint.yml:4 and release-please.yml:7 both usebranches: [jakarta], and release-please releases from jakarta. Therefore any Jenkins build of this branch sees BRANCH_NAME='jakarta' (or a PR/bot branch), never 'main', so the failure Slack alert is dead code and test/matrix failures go …
Full report: see the codebase-review-2026-07-16 branch (linked on the parent tracking issue).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
github_actionsPull requests that update GitHub Actions codePull requests that update GitHub Actions codestatus: on-holdWe can't start working on this issue yetWe can't start working on this issue yettype: enhancementNew feature or requestNew feature or request
Activity
shihyuho commentedon Jul 16, 2026
Triage Notes - needs human
Category: enhancement (bundles two CI/supply-chain hardening findings and one CI-config correctness bug)
Summary: The CI/CD surface on
jakartahas three confirmed weaknesses — third-party Actions pinned to mutable tags (including@latest) in a token-wielding auto-merge workflow, dependency-bump PRs auto-merged with no in-repo build/test gate, and a Jenkins failure-alert guard hardcoded to a branch (main) this line never builds — but every fix lands in CI/supply-chain infrastructure that cannot be verified by the in-repo JUnit suite.Current behavior
compare-versionjob usesmadhead/semver-utils@latest, a moving tag Dependabot cannot pin or update. The same workflow mints a GitHub App token (job permissionscontents: write+pull-requests: write), hands it to third-partypeter-evans/create-pull-request@v8, then runsgh pr merge --squash --autoon the bot's own PR with that token. Every third-party action across the workflows is pinned to a mutable tag, not a commit SHA —madhead/semver-utils@latest,peter-evans/create-pull-request@v8,shihyuho/go-jenkins-trigger@v2(receivesJENKINS_PAT),shihyuho/go-spring-version@v1,liskin/gh-workflow-keepalive@v1,wagoid/commitlint-github-action@v6,mukunku/[email protected],WyriHaximus/github-action-next-semvers@v1,peaceiris/actions-hugo@v3,peaceiris/actions-gh-pages@v4. Agithub-actionsDependabot lane is already configured (weekly).Commitlintis the onlypull_request-triggered check and it only lints commit messages / PR title;Site Build'spull_requesttrigger istypes: [closed]and builds only the Hugo site. No GitHub Actions workflow compiles or tests the Java code. Compile/test (make compile,make test, the Java 17/21 × Boot matrix) live solely in the Jenkins multibranch pipeline, and nothing in the repo shows the Jenkins status is a required check for auto-merge.post { failure { ... } }block, theslackSendalert is guarded byif (env.BRANCH_NAME == 'main' && ...). This Jenkinsfile lives on and buildsjakarta; there is noorigin/main/origin/master(confirmed — onlyjakartaand jakarta-derived bot/release branches exist), and every workflow targetsbranches: [jakarta]. SoBRANCH_NAMEisjakarta(or a PR/bot branch), nevermain, and the failure alert is unreachable dead code.Desired behavior
@latestreplaced with a fixed release SHA; Dependabot'sgithub-actionslane keeps SHA pins current. First-partyactions/*may stay on major tags.jakartabranch-protection rule, or a minimalmvn verifyGitHub Actions workflow runs onpull_requestso the gate is enforced in-repo before auto-merge lands.jakarta, or a comparison against the multibranch project's primary branch) instead of the hardcodedmain.Key interfaces (named, no line numbers)
.github/workflows/bump-spring.yml— jobscompare-version(madhead/semver-utils@latest),bump-spring(app-token →peter-evans/create-pull-request@v8→gh pr merge --squash --auto),keepalive..github/workflows/release-please.yml,.github/workflows/bump-snapshot.yml—shihyuho/go-jenkins-trigger@v2(holdsJENKINS_PAT),WyriHaximus/github-action-next-semvers@v1,mukunku/[email protected]..github/workflows/commitlint.yml,.github/workflows/site-build.yml— the onlypull_request-triggered workflows; neither compiles/tests Java..github/dependabot.yml— existinggithub-actionsupdate lane.Jenkinsfile—post { failure }block;BRANCH_NAMEguard; stagesUnit Tests,Matrix Tests.jakarta(out-of-repo).Acceptance criteria
@latestremains;actions/*first-party may remain on major tags per policy.github-actionslane still resolves and can propose SHA updates for the pinned actions.jakartabranch-protection rule lists the Jenkins build as a required status check (evidence attached), or an in-repopull_requestworkflow runsmvn verifyand is required.jakartaline triggers theslackSendalert (guard evaluates true for the active release branch); the alert stays suppressed for interrupted builds that never captured commit metadata.Out of scope
maketargets.Needs human because:
JENKINS_PATare exposed; it needs an owner's supply-chain sign-off, plus a policy call on whether first-partyactions/*are also pinned. There is no in-repo JUnit surface to verify workflow behavior — an agent self-verifying withmvn testcannot confirm the workflows still run.jakarta? — requires inspecting repository branch-protection settings the agent cannot reach. The alternative (adding a duplicatemvn verifyGitHub Actions gate) is a CI-strategy decision (duplicate the Jenkins build in Actions?) with no in-repo test to prove it gates auto-merge. Finding confidence waslow.postblock. A human should also confirm the intended target (hardcodejakartavs. compare against the multibranch primary branch).shihyuho commentedon Jul 20, 2026
Superseded by #197 in the execution map #204, which carries the same findings (DEP-02, TEST-01, COR-02). This 2026-07-16 static plan is being retired in favour of that map.