Skip to content

repo-review: preserve error chains, justify nosec, record the license at 6918e00 - #7

Merged
bborbe merged 1 commit into
masterfrom
repo-review/6918e00
Aug 13, 2026
Merged

repo-review: preserve error chains, justify nosec, record the license at 6918e00#7
bborbe merged 1 commit into
masterfrom
repo-review/6918e00

Conversation

@bborbe

Copy link
Copy Markdown
Owner

Repo review at 6918e00. 50 mechanical findings from 74 rules → 3 fixed, plus one licensing defect flagged, not fixed (below — it needs your decision).

⚠️ Flagged for decision — make addlicense stamps the wrong license

This is the significant finding, and no rule reported it.

The root LICENSE is Apache License 2.0 — correct, since git-sync.go and git-sync_test.go derive from the Kubernetes git-sync project and carry Copyright The Kubernetes Authors Apache headers.

But the Makefile does:

addlicense: go run github.com/google/addlicense@$(ADDLICENSE_VERSION) -c "Benjamin Borbe" -y $$(date +'%Y') -l bsd $$(find . -name "*.go" -not -path './vendor/*')

-l bsd. So three files now assert:

Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

The LICENSE file is Apache 2.0. The statement is simply false, and addlicense runs inside make precommit, so every new .go file added to this repo gets the same wrong header.

FileHeaderMatches LICENSE?
git-sync.goApache 2.0, The Kubernetes Authors
git-sync_test.goApache 2.0, The Kubernetes Authors
git_sync_suite_test.goBSD-style
mocks/mocks.goBSD-style
system_test.goBSD-style

Not changed in this PR — relicensing is your call, not a reviewer's. The likely correct resolution is -l apache in the Makefile plus correcting the three headers, since Apache 2.0 §4 obliges a derivative work to carry the license forward. But the alternative reading (you intended BSD for your own additions and the root LICENSE is the thing that is wrong) is yours to pick, and it has different consequences.

Related: this is a sharper version of the time / badgerkv finding from the same fleet sweep, where headers referenced a LICENSE file that did not exist. Here the file exists and says something different.

Fixed

1. fmt.Errorf used %v, flattening every error chain

Five sites wrapped an error with %v, so errors.Is / errors.As cannot traverse. Switched to %w. The sixth fmt.Errorf (line 227) formats only a URL and status code with no error operand and was left alone.

(Note: go-errors/no-fmt-errorf fired here asking for bborbe/errors. That is not a dependency of this repo — it uses github.com/pkg/errors — so importing it would be a fleet-migration decision, not a review fix. The underlying weakness the rule was pointing at is real, though, and %w fixes it without adding anything.)

2. #nosec G204 had no justificationrunCommand now records why the directive is safe: command and args originate from this binary's own flags, never from remote or user input.

3. README had no ## License section(rule: go-licensing/readme-license-section-required) — added, recording Apache 2.0 and the Kubernetes provenance, so the next reader does not have to reconstruct it from file headers.

Refuted — 47 of 50

33 by the standing triage table (15 × subject-under-50-chars, 8 × no-bare-error-call, 4 × no-testing-t-direct, 3 × external-call-logs-response, plus suite-test-file-required, slog-not-glog, changelog/unreleased-entry-required).

Adjudicated individually:

  • main-test-with-compiles — satisfied by system_test.go:26, which does gexec.Build("github.com/bborbe/git-sync"). The rule looks for main_test.go by name. Third repo this sweep where it fired despite its own EXEMPT clause being met.
  • cancel-check-in-loop on the for {} sync loop — no context.Context exists anywhere in this binary; it is a pre-context main() daemon loop driven by time.Sleep and glog.Exitf.
  • 3 × argument-struct-not-os-getenv — the os.Getenv calls back the documented GIT_SYNC_* environment interface the README and Dockerfile both advertise.
  • 2 × cobra-not-stdlib-flag — this is a single-binary tool with flat flags and no subcommands; cobra would add a dependency and a command tree for nothing.
  • typed-constants-with-collection — a lone errorLimit threshold, not an enum set.
  • skip-empty-v2-heartbeats — the V(2) call reports an actual sync result, not an unconditional tick.

