generated from TrueCloudLab/basic
[#33] pkg/chain: Support CondSliceContains condition #38
6 changed files with 91 additions and 0 deletions
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958
|
||||
github.com/nspcc-dev/neo-go v0.103.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
2
go.sum
2
go.sum
|
@ -31,6 +31,8 @@ github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1
|
|||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
|
|
|
@ -50,6 +50,9 @@ const (
|
|||
CondArnLike string = "ArnLike"
|
||||
CondArnNotEquals string = "ArnNotEquals"
|
||||
CondArnNotLike string = "ArnNotLike"
|
||||
|
||||
// Custom condition operators.
|
||||
CondSliceContains string = "SliceContains"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -191,6 +194,8 @@ func getConditionTypeAndConverter(op string) (chain.ConditionType, convertFuncti
|
|||
return chain.CondStringLike, noConvertFunction, nil
|
||||
case op == CondNotIPAddress:
|
||||
return chain.CondStringNotLike, noConvertFunction, nil
|
||||
case op == CondSliceContains:
|
||||
return chain.CondSliceContains, noConvertFunction, nil
|
||||
default:
|
||||
return 0, nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/util"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// ID is the ID of rule chain.
|
||||
|
@ -103,6 +104,8 @@ const (
|
|||
CondNumericLessThanEquals
|
||||
CondNumericGreaterThan
|
||||
CondNumericGreaterThanEquals
|
||||
|
||||
CondSliceContains
|
||||
)
|
||||
|
||||
func (c ConditionType) String() string {
|
||||
|
@ -139,11 +142,21 @@ func (c ConditionType) String() string {
|
|||
return "NumericGreaterThan"
|
||||
case CondNumericGreaterThanEquals:
|
||||
return "NumericGreaterThanEquals"
|
||||
case CondSliceContains:
|
||||
return "SliceContains"
|
||||
default:
|
||||
return "unknown condition type"
|
||||
}
|
||||
}
|
||||
|
||||
const condSliceContainsDelimiter = "\x00"
|
||||
|
||||
// FormCondSliceContainsValue builds value for ObjectResource or ObjectRequest property
|
||||
// that can be matched by CondSliceContains condition.
|
||||
func FormCondSliceContainsValue(values []string) string {
|
||||
return strings.Join(values, condSliceContainsDelimiter)
|
||||
}
|
||||
|
||||
func (c *Condition) Match(req resource.Request) bool {
|
||||
var val string
|
||||
switch c.Object {
|
||||
|
@ -178,6 +191,8 @@ func (c *Condition) Match(req resource.Request) bool {
|
|||
return val > c.Value
|
||||
case CondStringGreaterThanEquals:
|
||||
return val >= c.Value
|
||||
case CondSliceContains:
|
||||
return slices.Contains(strings.Split(val, condSliceContainsDelimiter), c.Value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource/testutil"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/common"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -73,3 +74,65 @@ func TestReturnFirstMatch(t *testing.T) {
|
|||
require.Equal(t, Allow, st)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCondSliceContainsMatch(t *testing.T) {
|
||||
propKey := common.PropertyKeyFrostFSIDGroupID
|
||||
groupID := "1"
|
||||
|
||||
ch := Chain{Rules: []Rule{{
|
||||
Status: Allow,
|
||||
Actions: Actions{Names: []string{native.MethodPutObject}},
|
||||
Resources: Resources{Names: []string{native.ResourceFormatRootContainers}},
|
||||
Condition: []Condition{{
|
||||
Op: CondSliceContains,
|
||||
Object: ObjectRequest,
|
||||
Key: propKey,
|
||||
Value: groupID,
|
||||
}},
|
||||
}}}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
value string
|
||||
status Status
|
||||
}{
|
||||
{
|
||||
name: "simple value",
|
||||
value: groupID,
|
||||
status: Allow,
|
||||
},
|
||||
{
|
||||
name: "simple value by func",
|
||||
value: FormCondSliceContainsValue([]string{groupID}),
|
||||
status: Allow,
|
||||
},
|
||||
{
|
||||
name: "multiple values by func",
|
||||
value: FormCondSliceContainsValue([]string{groupID, "2", "3"}),
|
||||
status: Allow,
|
||||
},
|
||||
{
|
||||
name: "simple mismatched",
|
||||
value: "3",
|
||||
status: NoRuleFound,
|
||||
},
|
||||
{
|
||||
name: "multiple mismatched",
|
||||
value: FormCondSliceContainsValue([]string{"11", "12"}),
|
||||
status: NoRuleFound,
|
||||
},
|
||||
{
|
||||
name: "comma correct handling mismatched",
|
||||
value: "1,11",
|
||||
status: NoRuleFound,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resource := testutil.NewResource(native.ResourceFormatRootContainers, nil)
|
||||
request := testutil.NewRequest(native.MethodPutObject, resource, map[string]string{propKey: tc.value})
|
||||
|
||||
st, _ := ch.Match(request)
|
||||
require.Equal(t, tc.status.String(), st.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
5
schema/common/consts.go
Normal file
5
schema/common/consts.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package common
|
||||
|
||||
const (
|
||||
PropertyKeyFrostFSIDGroupID = "frostfsid:groupID"
|
||||
)
|
Loading…
Reference in a new issue