forked from TrueCloudLab/policy-engine
[#1] chain: Add json marshal/unmarshal
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
parent
58386edf58
commit
88c2a476b0
10 changed files with 398 additions and 51 deletions
14
Makefile
14
Makefile
|
@ -5,6 +5,8 @@ TMP_DIR := .cache
|
||||||
OUTPUT_LINT_DIR ?= $(shell pwd)/bin
|
OUTPUT_LINT_DIR ?= $(shell pwd)/bin
|
||||||
LINT_VERSION ?= 1.55.1
|
LINT_VERSION ?= 1.55.1
|
||||||
LINT_DIR = $(OUTPUT_LINT_DIR)/golangci-lint-$(LINT_VERSION)-v$(TRUECLOUDLAB_LINT_VERSION)
|
LINT_DIR = $(OUTPUT_LINT_DIR)/golangci-lint-$(LINT_VERSION)-v$(TRUECLOUDLAB_LINT_VERSION)
|
||||||
|
EASYJSON_VERSION ?= $(shell go list -f '{{.Version}}' -m github.com/mailru/easyjson)
|
||||||
|
EASYJSON_DIR ?= $(shell pwd)/bin/easyjson-$(EASYJSON_VERSION)
|
||||||
|
|
||||||
# Run all code formatters
|
# Run all code formatters
|
||||||
fmts: fmt imports
|
fmts: fmt imports
|
||||||
|
@ -60,3 +62,15 @@ staticcheck-install:
|
||||||
# Run staticcheck
|
# Run staticcheck
|
||||||
staticcheck-run:
|
staticcheck-run:
|
||||||
@staticcheck ./...
|
@staticcheck ./...
|
||||||
|
|
||||||
|
easyjson-install:
|
||||||
|
@rm -rf $(EASYJSON_DIR)
|
||||||
|
@mkdir -p $(EASYJSON_DIR)
|
||||||
|
@GOBIN=$(EASYJSON_DIR) go install github.com/mailru/easyjson/...@$(EASYJSON_VERSION)
|
||||||
|
|
||||||
|
generate:
|
||||||
|
@if [ ! -d "$(EASYJSON_DIR)" ]; then \
|
||||||
|
make easyjson-install; \
|
||||||
|
fi
|
||||||
|
find ./ -name "_easyjson.go" -exec rm -rf {} \;
|
||||||
|
$(EASYJSON_DIR)/easyjson ./pkg/chain/chain.go
|
2
go.mod
2
go.mod
|
@ -5,6 +5,7 @@ go 1.20
|
||||||
require (
|
require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/mailru/easyjson v0.7.7
|
||||||
github.com/nspcc-dev/neo-go v0.103.0
|
github.com/nspcc-dev/neo-go v0.103.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
||||||
|
@ -14,6 +15,7 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231020160724-c3955f87d1b5 // indirect
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231020160724-c3955f87d1b5 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -11,6 +11,10 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
|
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
|
||||||
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaFCKt1pQJd7PXoMJabZWK9ejjbLOVrkl/lOUmshg=
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package chain
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -23,6 +22,7 @@ const (
|
||||||
MatchTypeFirstMatch MatchType = 1
|
MatchTypeFirstMatch MatchType = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//easyjson:json
|
||||||
type Chain struct {
|
type Chain struct {
|
||||||
ID ID
|
ID ID
|
||||||
|
|
||||||
|
@ -31,19 +31,6 @@ type Chain struct {
|
||||||
MatchType MatchType
|
MatchType MatchType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (id ID) MarshalJSON() ([]byte, error) {
|
|
||||||
return json.Marshal([]byte(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (id *ID) UnmarshalJSON(data []byte) error {
|
|
||||||
var idRaw []byte
|
|
||||||
if err := json.Unmarshal(data, &idRaw); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*id = ID(idRaw)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Chain) Bytes() []byte {
|
func (c *Chain) Bytes() []byte {
|
||||||
data, err := c.MarshalBinary()
|
data, err := c.MarshalBinary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -123,45 +110,36 @@ const (
|
||||||
CondSliceContains
|
CondSliceContains
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var condToStr = []struct {
|
||||||
|
ct ConditionType
|
||||||
|
str string
|
||||||
|
}{
|
||||||
|
{CondStringEquals, "StringEquals"},
|
||||||
|
{CondStringNotEquals, "StringNotEquals"},
|
||||||
|
{CondStringEqualsIgnoreCase, "StringEqualsIgnoreCase"},
|
||||||
|
{CondStringNotEqualsIgnoreCase, "StringNotEqualsIgnoreCase"},
|
||||||
|
{CondStringLike, "StringLike"},
|
||||||
|
{CondStringNotLike, "StringNotLike"},
|
||||||
|
{CondStringLessThan, "StringLessThan"},
|
||||||
|
{CondStringLessThanEquals, "StringLessThanEquals"},
|
||||||
|
{CondStringGreaterThan, "StringGreaterThan"},
|
||||||
|
{CondStringGreaterThanEquals, "StringGreaterThanEquals"},
|
||||||
|
{CondNumericEquals, "NumericEquals"},
|
||||||
|
{CondNumericNotEquals, "NumericNotEquals"},
|
||||||
|
{CondNumericLessThan, "NumericLessThan"},
|
||||||
|
{CondNumericLessThanEquals, "NumericLessThanEquals"},
|
||||||
|
{CondNumericGreaterThan, "NumericGreaterThan"},
|
||||||
|
{CondNumericGreaterThanEquals, "NumericGreaterThanEquals"},
|
||||||
|
{CondSliceContains, "SliceContains"},
|
||||||
|
}
|
||||||
|
|
||||||
func (c ConditionType) String() string {
|
func (c ConditionType) String() string {
|
||||||
switch c {
|
for _, v := range condToStr {
|
||||||
case CondStringEquals:
|
if v.ct == c {
|
||||||
return "StringEquals"
|
return v.str
|
||||||
case CondStringNotEquals:
|
}
|
||||||
return "StringNotEquals"
|
|
||||||
case CondStringEqualsIgnoreCase:
|
|
||||||
return "StringEqualsIgnoreCase"
|
|
||||||
case CondStringNotEqualsIgnoreCase:
|
|
||||||
return "StringNotEqualsIgnoreCase"
|
|
||||||
case CondStringLike:
|
|
||||||
return "StringLike"
|
|
||||||
case CondStringNotLike:
|
|
||||||
return "StringNotLike"
|
|
||||||
case CondStringLessThan:
|
|
||||||
return "StringLessThan"
|
|
||||||
case CondStringLessThanEquals:
|
|
||||||
return "StringLessThanEquals"
|
|
||||||
case CondStringGreaterThan:
|
|
||||||
return "StringGreaterThan"
|
|
||||||
case CondStringGreaterThanEquals:
|
|
||||||
return "StringGreaterThanEquals"
|
|
||||||
case CondNumericEquals:
|
|
||||||
return "NumericEquals"
|
|
||||||
case CondNumericNotEquals:
|
|
||||||
return "NumericNotEquals"
|
|
||||||
case CondNumericLessThan:
|
|
||||||
return "NumericLessThan"
|
|
||||||
case CondNumericLessThanEquals:
|
|
||||||
return "NumericLessThanEquals"
|
|
||||||
case CondNumericGreaterThan:
|
|
||||||
return "NumericGreaterThan"
|
|
||||||
case CondNumericGreaterThanEquals:
|
|
||||||
return "NumericGreaterThanEquals"
|
|
||||||
case CondSliceContains:
|
|
||||||
return "SliceContains"
|
|
||||||
default:
|
|
||||||
return "unknown condition type"
|
|
||||||
}
|
}
|
||||||
|
return "unknown condition type"
|
||||||
}
|
}
|
||||||
|
|
||||||
const condSliceContainsDelimiter = "\x00"
|
const condSliceContainsDelimiter = "\x00"
|
||||||
|
|
BIN
pkg/chain/chain_easyjson.go
Normal file
BIN
pkg/chain/chain_easyjson.go
Normal file
Binary file not shown.
153
pkg/chain/marshal_json.go
Normal file
153
pkg/chain/marshal_json.go
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
jlexer "github.com/mailru/easyjson/jlexer"
|
||||||
|
jwriter "github.com/mailru/easyjson/jwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Run `make generate`` if types added or changed
|
||||||
|
|
||||||
|
var matchTypeToJSONValue = []struct {
|
||||||
|
mt MatchType
|
||||||
|
str string
|
||||||
|
}{
|
||||||
|
{MatchTypeDenyPriority, "DenyPriority"},
|
||||||
|
{MatchTypeFirstMatch, "FirstMatch"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusToJSONValue = []struct {
|
||||||
|
s Status
|
||||||
|
str string
|
||||||
|
}{
|
||||||
|
{Allow, "Allow"},
|
||||||
|
{NoRuleFound, "NoRuleFound"},
|
||||||
|
{AccessDenied, "AccessDenied"},
|
||||||
|
{QuotaLimitReached, "QuotaLimitReached"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var objectTypeToJSONValue = []struct {
|
||||||
|
t ObjectType
|
||||||
|
str string
|
||||||
|
}{
|
||||||
|
{ObjectRequest, "Request"},
|
||||||
|
{ObjectResource, "Resource"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mt MatchType) MarshalEasyJSON(w *jwriter.Writer) {
|
||||||
|
for _, p := range matchTypeToJSONValue {
|
||||||
|
if p.mt == mt {
|
||||||
|
w.String(p.str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.String(strconv.FormatUint(uint64(mt), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mt *MatchType) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
|
str := l.String()
|
||||||
|
for _, p := range matchTypeToJSONValue {
|
||||||
|
if p.str == str {
|
||||||
|
*mt = p.mt
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.ParseUint(str, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
l.AddError(fmt.Errorf("failed to parse match type: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*mt = MatchType(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st Status) MarshalEasyJSON(w *jwriter.Writer) {
|
||||||
|
for _, p := range statusToJSONValue {
|
||||||
|
if p.s == st {
|
||||||
|
w.String(p.str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.String(strconv.FormatUint(uint64(st), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *Status) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
|
str := l.String()
|
||||||
|
for _, p := range statusToJSONValue {
|
||||||
|
if p.str == str {
|
||||||
|
*st = p.s
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.ParseUint(str, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
l.AddError(fmt.Errorf("failed to parse status: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*st = Status(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ot ObjectType) MarshalEasyJSON(w *jwriter.Writer) {
|
||||||
|
for _, p := range objectTypeToJSONValue {
|
||||||
|
if p.t == ot {
|
||||||
|
w.String(p.str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.String(strconv.FormatUint(uint64(ot), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ot *ObjectType) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
|
str := l.String()
|
||||||
|
for _, p := range objectTypeToJSONValue {
|
||||||
|
if p.str == str {
|
||||||
|
*ot = p.t
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.ParseUint(str, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
l.AddError(fmt.Errorf("failed to parse object type: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ot = ObjectType(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct ConditionType) MarshalEasyJSON(w *jwriter.Writer) {
|
||||||
|
for _, p := range condToStr {
|
||||||
|
if p.ct == ct {
|
||||||
|
w.String(p.str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.String(strconv.FormatUint(uint64(ct), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *ConditionType) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
|
str := l.String()
|
||||||
|
for _, p := range condToStr {
|
||||||
|
if p.str == str {
|
||||||
|
*ct = p.ct
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.ParseUint(str, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
l.AddError(fmt.Errorf("failed to parse condition type: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ct = ConditionType(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (id ID) MarshalEasyJSON(w *jwriter.Writer) {
|
||||||
|
w.Base64Bytes([]byte(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (id *ID) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
|
*id = ID(l.Bytes())
|
||||||
|
}
|
121
pkg/chain/marshal_json_test.go
Normal file
121
pkg/chain/marshal_json_test.go
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestID(t *testing.T) {
|
||||||
|
key, err := keys.NewPrivateKeyFromWIF("L5eVx6HcHaFpQpvjQ3fy29uKDZ8rQ34bfMVx4XfZMm52EqafpNMg") // s3-gw key
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
chain1 := &Chain{ID: ID(key.PublicKey().GetScriptHash().BytesBE())}
|
||||||
|
data := chain1.Bytes()
|
||||||
|
|
||||||
|
var chain2 Chain
|
||||||
|
require.NoError(t, chain2.DecodeBytes(data))
|
||||||
|
|
||||||
|
require.Equal(t, chain1.ID, chain2.ID)
|
||||||
|
|
||||||
|
data, err = chain1.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, chain2.UnmarshalJSON(data))
|
||||||
|
|
||||||
|
require.Equal(t, chain1.ID, chain2.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchTypeJson(t *testing.T) {
|
||||||
|
for _, mt := range []MatchType{MatchTypeDenyPriority, MatchTypeFirstMatch, MatchType(100)} {
|
||||||
|
var chain Chain
|
||||||
|
chain.MatchType = mt
|
||||||
|
|
||||||
|
data, err := chain.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
if mt == MatchTypeDenyPriority {
|
||||||
|
require.Equal(t, []byte("{\"ID\":\"\",\"Rules\":null,\"MatchType\":\"DenyPriority\"}"), data)
|
||||||
|
} else if mt == MatchTypeFirstMatch {
|
||||||
|
require.Equal(t, []byte("{\"ID\":\"\",\"Rules\":null,\"MatchType\":\"FirstMatch\"}"), data)
|
||||||
|
} else {
|
||||||
|
require.Equal(t, []byte(fmt.Sprintf("{\"ID\":\"\",\"Rules\":null,\"MatchType\":\"%d\"}", mt)), data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsed Chain
|
||||||
|
require.NoError(t, parsed.UnmarshalJSON(data))
|
||||||
|
require.Equal(t, chain, parsed)
|
||||||
|
|
||||||
|
require.Error(t, parsed.UnmarshalJSON([]byte("{\"ID\":\"\",\"Rules\":null,\"MatchType\":\"NotValid\"}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJsonEnums(t *testing.T) {
|
||||||
|
chain := Chain{
|
||||||
|
ID: "2cca5ae7-cee8-428d-b45f-567fb1d03f01", // will be encoded to base64
|
||||||
|
MatchType: MatchTypeFirstMatch,
|
||||||
|
Rules: []Rule{
|
||||||
|
{
|
||||||
|
Status: AccessDenied,
|
||||||
|
Actions: Actions{
|
||||||
|
Names: []string{native.MethodDeleteObject, native.MethodGetContainer},
|
||||||
|
},
|
||||||
|
Resources: Resources{
|
||||||
|
Names: []string{native.ResourceFormatAllObjects},
|
||||||
|
},
|
||||||
|
Condition: []Condition{
|
||||||
|
{
|
||||||
|
Op: CondStringEquals,
|
||||||
|
Object: ObjectRequest,
|
||||||
|
Key: native.PropertyKeyActorRole,
|
||||||
|
Value: native.PropertyValueContainerRoleOthers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: QuotaLimitReached,
|
||||||
|
Actions: Actions{
|
||||||
|
Inverted: true,
|
||||||
|
Names: []string{native.MethodPutObject},
|
||||||
|
},
|
||||||
|
Resources: Resources{
|
||||||
|
Names: []string{fmt.Sprintf(native.ResourceFormatRootContainerObjects, "9LPLUFZpEmfidG4n44vi2cjXKXSqWT492tCvLJiJ8W1J")},
|
||||||
|
},
|
||||||
|
Any: true,
|
||||||
|
Condition: []Condition{
|
||||||
|
{
|
||||||
|
Op: CondStringNotLike,
|
||||||
|
Object: ObjectResource,
|
||||||
|
Key: native.PropertyKeyObjectType,
|
||||||
|
Value: "regular",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Status: Status(100),
|
||||||
|
Condition: []Condition{
|
||||||
|
{
|
||||||
|
Op: ConditionType(255),
|
||||||
|
Object: ObjectType(128),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := chain.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var parsed Chain
|
||||||
|
require.NoError(t, parsed.UnmarshalJSON(data))
|
||||||
|
require.Equal(t, chain, parsed)
|
||||||
|
|
||||||
|
expected, err := os.ReadFile("./testdata/test_status_json.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NoError(t, parsed.UnmarshalJSON(expected))
|
||||||
|
require.Equal(t, chain, parsed)
|
||||||
|
}
|
75
pkg/chain/testdata/test_status_json.json
vendored
Normal file
75
pkg/chain/testdata/test_status_json.json
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"ID": "MmNjYTVhZTctY2VlOC00MjhkLWI0NWYtNTY3ZmIxZDAzZjAx",
|
||||||
|
"Rules": [
|
||||||
|
{
|
||||||
|
"Status": "AccessDenied",
|
||||||
|
"Actions": {
|
||||||
|
"Inverted": false,
|
||||||
|
"Names": [
|
||||||
|
"DeleteObject",
|
||||||
|
"GetContainer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Resources": {
|
||||||
|
"Inverted": false,
|
||||||
|
"Names": [
|
||||||
|
"native:object/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Any": false,
|
||||||
|
"Condition": [
|
||||||
|
{
|
||||||
|
"Op": "StringEquals",
|
||||||
|
"Object": "Request",
|
||||||
|
"Key": "$Actor:role",
|
||||||
|
"Value": "others"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Status": "QuotaLimitReached",
|
||||||
|
"Actions": {
|
||||||
|
"Inverted": true,
|
||||||
|
"Names": [
|
||||||
|
"PutObject"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Resources": {
|
||||||
|
"Inverted": false,
|
||||||
|
"Names": [
|
||||||
|
"native:object//9LPLUFZpEmfidG4n44vi2cjXKXSqWT492tCvLJiJ8W1J/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Any": true,
|
||||||
|
"Condition": [
|
||||||
|
{
|
||||||
|
"Op": "StringNotLike",
|
||||||
|
"Object": "Resource",
|
||||||
|
"Key": "$Object:objectType",
|
||||||
|
"Value": "regular"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Status": "100",
|
||||||
|
"Actions": {
|
||||||
|
"Inverted": false,
|
||||||
|
"Names": null
|
||||||
|
},
|
||||||
|
"Resources": {
|
||||||
|
"Inverted": false,
|
||||||
|
"Names": null
|
||||||
|
},
|
||||||
|
"Any": false,
|
||||||
|
"Condition": [
|
||||||
|
{
|
||||||
|
"Op": "255",
|
||||||
|
"Object": "128",
|
||||||
|
"Key": "",
|
||||||
|
"Value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"MatchType": "FirstMatch"
|
||||||
|
}
|
Loading…
Reference in a new issue