Repository navigation
enh(secu): manage invalid-revision range error - #64
Merged
Merged
Conversation
sc979
commented
Jul 28, 2026
sc979
commented
Jul 28, 2026
sc979
commented
Jul 28, 2026
sc979
commented
Jul 28, 2026
sc979
commented
Jul 28, 2026
sc979
commented
Jul 28, 2026
sc979
marked this pull request as draft
July 28, 2026 12:18
sc979
commented
Jul 29, 2026
sc979
commented
Jul 29, 2026
sc979
commented
Jul 29, 2026
sc979
commented
Jul 29, 2026
sc979
commented
Jul 29, 2026
sc979
marked this pull request as ready for review
July 29, 2026 09:25
sc979
commented
Jul 29, 2026
sc979
commented
Jul 29, 2026
sc979
commented
Jul 29, 2026
This was referenced Sep 21, 2026
Contributor
Author
✅ Automated Review — PassedThis PR was reviewed using the Centreon automated review skill. Complexity: high — Recommended reviewers: 2 No blocking issues found. Ready for human review.
Areas that deserve careful human attention:
|
sc979
marked this pull request as draft
October 7, 2026 08:41
Co-authored-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com> Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
already managed by the triggering pipeline. causing failing loop Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
On a push that creates a new branch (or rewrites history), the gitleaks range fell back to a full-history scan. Because a branch usually forks off the default branch, that re-scanned commits already living in the default branch and re-reported pre-existing secrets that the branch never introduced. Resolve the range against the default branch instead: scan only merge-base(origin/<default>, after)..after, i.e. the commits unique to the branch. The empty-"before" case now follows the same path, so it is consistent with a real new branch. When the default branch cannot be resolved, fall back to a full scan (over-scan is the safe direction). Also correct the range-resolved log to ::notice:: (::info:: is not a valid workflow command). Assisted-by: Claude Code (claude-opus-4-8)
Since persist-credentials: false, the re-fetch that recovers commits
missing from the clone ("invalid revision range") had no credentials
and could never succeed. Re-fetches now authenticate with the job token,
passed to each git process only through env-scoped config: nothing is
written to .git/config, shown on a command line or exported to
gitleaks. The PR base, the pushed SHA and tag pushes are handled too,
with a backoff between attempts and a warning on every fallback.
Make the scan cover what the change under test brings, and fail closed:
- PR scans include commits merged in from other branches, and
.gitattributes can no longer hide file contents (--text)
- a rewritten default branch gets a full scan instead of an empty range
- gitleaks errors, unsupported events and unresolvable ranges fail the
job; pull_request_target always fails, before checkout, as it is not
compliant with the security posture; branch deletions pass
- the gitleaks binary is verified against a sha256 pinned in the
workflow, and the job token is scoped to contents: read
Also document the workflow in CLAUDE.md and drop stray whitespace from
the PR template.
Assisted-by: Claude Code (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Since #74 the PR checkout is shallow (fetch-depth = PR commits + 2). When the base branch moved further than that since the PR forked, the merge-base was unreachable: the scan concluded "no shared history" and ran a full scan of the shallow clone, where gitleaks reads boundary commits as roots and reports every pre-existing secret in the tree. A clean PR then failed on secrets already on the base branch. The scan now deepens the PR history (32 to 1024 commits, doubling) until the fork point is reachable from both sides, unshallows as a last resort, and never scans a range holding a shallow boundary commit. "No shared history" is only concluded on a complete clone. Deepening goes through the authenticated fetch and stops when a fetch brings nothing, so the existing retry loop takes over. Also shorten the pull_request_target error message. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
Secrets already on the destination branch are that branch's own business: the scan must fail only when one of the analyzed branch's commits holds a secret, whatever the destination is called. Several ranges broke that rule: an unrelated-history PR, a rewritten or created default branch, workflow_dispatch and schedule scanned the full history of every branch; a new branch was compared with the default branch only (wrong for branches cut from dev-YY.MM.x); and a push merging the destination back in rescanned its commits. - pull_request scans base..head, the commits not on the PR base. - push, workflow_dispatch and schedule scan the ref's commits that are on no other branch (nor before the push), excluded through --remotes so the range does not grow with the branch count. An empty range passes without running gitleaks. - On the shallow PR checkout, only the base side is deepened, from the base SHA, until base..head holds no parentless commit, so the PR side is not fetched again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
A commit must be scanned until it is on the destination branch, even when another branch (load, performance or security tests...) already holds it: excluding every other branch let such commits through, e.g. a dispatch on a branch whose commits sit on feature branches, or one push updating two branches. - push to an existing branch scans before..after, every pushed non-merge commit; a "before" missing after a force-push is fetched once while the server still serves it. - push creating a branch (or whose "before" is gone), workflow_dispatch and schedule have no destination nor "before" to exclude, so they scan the ref's whole history. - pull_request is unchanged: base..head. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
The secret scan is a pull request gate; workflow_dispatch is kept to debug the pipeline. Push and schedule are no longer supported: the job fails closed on them, like on any other unsupported event, and security-checks.yml only calls the secret scan on pull_request and workflow_dispatch (its push and schedule runs keep the dependency scan). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
Align security-checks.yml with the supported scan events: drop the push and schedule triggers, so the per-job event filter on the secret scan is no longer needed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
The runner paragraph still named centreon-security and ubuntu-24.04: describe the runners selected since #75, and that internal repositories get the self-hosted runner too. Refs: SECU-1249 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
Some runners (centreon-ubuntu-26.04-small) already ship gitleaks. Keep it when `gitleaks version` reports the pinned GITLEAKS_VERSION, and install the pinned release, verified against GITLEAKS_SHA256, in every other case: gitleaks missing (e.g. the public ubuntu-26.04 runner) or any other version. Refs: SECU-1249 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
Use the rule of the centreon-ubuntu-26.04 runner images (centreon-images, runners/base-ubuntu-26.04/Dockerfile), so the private runner's preinstalled gitleaks is the expected one and gets reused: GITLEAKS_VERSION "latest" is the newest stable release published at least 4 days before the run, and a version can still be pinned. When the runner's gitleaks differs, the release for the runner's architecture is installed and verified against its checksums file. The GitHub API is called with the job token, passed through curl's config on stdin, to avoid the anonymous rate limit shared behind an egress IP. Refs: SECU-1249 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
The latest-release lookup sent the job token to the GitHub API only to lift the anonymous rate limit. Read the public releases feed instead: it needs no token and no API quota, and its <updated> date is at or after the publication date, so the 4-day delay still holds. Drafts are not in the feed and only vX.Y.Z tags are kept. jq is no longer needed. Refs: SECU-1249 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
An unreachable releases feed failed the job, blocking every pull request of the org. Install GITLEAKS_FALLBACK_VERSION (8.30.1) instead, still verified against its checksums file, and emit a gitleaks-version-fallback warning so the issue can be found and investigated. Refs: SECU-1249 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
Since #75, pull request scans run on centreon-ubuntu-26.04-slim: both the slim and small runners are built from base-ubuntu-26.04, which ships gitleaks. Refs: SECU-1249 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Assisted-by: Claude Code (claude-opus-5-5)
sc979
force-pushed
the
SECU-gitleaks-custom
branch
from
October 12, 2026 15:36
bdd0adb to
56075db
Compare
This was referenced Oct 13, 2026
sc979
marked this pull request as ready for review
October 13, 2026 15:59
sc979
commented
Oct 13, 2026
sc979
commented
Oct 13, 2026
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Signed-off-by: Stéphane Chapron <34628915+sc979@users.noreply.github.com>
Runners without the expected gitleaks (e.g. GitHub-hosted ubuntu-26.04) failed the install with a bare curl 404: the runner architecture detection had been dropped, so the tarball URL had an empty architecture. Restore it, and enable nounset in the install step so an undefined variable fails with an explicit error instead of a broken URL. Assisted-by: Claude Code (claude-opus-5-5)
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.
Description
What are your needs or what are you planning to do in this PR?
Resolves the "Invalid revision range" failures on the gitleaks job by replacing
gitleaks/gitleaks-actionwith the gitleaks binary (reused from the runner or installedand verified) driven by a script that resolves the scan range defensively
(authenticated re-fetch + retry), scans every commit of the analyzed branch that is
not already on the destination branch, and fails closed.
Includes SECU-1249 (#76, merged into
this branch): gitleaks install aligned on the
centreon-ubuntu-26.04runner images.Tests
centreon/centreon-documentation#5710
centreon/centreon-documentation#5711
https://github.com/centreon/delivery-tooling/pull/443
Tasks covered
the job token (env-scoped git config, never on disk nor on a command line), with a
5-attempt retry and live-tip fallbacks.
base..head, whatever thedestination is called; secrets already on the destination never fail it.
trustworthy, so no shallow boundary is scanned as a root.
pull_requestandworkflow_dispatchonly (whole ref historyon dispatch);
pull_request_targetrejected before checkout; any other event fails.security-checks.ymlruns on these two events only.fail the job;
.gitattributescannot hide file contents (--text).contents: read.release published at least 4 days ago, read from the public releases feed without
any token), runner binary reused when it matches, release verified against its
checksums file,
8.30.1fallback when the feed cannot be resolved.CLAUDE.mddescribes the workflow and the Ubuntu 26.04 runners from feat(ci): run the centreon scans on the sized ubuntu 26.04 runners #75.Quality gate
Every non-merge commit of the analyzed branch is scanned. Only the commits already on
the destination branch are excluded, whether or not they are also on other branches
(load, performance or security test branches…), so no new secret can reach the
destination unnoticed.
The workflow assumes no branch name (
main,develop,dev-YY.MM.x…): thedestination comes from the event itself.
Supported events:
pull_request(the quality gate) andworkflow_dispatch(mostly todebug the pipeline). Org usage, checked on 2026-10-07: 73 of the 76 non-archived
repositories (centreon + quanta-computing) call
gitleaks-analysis.yml@mainthroughsecu-secret-scan.yml, on exactly these two events. In this repository,security-checks.ymlnow runs on these two events only (its push and scheduletriggers are removed).
centreon/.githubhas no caller, andquanta-computing/cxm-zone-probeis empty.The branch is rebased on
main(after #75): it keeps the runners of #75,actions/checkoutv7.0.1 withpersist-credentials: false(#69, #71) and the shallow PRcheckout from #74 (
fetch-depth= PR commits + 2, full clone otherwise). The job token isscoped to
contents: readonly: the script calls no GitHub API, so thepull-requests: readadded for the action in #72 is dropped.Scan range per event
The range is passed to gitleaks as
--log-optsand validated withgit logfirst.Every range carries
--text, so a repository's.gitattributes(e.g.* -diff)cannot hide file contents from the scan.
pull_requestbase..head,--no-merges: every commit not on the PR base, including commits merged in from other branches (gitleaks-action's--first-parentskipped them), excluding the base commits merged into the PR. A PR with an unrelated history scans its own historyworkflow_dispatch--no-merges: no destination to excludepull_request_targetpush,schedule,merge_group…)An empty range (e.g. a PR whose head is already on its base) passes with a notice,
without running gitleaks.
Shallow PR checkout (#74)
Pull requests are checked out with
fetch-depth= PR commits + 2, which holds every PRcommit. When the base branch moved further than that since the PR forked, the base side
does not reach the shared history yet, and a shallow boundary commit looks parentless:
gitleaks would scan its whole tree and report every pre-existing secret. So, for
pull_request, the range is trusted only oncebase..headholds no parentless commit:--depth= PR commits + 1 + 32, 64 … 1024 from thebase SHA, through the same authenticated fetch), so the PR side is not fetched again;
--unshallowis the last resort (e.g. unrelated histories);In the tests, with
main100 commits ahead of a 1-commit PR, 3 deepen rounds fetchabout 130 base commits, and the clone stays shallow.
workflow_dispatchkeeps a fullclone (depth 0).
Re-fetch when hashes changed after checkout
actions/checkoutpins its refs and can't be re-run in a loop. When the event's SHAsare missing from the clone, the step re-fetches and retries, up to 5 attempts with a
5/10/15/20 s backoff:
refs/pull/<n>/head, the base branch, and the event's head/baseSHAs if still served. A head (or base) SHA force-pushed away falls back to the live
PR tip (or base branch tip), with a
::warning::.force-pushed away, falls back to the live tip of the branch, with a
::warning::(branches only: a tag never falls back to a same-name branch).
Failed fetches are logged as
::warning::. If the range is still unresolvable, the jobfails and points to those warnings.
Credentials stay unpersisted.
persist-credentials: falseis kept as a hardeningmeasure, so the clone holds no token. The re-fetches authenticate with the job token,
set on each
git fetchprocess only through env-scoped git config(
GIT_CONFIG_COUNT/KEY_0/VALUE_0): never written to.git/config, never on acommand line, masked in the logs, and not exported to the gitleaks process.
gitleaks install
Same rule as
runners/base-ubuntu-26.04/Dockerfilein centreon-images (#390):GITLEAKS_VERSION: "latest"is the newestvX.Y.Zrelease published at least 4 daysbefore the run, read from the public releases feed (
releases.atom): no token, noGitHub API call. A version can still be pinned.
GITLEAKS_FALLBACK_VERSION(8.30.1) is used, with agitleaks-version-fallbackwarning, so the run is not blocked.gitleaks versionmatches, the runner's binary is kept (thecentreon-ubuntu-26.04-*runners ship it). Otherwise the release for the runner'sarchitecture (
x64/arm64) is installed and verified against the release'schecksums file; a checksum mismatch fails the job.
Runner requirements for the install step:
curl,python3, GNUdate,sha256sum,tar(present onubuntu-26.04and thecentreon-ubuntu-26.04images; to check onquanta-security).Build outcome
2).gitleaks.toml)pull_request_targetpush,schedule…)Test coverage
Both
run:steps are extracted verbatim from the workflow and run withbash -e,as GitHub does. The scan runs against throwaway repos whose remote is served over smart
HTTP and rejects any request without the job token: a runner-like full clone
(
fetch-depth: 0, no persisted credentials, detached HEAD) with commits pushed afterthe clone, and a shallow PR checkout (merge commit fetched at depth PR commits + 2, as
actions/checkoutdoes,main100 commits ahead of the fork point).mainanddev-26.10.x+ clean branch → OK; branch leak → KO, only the branch's file reported; after mergingmainthat brought a new secret → OK; unrelated history → OK when clean, KO when it leaks. Dispatch: whole history scanned (KO on any secret in it, OK on a clean orphan branch)main100 commits ahead → pass, 3 base-side deepen rounds, no boundary commit scanned, no unshallow; PR's own leak reported (notmain's);mainmerged in →main's secret not reported; leaking side branch reported; unrelated history with secrets on base → unshallow, pass; deepen with an invalid token → fail closed, one fetch per attempt, token not in argv::warning::+ failure; tag dispatch with its SHA gone → no fallback to a same-name branch.git/, not in any git argv, not in gitleaks' environment, base64 header maskedpush,schedule,merge_group→ fail (unsupported);pull_request_targetrejected by the first step (before checkout) and by the script;security-checks.ymltriggers on PR and dispatch only0pass;2fail;1/126fail; empty range → pass without running gitleaks.gitattributes* -diffdoesn't hide a leak (PR and dispatch); broken.gitleaks.toml→ job fails8.30.1/v8.30.1) and replaced otherwise (8.31.0, missing, distro build), pinned version (no feed read), feed fallback to8.30.1with a warning, checksum mismatch / missing checksums file → fail,arm64tarball, unsupported architecture → fail, no token sentResult: 131 / 131 passed on the rebased branch. Release downloads are served by a
curl stub from the real
8.30.1tarball and checksums file; the feed parser also returns8.30.1on the real feed.🤖 Generated with Claude Code