generated from TrueCloudLab/basic
schema: Add resource name validation method #27
3 changed files with 162 additions and 0 deletions
20
docs/resource.md
Normal file
20
docs/resource.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Resource
|
||||
|
||||
From the point of the access policy engine, a resource is an object to which a request is being performed.
|
||||
This can be an object in a container within a namespace, or all objects in a container,
|
||||
or all containers within the root namespace etc.
|
||||
|
||||
A resource can be viewed from two sides:
|
||||
|
||||
- As part of a [request](../pkg/resource/resource.go). In this case a resource has a name and properties.
|
||||
- As part of rule [chain](../pkg/chain/chain.go): a resource has just a name.
|
||||
|
||||
## Resource name
|
||||
|
||||
A resource name must have a such format that can be processed by a chain router that matches a request
|
||||
either with local overrides or with rules within policy contract to get if this request is allowed to be performed.
|
||||
The main idea of this format is for the chain router to match by full name (`native:object//cnrID/objID`) or
|
||||
wildcard (`native:object//cnrID/*`).
|
||||
|
||||
Check out formats that are defined in the schema: [native formats](../schema/native/consts.go), [s3 formats](../schema/s3/consts.go).
|
||||
You should validate a resource name using [util](../schema/native/util/validation.go) before instantiating a request or
|
||||
before putting it to either to local override storage or the policy contract storage.
|
45
schema/native/util/validation.go
Normal file
45
schema/native/util/validation.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||
)
|
||||
|
||||
var nativePatterns = []string{
|
||||
native.ResourceFormatNamespaceObjects, native.ResourceFormatNamespaceContainerObjects,
|
||||
native.ResourceFormatNamespaceContainerObject, native.ResourceFormatRootObjects,
|
||||
native.ResourceFormatRootContainerObjects, native.ResourceFormatRootContainerObject,
|
||||
native.ResourceFormatAllObjects, native.ResourceFormatNamespaceContainer,
|
||||
native.ResourceFormatNamespaceContainers, native.ResourceFormatRootContainer,
|
||||
native.ResourceFormatRootContainers, native.ResourceFormatAllContainers,
|
||||
}
|
||||
|
||||
func match(resource, pattern string) bool {
|
||||
rTokens := strings.Split(resource, "/")
|
||||
pToken := strings.Split(pattern, "/")
|
||||
|
||||
if len(rTokens) != len(pToken) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range rTokens {
|
||||
if pToken[i] == "%s" {
|
||||
continue
|
||||
}
|
||||
if pToken[i] != rTokens[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func IsNativeResourceNameValid(resource string) bool {
|
||||
fyrchik
commented
Validation method is nice, but can we also describe this somewhere in docs? Validation method is nice, but can we also describe this somewhere in docs?
Also, what about a benchmark? There are some opportunities for an optimization.
aarifullin
commented
I've added I've added `docs` where I also describe what is a resource from the APE point. Waiting for your comments and notes :)
aarifullin
commented
I've also added a benchmark test I've also added a benchmark test
|
||||
for _, pattern := range nativePatterns {
|
||||
if match(resource, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
97
schema/native/util/validation_test.go
Normal file
97
schema/native/util/validation_test.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
expected bool
|
||||
resource string
|
||||
}{
|
||||
{
|
||||
name: "ResourceFormatNamespaceObjects",
|
||||
expected: true,
|
||||
resource: "native:object/RootNamespace/*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatNamespaceContainerObjects",
|
||||
expected: true,
|
||||
resource: "native:object/RootNamespace/BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatNamespaceContainerObject",
|
||||
expected: true,
|
||||
resource: "native:object/RootNamespace/BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/AeZa5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB4E",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatRootObjects",
|
||||
expected: true,
|
||||
resource: "native:object//*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatRootContainerObjects",
|
||||
expected: true,
|
||||
resource: "native:object//BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatRootContainerObject",
|
||||
expected: true,
|
||||
resource: "native:object//BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R/AeZa5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB4E",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatAllObjects",
|
||||
expected: true,
|
||||
resource: "native:object/*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatNamespaceContainer",
|
||||
expected: true,
|
||||
resource: "native:container/RootNamespace/BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatNamespaceContainers",
|
||||
expected: true,
|
||||
resource: "native:container/RootNamespace/*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatRootContainers",
|
||||
expected: true,
|
||||
resource: "native:container//*",
|
||||
},
|
||||
{
|
||||
name: "ResourceFormatAllContainers",
|
||||
expected: true,
|
||||
resource: "native:container/*",
|
||||
},
|
||||
{
|
||||
name: "Invalid resource 1",
|
||||
expected: false,
|
||||
resource: "native:::container/*",
|
||||
},
|
||||
{
|
||||
name: "Invalid resource 2",
|
||||
expected: false,
|
||||
resource: "native:container/RootNamespace/w5HH3feoxFDD5tCTtoRzB3R/Bz726qzgLfxEE7wgtoRzB3R/RootNamespace",
|
||||
},
|
||||
}
|
||||
|
||||
func TestIsNativeResourceNameValid(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
require.Equal(t, test.expected, IsNativeResourceNameValid(test.resource))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsNativeResourceNameValid(b *testing.B) {
|
||||
for _, test := range tests {
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
fyrchik
commented
Why Why `2000`, not `b.N`?
aarifullin
commented
Fixed! Fixed!
|
||||
_ = IsNativeResourceNameValid(test.resource)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue
The idea is not fully unfolded, but I suggest to give more details when we will describe the chain router