[#1124] cli: Improve APE rule parsing
All checks were successful
Vulncheck / Vulncheck (pull_request) Successful in 1m25s
DCO action / DCO (pull_request) Successful in 1m59s
Build / Build Components (1.21) (pull_request) Successful in 2m27s
Build / Build Components (1.22) (pull_request) Successful in 4m25s
Pre-commit hooks / Pre-commit (pull_request) Successful in 4m57s
Tests and linters / Staticcheck (pull_request) Successful in 5m38s
Tests and linters / gopls check (pull_request) Successful in 5m57s
Tests and linters / Lint (pull_request) Successful in 6m26s
Tests and linters / Tests (1.22) (pull_request) Successful in 9m5s
Tests and linters / Tests (1.21) (pull_request) Successful in 9m11s
Tests and linters / Tests with -race (pull_request) Successful in 9m4s
All checks were successful
Vulncheck / Vulncheck (pull_request) Successful in 1m25s
DCO action / DCO (pull_request) Successful in 1m59s
Build / Build Components (1.21) (pull_request) Successful in 2m27s
Build / Build Components (1.22) (pull_request) Successful in 4m25s
Pre-commit hooks / Pre-commit (pull_request) Successful in 4m57s
Tests and linters / Staticcheck (pull_request) Successful in 5m38s
Tests and linters / gopls check (pull_request) Successful in 5m57s
Tests and linters / Lint (pull_request) Successful in 6m26s
Tests and linters / Tests (1.22) (pull_request) Successful in 9m5s
Tests and linters / Tests (1.21) (pull_request) Successful in 9m11s
Tests and linters / Tests with -race (pull_request) Successful in 9m4s
* Make APE rule parser to read condition's kind in unambiguous using lexemes `ResourceCondition`, `RequestCondition` instead confusing `Object.Request`, `Object.Resource`. * Fix unit-tests. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
20baf6e112
commit
952d13cd2b
8 changed files with 151 additions and 147 deletions
|
@ -21,7 +21,7 @@ var (
|
|||
errUnknownAction = errors.New("action is not recognized")
|
||||
errUnknownBinaryOperator = errors.New("binary operator is not recognized")
|
||||
errUnknownCondObjectType = errors.New("condition object type is not recognized")
|
||||
errMixedTypesInRule = errors.New("found mixed type of actions and conditions in rule")
|
||||
errMixedTypesInRule = errors.New("found mixed type of actions in rule")
|
||||
errNoActionsInRule = errors.New("there are no actions in rule")
|
||||
errUnsupportedResourceFormat = errors.New("unsupported resource format")
|
||||
errFailedToParseAllAny = errors.New("any/all is not parsed")
|
||||
|
@ -38,10 +38,10 @@ func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
|||
cmd.Println("\tConditions:")
|
||||
for _, c := range rule.Condition {
|
||||
var ot string
|
||||
switch c.Object {
|
||||
case apechain.ObjectResource:
|
||||
switch c.Kind {
|
||||
case apechain.KindResource:
|
||||
ot = "Resource"
|
||||
case apechain.ObjectRequest:
|
||||
case apechain.KindRequest:
|
||||
ot = "Request"
|
||||
default:
|
||||
panic("unknown object type")
|
||||
|
@ -100,9 +100,9 @@ func ParseAPEChain(chain *apechain.Chain, rules []string) error {
|
|||
// deny Object.Put *
|
||||
// deny:QuotaLimitReached Object.Put *
|
||||
// allow Object.Put *
|
||||
// allow Object.Get Object.Resource:Department=HR Object.Request:Actor=ownerA *
|
||||
// allow Object.Get any Object.Resource:Department=HR Object.Request:Actor=ownerA *
|
||||
// allow Object.Get all Object.Resource:Department=HR Object.Request:Actor=ownerA *
|
||||
// allow Object.Get ResourceCondition:Department=HR RequestCondition:Actor=ownerA *
|
||||
// allow Object.Get any ResourceCondition:Department=HR RequestCondition:Actor=ownerA *
|
||||
// allow Object.Get all ResourceCondition:Department=HR RequestCondition:Actor=ownerA *
|
||||
// allow Object.* *
|
||||
// allow Container.* *
|
||||
//
|
||||
|
@ -138,7 +138,9 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var isObject *bool
|
||||
var objectTargeted bool
|
||||
var containerTargeted bool
|
||||
|
||||
for i, lexeme := range lexemes[1:] {
|
||||
anyExpr, anyErr := parseAnyAll(lexeme)
|
||||
if anyErr == nil {
|
||||
|
@ -156,23 +158,30 @@ func parseRuleLexemes(r *apechain.Rule, lexemes []string) error {
|
|||
lexemes = lexemes[i+1:]
|
||||
break
|
||||
}
|
||||
actionType = condition.Object == apechain.ObjectResource || condition.Object == apechain.ObjectRequest
|
||||
r.Condition = append(r.Condition, *condition)
|
||||
} else {
|
||||
if actionType {
|
||||
objectTargeted = true
|
||||
} else {
|
||||
containerTargeted = true
|
||||
}
|
||||
if objectTargeted && containerTargeted {
|
||||
// Actually, APE chain allows to define rules for several resources, for example, if
|
||||
// chain target is namespace, but the parser primitevly compiles verbs,
|
||||
// conditions and resources in one rule. So, for the parser, one rule relates only to
|
||||
// one resource type - object or container.
|
||||
return errMixedTypesInRule
|
||||
}
|
||||
|
||||
r.Actions.Names = append(r.Actions.Names, names...)
|
||||
}
|
||||
if isObject == nil {
|
||||
isObject = &actionType
|
||||
} else if actionType != *isObject {
|
||||
return errMixedTypesInRule
|
||||
}
|
||||
}
|
||||
r.Actions.Names = unique(r.Actions.Names)
|
||||
if len(r.Actions.Names) == 0 {
|
||||
return fmt.Errorf("%w:%w", err, errNoActionsInRule)
|
||||
}
|
||||
for _, lexeme := range lexemes {
|
||||
resource, errRes := parseResource(lexeme, *isObject)
|
||||
resource, errRes := parseResource(lexeme, objectTargeted)
|
||||
if errRes != nil {
|
||||
return fmt.Errorf("%w:%w", err, errRes)
|
||||
}
|
||||
|
@ -308,32 +317,27 @@ func parseResource(lexeme string, isObj bool) (string, error) {
|
|||
}
|
||||
|
||||
const (
|
||||
ObjectResource = "object.resource"
|
||||
ObjectRequest = "object.request"
|
||||
|
||||
ContainerResource = "container.resource"
|
||||
ContainerRequest = "container.request"
|
||||
ResourceCondition = "resourcecondition"
|
||||
RequestCondition = "requestcondition"
|
||||
)
|
||||
|
||||
var typeToCondObject = map[string]apechain.ObjectType{
|
||||
ObjectResource: apechain.ObjectResource,
|
||||
ObjectRequest: apechain.ObjectRequest,
|
||||
ContainerResource: apechain.ContainerResource,
|
||||
ContainerRequest: apechain.ContainerRequest,
|
||||
var typeToCondKindType = map[string]apechain.ConditionKindType{
|
||||
ResourceCondition: apechain.KindResource,
|
||||
RequestCondition: apechain.KindRequest,
|
||||
}
|
||||
|
||||
func parseCondition(lexeme string) (*apechain.Condition, error) {
|
||||
typ, expression, found := strings.Cut(lexeme, ":")
|
||||
typ = strings.ToLower(typ)
|
||||
|
||||
objType, ok := typeToCondObject[typ]
|
||||
condKindType, ok := typeToCondKindType[typ]
|
||||
if ok {
|
||||
if !found {
|
||||
return nil, fmt.Errorf("%w: %s", errInvalidConditionFormat, lexeme)
|
||||
}
|
||||
|
||||
var cond apechain.Condition
|
||||
cond.Object = objType
|
||||
cond.Kind = condKindType
|
||||
|
||||
lhs, rhs, binExpFound := strings.Cut(expression, "!=")
|
||||
if !binExpFound {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue