Resolves #45220. Manual dispatch of golangci-lint automation to catch any issues in macOS and Windows: https://github.com/fleetdm/fleet/actions/runs/26230838836. ## Testing - [X] QA'd all new/changed functionality manually Manually tested by adding fake imports of "testing" in production packages. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Enforced a new pre-lint build check that fails when production binaries depend on test-only packages, preventing accidental testing imports in releases. * Added a CLI-based dependency audit and integrated it into the lint workflow, plus updated build help text to surface the new check. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45977?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
118 lines
3.5 KiB
Go
118 lines
3.5 KiB
Go
// Command check-no-testing-in-prod fails the build if any Fleet-owned (i.e.
|
|
// github.com/fleetdm/fleet/v4/...) package reachable from cmd/fleet,
|
|
// cmd/fleetctl, or orbit/cmd/orbit directly imports Go's "testing"
|
|
// package.
|
|
//
|
|
// Background: see https://github.com/fleetdm/fleet/issues/45220. Test
|
|
// helpers used to be sprinkled across production packages as
|
|
// testing_utils.go files that imported "testing"; that pulled the test
|
|
// scaffolding (and its -test.* flags, etc.) into the shipping binaries.
|
|
// The cleanup moved each such helper into a sibling *test subpackage or
|
|
// _test.go file. This guard makes sure nothing slips back.
|
|
//
|
|
// Usage:
|
|
//
|
|
// go run ./tools/check-no-testing-in-prod
|
|
//
|
|
// Wired into make lint-go (see Makefile).
|
|
//
|
|
// Note: third-party dependencies (currently a few pkcs7 forks and
|
|
// apache/thrift) are intentionally NOT checked here -- they're out of our
|
|
// control without an upstream swap. The intent of this check is to make
|
|
// sure Fleet code never reintroduces the issue.
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// Production binaries to audit. Any first-party package reachable from
|
|
// these must not import "testing" directly.
|
|
//
|
|
// Important: these are bare binary paths, NOT "./cmd/fleet/..." — the
|
|
// "..." form expands to include _test.go-only sibling packages that aren't
|
|
// actually linked into the binary.
|
|
var roots = []string{
|
|
"./cmd/fleet",
|
|
"./cmd/fleetctl",
|
|
"./orbit/cmd/orbit",
|
|
}
|
|
|
|
const fleetModulePrefix = "github.com/fleetdm/fleet/v4/"
|
|
|
|
type pkgInfo struct {
|
|
ImportPath string `json:"ImportPath"`
|
|
Imports []string `json:"Imports"`
|
|
Standard bool `json:"Standard"`
|
|
}
|
|
|
|
func main() {
|
|
// Use the same build tags as the production build (see Makefile).
|
|
//
|
|
// -e lets `go list` report packages even when they have load errors. We
|
|
// need this so the audit works on fresh checkouts where `make
|
|
// generate-go` hasn't been run yet (server/bindata/generated.go is not
|
|
// committed; without -e, the `-tags full` build sees no Go files in
|
|
// that package and fails). The import graph we walk is still complete
|
|
// because go list emits the package record either way.
|
|
args := []string{
|
|
"list",
|
|
"-tags", "full,fts5,netgo",
|
|
"-e",
|
|
"-deps",
|
|
"-json",
|
|
}
|
|
args = append(args, roots...)
|
|
|
|
cmd := exec.Command("go", args...)
|
|
cmd.Stderr = os.Stderr
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "go list failed: %v\n", err)
|
|
os.Exit(2)
|
|
}
|
|
|
|
dec := json.NewDecoder(strings.NewReader(string(out)))
|
|
var offenders []string
|
|
seen := make(map[string]struct{})
|
|
for {
|
|
var p pkgInfo
|
|
if err := dec.Decode(&p); err != nil {
|
|
break
|
|
}
|
|
if p.Standard {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(p.ImportPath, fleetModulePrefix) {
|
|
continue
|
|
}
|
|
if slices.Contains(p.Imports, "testing") {
|
|
if _, ok := seen[p.ImportPath]; !ok {
|
|
offenders = append(offenders, p.ImportPath)
|
|
seen[p.ImportPath] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(offenders) == 0 {
|
|
return
|
|
}
|
|
|
|
sort.Strings(offenders)
|
|
fmt.Fprintln(os.Stderr, "check-no-testing-in-prod: the following Fleet packages are reachable from")
|
|
fmt.Fprintln(os.Stderr, "the production binaries (cmd/fleet, cmd/fleetctl, orbit/cmd/orbit) AND import")
|
|
fmt.Fprintln(os.Stderr, "the \"testing\" package directly. Move the test-only code into a sibling")
|
|
fmt.Fprintln(os.Stderr, "*test subpackage or a _test.go file. See https://github.com/fleetdm/fleet/issues/45220.")
|
|
fmt.Fprintln(os.Stderr)
|
|
for _, o := range offenders {
|
|
fmt.Fprintf(os.Stderr, " - %s\n", o)
|
|
}
|
|
os.Exit(1)
|
|
}
|