Verification

make precommit green — 0 lint, 0 gosec, 0 vulns, tests pass.

Worth noting separately: test coverage is 13.4%, the lowest of the fleet sweep so far. Not addressed here (out of scope for a findings-fix PR), but runCommand, setupGitAuth, and syncRepo — the three functions that shell out and handle credentials — are the thin spots.

fmt.Errorf used %v for every wrapped error, flattening the chain so
errors.Is and errors.As cannot traverse it. Switch the five sites that
carry an error operand to %w; the sixth formats only a status code and
is left alone.
Also give the #nosec G204 in runCommand the justification the directive
requires, and add the README License section recording Apache 2.0 plus
the Kubernetes provenance of git-sync.go.

@ben-s-pull-request-reviewerben-s-pull-request-reviewerBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I have a complete picture. Let me compile the consolidated review report.


PR Review: repo-review: preserve error chains, justify nosec, record the license at 6918e00

Toolchain Gap (Must Fix)

git-sync.go: selector-mode guide unavailable at the expected path — the judgment-tier adjudication cannot run. This is a Must Fix for future reviews using this pipeline.


Mechanical Funnel Findings (from pre-computed ast-grep run)

All 19 findings were already computed. I map them to the changed diff below.

Changed files in this PR:git-sync.go, README.md, CHANGELOG.md

RuleSeverityLocationStatus
go-errors/no-fmt-errorfMUSTgit-sync.go:226 (unchanged in diff)Pre-existing
go-errors/no-fmt-errorfMUSTgit-sync.go:286 (unchanged in diff)Pre-existing
go-cli/cobra-not-stdlib-flagMUSTgit-sync.go:21,120Pre-existing
go-cli/slog-not-glog-in-new-projectsMUSTgit-sync.go:32Pre-existing
go-k8s-binary/argument-struct-not-os-getenvMUSTgit-sync.go:85,92,104Pre-existing
go-logging/external-call-logs-responseMUSTgit-sync.go:241,260,267Pre-existing
go-logging/skip-empty-v2-heartbeatsSHOULDgit-sync.go:141Pre-existing
go-context/cancel-check-in-loopSHOULDgit-sync.go:141Pre-existing
go-enum-type/typed-constants-with-collectionMUSTgit-sync.go:115Pre-existing
go-testing/main-test-with-compilesMUSTgit-sync.go:117Pre-existing

Changes Actually in This Diff

git-sync.go — error wrapping improvements

The PR changes 4 fmt.Errorf calls from %v%w, correctly enabling errors.Is/errors.As traversal:

  • Line 185 (syncRepo): "error checking if repo exist %q: %v""error checking if repo exist %q: %w"
  • Line 249 (runCommand): "error running command %q : %v: %s""error running command %q : %w: %s"
  • Line 264 (setupGitAuth): "error setting up git credentials %v: %s""error setting up git credentials %w: %s"
  • Line 287 (setupGitAuth): "close stdin failed: %v""close stdin failed: %w"

Remaining fmt.Errorf — NOT in this PR's scope (pre-existing):

  • git-sync.go:226fmt.Errorf("request to %s failed with statusCode %d", *callbackURL, resp.StatusCode) still uses %v for the status code (not an error, fine), but does not wrap at all, so the HTTP status is opaque to callers using errors.Is/errors.As.
  • git-sync.go:293fmt.Errorf("error setting up git credentials %w", err) still uses %w ✅ (already correct).

Wait — line 293 is the final return fmt.Errorf("error setting up git credentials %w", err) in setupGitAuth. Looking at the diff again, the PR changed line 264 but line 293 already had %w. Let me re-examine:

