diff --git a/go.mod b/go.mod index b03f35e4fd..83cbb9e1fe 100644 --- a/go.mod +++ b/go.mod @@ -42,10 +42,10 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/scylladb/go-reflectx v1.0.1 github.com/shopspring/decimal v1.4.0 - github.com/smartcontractkit/chain-selectors v1.0.100 + github.com/smartcontractkit/chain-selectors v1.0.104 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260622152157-c8e129347b8b + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260804200254-c1accce563a8 github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260709145319-7782fb89eb16 diff --git a/go.sum b/go.sum index 773442329f..5787b1f15f 100644 --- a/go.sum +++ b/go.sum @@ -256,14 +256,14 @@ github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cj github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chain-selectors v1.0.100 h1:wpiSpmI/eFjY+wx/nPr5VuNF4hki0prIBMKEaQWn3g4= -github.com/smartcontractkit/chain-selectors v1.0.100/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chain-selectors v1.0.104 h1:/n9pPGM5W/+r1eHoWZv4VwX9LNS1af4+ICyhM8zKRNM= +github.com/smartcontractkit/chain-selectors v1.0.104/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72 h1:uWEwl7i2ryuRVoV4DmIKm6mqYevf1lH/8cQYhw/JXko= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20260724142814-45996a1bcb72/go.mod h1:UYcRMb4dZcoaIPgZJ3hckCySTqtJc9K4Q+tOKErwTq0= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260622152157-c8e129347b8b h1:VDgJWDipihV9f7M5+d21d1RzSsg5rEv+iI12oN1VQbo= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260622152157-c8e129347b8b/go.mod h1:vTFHTCbLui4Vn8fTmAadfE3rdnvfrDwOmMujmW857D0= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260804200254-c1accce563a8 h1:PuLjldCKeHUZf9JJzsX8aKEzqIJOpoY3wPeuGfm47C8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260804200254-c1accce563a8/go.mod h1:/i8hjTPFdVWHiY+QjeSiVS2Z3GB3WAZznGgXHstC02E= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/metering/go v0.0.0-20260710151514-27b5a126dabe h1:MDnY5wQbWTpFdDnMRicEnoMfSP5nM/KncARr4skP1ug= diff --git a/pkg/workflows/host/execution_restrictions.go b/pkg/workflows/host/execution_restrictions.go index 10eb80856f..aec7d54098 100644 --- a/pkg/workflows/host/execution_restrictions.go +++ b/pkg/workflows/host/execution_restrictions.go @@ -3,6 +3,7 @@ package host import ( "context" "fmt" + "math" "strings" "sync" @@ -27,7 +28,7 @@ type secretKey struct { type prefixRestriction struct { prefix string namespace string - maxCalls int32 + maxCalls uint32 } // TODO refactor to instead be injected INTO the hepler @@ -39,11 +40,11 @@ type executionRestrictions struct { hasCaps bool capType sdk.CapabilityRestrictionType - maxTotalCalls int32 - methods map[methodKey]int32 + maxTotalCalls uint32 + methods map[methodKey]uint32 hasSecrets bool - maxSecrets int32 + maxSecrets uint32 exactSecrets map[secretKey]bool prefixSecrets []prefixRestriction } @@ -130,7 +131,7 @@ func NewRestrictedExecutionHelper(inner ExecutionHelper, r *sdk.Restrictions) Ex er.hasCaps = true er.capType = caps.Type er.maxTotalCalls = caps.MaxTotalCalls - er.methods = make(map[methodKey]int32) + er.methods = make(map[methodKey]uint32) for _, cr := range caps.Restrictions { m, ok := cr.Restriction.(*sdk.CapabilityRestriction_Method) if !ok || m.Method == nil { @@ -139,7 +140,7 @@ func NewRestrictedExecutionHelper(inner ExecutionHelper, r *sdk.Restrictions) Ex mr := m.Method key := methodKey{id: mr.Id, method: mr.Method} existing, found := er.methods[key] - if !found || (mr.MaxCalls >= 0 && (existing < 0 || mr.MaxCalls < existing)) { + if !found || (mr.MaxCalls != math.MaxUint32 && (existing == math.MaxUint32 || mr.MaxCalls < existing)) { er.methods[key] = mr.MaxCalls } } @@ -209,7 +210,7 @@ func (e *executionRestrictions) reserveCapabilityCall(request *sdk.CapabilityReq if e.capType == sdk.CapabilityRestrictionType_CAPABILITY_RESTRICTION_TYPE_CLOSED { return false } - if e.maxTotalCalls > 0 { + if e.maxTotalCalls != math.MaxUint32 && e.maxTotalCalls > 0 { e.maxTotalCalls-- } return true @@ -219,10 +220,10 @@ func (e *executionRestrictions) reserveCapabilityCall(request *sdk.CapabilityReq return false } - if remaining > 0 { + if remaining != math.MaxUint32 && remaining > 0 { e.methods[key] = remaining - 1 } - if e.maxTotalCalls > 0 { + if e.maxTotalCalls != math.MaxUint32 && e.maxTotalCalls > 0 { e.maxTotalCalls-- } return true @@ -256,11 +257,11 @@ func (e *executionRestrictions) reserveSecret(request *sdk.SecretRequest) bool { } for _, p := range matchedPrefixes { - if p.maxCalls > 0 { + if p.maxCalls != math.MaxUint32 && p.maxCalls > 0 { p.maxCalls-- } } - if e.maxSecrets > 0 { + if e.maxSecrets != math.MaxUint32 && e.maxSecrets > 0 { e.maxSecrets-- } return true diff --git a/pkg/workflows/host/execution_restrictions_test.go b/pkg/workflows/host/execution_restrictions_test.go index 77cfd6a6ab..8fb1fe96c3 100644 --- a/pkg/workflows/host/execution_restrictions_test.go +++ b/pkg/workflows/host/execution_restrictions_test.go @@ -3,6 +3,7 @@ package host_test import ( "context" "errors" + "math" "testing" "github.com/stretchr/testify/assert" @@ -251,7 +252,7 @@ func TestRequirementSelectingModule_CallCapWithRestrictions(t *testing.T) { req := &sdk.CapabilityRequest{Id: "cap@1.0.0", Method: "Foo"} got := capabilitySequence(t, &sdk.Restrictions{ Capabilities: &sdk.CapabilityRestrictions{ - MaxTotalCalls: -1, + MaxTotalCalls: math.MaxUint32, Type: sdk.CapabilityRestrictionType_CAPABILITY_RESTRICTION_TYPE_CLOSED, Restrictions: []*sdk.CapabilityRestriction{ {Restriction: &sdk.CapabilityRestriction_Method{ @@ -271,7 +272,7 @@ func TestRequirementSelectingModule_CallCapWithRestrictions(t *testing.T) { Type: sdk.CapabilityRestrictionType_CAPABILITY_RESTRICTION_TYPE_CLOSED, Restrictions: []*sdk.CapabilityRestriction{ {Restriction: &sdk.CapabilityRestriction_Method{ - Method: &sdk.MethodRestriction{Id: "cap@1.0.0", Method: "Foo", MaxCalls: -1}, + Method: &sdk.MethodRestriction{Id: "cap@1.0.0", Method: "Foo", MaxCalls: math.MaxUint32}, }}, }, }, @@ -306,7 +307,7 @@ func TestRequirementSelectingModule_CallCapWithRestrictions(t *testing.T) { Type: sdk.CapabilityRestrictionType_CAPABILITY_RESTRICTION_TYPE_CLOSED, Restrictions: []*sdk.CapabilityRestriction{ {Restriction: &sdk.CapabilityRestriction_Method{ - Method: &sdk.MethodRestriction{Id: "cap@1.0.0", Method: "Foo", MaxCalls: -1}, + Method: &sdk.MethodRestriction{Id: "cap@1.0.0", Method: "Foo", MaxCalls: math.MaxUint32}, }}, {Restriction: &sdk.CapabilityRestriction_Method{ Method: &sdk.MethodRestriction{Id: "cap@1.0.0", Method: "Foo", MaxCalls: 3}, @@ -338,7 +339,7 @@ func TestRequirementSelectingModule_CallCapWithRestrictions(t *testing.T) { t.Run("closed with no methods denies all", func(t *testing.T) { got := capabilitySequence(t, &sdk.Restrictions{ Capabilities: &sdk.CapabilityRestrictions{ - MaxTotalCalls: -1, + MaxTotalCalls: math.MaxUint32, Type: sdk.CapabilityRestrictionType_CAPABILITY_RESTRICTION_TYPE_CLOSED, }, }, &sdk.CapabilityRequest{Id: "cap@1.0.0", Method: "Foo"}) @@ -659,7 +660,7 @@ func TestRequirementSelectingModule_GetSecretsWithRestrictions(t *testing.T) { } got := secretSequence(t, &sdk.Restrictions{ Secrets: &sdk.SecretsRestritions{ - MaxSecrets: -1, + MaxSecrets: math.MaxUint32, Restrictions: []*sdk.SecretRestriction{ {Restriction: &sdk.SecretRestriction_ExactSecret{ ExactSecret: &sdk.Secret{Id: "db-password", Namespace: "infra"}, @@ -680,7 +681,7 @@ func TestRequirementSelectingModule_GetSecretsWithRestrictions(t *testing.T) { Restrictions: []*sdk.SecretRestriction{ {Restriction: &sdk.SecretRestriction_PrefixedSecret{ PrefixedSecret: &sdk.SecretPrefixRestriction{ - Prefix: "db-", Namespace: "infra", MaxSecrets: -1, + Prefix: "db-", Namespace: "infra", MaxSecrets: math.MaxUint32, }, }}, }, @@ -711,7 +712,7 @@ func TestRequirementSelectingModule_GetSecretsWithRestrictions(t *testing.T) { req := &sdk.SecretRequest{Id: "db-password", Namespace: "infra"} got := secretSequence(t, &sdk.Restrictions{ Secrets: &sdk.SecretsRestritions{ - MaxSecrets: -1, + MaxSecrets: math.MaxUint32, Restrictions: []*sdk.SecretRestriction{ {Restriction: &sdk.SecretRestriction_ExactSecret{ ExactSecret: &sdk.Secret{Id: "db-password", Namespace: "infra"}, @@ -768,7 +769,7 @@ func TestRequirementSelectingModule_GetSecretsWithRestrictions(t *testing.T) { t.Run("multiple overlapping prefixes all decrement on match", func(t *testing.T) { got := secretSequence(t, &sdk.Restrictions{ Secrets: &sdk.SecretsRestritions{ - MaxSecrets: -1, + MaxSecrets: math.MaxUint32, Restrictions: []*sdk.SecretRestriction{ {Restriction: &sdk.SecretRestriction_PrefixedSecret{ PrefixedSecret: &sdk.SecretPrefixRestriction{ @@ -813,7 +814,7 @@ func TestRequirementSelectingModule_GetSecretsWithRestrictions(t *testing.T) { }).Once() h := host.NewRestrictedExecutionHelper(inner, &sdk.Restrictions{Secrets: &sdk.SecretsRestritions{ - MaxSecrets: -1, + MaxSecrets: math.MaxUint32, Restrictions: []*sdk.SecretRestriction{{Restriction: &sdk.SecretRestriction_ExactSecret{ExactSecret: secret}}}, }}) @@ -851,7 +852,7 @@ func TestRequirementSelectingModule_GetRawSecretsWithRestrictions(t *testing.T) t.Run("blocked secret returns error response without calling inner", func(t *testing.T) { inner, h := newHelper(t) - inner.EXPECT().GetOwner().Return("owner-1") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint32") resp, err := h.GetRawSecrets(t.Context(), &sdk.GetSecretsRequest{ Requests: []*sdk.SecretRequest{{Id: "blocked-secret", Namespace: "ns"}}, @@ -861,12 +862,12 @@ func TestRequirementSelectingModule_GetRawSecretsWithRestrictions(t *testing.T) assert.Contains(t, resp[0].GetError(), "denied by user pre-hook restrictions") assert.Equal(t, "blocked-secret", resp[0].GetId().GetKey()) assert.Equal(t, "ns", resp[0].GetId().GetNamespace()) - assert.Equal(t, "owner-1", resp[0].GetId().GetOwner()) + assert.Equal(t, "ownermath.MaxUint32", resp[0].GetId().GetOwner()) }) t.Run("allows permitted secret", func(t *testing.T) { inner, h := newHelper(t) - inner.EXPECT().GetOwner().Return("owner-1") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint32") inner.EXPECT().GetRawSecrets(matches.AnyContext, mock.MatchedBy(func(r *sdk.GetSecretsRequest) bool { return len(r.Requests) == 1 && r.Requests[0].Id == "allowed-secret" }), mock.Anything).Return([]*vault.SecretResponse{{}}, nil) @@ -880,7 +881,7 @@ func TestRequirementSelectingModule_GetRawSecretsWithRestrictions(t *testing.T) t.Run("mixed batch: blocked gets error response, allowed goes to inner", func(t *testing.T) { inner, h := newHelper(t) - inner.EXPECT().GetOwner().Return("owner-1") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint32") inner.EXPECT().GetRawSecrets(matches.AnyContext, mock.MatchedBy(func(r *sdk.GetSecretsRequest) bool { return len(r.Requests) == 1 && r.Requests[0].Id == "allowed-secret" }), mock.Anything).Return([]*vault.SecretResponse{{}}, nil) @@ -897,7 +898,7 @@ func TestRequirementSelectingModule_GetRawSecretsWithRestrictions(t *testing.T) t.Run("delegates the encryption key fetcher to inner", func(t *testing.T) { inner, h := newHelper(t) - inner.EXPECT().GetOwner().Return("owner-1") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint32") var gotFetcher host.EncryptionKeyFetcher inner.EXPECT().GetRawSecrets(matches.AnyContext, mock.Anything, mock.Anything). RunAndReturn(func(_ context.Context, _ *sdk.GetSecretsRequest, f host.EncryptionKeyFetcher) ([]*vault.SecretResponse, error) { @@ -914,7 +915,7 @@ func TestRequirementSelectingModule_GetRawSecretsWithRestrictions(t *testing.T) t.Run("all blocked does not call inner", func(t *testing.T) { inner, h := newHelper(t) - inner.EXPECT().GetOwner().Return("owner-1") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint32") resp, err := h.GetRawSecrets(t.Context(), &sdk.GetSecretsRequest{ Requests: []*sdk.SecretRequest{ @@ -930,7 +931,7 @@ func TestRequirementSelectingModule_GetRawSecretsWithRestrictions(t *testing.T) t.Run("inner error is propagated", func(t *testing.T) { inner, h := newHelper(t) - inner.EXPECT().GetOwner().Return("owner-1") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint32") inner.EXPECT().GetRawSecrets(matches.AnyContext, mock.Anything, mock.Anything).Return(nil, errors.New("boom")) resp, err := h.GetRawSecrets(t.Context(), &sdk.GetSecretsRequest{ @@ -949,11 +950,11 @@ func TestRequirementSelectingModule_GetOwner(t *testing.T) { } inner := mocks.NewMockExecutionHelperWithRawSecrets(t) - inner.EXPECT().GetOwner().Return("owner-123") + inner.EXPECT().GetOwner().Return("ownermath.MaxUint3223") h := host.NewRestrictedExecutionHelper(inner, restrictions).(host.ExecutionHelperWithRawSecrets) owner := h.GetOwner() - assert.Equal(t, "owner-123", owner) + assert.Equal(t, "ownermath.MaxUint3223", owner) } func TestRequirementSelectingModule_NewCreatesTheRightInterface(t *testing.T) {