Repository navigation
ci(gosec): run one rule set from a shared script in the hook, Makefile and CI - #1145
Conversation
…e and CI gosec ran with three different rule sets: the pre-commit hook excluded 15 rules, `make security-scan-go` excluded 8 and scanned only the root module (and exited 0 when gosec was not installed), and CI excluded none. A clean local run did not predict CI. scripts/run-gosec.sh now owns the gosec pin (v2.28.0), the module list (every go.work module: . and tests/e2e) and the rule set (gosec defaults, no -exclude, matching what CI already enforced). The hook only maps staged files to module/package pairs and calls it; make security-scan-go, the CI gosec step and scripts/security-scan.sh call it too. CI keeps its SARIF file names, automationDetails ids, failure semantics and upload step. The unified rule set reports 0 findings on both modules, so no code changes or new #nosec suppressions were needed. scripts/test-run-gosec.sh (run in the security-scan job) pins the module list, the absence of -exclude, the hook's package mapping and the three callers, using a fake gosec. Closes LeanerCloud#340 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 7
✨ Finishing Touches
Comment |
…issing Without scripts/run-gosec.sh the self-test stopped at its first line, so a run against the pre-fix tree showed one error instead of which callers diverge. Report the missing pin as a failed case and run the rest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
make -C prints Entering/Leaving directory lines on GNU make (the CI runner) but not on macOS make, so the exact-output check failed only in CI. Pass --no-print-directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Fixed the red Security Scanning job in f25ca0c. The new self-test compared the output of |
|
VERDICT: APPROVE f25ca0c Base: merge-base e0215b0 is stale, but Findings (none blocking)
Rule set before vs after (effective)
Attacked / local results
|
|
Independent review 2 (claude-fleet, cold): APPROVE f25ca0c Findings (none blocking):
Against #340: all four acceptance criteria are met, and this fixes the root cause.
Attacked:
Verified locally, on git-initialised scratch copies with no cloud credentials:
Reviewed by an independent agent with no author context (second reviewer). Review only: nothing was pushed, and the GitHub review state is unchanged. |
|
Local verification at
|
|
Marked ready and merged by IAmJSD's agent, at IAmJSD's request, after 2 independent reviews and local verification (see the review and verification comments above, all at |
…es it Since LeanerCloud#1145 (LeanerCloud#340), `make security-scan-go` runs scripts/run-gosec.sh, which prints text findings or writes SARIF into a given directory; nothing writes gosec-report.json at the repo root any more. Drop the /gosec-report.json rule and its test row. The test's "still in the Makefile" check kept passing for that name only because the `make clean` rm line still lists it, which is the stale guard the check was meant to catch. Skip `rm` lines when looking for the name, so a target that stops writing a file fails the test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts with LeanerCloud#1145 (scripts/run-gosec.sh, issue LeanerCloud#340), which moved the gosec install, rule set and module list into one shared script called by the pre-commit hook, `make security-scan-go`, CI and security-scan.sh, with its own GOSEC_VERSION="v2.28.0" literal. - scripts/gosec-hook.sh, scripts/security-scan.sh, ci.yml gosec step and .pre-commit-config.yaml: take main's run-gosec.sh delegation; only the comments now name .gosec-version as the version source. - scripts/run-gosec.sh: read and validate .gosec-version (the validation this branch had in gosec-hook.sh) instead of the literal, before Go runs or the cache is touched. The cache path is unchanged for v2.28.0. - scripts/test-run-gosec.sh: read the pin from .gosec-version. - scripts/test-check-gosec-pin.sh: the reader cases now run run-gosec.sh (directly and through the hook) with a stub go. - Makefile, pre-commit.yml, check-gosec-pin.sh: comments name run-gosec.sh as the reader. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Root cause
gosec ran with three different rule sets in three places:
scripts/gosec-hook.sh(pre-commit) excluded 15 rules (G101,G104,G115,G117,G118,G122,G204,G301,G304,G402,G505,G702,G703,G705,G706).make security-scan-goexcluded 8 different rules, scanned only the root module, and exited 0 when gosec was not on PATH.So a clean pre-commit or
make security-scan-gorun predicted nothing about CI.Fix
This mirrors LeanerCloud/cloud-commitments-go#485.
scripts/run-gosec.shis the single source of truth. It holds the gosec pin (v2.28.0), the module list (everygo.workmodule:.andtests/e2e) and the rule set: gosec defaults with no-exclude, which is what CI already enforced. It takes--module MOD [PKG...],--sarif-dir DIR(CI) and--list-modules(hook). It rejects any other argument.scripts/gosec-hook.shnow only maps staged files to module/package pairs andexecs the script. Per-changed-package scanning is unchanged.make security-scan-goand the CI gosec step call the script. CI keeps the same SARIF file names (gosec-root.sarif,gosec-tests-e2e.sarif), the sameautomationDetailsids (gosec-root/,gosec-tests-e2e/, checked by running the step locally), the same "scan every module, then fail" behavior (#1717), and the same merge and upload steps.scripts/security-scan.sh(a standalone helper that nothing invokes) ran a fourth, unpinned, root-only gosec. It now calls the script too.go.modtoolchain (CI'sGOTOOLCHAIN=localis respected) and cached under~/.cache/gosec/<gosec>-<go env GOVERSION>/. It is installed into a temp dir and then moved into place. If the toolchain doesn't match, gosec can't read the export data and reports 0 issues without scanning anything, so the key includes the Go version.gosec-report.json. Nothing reads it; onlycleanmentions it.scripts/test-run-gosec.shruns in thesecurity-scanjob before the gosec step. It uses a fake gosec, so it is fast and offline. It pins:-exclude) for full, SARIF and per-package runsmake -n security-scan-goruns only the script-exclude=G…list and no directgosec -flagcall exists in the Makefile, workflows orscripts/*.shoutside the scriptNew findings from unifying: none. gosec v2.28.0 (go1.26.9 build) with no excludes reports 0 issues on both modules (root: 244 files, 78,333 lines, 43 existing
#nosec). So nothing needed fixing and no#nosecwas added. This matches CI, which already ran without excludes and is green on main.Closes #340
Verification
All of this is local evidence on macOS (bash 5 and
/bin/bash3.2): shell tests with a fake gosec, plus real gosec runs on scratch copies. CI on this PR is the remaining check of the workflow change on Linux.bash scripts/test-run-gosec.sh: 17 PASS, exit 0 (also under/bin/bash3.2).origin/maincopy fails 15 checks and passes only "hook runs no scan when nothing survives filtering". The script is missing (exit 127), the old hook tries to install its own gosec,make -n security-scan-goshows the-exclude=G101,…recipe, the CI step runsgosec -fmt sarifdirectly, and the guards list the stray rule sets (Makefile:165andGOSEC_EXCLUDEinscripts/gosec-hook.sh) and the direct gosec calls (Makefile,ci.ymlandscripts/security-scan.sh).-exclude=G104to the script's args fails 5 cases. Droppingtests/e2efromMODULESfails 5 cases.os.Remove("x")(G104) andos.ReadFile(p)(G304), both of which the old hook excluded.origin/maincopy: exit 0.make security-scan-go: fails (gosec exit 1).make security-scan-go: printed "gosec not installed" and exited 0.gosec-root/with 2 results.security-scan.shgosec section:OVERALL_STATUS=1.make security-scan-go: exit 0.scripts/run-gosec.sh --sarif-dir …: exit 0, 0 results in both SARIF files.RUNNER_TEMPset: exit 0, "Merged 2 SARIF runs", idsgosec-root/andgosec-tests-e2e/.shellcheck0.11.0 on all changed scripts: clean.actionlint .github/workflows/ci.yml: clean.zizmor==1.29.0 --offline --persona=pedantic --min-severity=medium: no findings.git diff --check: clean. YAML parses.--register-aws, fresh repo, isolated HOME) over all tracked files: clean.scripts/test-git-secrets-allowlist.sh: 42 PASS.Out of scope / follow-ups
.github/workflows/pre-commit.ymlstill installsgosec@v2.28.0into~/go/bin, but its gosec hook isSKIPped in CI, so the binary is never used. That pin is dead but still duplicated. The Makefile'sGOSEC_VERSIONforinstall-dev-toolsalso remains. go#485 left the equivalent in place..golangci.ymlconfigures golangci-lint's own gosec linter (excludes: [G104]). That is a different tool and gate, and I didn't touch it.Maintainer: please mirror the issue's triage labels onto this PR:
priority/p2,severity/medium,urgency/this-quarter,impact/internal,effort/s,type/chore,triaged.🤖 Generated with Claude Code