Skip to content

refactor(tooling): base-ref resolution is duplicated across four CI guards while scripts/lib exists #13984

Closed

Description

@mrveiss

Discovered while delivering #13876, #13879 and #13880. Partly self-inflicted — two of the four copies were added by that work.

The duplication

Every changed-files guard now resolves a base ref and status-checks its git calls, independently:

File base-resolution call sites
pipeline-scripts/check-pre-commit-hook-pr.sh 5
.github/workflows/code-quality.yml (inline) 4
scripts/lint-conventions.sh 1
scripts/verify-done.sh 1

All four encode the same hard-won rules: on a pull_request the checkout is the merge commit so HEAD^1..HEAD is the PR's own changes; origin/<base> is the base's current tip and drags in other PRs' merges; an unresolvable ref must be fatal rather than read as "no changes". Those rules were learned once and written four times, so the next correction has to be applied four times or the copies drift.

scripts/lib/ already exists as the canonical home for shared shell helpers (branch-guards.sh, project_root.sh), each with a colocated *_test.sh. Neither new script sources it. That is a "consolidate, never fork" violation.

Second, related finding: function length

scripts/verify-done.sh's branch_state() is 113 lines against the repo's ≤30-line rule. It accumulated one guard per review round (seven rounds, thirteen defects) and each is individually justified, but the result is a single function holding six distinct decisions. Extracting them is the same refactor as the above — the guards become named, testable helpers.

Change

  • scripts/lib/git-scope.sh — one status-checked base/head resolver encoding the merge-commit rule, with a colocated test
  • All four call sites source it; the inline workflow copy becomes a call
  • branch_state() decomposed into named predicates (has_merge_unique_content, substantive_commits, content_in_base, …), each ≤30 lines and independently testable

Implementation order

Wave 1 — extract scripts/lib/git-scope.sh + tests from the existing four copies (no blockers)
Wave 2 — repoint check-pre-commit-hook-pr.sh and code-quality.yml (depends on wave 1)
Wave 3 — repoint lint-conventions.sh, decompose branch_state() (depends on wave 1)

Acceptance criteria

  • One resolver in scripts/lib/, sourced by all four call sites
  • Colocated *_test.sh or *_test.py covering the merge-commit, shallow-clone and unresolvable-ref cases
  • No function in scripts/verify-done.sh exceeds 30 lines
  • Existing suites (verify_done_test.py, lint_conventions_test.py, check-pre-commit-hook-pr_test.py) still pass unchanged

Activity

  1. mrveiss commented on Aug 11, 2026

    @mrveiss
    OwnerAuthor

    Discovered during the #13874/#13876/#13879/#13880 session. Cross-linked from those issues' closure comments.

  2. github-actions commented on Aug 11, 2026

    @github-actions
    Contributor

    👋 Auto-triage could not confidently classify this issue (no confident signal). Could a maintainer add the appropriate labels (frontend, backend, infrastructure, docs, testing and good-first-issue, intermediate, advanced)?

  3. mrveiss commented on Aug 23, 2026

    @mrveiss
    OwnerAuthor

    Delivered in #14883 as part of the CI-guard cluster (#14371, #13984, #12986, #14034). #14181 was measured and deliberately excluded — see the comment there for where it actually stands. Discovered and filed rather than dropped: #14884, #14885.

  4. mrveiss commented on Aug 23, 2026

    @mrveiss
    OwnerAuthor

    Delivered and merged.

    Verified in base after merge:

    scripts/lib/hardcoded-value-rules.sh          PRESENT
    pipeline-scripts/check_baseline_no_growth.sh  PRESENT
    pipeline-scripts/hardcoded_values_baseline.txt PRESENT
    scripts/lib/git-scope.sh                      PRESENT
    

    Union preserved — rules a survivor-pick would have deleted:

    Rule Existed only in Now
    VM IP, any fourth octet CI scanner kept wide; the hook's narrow (19|2[0-5]) did not win
    Ports 8443 / 5432 / 9090 CI scanner's PORT_PATTERN — declared and never grep'd wired in for the first time
    Per-value SSOT key suggestions, generic model regex, hardcoded-URL rule dormant fork carried
    Account identity (User=, chown, sudoers) CI scanner carried
    offset=0 as WARNING not VIOLATION hook severity preserved

    scripts/lib/hardcoded_value_rules_test.py fails by name per former detector, so a substitution cannot pass as a merge.

    One HIGH finding was raised in review and fixed before merge, not deferred. The baseline suppressing 1977 findings had no anti-growth check: a PR could hardcode a value and append a matching baseline line in the same commit, and ssot-coverage would report ssot_violations=0. check_baseline_no_growth.sh now diffs the baseline against the base ref and fails on any new key or increased count, failing closed on an unresolvable base, an unreadable baseline, or a parse error. Mutation-proved in a scratch repo both directions — growth red, shrinkage green.

    A real credential exposure was found and fixed while doing it. Two postgresql://user:pass@host/db values were already sitting in the generated baseline, a tracked file that also reaches public CI output. One shared _hv_redact_userinfo now serves both the DSN and URL rules; scheme and host survive so findings stay actionable. Verified in base: zero user:pass@ patterns remain, and the baseline totals are unchanged at 1434 lines / 1977 — the redaction dropped no finding.

    Also fixed: api-wiring — a required check — omitted autobot_shared/**/*.py from its path filter while audit_api_wiring.py imports two modules from that tree, so it reported green over an audit that never ran (#12986).

    #14181 was deliberately not closed by this PR — measured at 8/10 on one criterion with the remainder blocked by epic #7442. Follow-ups filed: #14884, #14885, #14891.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions