diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 48e146475..3d1b5a491 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -198,55 +198,10 @@ jobs: integration-tests: uses: ./.github/workflows/integration-tests.yml - lint: - needs: affected - if: ${{fromJson(needs.affected.outputs.nx).run_checks}} - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - actions: read - strategy: - fail-fast: false - matrix: - projects: ${{fromJson(needs.affected.outputs.nx).projects}} - steps: - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Set up project environment - id: setup - uses: ./.github/actions/setup - with: - project: ${{ matrix.projects }} - go-module-file: ${{ fromJson(needs.affected.outputs.nx)[matrix.projects].go_sum }} - task: "lint" - - - name: Support private Go modules - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: ./.github/scripts/support-private-gomods.sh - - - name: Get golangci-lint version from asdf - id: get-version - run: | - version=$(grep '^golangci-lint ' .tool-versions | awk '{print $2}') - echo "version=${version}" | tee -a "$GITHUB_OUTPUT" - - - name: golangci-lint (${{ matrix.projects }}) - uses: smartcontractkit/.github/actions/ci-lint-go@ci-lint-go/4.2.1 - with: - checkout-repo: false - golangci-lint-config: ${{ github.workspace }}/.golangci.yml - golangci-lint-version: v${{ steps.get-version.outputs.version }} - go-directory: ${{fromJson(needs.affected.outputs.nx)[matrix.projects].root}} - - # Formats the protos and Go, and regenerates and tidies every module. It runs code from the pull request, so it only - # reads, and autofix-commit pushes what it changed. On main and in the merge queue it can't commit, so it fails when - # anything is out of date instead. + # Formats the protos and Go, regenerates and tidies the modules the pull request changed, and lints them, fixing what + # golangci-lint can. It runs code from the pull request, so it only reads, and autofix-commit pushes what it changed. + # Lint issues it can't fix fail it after the fixes are uploaded. On main and in the merge queue it can't commit, and + # checks every module, so it fails when anything is out of date instead. autofix: runs-on: ubuntu-latest permissions: @@ -275,9 +230,13 @@ jobs: - name: Install tools run: make mockery buf + - name: Get golangci-lint version from asdf + id: golangci-lint-version + run: echo "version=v$(awk '$1 == "golangci-lint" {print $2}' .tool-versions)" | tee -a "$GITHUB_OUTPUT" + - name: Autofix id: autofix - uses: smartcontractkit/.github/actions/autofix@autofix/v1 + uses: smartcontractkit/.github/actions/autofix@049f997ae9c2db0e2b1695db6ff3cdf2099b96c0 env: # The runner has no SSH key, which protofetch fetches with by default. PROTOFETCH_GIT_PROTOCOL: https @@ -286,6 +245,9 @@ jobs: # formatted sources, and tidy. go.md graphs the tidied modules, so it's made last. setup: ./script/format-protos.sh go: true + go-changed-only: true + golangci-lint: true + golangci-lint-version: ${{ steps.golangci-lint-version.outputs.version }} run: make modgraph # The setup action's cache is only saved when the job succeeds. Save it when it fails too, so a rerun doesn't @@ -310,7 +272,9 @@ jobs: # GATI token. It holds that token, so it runs nothing from the pull request and checks out nothing. autofix-commit: needs: autofix - if: needs.autofix.outputs.commit == 'true' + # Runs when autofix failed too: lint issues it couldn't fix fail it after the fixes it could make are uploaded, and + # those should still be pushed. + if: ${{ !cancelled() && needs.autofix.outputs.commit == 'true' }} runs-on: ubuntu-latest permissions: id-token: write @@ -323,7 +287,7 @@ jobs: aws-lambda-url: ${{ secrets.AWS_LAMBDA_URL_GATI }} - name: Commit - uses: smartcontractkit/.github/actions/autofix/commit@autofix/v1 + uses: smartcontractkit/.github/actions/autofix/commit@049f997ae9c2db0e2b1695db6ff3cdf2099b96c0 with: artifact: ${{ needs.autofix.outputs.artifact }} paths: . @@ -333,7 +297,6 @@ jobs: checks: runs-on: ubuntu-latest needs: - - lint - build - test - race diff --git a/.golangci.yml b/.golangci.yml index 2c0d10e3a..4ddeecf87 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -173,6 +173,17 @@ linters: - linters: - depguard path: integration_tests + # A context only covers resolving the address, and listeners here bind + # local or configured addresses, so net.Listen is fine. + - linters: + - noctx + text: "net.Listen must not be called" + # http_action still reads and writes the deprecated Headers for callers + # that don't use MultiHeaders yet. + - linters: + - staticcheck + path: http_action/ + text: "SA1019: .*\\.Headers is deprecated" paths: - third_party$ - builtin$ diff --git a/consensus/action/capability.go b/consensus/action/capability.go index 6c7d29646..e39097312 100644 --- a/consensus/action/capability.go +++ b/consensus/action/capability.go @@ -238,7 +238,7 @@ func (c *consensusCapability) setConfiguration(cfg string) error { } requestSizeLimit.DefaultValue = configuredLimit - maxRequestSizeBytes, err := limits.MakeBoundLimiter(c.limitsFactory, requestSizeLimit) + maxRequestSizeBytes, err := limits.MakeUpperBoundLimiter(c.limitsFactory, requestSizeLimit) if err != nil { return err } diff --git a/consensus/oracle/plugin/batching/observation_batch_test.go b/consensus/oracle/plugin/batching/observation_batch_test.go index 34973c27a..ea83d99c3 100644 --- a/consensus/oracle/plugin/batching/observation_batch_test.go +++ b/consensus/oracle/plugin/batching/observation_batch_test.go @@ -52,7 +52,7 @@ func generateRandomStringBetweenBounds(lowerBound int, upperBound int) string { n := rand.Intn(upperBound-lowerBound) + lowerBound runes := make([]rune, n) for i := range runes { - runes[i] = 'A' + rune(rand.Intn(25)) + runes[i] = 'A' + rune(rand.Intn(25)) //nolint:gosec // G115: below 25 } return string(runes) } diff --git a/consensus/oracle/plugin/batching/outcome_batch.go b/consensus/oracle/plugin/batching/outcome_batch.go index c9aac3f9d..15e704627 100644 --- a/consensus/oracle/plugin/batching/outcome_batch.go +++ b/consensus/oracle/plugin/batching/outcome_batch.go @@ -240,7 +240,6 @@ func (o *OutcomeBatch) outcomeWouldFit(startingSize int, requestID string, reque func (o *OutcomeBatch) checkOutcomeBatchHasCapacity(requestID string, requestOutcome proto.Message, historicalSeqNr uint64) bool { - // The number of outcomes should never exceed the max number of reports as this would cause outcomes to be lost and need recalculating on subsequent rounds if len(o.Outcomes) == o.maxNumberOfReports { o.lggr.Debugw("outcome batch has reached maximum number of reports", "maxNumberOfReports", o.maxNumberOfReports) diff --git a/consensus/oracle/plugin/plugin_observation.go b/consensus/oracle/plugin/plugin_observation.go index 0383e2d98..0c7be7283 100644 --- a/consensus/oracle/plugin/plugin_observation.go +++ b/consensus/oracle/plugin/plugin_observation.go @@ -36,8 +36,8 @@ func (r *reportingPlugin) Observation(ctx context.Context, outctx ocr3types.Outc Input: req.Input, // Emit true for these flags even though nothing uses them in the Outcome phase. // This ensures that the flag doesn't accidentally revert during the rollout of the new version. - RemoveLibUseInFailureMessageFormattingFlag: true, - UpdateErrorHandlingFlag: true, + RemoveLibUseInFailureMessageFormattingFlag: true, //nolint:staticcheck // SA1019: see above + UpdateErrorHandlingFlag: true, //nolint:staticcheck // SA1019: see above Median_2Fplus1QuorumFlag: req.StricterMedianQuorum, IncludeAllTimestampsFlag: req.IncludeAllTimestamps, } diff --git a/http_action/validate/validator.go b/http_action/validate/validator.go index a71817b2e..80ebfd391 100644 --- a/http_action/validate/validator.go +++ b/http_action/validate/validator.go @@ -41,22 +41,22 @@ type Validator struct { // NewValidator creates a new Validator with initialized limiters func NewValidator(lggr logger.Logger, limitsFactory limits.Factory) (*Validator, error) { - responseSizeLimiter, err := limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.ResponseSizeLimit) + responseSizeLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.ResponseSizeLimit) if err != nil { return nil, fmt.Errorf("failed to create response size limiter: %w", err) } - requestSizeLimiter, err := limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.RequestSizeLimit) + requestSizeLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.RequestSizeLimit) if err != nil { return nil, fmt.Errorf("failed to create request size limiter: %w", err) } - connectionTimeoutLimiter, err := limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.ConnectionTimeout) + connectionTimeoutLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.ConnectionTimeout) if err != nil { return nil, fmt.Errorf("failed to create connection timeout limiter: %w", err) } - cacheAgeLimiter, err := limits.MakeBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.CacheAgeLimit) + cacheAgeLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.PerWorkflow.HTTPAction.CacheAgeLimit) if err != nil { return nil, fmt.Errorf("failed to create cache age limiter: %w", err) } diff --git a/http_trigger/trigger/config_test.go b/http_trigger/trigger/config_test.go index 9f72f7a30..0b9f23524 100644 --- a/http_trigger/trigger/config_test.go +++ b/http_trigger/trigger/config_test.go @@ -53,5 +53,4 @@ func TestServiceConfig_AllDefaults(t *testing.T) { require.Equal(t, uint16(defaultSendChannelBufferSize), appliedCfg.SendChannelBufferSize) require.Equal(t, uint16(defaultMaxAuthorizedKeysPerWorkflow), appliedCfg.MaxAuthorizedKeysPerWorkflow) require.Equal(t, uint32(defaultRequestCacheTTL), appliedCfg.RequestCacheTTL) - } diff --git a/http_trigger/trigger/connector_handler.go b/http_trigger/trigger/connector_handler.go index 239f93a8d..c877af88c 100644 --- a/http_trigger/trigger/connector_handler.go +++ b/http_trigger/trigger/connector_handler.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/triggers/http" - "github.com/smartcontractkit/chainlink-common/pkg/contexts" "github.com/smartcontractkit/chainlink-common/pkg/custmsg" jsonrpc "github.com/smartcontractkit/chainlink-common/pkg/jsonrpc2" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -116,7 +115,7 @@ func (h *connectorHandler) HealthReport() map[string]error { } func (h *connectorHandler) Ready() error { - return h.StateMachine.Healthy() + return h.Healthy() } func (h *connectorHandler) Name() string { @@ -288,7 +287,6 @@ func (h *connectorHandler) processTrigger(ctx context.Context, gatewayID string, } workflowExecutionID, err := h.generateWorkflowExecutionID( - ctx, workflowMetadata.WorkflowID, workflowMetadata.WorkflowOwner, orgID, @@ -447,7 +445,6 @@ func (h *connectorHandler) populateMetadataFromWorkflow(workflowID string, metad } func (h *connectorHandler) generateWorkflowExecutionID( - ctx context.Context, workflowID, workflowOwner, orgID, reqID, referenceID string, l logger.Logger, ) (string, error) { @@ -461,12 +458,6 @@ func (h *connectorHandler) generateWorkflowExecutionID( } l = logger.With(l, "triggerIndex", triggerIndex) - ctx = contexts.WithCRE(ctx, contexts.CRE{ - Org: orgID, - Owner: workflowOwner, - Workflow: workflowID, - }) - strippedWorkflowID := strings.TrimPrefix(workflowID, "0x") workflowExecutionID, execIDErr := workflows.GenerateExecutionIDWithTriggerIndex(strippedWorkflowID, reqID, triggerIndex) if execIDErr != nil { diff --git a/http_trigger/trigger/gateway_metadata_publisher.go b/http_trigger/trigger/gateway_metadata_publisher.go index 6aa69f1f5..f09c35d2b 100644 --- a/http_trigger/trigger/gateway_metadata_publisher.go +++ b/http_trigger/trigger/gateway_metadata_publisher.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink-common/pkg/types/gateway" - gateway_common "github.com/smartcontractkit/chainlink-common/pkg/types/gateway" ) var _ GatewayMetadataPublisher = (*gatewayMetadataPublisher)(nil) @@ -75,7 +74,7 @@ func (h *gatewayMetadataPublisher) BroadcastWorkflowMetadata(ctx context.Context for _, gatewayID := range gatewayIDs { backoff := time.Duration(h.cfg.GatewayConnectionConfig.RetryConfig.InitialIntervalMs) * time.Millisecond for { - err := h.sendResponse(ctx, gatewayID, &gatewayResp, gateway_common.MethodPushWorkflowMetadata) + err := h.sendResponse(ctx, gatewayID, &gatewayResp, gateway.MethodPushWorkflowMetadata) if err == nil { h.lggr.Debugw("successfully sent metadata", "gatewayID", gatewayID) break @@ -116,12 +115,12 @@ func (h *gatewayMetadataPublisher) SendWorkflowMetadata(ctx context.Context, gat return errors.New("request cannot be nil") } if req.ID == "" { - h.sendErrorResponse(ctx, gatewayID, req.ID, jsonrpc.ErrInvalidRequest, "empty request ID", gateway_common.MethodPullWorkflowMetadata) + h.sendErrorResponse(ctx, gatewayID, req.ID, jsonrpc.ErrInvalidRequest, "empty request ID", gateway.MethodPullWorkflowMetadata) return errors.New("empty request ID") } methodName, _, _ := strings.Cut(req.ID, "/") if methodName != gateway.MethodPullWorkflowMetadata { - h.sendErrorResponse(ctx, gatewayID, req.ID, jsonrpc.ErrInvalidRequest, "invalid request ID for workflow pull metadata", gateway_common.MethodPullWorkflowMetadata) + h.sendErrorResponse(ctx, gatewayID, req.ID, jsonrpc.ErrInvalidRequest, "invalid request ID for workflow pull metadata", gateway.MethodPullWorkflowMetadata) return fmt.Errorf("invalid request ID for workflow pull metadata: %s", req.ID) } ctx, cancel := context.WithTimeout(ctx, time.Duration(h.cfg.GatewayConnectionConfig.MaxPullMetadataDurationMs)*time.Millisecond) @@ -150,7 +149,7 @@ func (h *gatewayMetadataPublisher) SendWorkflowMetadata(ctx context.Context, gat payload, err := json.Marshal(batchData) if err != nil { - h.sendErrorResponse(ctx, gatewayID, req.ID, jsonrpc.ErrInternal, "failed to marshal batch metadata", gateway_common.MethodPullWorkflowMetadata) + h.sendErrorResponse(ctx, gatewayID, req.ID, jsonrpc.ErrInternal, "failed to marshal batch metadata", gateway.MethodPullWorkflowMetadata) return fmt.Errorf("failed to marshal batch metadata: %w", err) } @@ -162,7 +161,7 @@ func (h *gatewayMetadataPublisher) SendWorkflowMetadata(ctx context.Context, gat Result: &rawRes, } - err = h.sendResponse(ctx, gatewayID, &gatewayResp, gateway_common.MethodPullWorkflowMetadata) + err = h.sendResponse(ctx, gatewayID, &gatewayResp, gateway.MethodPullWorkflowMetadata) if err != nil { return fmt.Errorf("failed to send batch metadata to gateway for workflow: %w", err) } diff --git a/http_trigger/trigger/trigger.go b/http_trigger/trigger/trigger.go index 2f8428fa6..aa01dda53 100644 --- a/http_trigger/trigger/trigger.go +++ b/http_trigger/trigger/trigger.go @@ -116,7 +116,7 @@ func (s *service) HealthReport() map[string]error { } func (s *service) Ready() error { - return s.StateMachine.Healthy() + return s.Healthy() } func (s *service) Name() string { diff --git a/libs/capability/observability_test.go b/libs/capability/observability_test.go index 79a2238c5..83043ac7c 100644 --- a/libs/capability/observability_test.go +++ b/libs/capability/observability_test.go @@ -108,12 +108,12 @@ func TestWebServerServes(t *testing.T) { // TestWebServerReportsAPortItCannotHave covers the failure a misconfigured port gives: it is // reported where it happens rather than as a server that silently never listens. func TestWebServerReportsAPortItCannotHave(t *testing.T) { - taken, err := net.Listen("tcp", ":0") + taken, err := net.Listen("tcp", ":0") //nolint:gosec // G102 require.NoError(t, err) t.Cleanup(func() { _ = taken.Close() }) // Building it registers routes and binds nothing, so the failure is at start. - port := uint16(taken.Addr().(*net.TCPAddr).Port) + port := uint16(taken.Addr().(*net.TCPAddr).Port) //nolint:gosec // G115: ports fit in a uint16 web := newWebServer(logger.Test(t), HTTPConfig{Port: port}, http.NewServeMux(), &probes{}) require.ErrorContains(t, web.Start(t.Context()), fmt.Sprintf("failed to listen on port %d", port)) diff --git a/libs/capability/run_test.go b/libs/capability/run_test.go index 26d5f34da..6119467ba 100644 --- a/libs/capability/run_test.go +++ b/libs/capability/run_test.go @@ -162,7 +162,7 @@ func httpGet(ctx context.Context, url string) (*http.Response, error) { func freePort(t *testing.T) int { t.Helper() - l, err := net.Listen("tcp", ":0") + l, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) port := l.Addr().(*net.TCPAddr).Port require.NoError(t, l.Close()) diff --git a/libs/capability/runner_test.go b/libs/capability/runner_test.go index c94ea1cae..884467db5 100644 --- a/libs/capability/runner_test.go +++ b/libs/capability/runner_test.go @@ -29,7 +29,7 @@ import ( func runArgs(t *testing.T) (*config, uint16) { t.Helper() - port := uint16(freePort(t)) + port := uint16(freePort(t)) //nolint:gosec // G115: ports fit in a uint16 cfg := defaultConfig("TEST_APP") cfg.grpc.Registerer = prometheus.NewRegistry() cfg.observability.http.Port = port diff --git a/libs/loopserver/main.go b/libs/loopserver/main.go index 1a9ad232a..d2b95cd89 100644 --- a/libs/loopserver/main.go +++ b/libs/loopserver/main.go @@ -21,7 +21,8 @@ func Serve[T loop.StandardCapabilities](serviceName string, createPluginServer f } func ServeNew[T loop.StandardCapabilities](serviceName string, newServer func(*loop.Server) T, opts ...loop.ServerOpt) { - atomicSettings := loop.NewAtomicSettings(cresettings.DefaultGetter) + atomicSettings := &loop.AtomicSettings{} + atomicSettings.SetGetter(cresettings.DefaultGetter) opts = append(opts, loop.WithSettingsGetter(atomicSettings)) s := loop.MustNewStartedServer(serviceName, opts...) defer s.Stop() diff --git a/libs/monitoring/common.go b/libs/monitoring/common.go index dd11ec0e8..a0c98d5be 100644 --- a/libs/monitoring/common.go +++ b/libs/monitoring/common.go @@ -109,9 +109,10 @@ func (m *MetricsCapBasic) RecordEmit(ctx context.Context, start, emit uint64, at m.count.Add(ctx, 1, attrs) // Timestamp events - m.capTimestampStart.Record(ctx, int64(start), attrs) - m.capTimestampEmit.Record(ctx, int64(emit), attrs) - m.capDuration.Record(ctx, int64(emit-start), attrs) + // Unix timestamps, far below math.MaxInt64. + m.capTimestampStart.Record(ctx, int64(start), attrs) //nolint:gosec // G115 + m.capTimestampEmit.Record(ctx, int64(emit), attrs) //nolint:gosec // G115 + m.capDuration.Record(ctx, int64(emit-start), attrs) //nolint:gosec // G115 } func RequestID(workflowExecutionID, reference string) string { diff --git a/libs/testutils/oracle_factory.go b/libs/testutils/oracle_factory.go index ccdbebeaa..f2857b75b 100644 --- a/libs/testutils/oracle_factory.go +++ b/libs/testutils/oracle_factory.go @@ -9,7 +9,6 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -153,10 +152,10 @@ func (o *oracle) Start(ctx context.Context) error { err = o.config.ContractTransmitter.Transmit( ctx, - types.ConfigDigest{}, + ocrtypes.ConfigDigest{}, outcomeCtx.SeqNr, report.ReportWithInfo, - []types.AttributedOnchainSignature{}, + []ocrtypes.AttributedOnchainSignature{}, ) if err != nil { o.lggr.Errorf("failed to transmit report: %v", err)