Skip to content

fix: gate go-licensing rules on real repo visibility - #105

Merged
bborbe merged 1 commit into
masterfrom
fix/license-rule-private-repos
Aug 13, 2026
Merged

fix: gate go-licensing rules on real repo visibility#105
bborbe merged 1 commit into
masterfrom
fix/license-rule-private-repos

Conversation

@bborbe

@bborbe bborbe commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Problem

check_license_file_required (scripts/rule-checks.sh) was a bare [ ! -f "$TARGET_DIR/LICENSE" ]. Its emitted message reads "Public Go projects must have a root LICENSE file", but nothing in the function ever determined whether the repo was public — so docs/go-licensing-guide.md's private-repo exemption was documented and never implemented. check_readme_license_section had the same gap.

Two further defects in the same rule:

  • The guide's detection heuristic ("hosted on github.com → public") predates the Octopus migration, which moved 73 private Seibert-Data repos onto github.com. Host stopped implying visibility.
  • The rule was not actually Go-scoped despite its own comment saying "applies to any Go project" — it fired on repos containing no Go at all.

Measured impact: 4 of 73 non-archived Seibert-Data repos have a LICENSE. This MUST-tier rule was firing on essentially every repo in the org, on every PR. Seibert-Data/agent#7 had to be admin-merged to get past it.

Change

  • repo_visibility() — reads gh repo view --json isPrivate, memoised (one call per run at most) and consulted only when a finding would otherwise fire, so the common path stays cheap.
  • repo_is_public() — true only when the repo is known public. Fails open on unknown (no gh, no remote, offline, not a repo): a MUST-tier false positive blocks every PR in an org, while a missed finding on a public repo surfaces at the next review.
  • license-file-required now also requires go.mod, matching its documented Go scope.
  • Guide rewritten to use the isPrivate flag, with an explicit "do NOT infer visibility from the host" note and the fail-open behaviour documented.

Verification

make precommit passes (30 rule-coverage tests, 225 bench tests). Six behavioural cases run against real clones:

Case Expected Result
No remote / not a repo fail open, silent ✅ no findings
Private + go.mod, no LICENSE silent ✅ no findings
Public + go.mod, no LICENSE still fires license-file-required
Private, README without ## License silent ✅ no findings
Public, README without ## License still fires ✅ both rules
No go.mod silent (Go-scoped) ✅ no findings

The regression cases matter as much as the fix: this must not silently disable licensing enforcement on public repos, and it doesn't.

check_license_file_required was a bare [ ! -f LICENSE ] test. Its message
claimed 'Public Go projects must have a root LICENSE file', but nothing in
the function determined whether the repo was public, so the licensing
guide's private-repo exemption was documented and never implemented.
check_readme_license_section had the same gap.

Visibility now comes from the repo's own isPrivate flag via gh, memoised
and only consulted when a finding would otherwise be emitted. Both rules
fail open when visibility cannot be determined: these are MUST-tier, so a
false positive blocks every PR in an org, while a missed finding on a
public repo is caught at the next review.

license-file-required is now Go-scoped as its own docs already claimed.

The guide's host-based heuristic is replaced too — the Octopus migration
moved 73 private repos onto github.com, so host stopped implying
visibility. 69 of 73 non-archived Seibert-Data repos carry no LICENSE by
design, so the rule was blocking essentially every PR org-wide.

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot 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.

{
  "verdict": "approve",
  "summary": "Clean fix. The PR correctly gates both go-licensing MUST rules on real repo visibility (via `gh repo view --json isPrivate`) instead of the broken host-based heuristic, bringing the enforcement in line with what the rule's own `applies_when` always stated. Fail-open is documented and intentional. The go.mod scoping on `license-file-required` aligns with the rule's docs. Conventional-prefix changelog entries are correct. Shellcheck passed with zero findings.",
  "comments": [],
  "concerns_addressed": [
    "correctness: fail-open behavior on 'unknown' visibility is documented intentional design — MUST-tier false positives block all PRs, missed findings on public repos surface at next review",
    "correctness: license-file-required now requires go.mod (Go-scoped per its own docs) — narrowing scope away from non-Go repos with LICENSE files is the correct behavior",
    "correctness: REPO_VISIBILITY_CACHE is a single-run script with correct short-circuit on cache hit — no stale-cache issue in practice"
  ]
}

@bborbe
bborbe merged commit b5f1505 into master Aug 13, 2026
1 check passed
@bborbe
bborbe deleted the fix/license-rule-private-repos branch August 13, 2026 20:13
Sign up for free to 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