Policy Engine Expression Language - PEEL

Table of contents

Policy Engine Expression Language - PEEL is a representation of a Policy Engine entities in String format. Policy Engine is capable of lexing and parsing PEEL strings and converting them to Policy Engine entities.

PEEL Syntax

Every PEEL string contains a command that represents one of Policy Engine entities. Command format is always same:

<command>(<content|command>{0,},<options>?) -> <PolicyEngineEntity>

where every command has the following parameters:

  • command: String that represents Policy Engine entity and starts with * character for dynamic commands and # character for static commands
  • command parameter borders are always ( and )
  • parameters: Comma separated list of parameters that are passed to Policy Engine entity. They can be either a content or another command.
  • options: Comma separated list of options that are passed to Policy Engine entity.

Example of PEEL string

*permit(#ref(cond1))

This is a Permit Policy that references a PolicyCondition with id cond1.

Content parsing

PEEL only parses following types of characters:

  • letters - both lowercase and uppercase
  • numbers - 0-9
  • special characters - ()[]{},.-+*/=$#`“_

All other characters are skipped unless they are part of command content or if they are escaped. Command content is considered to be everything between brackets, delimited by comma. Content can be a string, another command or options placeholder.

When PEEL string contains special characters, they must be escaped. Following character are considered special:

  • (
  • )
  • ,
  • #
  • *
  • =

Escaping can be done by putting string content between following characters:

  • ” - double quotes - ASCII 34
  • ` - backtick - ASCII 96
  • ””” - triple quotes - ASCII 34 three times

Same character must be used for escaping and unescaping.

Example of PEEL string with escaped characters

#time("14/30/00",#opts(timeFormat="HH/mm/ss"))

In this case, both command content and option value are escaped. This example could also be written with different escape characters as:

#time(`14/30/00`,#opts(timeFormat="""HH/mm/ss"""))

Options

Options are optional and can be omitted. Options are always in format #opts(<key=value>{1,}) and are separated by comma. Boolean options can contain only name of the option, while other options must contain name and value.

Example of PEEL string with options

*permit(#ref(cond1),#opts(id="policy1"))

There are common options that can be used in every command:

  • id - unique identifier of the Policy Engine entity
  • ver - version of the Policy Engine entity. Must be in SemVer format
  • desc - description of the Policy Engine entity
  • labels - labels of the Policy Engine entity. They must be separated by vertical line | character (ASCII 124). If labels contain special characters, they must be escaped.

Example of PEEL string with options

*permit(#ref(cond1),#opts(id=policy1,ver=1.0.0,desc="This is a policy",labels=label1|"label 2"))

Reference

Template: #ref(<content>{1,2})
Reference expression can only contain 2 content parameters:

  • id - string, mandatory, contains id of a referred entity
  • version - string, optional, contains version of a referred entity. Must be in SemVer format

Reference expression will be deserialized to specific entity Ref depending on the command it is used in. If it is used in PolicyVariableDynamic, it will be deserialized to PolicyVariableResolverRef, and if used in Policy it will be deserialized to PolicyConditionRef.

Reference mapping table

PositionMappedTo
PolicyVariableDynamicPolicyVariableResolverRef
PolicyConditionAtomicPolicyVariableRef
PolicyConditionCompositePolicyConditionRef
PolicyActionPolicyVariableRef
PolicyPolicyConditionRef
PolicySetPolicyRef
PolicyConstraintPolicyConditionRef
PolicyActionRelationshipPolicyActionRef
PolicyRelationshipPolicyRef

Minimal example:

*permit(*all(#ref(pcr1),#ref(pcr2)))

Full example with options:

*permit(*all(#ref(pcr1,1.2.3),#ref(pcr2, 4.5.6)))

Full PEEL command table

CommandTypeformatoptions
#strPolicyVariableStatic#str(<content>{1,1},#opts?)isJson(*)
#datePolicyVariableStatic#date(<content>{1,1},#opts?)dateFormat
#dTimePolicyVariableStatic#dTime(<content>{1,1},#opts?)dateTimeFormat
#timePolicyVariableStatic#time(<content>{1,1},#opts?)timeFormat
#perPolicyVariableStatic#per(<content>{1,1},#opts?) 
#durPolicyVariableStatic#dur(<content>{1,1},#opts?) 
#intPolicyVariableStatic#int(<content>{1,1},#opts?) 
#longPolicyVariableStatic#long(<content>{1,1},#opts?) 
#numPolicyVariableStatic#num(<content>{1,1},#opts?) 
#floatPolicyVariableStatic#float(<content>{1,1},#opts?) 
#bigDPolicyVariableStatic#bigD(<content>{1,1},#opts?) 
#boolPolicyVariableStatic#bool(<content>{1,1},#opts?) 
#objPolicyVariableStatic#obj(<content>{1,1},#opts?) 
#arrPolicyVariableStatic#arr(<content>{1,1},#opts?) 
*dynPolicyVariableDynamic*dyn(<PolicyVariableResolver|Reference>{1,},#opts?)type, format, timeFormat, dateFormat, dateTimeFormat
*keyPolicyVariableResolver*key(<content>{1,1},#opts?)source
*pathPolicyVariableResolver*path(<content>{1,1},#opts?)source, key
*jqPolicyVariableResolver*jq(<content>{1,1},#opts?)source, key
*gtPolicyConditionAtomic*gt(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*)
*gtePolicyConditionAtomic*gte(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*)
*ltPolicyConditionAtomic*lt(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*)
*ltePolicyConditionAtomic*lte(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*)
*isNullPolicyConditionAtomic*isNull(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*notNullPolicyConditionAtomic*notNull(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*isEmptyPolicyConditionAtomic*isEmpty(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*notEmptyPolicyConditionAtomic*notEmpty(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*isBlankPolicyConditionAtomic*isBlank(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*notBlankPolicyConditionAtomic*notBlank(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*swPolicyConditionAtomic*sw(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*), fieldsStrictCheck(*), arrayOrderStrictCheck(*)
*ewPolicyConditionAtomic*ew(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*), fieldsStrictCheck(*), arrayOrderStrictCheck(*)
*containsPolicyConditionAtomic*contains(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*), fieldsStrictCheck(*), arrayOrderStrictCheck(*)
*isInPolicyConditionAtomic*isIn(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*), fieldsStrictCheck(*), arrayOrderStrictCheck(*)
*eqPolicyConditionAtomic*eq(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*), stringIgnoreCase(*), fieldsStrictCheck(*), arrayOrderStrictCheck(*)
*posPolicyConditionAtomic*pos(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*negPolicyConditionAtomic*neg(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*zeroPolicyConditionAtomic*zero(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*pastPolicyConditionAtomic*past(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*futurePolicyConditionAtomic*future(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*regexpPolicyConditionAtomic*regexp(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*)
*hasKeyPolicyConditionAtomic*hasKey(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*)
*uniquePolicyConditionAtomic*unique(<PolicyVariable|Reference>{1,1},#opts?)negateResult(*)
*schemaPolicyConditionAtomic*schema(<PolicyVariable|Reference>{2,2},#opts?)negateResult(*)
*anyPolicyConditionComposite*any(<PolicyCondition|Reference>{1,},#opts?)negateResult(*), strictCheck(*)
*allPolicyConditionComposite*all(<PolicyCondition|Reference>{1,},#opts?)negateResult(*), strictCheck(*)
*notPolicyConditionComposite*not(<PolicyCondition|Reference>{1,1},#opts?)negateResult(*)
*nOfPolicyConditionComposite*nOf(<PolicyCondition|Reference>{1,},#opts)minimumConditions(**), negateResult(*), strictCheck(*), optimize(*)
#truePolicyConditionDefault#true(<>{0,0}) 
#falsePolicyConditionDefault#false(<>{0,0}) 
#nullPolicyConditionDefault#null(<>{0,0}) 
*permitPolicy*permit(<PolicyCondition|Reference>{1,1},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, strictTargetEffect(*)
*denyPolicy*deny(<PolicyCondition|Reference>{1,1},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, strictTargetEffect(*)
*DOverridesPolicySet*DOverrides(<Policy|Reference>{1,},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, skipCache(*), runChildActions(*), indeterminateOnActionFail(*)
*POverridesPolicySet*POverrides(<Policy|Reference>{1,},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, skipCache(*), runChildActions(*), indeterminateOnActionFail(*)
*DUnlessPPolicySet*DUnlessP(<Policy|Reference>{1,},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, skipCache(*), runChildActions(*), indeterminateOnActionFail(*), strictUnlessLogic(*)
*PUnlessDPolicySet*PUnlessD(<Policy|Reference>{1,},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, skipCache(*), runChildActions(*), indeterminateOnActionFail(*), strictUnlessLogic(*)
*firstApplPolicySet*firstAppl(<Policy|Reference>{1,},<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority, skipCache(*), runChildActions(*), indeterminateOnActionFail(*)
#permitPolicyDefault#permit(<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority
#denyPolicyDefault#deny(<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority
#NAPolicyDefault#NA(<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority
#indDPPolicyDefault#indDP(<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority
#indDPolicyDefault#indD(<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority
#indPPolicyDefault#indP(<PolicyAction|PolicyActionRelationship>{0,},*constraint?,#opts?)lenientConstraints(*), actionExecutionStrategy, ignoreErrors(*), priority
*savePolicyAction*save(<content|PolicyVariable|Reference>{2,2},#opts?)failOnMissingKey(*), failOnExistingKey(*), failOnNullSource(*)
*clearPolicyAction*clear(<content>{1,1},#opts?)failOnMissingKey(*)
*patchPolicyAction*patch((<content|PolicyVariable|Reference>{3,3},#opts?)failOnMissingKey(*), failOnExistingKey(*), failOnNullSource(*), castNullSourceToArray(*)
*mergePolicyAction*merge((<content|PolicyVariable|Reference>{3,3},#opts?)failOnMissingKey(*), failOnExistingKey(*), failOnNullSource(*), failOnNullMerge(*), type, format
*constraintPolicyConstraint*constraint(<PolicyCondition|Reference>{1,1}) 
*actPolicyActionRelationship*act(<PolicyAction|Reference>{1,1},*constraint?,#opts?)executionMode, priority
*polPolicyRelationship*pol(<Policy|Reference>{1,1},*constraint?,#opts?)runAction(*), priority
#refReference#ref(<content>{1,2}) 

(*) - Boolean condition
(**) - Mandatory option


Table of contents