Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 12 additions & 11 deletions pkg/workflows/host/execution_restrictions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package host
import (
"context"
"fmt"
"math"
"strings"
"sync"

Expand All @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
37 changes: 19 additions & 18 deletions pkg/workflows/host/execution_restrictions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package host_test
import (
"context"
"errors"
"math"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -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{
Expand All @@ -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},
}},
},
},
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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"})
Expand Down Expand Up @@ -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"},
Expand All @@ -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,
},
}},
},
Expand Down Expand Up @@ -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"},
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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}}},
}})

Expand Down Expand Up @@ -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"}},
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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) {
Expand All @@ -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{
Expand All @@ -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{
Expand All @@ -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) {
Expand Down
Loading