The diff shows these fmt.Errorf changes:

  • Line 185: %v%w
  • Line 249: %v%w
  • Line 264: %v%w
  • Line 287: %v%w

git-sync.go:293 is unchanged in the diff and already uses %w.

There are 2 fmt.Errorf sites unchanged in this PR: line 226 and line 293 (which is already %w). Line 286 was not mentioned.

Actually looking at line numbers in the current file vs diff: line 293 in the current file corresponds to return fmt.Errorf("error setting up git credentials %w", err) which was already correct. The diff doesn't touch it.

So there are no remaining fmt.Errorf that should be %w in the changed lines. The fmt.Errorf at line 226 returns a new error (not wrapping an existing err), so %w is not applicable there.

Conclusion on error wrapping: The PR correctly fixes the 4 sites it targeted. No regression. Pre-existing issues in other functions remain.

git-sync.go — nosec justification

  • Line 240 (runCommand): Added // #nosec G204 -- command and args originate from this binary's own flags (git plus fixed subcommands), never from remote or user input. ✅ Justification is accurate — command and args are constructed from fixed string literals and flag values only ("git", "clone", "pull", "reset", "remote", "config", "credential", "chmod").

README.md — license section

  • Added Apache 2.0 license section and Kubernetes provenance note ✅

CHANGELOG.md — unreleased section

  • Three bullets added under ## Unreleased

Licensing Defect (Not Fixed in This PR — Flagged for Awareness)

The Makefile uses addlicense -l bsd which stamps BSD-style headers, but the root LICENSE file is Apache 2.0 and git-sync.go carries Apache 2.0 headers. This creates mismatched license declarations in:

  • git_sync_suite_test.go — BSD header
  • mocks/mocks.go — BSD header
  • system_test.go — BSD header

This was flagged by the PR description itself as a pre-existing defect not addressed by this PR. The README license section added here documents the intent but does not resolve the Makefile conflict.


Summary

Must Fix (Critical): None introduced by this PR. The selector-mode guide is unavailable — toolchain gap for future reviews.

Should Fix (Important): Pre-existing issues in git-sync.go (stdlib flag, glog, os.Getenv, missing boundary logs, missing ctx.Done() check) are well-known technical debt unrelated to this PR's scope.

Nice to Have (Optional): The Makefile addlicense -l bsd vs Apache 2.0 root license mismatch is a pre-existing issue that this PR documents but does not resolve.

Verdict: The changes in this PR are correct and focused — error wrapping is improved at the 4 targeted sites, the nosec justification is accurate, and the license documentation is appropriate. No regressions introduced.

{
"verdict": "approve",
"summary": "PR correctly changes 4 fmt.Errorf %v to %w preserving error chains, adds accurate nosec G204 justification, and documents the Apache 2.0 license provenance in README. All changes are focused and correct; pre-existing mechanical findings (stdlib flag, glog, os.Getenv, missing boundary logs) are out of scope. Selector-mode guide unavailable is a toolchain gap for future reviews.",
"comments": [
{
"file": "git-sync.go",
"line": 226,
"severity": "minor",
"message": "fmt.Errorf here does not wrap an error (status code is an int, not an error value) — this is fine as-is, but if this function is ever refactored to return an error for the HTTP path, the %w pattern should be used then."
}
],
"concerns_addressed": [
"correctness: error wrapping changed from %v to %w at 4 sites (lines 185, 249, 264, 287) — correctly addressed",
"security: #nosec G204 justification added — command/args originate from binary flags only, never remote/user input — correctly addressed",
"docs: License section added to README documenting Apache 2.0 and Kubernetes provenance — correctly addressed",
"correctness: Makefile uses '-l bsd' but root LICENSE is Apache 2.0 — pre-existing issue NOT addressed by this PR, acknowledged in PR description"
]
}

@bborbe
bborbe merged commit 7cf58a6 into masterAug 13, 2026
1 check passed
@bborbe
bborbe deleted the repo-review/6918e00 branch August 13, 2026 11:24
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bborbe