Skip to content

ci(lint): verify the golangci config against a vendored schema - #445

Merged
cristim merged 1 commit into
mainfrom
ci/420-golangci-schema-offline
Oct 16, 2026
Merged

cristim merged 1 commit into
mainfrom
ci/420-golangci-schema-offline

Conversation

@cristim

@cristim cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member

Summary

CI lint failed intermittently before any source was checked. golangci-lint v2.10.1's config verify downloads https://golangci-lint.run/jsonschema/golangci.v2.10.jsonschema.json with a hard 2s HTTP timeout (pkg/commands/config_verify.go:217-221), and golangci/golangci-lint-action runs that verify by default on every matrix leg. This hit #413, #419, #444 and #429.

The fix keeps validation and removes the live network dependency. It uses upstream's own mechanism: the --schema flag accepts file:// (config_verify.go:129-137), and upstream CI uses it (pr-checks.yml:92).

  • Vendored schema. .github/golangci/golangci.v2.10.jsonschema.json is a byte-exact copy of jsonschema/golangci.jsonschema.json at tag v2.10.1. That file is identical to what the site serves for v2.10; the versioned filename only exists from v2.11.0. Its sha256 (692e8da7…e3403) is pinned in a .sha256 file. Both files are excluded from the whitespace hooks, and the JSON also from check-json.
  • scripts/verify-golangci-config.sh <bin> [config]. It builds an absolute file:// path; a relative one parses as the URL host. It checks the schema sha256, then runs config verify --schema file://…. It fails loud if the Makefile pin, the action's version: (read only from the lint-action step) and the go install pin are not all the same version, or if the installed binary's version doesn't match them.
  • ci.yml, lint job.
    • On one leg (if: strategy.job-index == 0, so a matrix rename can't silently skip it), the job installs v2.10.1, verifies the real config, then runs a negative step. That step verifies a generated invalid config and requires a non-zero exit plus both does not validate and invalid elements, so a missing or corrupt schema cannot pass.
    • The action gets verify: false on every leg. It still lints.

Not done, by design:

  • No retries.
  • Validation is not disabled.
  • No runtime fetch from another host, since that is the same failure class.

Closes #420

Verification (macOS, golangci-lint v2.10.1 via go install, network blocked with HTTPS_PROXY=HTTP_PROXY=http://127.0.0.1:9)

Case rc Result
Baseline config verify --config .golangci.yml 3 proxyconnect … connection refused (the bug)
scripts/verify-golangci-config.sh <bin> 0 Passes offline
Invalid config (linters: {bogus: 1}) 3 Prints "linters" does not validate … additional properties 'bogus' not allowed and the configuration contains invalid elements
Mutation: --schema dropped 3 Fetch error
Mutation: go install pin changed 1 Pin mismatch
Mutation: action version: changed 1 Mismatch; the awk scope ignores other version: keys in ci.yml
Mutation: one byte appended to the schema 1 Checksum mismatch

All mutations ran in scratch copies. Vendored file: cmp against a fresh gh api fetch at v2.10.1 returned rc 0.

Tooling: actionlint rc 0, shellcheck clean, zizmor (pedantic) no new findings, and pre-commit hooks passed on commit.

Review: an independent non-author reviewer reviewed the plan in two passes and the diff in one. Findings fixed:

  • absolute file:// path;
  • non-vacuous negative test;
  • hook excludes;
  • leg-index gate instead of module name;
  • step-scoped drift grep.

No actionable findings on tree e7b11496.

The Linux paths (go install on the runner, the sha256sum fallback) are proven only by this PR's CI run.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 5 billable files and costs up to $1.25.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 33 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 65 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-go/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: a5a17d00-1cae-4e87-ab94-92ed6c946608
📥 Commits

Reviewing files that changed from the base of the PR and between 53dfba9 and 35da47f.

📒 Files selected for processing: 5
  • .github/golangci/golangci.v2.10.jsonschema.json
  • .github/golangci/golangci.v2.10.jsonschema.json.sha256
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • scripts/verify-golangci-config.sh
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cristim cristim added priority/p2 Backlog-worthy urgency/this-sprint Within the current sprint impact/internal Team-internal only severity/low Minor harm effort/s Hours type/bug Defect triaged Item has been triaged labels Oct 16, 2026
@cristim

cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Independent review verdict: CLEAN at 9bf5a43

Reviewer: fresh Claude agent (Sonnet, high effort), not the author. Coordinator: claude-cc-reviewer.

Blocking findings: none.

What was checked:

  • Genuine schema: the vendored golangci.v2.10.jsonschema.json has sha256 692e8da79dc1f110a4a4f3bb841b26ed44e461d3503678eaaae90ae8876e3403, which equals the .sha256 file and the live https://golangci-lint.run/jsonschema/golangci.v2.10.jsonschema.json byte for byte (cmp). The v2.10.1 tag's jsonschema/golangci.jsonschema.json hashes to the same value.
  • ci.yml:73-103: the action step gets verify: false but still runs golangci-lint with unchanged args, so linting stays enforced. Matrix index 0 installs the binary and runs the verify script and a negative test, which requires a non-zero exit plus "does not validate"/"invalid elements" on an invalid config.
  • Mutation: appending bogus_key: 1 to .golangci.yml makes the script return rc=3 ("additional properties 'bogus_key' not allowed"), and linters.bogus also gives rc=3. The real config gives rc=0.
  • scripts/verify-golangci-config.sh: uses set -euo pipefail and quotes its variables. It checks that the Makefile pin, the action version, the go install pin and the binary version all agree. It checks the schema's sha256 before config verify --schema file://..., so the verification step needs no network.
  • .pre-commit-config.yaml: the vendored directory is excluded from trailing-whitespace, end-of-file-fixer and check-json. pre-commit validate-config is ok. actionlint .github/workflows/ci.yml exits 0.

Non-blocking notes:

  • The new go install ...@v2.10.1 step still uses the Go module proxy. That is a smaller flake risk than before, but not zero.
  • make lint (and any local golangci run) still uses the default network schema fetch.

Gate:

@cristim

cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

CI is green on head 9bf5a43 (pre-commit 38924031539, Build & Test 38924031636). This is the Linux evidence the body was waiting for.

  • Lint Code (pkg), strategy.job-index == 0: three new steps passed.
    • Install golangci-lint for config verify.
    • Verify golangci-lint config against vendored schema.
    • Verify golangci-lint config check rejects an invalid config.
    • Run golangci-lint, with verify: false, also passed.
  • The other four legs (providers/aws, providers/azure, providers/gcp, ci_cd_sanity_tests): the three steps were skipped, and Run golangci-lint passed.

So the runner's go install and sha256sum paths work, the invalid config fails for a schema reason, and no leg fetched the schema from golangci-lint.run.

golangci-lint v2.10.1 config verify downloads its JSON schema from
golangci-lint.run with a 2s timeout, and the lint action runs it on every
leg, so a slow schema endpoint failed lint before any source was checked.
The schema is now vendored byte-for-byte from the v2.10.1 tag with a
pinned sha256, and one leg verifies the config against it through
--schema file://. A negative step proves an invalid config still fails
for a schema reason, and the script fails loud if the Makefile pin, the
action version and the installed binary drift apart.

Closes #420

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim
cristim force-pushed the ci/420-golangci-schema-offline branch from 9bf5a43 to 35da47f Compare October 16, 2026 15:49
@cristim

cristim commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Rebased onto main (server-side gh pr update-branch --rebase; the branch was BEHIND after #429 merged). git range-diff: 1: 9bf5a43 = 1: 35da47f, so the commit is identical. The CLEAN verdict carries over to 35da47f. Merge waits on CI at this head. (claude-cc-reviewer)

@cristim
cristim merged commit 071a496 into main Oct 16, 2026
15 checks passed
@cristim
cristim deleted the ci/420-golangci-schema-offline branch October 16, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/internal Team-internal only priority/p2 Backlog-worthy severity/low Minor harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: investigate schema-download failures before pinned lint verification

1 participant