Skip to content

[Bug] golangci-lint runs in CI but not in any task target, so lint failures only surface on the PR #299

Description

@arasHi87

Description

CI runs golangci-lint as its own lint job, but there is no lint target in the Taskfile.yml — so it is not part of task test, task test-integration, or task ci. A developer can run the whole local suite green and still fail CI.

That happened on #298: 40/40 packages passed locally, CI failed on a one-line ineffassign. golangci-lint was already on the developer's PATH; nothing pointed at it.

Why it needs its own ticket

Adding the target is two lines, but making it pass is not. Two flags are needed to match CI rather than merely resemble it:

  • --build-tags=integration, or integration-tagged files are excluded and their findings only ever surface on the PR;
  • GOOS=linux, because the kernel-facing packages are linux-only — on a darwin host every file in them is excluded by build constraints and golangci-lint exits non-zero on the resulting typecheck error.

Resolved during the work — recorded because it is the interesting part. GOOS=linux on a darwin host looked like the obvious way to get the linux-only packages to typecheck, and it produced two findings CI does not report:

internal/neutron/resolve_test.go:218:5: SA5011(related information): this check suggests that the pointer can be nil
internal/neutron/resolve_test.go:221:9: SA5011: possible nil pointer dereference

Both are false positives. The deref sits after a t.Fatalf, which never returns — the code is correct. Cross-compiling loses staticcheck's fact that testing.T.Fatalf is terminal, so it flags a sound pattern. CI, running natively, has the fact and stays quiet.

So the discrepancy was cross-compilation over-reporting, not CI under-reporting, and the GOOS=linux approach is unusable: a lint target that invents failures is worse than no target. The faithful option is to run it where CI runs it — natively, inside the existing Docker builder.

Second requirement found the same way: the target must depend on generate. Without the bpf2go-generated types internal/bpf does not typecheck and every dependent package is analysed with degraded facts — silently, with no error that says so. CI already runs task generate before lint for exactly this reason.

Definition of Done (DoD)

  • lint target in Taskfile.yml running the same command and flags as the CI job — in the builder, deps: [generate]
  • Folded into task ci alongside test and bench-gate
  • task lint exits 0 on a clean tree, from any host — it runs in the linux builder, so the host OS stops mattering
  • The two SA5011 findings resolved — false positives, no code change: the deref follows a t.Fatalf. Not excluded either; running natively means they never appear
  • The native-linux vs cross-compiled discrepancy explained — see above, and recorded in comments on both the Dockerfile line and the task target
  • golangci-lint pinned in the builder image to the version the workflow installs (2.12.2), with a note to bump both together

Technical notes

Verified by mutation: reintroducing the exact ineffassign that failed CI on #298 makes task lint report 1 issues; reverting returns 0 issues.

One cost to know about: golangci-lint now lives in the builder image, so task setup must be re-run after pulling this or task lint fails on a missing binary. Every other real task in this repo (generate, binary, test-integration) already goes through the builder, so this follows the grain rather than adding a new mechanism.

Output artifacts (Definition of Done)

Beyond code, docs, and config changes, completing this issue must also deliver:

  • Handbook knowledge update — only if the discrepancy turns out to be
    generally useful (e.g. "how to run this repo's CI checks locally"); a
    two-line Taskfile target on its own does not need a kb entry.

Activity

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions