diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8ca3638ae..eefc88c6c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,7 @@ jobs: - name: Lint Go uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: - version: v2.4.0 + version: v2.10.0 skip-cache: true vulnerability-scan: @@ -105,7 +105,9 @@ jobs: contents: read security-events: write # for reporting vulnerabilities via code-scanning API with: - target-branch: ${{ github.event.pull_request.base.ref || github.ref_name }} + # Use PR head branch (the feature branch) when running from a pull_request event. + # Fallback to github.head_ref (sanity) or ref name for other contexts. + target-branch: ${{ github.event.pull_request.head.ref || github.head_ref || github.ref_name }} unit-test: name: Unit Tests diff --git a/.github/workflows/vulncheck.yml b/.github/workflows/vulncheck.yml index 9bac1ae9d8..7e1c06f520 100644 --- a/.github/workflows/vulncheck.yml +++ b/.github/workflows/vulncheck.yml @@ -29,7 +29,10 @@ jobs: with: persist-credentials: false fetch-depth: 0 - ref: ${{ inputs.target-branch || 'main' }} + # For a pull_request event use the PR head branch (github.head_ref) + # to this ensures vulncheck runs against the feature branch. + # Otherwise, fall back to inputs.target-branch, github.ref_name, then 'main'. + ref: ${{ (github.event_name == 'pull_request' && github.head_ref) || inputs.target-branch || github.ref_name || 'main' }} - name: Check Go version id: get-go-version diff --git a/Makefile.tools b/Makefile.tools index e850a1d028..6031d71201 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -1,9 +1,9 @@ OAPICODEGEN = github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.1.0 LEFTHOOK = github.com/evilmartians/lefthook@v1.6.9 -GOLANGCILINT = github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.4.0 +GOLANGCILINT = github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.0 PROTOCGENGO = google.golang.org/protobuf/cmd/protoc-gen-go@v1.32.0 GOFUMPT = mvdan.cc/gofumpt@v0.6.0 -COUNTERFEITER = github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 +COUNTERFEITER = github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 NFPM = github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.36.1 GOTESTCOVERAGE = github.com/vladopajic/go-test-coverage/v2@v2.10.1 BENCHSTAT = golang.org/x/perf/cmd/benchstat@v0.0.0-20240404204407-f3e401e020e4 diff --git a/api/grpc/mpi/v1/mocks.go b/api/grpc/mpi/v1/mocks.go index 7e61786103..da49747981 100644 --- a/api/grpc/mpi/v1/mocks.go +++ b/api/grpc/mpi/v1/mocks.go @@ -5,7 +5,7 @@ package v1 -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . CommandServiceClient //counterfeiter:generate . FileServiceClient //counterfeiter:generate . FileService_GetFileStreamServer diff --git a/go.mod b/go.mod index 02d36520af..320c02bcbc 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/nginx/agent/v3 -go 1.24.2 +go 1.25.0 -toolchain go1.24.13 +toolchain go1.25.7 require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.9-20250912141014-52f32327d4b0.1 @@ -39,6 +39,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.141.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/tcplogreceiver v0.141.0 github.com/open-telemetry/opentelemetry-collector-contrib/testbed v0.141.0 + github.com/pkg/errors v0.9.1 github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.67.4 github.com/shirou/gopsutil/v4 v4.25.11 @@ -250,7 +251,6 @@ require ( github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect diff --git a/internal/collector/containermetricsreceiver/internal/scraper/cpuscraper/internal/cgroup/cpu_test.go b/internal/collector/containermetricsreceiver/internal/scraper/cpuscraper/internal/cgroup/cpu_test.go index be277af858..f0e48211ce 100644 --- a/internal/collector/containermetricsreceiver/internal/scraper/cpuscraper/internal/cgroup/cpu_test.go +++ b/internal/collector/containermetricsreceiver/internal/scraper/cpuscraper/internal/cgroup/cpu_test.go @@ -13,7 +13,9 @@ import ( "strconv" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCollectCPUStats(t *testing.T) { @@ -78,8 +80,14 @@ func TestCollectCPUStats(t *testing.T) { cgroupCPUSource := NewCPUSource(test.basePath) cpuStat, err := cgroupCPUSource.collectCPUStats(ctx) - // Assert error - assert.IsType(tt, test.errorType, err) + if test.errorType != nil { + // satisfy the linter's requirement for a more specific check than IsType. + require.Condition(tt, func() bool { + return errors.As(err, &test.errorType) + }, "Error should be of type %T", test.errorType) + } else { + require.NoError(tt, err) + } // Assert result assert.Equal(tt, test.cpuStat, cpuStat) diff --git a/internal/collector/containermetricsreceiver/internal/scraper/memoryscraper/internal/cgroup/memory_test.go b/internal/collector/containermetricsreceiver/internal/scraper/memoryscraper/internal/cgroup/memory_test.go index fd4ec3a918..42cc9497b7 100644 --- a/internal/collector/containermetricsreceiver/internal/scraper/memoryscraper/internal/cgroup/memory_test.go +++ b/internal/collector/containermetricsreceiver/internal/scraper/memoryscraper/internal/cgroup/memory_test.go @@ -13,8 +13,10 @@ import ( "strconv" "testing" + "github.com/pkg/errors" "github.com/shirou/gopsutil/v4/mem" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestVirtualMemoryStat(t *testing.T) { @@ -115,7 +117,14 @@ func TestVirtualMemoryStat(t *testing.T) { virtualMemoryStat, err := cgroupCPUSource.VirtualMemoryStat() // Assert error - assert.IsType(tt, test.errorType, err) + if test.errorType != nil { + // satisfy the linter's requirement for a more specific check than IsType. + require.Condition(tt, func() bool { + return errors.As(err, &test.errorType) + }, "Error should be of type %T", test.errorType) + } else { + require.NoError(tt, err) + } // Assert result assert.Equal(tt, test.virtualMemoryStat, *virtualMemoryStat) diff --git a/internal/collector/nginxreceiver/internal/scraper/accesslog/nginx_log_scraper.go b/internal/collector/nginxreceiver/internal/scraper/accesslog/nginx_log_scraper.go index 54a9c08d97..15aa7c472e 100644 --- a/internal/collector/nginxreceiver/internal/scraper/accesslog/nginx_log_scraper.go +++ b/internal/collector/nginxreceiver/internal/scraper/accesslog/nginx_log_scraper.go @@ -74,7 +74,7 @@ func NewScraper( mb := metadata.NewMetricsBuilder(cfg.MetricsBuilderConfig, settings) rb := mb.NewResourceBuilder() - operators := make([]operator.Config, 0) + operators := make([]operator.Config, 0, len(cfg.AccessLogs)) for _, accessLog := range cfg.AccessLogs { logger.Info("Adding access log file operator", zap.String("file_path", accessLog.FilePath)) diff --git a/internal/collector/types/mocks.go b/internal/collector/types/mocks.go index bdb44f6291..fb50d49108 100644 --- a/internal/collector/types/mocks.go +++ b/internal/collector/types/mocks.go @@ -5,5 +5,5 @@ package types -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . CollectorInterface diff --git a/internal/command/command_plugin.go b/internal/command/command_plugin.go index a27104b128..6b621a41e8 100644 --- a/internal/command/command_plugin.go +++ b/internal/command/command_plugin.go @@ -25,7 +25,7 @@ import ( var _ bus.Plugin = (*CommandPlugin)(nil) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . commandService type ( diff --git a/internal/config/config.go b/internal/config/config.go index b490aea5e3..d7c4d7a702 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1407,7 +1407,7 @@ func resolveExtensions() Extensions { func updateHeaders(headers []Header) []Header { var err error - newHeaders := []Header{} + newHeaders := make([]Header, 0, len(headers)) for _, header := range headers { value := header.Value diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 313ef8e42f..dcef2674ab 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -977,7 +977,7 @@ func TestResolveExtensions(t *testing.T) { extension := resolveExtensions() require.NotNil(t, extension) - var result []string + result := make([]string, 0, len(extension.HeadersSetter.Headers)) for _, header := range extension.HeadersSetter.Headers { result = append(result, header.Value) } diff --git a/internal/datasource/config/nginx_config_parser.go b/internal/datasource/config/nginx_config_parser.go index 59740cc9ee..9c4b2b0622 100644 --- a/internal/datasource/config/nginx_config_parser.go +++ b/internal/datasource/config/nginx_config_parser.go @@ -68,7 +68,7 @@ var globFunction = func(path string) ([]string, error) { return matches, nil } -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . ConfigParser type ( diff --git a/internal/file/file_manager_service.go b/internal/file/file_manager_service.go index 5798b09766..fce1cd0898 100644 --- a/internal/file/file_manager_service.go +++ b/internal/file/file_manager_service.go @@ -27,13 +27,13 @@ import ( "github.com/nginx/agent/v3/pkg/files" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . fileOperator -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . fileManagerServiceInterface -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . fileServiceOperatorInterface const ( diff --git a/internal/grpc/grpc.go b/internal/grpc/grpc.go index 2f369ab956..3d9b97be2a 100644 --- a/internal/grpc/grpc.go +++ b/internal/grpc/grpc.go @@ -36,7 +36,7 @@ import ( "google.golang.org/protobuf/proto" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . GrpcConnectionInterface type ( diff --git a/internal/grpc/grpc_test.go b/internal/grpc/grpc_test.go index eeb3d0125d..76126fb605 100644 --- a/internal/grpc/grpc_test.go +++ b/internal/grpc/grpc_test.go @@ -350,10 +350,11 @@ func validateError(t *testing.T, validationError error, isErrorExpected bool) { func Test_ValidateGrpcError(t *testing.T) { result := ValidateGrpcError(TestError{}) - assert.IsType(t, TestError{}, result) - + if result != nil { + require.ErrorIs(t, TestError{}, result) + } result = ValidateGrpcError(status.Errorf(codes.InvalidArgument, "error")) - assert.IsType(t, &backoff.PermanentError{}, result) + require.ErrorIs(t, &backoff.PermanentError{}, result) } func Test_transportCredentials(t *testing.T) { diff --git a/internal/resource/resource_service.go b/internal/resource/resource_service.go index 2ae6ede88e..2be1f7b649 100644 --- a/internal/resource/resource_service.go +++ b/internal/resource/resource_service.go @@ -43,16 +43,16 @@ const ( unixPlusAPIFormat = "http://nginx-plus-api%s" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . resourceServiceInterface -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . logTailerOperator -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . instanceOperator -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . processOperator type resourceServiceInterface interface { diff --git a/internal/watcher/credentials/credential_watcher_service_test.go b/internal/watcher/credentials/credential_watcher_service_test.go index 2d33ad253c..9d7b578004 100644 --- a/internal/watcher/credentials/credential_watcher_service_test.go +++ b/internal/watcher/credentials/credential_watcher_service_test.go @@ -104,7 +104,7 @@ func TestCredentialWatcherService_addWatcher(t *testing.T) { } func TestCredentialWatcherService_watchFiles(t *testing.T) { - var files []string + files := make([]string, 0, 3) ctx := context.Background() cws := NewCredentialWatcherService(types.AgentConfig(), model.Command) diff --git a/internal/watcher/health/health_watcher_service.go b/internal/watcher/health/health_watcher_service.go index 87768f4b1a..ff02724eea 100644 --- a/internal/watcher/health/health_watcher_service.go +++ b/internal/watcher/health/health_watcher_service.go @@ -20,7 +20,7 @@ import ( mpi "github.com/nginx/agent/v3/api/grpc/mpi/v1" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . healthWatcherOperator type ( @@ -139,7 +139,7 @@ func (hw *HealthWatcherService) Watch(ctx context.Context, ch chan<- InstanceHea func (hw *HealthWatcherService) health(ctx context.Context) (updatedStatuses []*mpi.InstanceHealth, isHealthDiff bool, ) { currentHealth := make(map[string]*mpi.InstanceHealth, len(hw.watchers)) - allStatuses := make([]*mpi.InstanceHealth, 0) + allStatuses := make([]*mpi.InstanceHealth, 0, len(hw.watchers)) for instanceID, watcher := range hw.watchers { instanceHealth, err := watcher.Health(ctx, hw.instances[instanceID]) diff --git a/internal/watcher/instance/instance_watcher_service.go b/internal/watcher/instance/instance_watcher_service.go index 0279375992..7484e9fb9d 100644 --- a/internal/watcher/instance/instance_watcher_service.go +++ b/internal/watcher/instance/instance_watcher_service.go @@ -32,7 +32,7 @@ import ( const defaultAgentPath = "/run/nginx-agent" -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . processParser type ( @@ -188,7 +188,6 @@ func (iw *InstanceWatcherService) HandleNginxConfigContextUpdate(ctx context.Con func (iw *InstanceWatcherService) checkForUpdates( ctx context.Context, ) { - var instancesToParse []*mpi.Instance correlationID := logger.GenerateCorrelationID() newCtx := context.WithValue(ctx, logger.CorrelationIDContextKey, correlationID) @@ -197,6 +196,8 @@ func (iw *InstanceWatcherService) checkForUpdates( slog.ErrorContext(newCtx, "Instance watcher updates", "error", err) } + instancesToParse := make([]*mpi.Instance, 0, len(instanceUpdates.UpdatedInstances)+ + len(instanceUpdates.NewInstances)) instancesToParse = append(instancesToParse, instanceUpdates.UpdatedInstances...) instancesToParse = append(instancesToParse, instanceUpdates.NewInstances...) diff --git a/internal/watcher/process/process_operator.go b/internal/watcher/process/process_operator.go index c4dcff8e8f..9acaa3a8c7 100644 --- a/internal/watcher/process/process_operator.go +++ b/internal/watcher/process/process_operator.go @@ -13,7 +13,7 @@ import ( "github.com/shirou/gopsutil/v4/process" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . ProcessOperatorInterface type ( // ProcessOperator provides details about running NGINX processes. diff --git a/internal/watcher/watcher_plugin.go b/internal/watcher/watcher_plugin.go index 99a4b673f9..cd7d502227 100644 --- a/internal/watcher/watcher_plugin.go +++ b/internal/watcher/watcher_plugin.go @@ -27,7 +27,7 @@ import ( pkgConfig "github.com/nginx/agent/v3/pkg/config" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . instanceWatcherServiceInterface type ( diff --git a/pkg/files/file_helpers.go b/pkg/files/file_helpers.go index fccd353cd7..c4849be657 100644 --- a/pkg/files/file_helpers.go +++ b/pkg/files/file_helpers.go @@ -16,6 +16,7 @@ import ( "os" "slices" "strconv" + "strings" mpi "github.com/nginx/agent/v3/api/grpc/mpi/v1" "github.com/nginx/agent/v3/internal/datasource/cert" @@ -120,7 +121,7 @@ func FileMode(mode string) os.FileMode { // GenerateConfigVersion returns a unique config version for a set of files. // The config version is calculated by joining the file hashes together and generating a unique ID. func GenerateConfigVersion(fileSlice []*mpi.File) string { - var hashes string + var sb strings.Builder files := make([]*mpi.File, len(fileSlice)) copy(files, fileSlice) @@ -129,10 +130,10 @@ func GenerateConfigVersion(fileSlice []*mpi.File) string { }) for _, file := range files { - hashes += file.GetFileMeta().GetHash() + sb.WriteString(file.GetFileMeta().GetHash()) } - return GenerateHash([]byte(hashes)) + return GenerateHash([]byte(sb.String())) } // GenerateHash returns the hash value of a file's contents. diff --git a/pkg/host/exec/exec.go b/pkg/host/exec/exec.go index e8b1b6a095..516fc7a5c8 100644 --- a/pkg/host/exec/exec.go +++ b/pkg/host/exec/exec.go @@ -16,7 +16,7 @@ import ( "github.com/shirou/gopsutil/v4/host" ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . ExecInterface type ExecInterface interface { RunCmd(ctx context.Context, cmd string, args ...string) (*bytes.Buffer, error) diff --git a/pkg/host/info.go b/pkg/host/info.go index 3dfc7d2fc9..ce9ae30a8f 100644 --- a/pkg/host/info.go +++ b/pkg/host/info.go @@ -68,7 +68,7 @@ var ( containerdPattern = regexp.MustCompile("sandboxes/([a-f0-9]{64})") ) -//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.8.1 -generate +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6@v6.11.2 -generate //counterfeiter:generate . InfoInterface type ( diff --git a/test/helpers/go_utils_test.go b/test/helpers/go_utils_test.go index fa5fc1f40d..c65533f543 100644 --- a/test/helpers/go_utils_test.go +++ b/test/helpers/go_utils_test.go @@ -13,7 +13,7 @@ import ( ) func TestGoVersion(t *testing.T) { - expected := "1.24.0" + expected := "1.25.7" actual, err := GoVersion(t, 2) diff --git a/test/integration/metrics/metrics_test.go b/test/integration/metrics/metrics_test.go index 9e329bf00f..3c3fef1ea0 100644 --- a/test/integration/metrics/metrics_test.go +++ b/test/integration/metrics/metrics_test.go @@ -53,7 +53,7 @@ func (s *MetricsTestSuite) TestNginxMetrics_TestRequestCount() { family := s.metricFamilies[metricName] s.Require().NotNil(family) - var baselineMetric []float64 + baselineMetric := make([]float64, 0, 1) baselineMetric = append(baselineMetric, utils.SumMetricFamily(family)) s.T().Logf("NGINX HTTP request count total: %v", baselineMetric[0])