test_cases:
- name: simple_string_equals
condition: "@Request[Microsoft.Storage:storageAccount] StringEquals 'test-account'"
expected:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Request
namespace: Microsoft.Storage
attribute: storageAccount
right:
type: StringLiteral
value: test-account
- name: numeric_greater_than
condition: "@Resource[size] NumericGreaterThan 1024"
expected:
type: Binary
operator: NumericGreaterThan
left:
type: AttributeReference
source: Resource
attribute: size
right:
type: NumberLiteral
raw: "1024"
- name: boolean_equals_true
condition: "@Principal[isActive] BoolEquals true"
expected:
type: Binary
operator: BoolEquals
left:
type: AttributeReference
source: Principal
attribute: isActive
right:
type: BooleanLiteral
value: true
- name: boolean_equals_false
condition: "@Environment[isPrivateLink] BoolEquals false"
expected:
type: Binary
operator: BoolEquals
left:
type: AttributeReference
source: Environment
attribute: isPrivateLink
right:
type: BooleanLiteral
value: false
- name: logical_and_expression
condition: "@Request[action] StringEquals 'read' AND @Resource[type] StringEquals 'blob'"
expected:
type: Logical
operator: And
left:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Request
attribute: action
right:
type: StringLiteral
value: read
right:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Resource
attribute: type
right:
type: StringLiteral
value: blob
- name: logical_or_expression
condition: "@Principal[department] StringEquals 'IT' OR @Principal[department] StringEquals 'Security'"
expected:
type: Logical
operator: Or
left:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Principal
attribute: department
right:
type: StringLiteral
value: IT
right:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Principal
attribute: department
right:
type: StringLiteral
value: Security
- name: unary_not_expression
condition: "NOT @Resource[encrypted] BoolEquals false"
expected:
type: Unary
operator: Not
operand:
type: Binary
operator: BoolEquals
left:
type: AttributeReference
source: Resource
attribute: encrypted
right:
type: BooleanLiteral
value: false
- name: exists_expression
condition: "Exists @Principal[Microsoft.Directory:department]"
expected:
type: Unary
operator: Exists
operand:
type: AttributeReference
source: Principal
namespace: Microsoft.Directory
attribute: department
- name: not_exists_expression
condition: "NotExists @Request[customAttribute]"
expected:
type: Unary
operator: NotExists
operand:
type: AttributeReference
source: Request
attribute: customAttribute
- name: parenthesized_expression
condition: "(@Principal[role] StringEquals 'admin' OR @Principal[role] StringEquals 'owner') AND @Resource[confidential] BoolEquals true"
expected:
type: Logical
operator: And
left:
type: Logical
operator: Or
left:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Principal
attribute: role
right:
type: StringLiteral
value: admin
right:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Principal
attribute: role
right:
type: StringLiteral
value: owner
right:
type: Binary
operator: BoolEquals
left:
type: AttributeReference
source: Resource
attribute: confidential
right:
type: BooleanLiteral
value: true
- name: function_call_expression
condition: "ToLower(@Principal[email]) StringContains '@company.com'"
expected:
type: Binary
operator: StringContains
left:
type: FunctionCall
function: ToLower
arguments:
- type: AttributeReference
source: Principal
attribute: email
right:
type: StringLiteral
value: "@company.com"
- name: set_literal_expression
condition: "@Principal[role] StringEquals {'admin', 'owner', 'contributor'}"
expected:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Principal
attribute: role
right:
type: SetLiteral
elements:
- type: StringLiteral
value: admin
- type: StringLiteral
value: owner
- type: StringLiteral
value: contributor
- name: list_literal_expression
condition: "@Request[allowedActions] ListContains ['read', 'write']"
expected:
type: Binary
operator: ListContains
left:
type: AttributeReference
source: Request
attribute: allowedActions
right:
type: ListLiteral
elements:
- type: StringLiteral
value: read
- type: StringLiteral
value: write
- name: datetime_comparison
condition: "@Environment[utcNow] DateTimeGreaterThan '2023-01-01T00:00:00Z'"
expected:
type: Binary
operator: DateTimeGreaterThan
left:
type: AttributeReference
source: Environment
attribute: utcNow
right:
type: StringLiteral
value: "2023-01-01T00:00:00Z"
- name: ip_range_check
condition: "@Request[clientIP] IpInRange '192.168.1.0/24'"
expected:
type: Binary
operator: IpInRange
left:
type: AttributeReference
source: Request
attribute: clientIP
right:
type: StringLiteral
value: "192.168.1.0/24"
- name: null_literal
condition: "@Resource[metadata] StringEquals null"
expected:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Resource
attribute: metadata
right:
type: NullLiteral
- name: string_case_insensitive
condition: "@Principal[displayName] StringEqualsIgnoreCase 'John Doe'"
expected:
type: Binary
operator: StringEqualsIgnoreCase
left:
type: AttributeReference
source: Principal
attribute: displayName
right:
type: StringLiteral
value: "John Doe"
- name: time_range_check
condition: "@Environment[timeOfDay] TimeOfDayInRange '09:00:00'"
expected:
type: Binary
operator: TimeOfDayInRange
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: StringLiteral
value: "09:00:00"
- name: guid_comparison
condition: "@Principal[objectId] GuidEquals '12345678-1234-1234-1234-123456789012'"
expected:
type: Binary
operator: GuidEquals
left:
type: AttributeReference
source: Principal
attribute: objectId
right:
type: StringLiteral
value: "12345678-1234-1234-1234-123456789012"
- name: complex_logical_precedence
condition: "NOT (@Request[action] StringEquals 'write' AND (@Resource[type] StringEquals 'blob' OR @Resource[type] StringEquals 'file')) OR @Environment[Microsoft.Time:weekday] StringEquals 'Saturday'"
expected:
type: Logical
operator: Or
left:
type: Unary
operator: Not
operand:
type: Logical
operator: And
left:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Request
attribute: action
right:
type: StringLiteral
value: write
right:
type: Logical
operator: Or
left:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Resource
attribute: type
right:
type: StringLiteral
value: blob
right:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Resource
attribute: type
right:
type: StringLiteral
value: file
right:
type: Binary
operator: StringEquals
left:
type: AttributeReference
source: Environment
namespace: Microsoft.Time
attribute: weekday
right:
type: StringLiteral
value: Saturday
- name: numeric_in_range_set
condition: "@Resource[size] NumericInRange {0, 10}"
expected:
type: Binary
operator: NumericInRange
left:
type: AttributeReference
source: Resource
attribute: size
right:
type: SetLiteral
elements:
- type: NumberLiteral
raw: "0"
- type: NumberLiteral
raw: "10"
- name: time_of_day_less_than_equals_function
condition: "@Environment[timeOfDay] TimeOfDayLessThanEquals ToTime('18:30:00')"
expected:
type: Binary
operator: TimeOfDayLessThanEquals
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: FunctionCall
function: ToTime
arguments:
- type: StringLiteral
value: "18:30:00"
- name: list_not_contains
condition: "@Request[allowedIPRanges] ListNotContains ['10.0.0.1', '10.0.0.2']"
expected:
type: Binary
operator: ListNotContains
left:
type: AttributeReference
source: Request
attribute: allowedIPRanges
right:
type: ListLiteral
elements:
- type: StringLiteral
value: "10.0.0.1"
- type: StringLiteral
value: "10.0.0.2"
- name: ip_not_match
condition: "@Request[clientIP] IpNotMatch '10.0.0.0/24'"
expected:
type: Binary
operator: IpNotMatch
left:
type: AttributeReference
source: Request
attribute: clientIP
right:
type: StringLiteral
value: "10.0.0.0/24"
- name: guid_not_equals
condition: "@Principal[objectId] GuidNotEquals '87654321-4321-4321-4321-210987654321'"
expected:
type: Binary
operator: GuidNotEquals
left:
type: AttributeReference
source: Principal
attribute: objectId
right:
type: StringLiteral
value: "87654321-4321-4321-4321-210987654321"
- name: string_complex_operators
condition: "(@Resource[category] StringStartsWith 'finance' AND (@Resource[label] StringNotContains 'deprecated' AND @Resource[name] StringEndsWith '-prod')) OR @Resource[description] StringMatches '^FIN-[0-9]{4}$'"
expected:
type: Logical
operator: Or
left:
type: Logical
operator: And
left:
type: Binary
operator: StringStartsWith
left:
type: AttributeReference
source: Resource
attribute: category
right:
type: StringLiteral
value: finance
right:
type: Logical
operator: And
left:
type: Binary
operator: StringNotContains
left:
type: AttributeReference
source: Resource
attribute: label
right:
type: StringLiteral
value: deprecated
right:
type: Binary
operator: StringEndsWith
left:
type: AttributeReference
source: Resource
attribute: name
right:
type: StringLiteral
value: -prod
right:
type: Binary
operator: StringMatches
left:
type: AttributeReference
source: Resource
attribute: description
right:
type: StringLiteral
value: "^FIN-[0-9]{4}$"
- name: identifier_action_matches
condition: "operationName ActionMatches 'Microsoft.Storage/storageAccounts/write'"
expected:
type: Binary
operator: ActionMatches
left:
type: Identifier
name: operationName
right:
type: StringLiteral
value: "Microsoft.Storage/storageAccounts/write"
- name: function_call_chain
condition: "ToUpper(Trim(@Principal[displayName])) StringNotEqualsIgnoreCase 'SERVICE PRINCIPAL'"
expected:
type: Binary
operator: StringNotEqualsIgnoreCase
left:
type: FunctionCall
function: ToUpper
arguments:
- type: FunctionCall
function: Trim
arguments:
- type: AttributeReference
source: Principal
attribute: displayName
right:
type: StringLiteral
value: "SERVICE PRINCIPAL"
- name: time_of_day_in_range_set
condition: "@Environment[timeOfDay] TimeOfDayInRange {'08:00:00', '17:00:00'}"
expected:
type: Binary
operator: TimeOfDayInRange
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: SetLiteral
elements:
- type: StringLiteral
value: "08:00:00"
- type: StringLiteral
value: "17:00:00"
- name: datetime_less_than_equals_function
condition: "@Environment[utcNow] DateTimeLessThanEquals AddDays('2023-03-15T00:00:00Z', 5)"
expected:
type: Binary
operator: DateTimeLessThanEquals
left:
type: AttributeReference
source: Environment
attribute: utcNow
right:
type: FunctionCall
function: AddDays
arguments:
- type: StringLiteral
value: "2023-03-15T00:00:00Z"
- type: NumberLiteral
raw: "5"
- name: boolean_not_equals
condition: "@Environment[isHoliday] BoolNotEquals true"
expected:
type: Binary
operator: BoolNotEquals
left:
type: AttributeReference
source: Environment
attribute: isHoliday
right:
type: BooleanLiteral
value: true
- name: exists_function_operand
condition: "Exists ToLower(@Principal[Microsoft.Directory:department])"
expected:
type: Unary
operator: Exists
operand:
type: FunctionCall
function: ToLower
arguments:
- type: AttributeReference
source: Principal
namespace: Microsoft.Directory
attribute: department
- name: not_exists_namespace_context
condition: "NotExists @Context[Custom.Extension:claimType]"
expected:
type: Unary
operator: NotExists
operand:
type: AttributeReference
source: Context
namespace: Custom.Extension
attribute: claimType
- name: string_not_equals
condition: "@Resource[classification] StringNotEquals 'internal'"
expected:
type: Binary
operator: StringNotEquals
left:
type: AttributeReference
source: Resource
attribute: classification
right:
type: StringLiteral
value: internal
- name: string_like_pattern
condition: "@Resource[name] StringLike 'prod-*'"
expected:
type: Binary
operator: StringLike
left:
type: AttributeReference
source: Resource
attribute: name
right:
type: StringLiteral
value: prod-*
- name: string_not_like_pattern
condition: "@Resource[name] StringNotLike 'dev-*'"
expected:
type: Binary
operator: StringNotLike
left:
type: AttributeReference
source: Resource
attribute: name
right:
type: StringLiteral
value: dev-*
- name: string_not_starts_with
condition: "@Resource[path] StringNotStartsWith '/secure/'"
expected:
type: Binary
operator: StringNotStartsWith
left:
type: AttributeReference
source: Resource
attribute: path
right:
type: StringLiteral
value: "/secure/"
- name: string_not_ends_with
condition: "@Resource[fileName] StringNotEndsWith '.tmp'"
expected:
type: Binary
operator: StringNotEndsWith
left:
type: AttributeReference
source: Resource
attribute: fileName
right:
type: StringLiteral
value: .tmp
- name: string_not_matches
condition: "@Resource[identifier] StringNotMatches 'TEMP-[0-9]+'"
expected:
type: Binary
operator: StringNotMatches
left:
type: AttributeReference
source: Resource
attribute: identifier
right:
type: StringLiteral
value: "TEMP-[0-9]+"
- name: numeric_equals
condition: "@Resource[version] NumericEquals 2"
expected:
type: Binary
operator: NumericEquals
left:
type: AttributeReference
source: Resource
attribute: version
right:
type: NumberLiteral
raw: "2"
- name: numeric_not_equals
condition: "@Resource[count] NumericNotEquals 5"
expected:
type: Binary
operator: NumericNotEquals
left:
type: AttributeReference
source: Resource
attribute: count
right:
type: NumberLiteral
raw: "5"
- name: numeric_less_than
condition: "@Request[latency] NumericLessThan 100"
expected:
type: Binary
operator: NumericLessThan
left:
type: AttributeReference
source: Request
attribute: latency
right:
type: NumberLiteral
raw: "100"
- name: numeric_less_than_equals
condition: "@Request[latency] NumericLessThanEquals 200"
expected:
type: Binary
operator: NumericLessThanEquals
left:
type: AttributeReference
source: Request
attribute: latency
right:
type: NumberLiteral
raw: "200"
- name: numeric_greater_than_equals
condition: "@Resource[replicaCount] NumericGreaterThanEquals 3"
expected:
type: Binary
operator: NumericGreaterThanEquals
left:
type: AttributeReference
source: Resource
attribute: replicaCount
right:
type: NumberLiteral
raw: "3"
- name: datetime_equals
condition: "@Environment[utcNow] DateTimeEquals '2023-05-01T12:00:00Z'"
expected:
type: Binary
operator: DateTimeEquals
left:
type: AttributeReference
source: Environment
attribute: utcNow
right:
type: StringLiteral
value: "2023-05-01T12:00:00Z"
- name: datetime_not_equals
condition: "@Environment[utcNow] DateTimeNotEquals '2023-06-01T12:00:00Z'"
expected:
type: Binary
operator: DateTimeNotEquals
left:
type: AttributeReference
source: Environment
attribute: utcNow
right:
type: StringLiteral
value: "2023-06-01T12:00:00Z"
- name: datetime_greater_than_equals
condition: "@Environment[utcNow] DateTimeGreaterThanEquals '2023-04-01T00:00:00Z'"
expected:
type: Binary
operator: DateTimeGreaterThanEquals
left:
type: AttributeReference
source: Environment
attribute: utcNow
right:
type: StringLiteral
value: "2023-04-01T00:00:00Z"
- name: datetime_less_than
condition: "@Environment[utcNow] DateTimeLessThan '2023-12-31T23:59:59Z'"
expected:
type: Binary
operator: DateTimeLessThan
left:
type: AttributeReference
source: Environment
attribute: utcNow
right:
type: StringLiteral
value: "2023-12-31T23:59:59Z"
- name: time_of_day_equals
condition: "@Environment[timeOfDay] TimeOfDayEquals '10:15:00'"
expected:
type: Binary
operator: TimeOfDayEquals
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: StringLiteral
value: "10:15:00"
- name: time_of_day_not_equals
condition: "@Environment[timeOfDay] TimeOfDayNotEquals '20:00:00'"
expected:
type: Binary
operator: TimeOfDayNotEquals
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: StringLiteral
value: "20:00:00"
- name: time_of_day_greater_than
condition: "@Environment[timeOfDay] TimeOfDayGreaterThan '17:00:00'"
expected:
type: Binary
operator: TimeOfDayGreaterThan
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: StringLiteral
value: "17:00:00"
- name: time_of_day_greater_than_equals
condition: "@Environment[timeOfDay] TimeOfDayGreaterThanEquals '09:00:00'"
expected:
type: Binary
operator: TimeOfDayGreaterThanEquals
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: StringLiteral
value: "09:00:00"
- name: time_of_day_less_than
condition: "@Environment[timeOfDay] TimeOfDayLessThan '12:00:00'"
expected:
type: Binary
operator: TimeOfDayLessThan
left:
type: AttributeReference
source: Environment
attribute: timeOfDay
right:
type: StringLiteral
value: "12:00:00"
- name: ip_match
condition: "@Request[clientIP] IpMatch '10.1.0.0/16'"
expected:
type: Binary
operator: IpMatch
left:
type: AttributeReference
source: Request
attribute: clientIP
right:
type: StringLiteral
value: "10.1.0.0/16"
- name: sub_operation_matches
condition: "subOperationName SubOperationMatches 'Microsoft.Storage/storageAccounts/write/sas'"
expected:
type: Binary
operator: SubOperationMatches
left:
type: Identifier
name: subOperationName
right:
type: StringLiteral
value: "Microsoft.Storage/storageAccounts/write/sas"
- name: for_any_of_any_values
condition: "@Resource[tags] ForAnyOfAnyValues @Request[allowedTags]"
expected:
type: Binary
operator: ForAnyOfAnyValues
left:
type: AttributeReference
source: Resource
attribute: tags
right:
type: AttributeReference
source: Request
attribute: allowedTags
- name: for_all_of_any_values
condition: "@Resource[tags] ForAllOfAnyValues @Request[requiredTags]"
expected:
type: Binary
operator: ForAllOfAnyValues
left:
type: AttributeReference
source: Resource
attribute: tags
right:
type: AttributeReference
source: Request
attribute: requiredTags
- name: for_any_of_all_values
condition: "@Resource[tags] ForAnyOfAllValues @Request[restrictedTags]"
expected:
type: Binary
operator: ForAnyOfAllValues
left:
type: AttributeReference
source: Resource
attribute: tags
right:
type: AttributeReference
source: Request
attribute: restrictedTags
- name: for_all_of_all_values
condition: "@Resource[tags] ForAllOfAllValues @Request[mandatoryTags]"
expected:
type: Binary
operator: ForAllOfAllValues
left:
type: AttributeReference
source: Resource
attribute: tags
right:
type: AttributeReference
source: Request
attribute: mandatoryTags
- name: deeply_nested_quantifiers
condition: "((@Resource[tags] ForAllOfAnyValues @Request[requiredTags]) AND (NormalizeSet(@Resource[regions]) ForAnyOfAllValues NormalizeSet(@Environment[allowedRegions]))) OR (NOT Exists ToLower(@Principal[manager]) AND (@Resource[sensitivity] StringNotEqualsIgnoreCase 'high'))"
expected:
type: Logical
operator: Or
left:
type: Logical
operator: And
left:
type: Binary
operator: ForAllOfAnyValues
left:
type: AttributeReference
source: Resource
attribute: tags
right:
type: AttributeReference
source: Request
attribute: requiredTags
right:
type: Binary
operator: ForAnyOfAllValues
left:
type: FunctionCall
function: NormalizeSet
arguments:
- type: AttributeReference
source: Resource
attribute: regions
right:
type: FunctionCall
function: NormalizeSet
arguments:
- type: AttributeReference
source: Environment
attribute: allowedRegions
right:
type: Logical
operator: And
left:
type: Unary
operator: Not
operand:
type: Unary
operator: Exists
operand:
type: FunctionCall
function: ToLower
arguments:
- type: AttributeReference
source: Principal
attribute: manager
right:
type: Binary
operator: StringNotEqualsIgnoreCase
left:
type: AttributeReference
source: Resource
attribute: sensitivity
right:
type: StringLiteral
value: high
- name: multi_level_mixed_chains
condition: "(ToUpper(@Principal[role]) StringEquals 'OWNER' AND (@Resource[tags] ForAllOfAllValues @Request[mandatoryTags]) AND (NormalizeList(@Resource[scopes]) ForAnyOfAnyValues NormalizeList(@Principal[assignableScopes]))) OR (Exists @Resource[metadata] AND NOT (@Request[operations] ListContains ['read', 'list']))"
expected:
type: Logical
operator: Or
left:
type: Logical
operator: And
left:
type: Logical
operator: And
left:
type: Binary
operator: StringEquals
left:
type: FunctionCall
function: ToUpper
arguments:
- type: AttributeReference
source: Principal
attribute: role
right:
type: StringLiteral
value: OWNER
right:
type: Binary
operator: ForAllOfAllValues
left:
type: AttributeReference
source: Resource
attribute: tags
right:
type: AttributeReference
source: Request
attribute: mandatoryTags
right:
type: Binary
operator: ForAnyOfAnyValues
left:
type: FunctionCall
function: NormalizeList
arguments:
- type: AttributeReference
source: Resource
attribute: scopes
right:
type: FunctionCall
function: NormalizeList
arguments:
- type: AttributeReference
source: Principal
attribute: assignableScopes
right:
type: Logical
operator: And
left:
type: Unary
operator: Exists
operand:
type: AttributeReference
source: Resource
attribute: metadata
right:
type: Unary
operator: Not
operand:
type: Binary
operator: ListContains
left:
type: AttributeReference
source: Request
attribute: operations
right:
type: ListLiteral
elements:
- type: StringLiteral
value: read
- type: StringLiteral
value: list