aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/policy_engine/conditions.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/s3api/policy_engine/conditions.go')
-rw-r--r--weed/s3api/policy_engine/conditions.go768
1 files changed, 768 insertions, 0 deletions
diff --git a/weed/s3api/policy_engine/conditions.go b/weed/s3api/policy_engine/conditions.go
new file mode 100644
index 000000000..fc8005fd0
--- /dev/null
+++ b/weed/s3api/policy_engine/conditions.go
@@ -0,0 +1,768 @@
+package policy_engine
+
+import (
+ "fmt"
+ "net"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/seaweedfs/seaweedfs/weed/glog"
+)
+
+// LRUNode represents a node in the doubly-linked list for efficient LRU operations
+type LRUNode struct {
+ key string
+ value []string
+ prev *LRUNode
+ next *LRUNode
+}
+
+// NormalizedValueCache provides size-limited caching for normalized values with efficient LRU eviction
+type NormalizedValueCache struct {
+ mu sync.RWMutex
+ cache map[string]*LRUNode
+ maxSize int
+ head *LRUNode // Most recently used
+ tail *LRUNode // Least recently used
+}
+
+// NewNormalizedValueCache creates a new normalized value cache with configurable size
+func NewNormalizedValueCache(maxSize int) *NormalizedValueCache {
+ if maxSize <= 0 {
+ maxSize = 1000 // Default size
+ }
+
+ // Create dummy head and tail nodes for easier list manipulation
+ head := &LRUNode{}
+ tail := &LRUNode{}
+ head.next = tail
+ tail.prev = head
+
+ return &NormalizedValueCache{
+ cache: make(map[string]*LRUNode),
+ maxSize: maxSize,
+ head: head,
+ tail: tail,
+ }
+}
+
+// Get retrieves a cached value and updates access order in O(1) time
+func (c *NormalizedValueCache) Get(key string) ([]string, bool) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if node, exists := c.cache[key]; exists {
+ // Move to head (most recently used) - O(1) operation
+ c.moveToHead(node)
+ return node.value, true
+ }
+ return nil, false
+}
+
+// Set stores a value in the cache with size limit enforcement in O(1) time
+func (c *NormalizedValueCache) Set(key string, value []string) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if node, exists := c.cache[key]; exists {
+ // Update existing node and move to head
+ node.value = value
+ c.moveToHead(node)
+ return
+ }
+
+ // Create new node
+ newNode := &LRUNode{
+ key: key,
+ value: value,
+ }
+
+ // If at max size, evict least recently used
+ if len(c.cache) >= c.maxSize {
+ c.evictLeastRecentlyUsed()
+ }
+
+ // Add to cache and move to head
+ c.cache[key] = newNode
+ c.addToHead(newNode)
+}
+
+// moveToHead moves a node to the head of the list (most recently used) - O(1)
+func (c *NormalizedValueCache) moveToHead(node *LRUNode) {
+ c.removeNode(node)
+ c.addToHead(node)
+}
+
+// addToHead adds a node right after the head - O(1)
+func (c *NormalizedValueCache) addToHead(node *LRUNode) {
+ node.prev = c.head
+ node.next = c.head.next
+ c.head.next.prev = node
+ c.head.next = node
+}
+
+// removeNode removes a node from the list - O(1)
+func (c *NormalizedValueCache) removeNode(node *LRUNode) {
+ node.prev.next = node.next
+ node.next.prev = node.prev
+}
+
+// removeTail removes the last node before tail (least recently used) - O(1)
+func (c *NormalizedValueCache) removeTail() *LRUNode {
+ lastNode := c.tail.prev
+ c.removeNode(lastNode)
+ return lastNode
+}
+
+// evictLeastRecentlyUsed removes the least recently used item in O(1) time
+func (c *NormalizedValueCache) evictLeastRecentlyUsed() {
+ tail := c.removeTail()
+ delete(c.cache, tail.key)
+}
+
+// Clear clears all cached values
+func (c *NormalizedValueCache) Clear() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.cache = make(map[string]*LRUNode)
+ c.head.next = c.tail
+ c.tail.prev = c.head
+}
+
+// GetStats returns cache statistics
+func (c *NormalizedValueCache) GetStats() (size int, maxSize int) {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return len(c.cache), c.maxSize
+}
+
+// Global cache instance with size limit
+var normalizedValueCache = NewNormalizedValueCache(1000)
+
+// getCachedNormalizedValues returns cached normalized values or caches new ones
+func getCachedNormalizedValues(value interface{}) []string {
+ // Create a string key for caching - more efficient than fmt.Sprintf
+ typeStr := reflect.TypeOf(value).String()
+ cacheKey := typeStr + ":" + fmt.Sprint(value)
+
+ // Try to get from cache
+ if cached, exists := normalizedValueCache.Get(cacheKey); exists {
+ return cached
+ }
+
+ // Not in cache, normalize and store
+ // Use the error-handling version for better error reporting
+ normalized, err := normalizeToStringSliceWithError(value)
+ if err != nil {
+ glog.Warningf("Failed to normalize policy value %v: %v", value, err)
+ // Fallback to string conversion for backward compatibility
+ normalized = []string{fmt.Sprintf("%v", value)}
+ }
+
+ normalizedValueCache.Set(cacheKey, normalized)
+
+ return normalized
+}
+
+// ConditionEvaluator evaluates policy conditions
+type ConditionEvaluator interface {
+ Evaluate(conditionValue interface{}, contextValues []string) bool
+}
+
+// StringEqualsEvaluator evaluates StringEquals conditions
+type StringEqualsEvaluator struct{}
+
+func (e *StringEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ for _, contextValue := range contextValues {
+ if expected == contextValue {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// StringNotEqualsEvaluator evaluates StringNotEquals conditions
+type StringNotEqualsEvaluator struct{}
+
+func (e *StringNotEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ for _, contextValue := range contextValues {
+ if expected == contextValue {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// StringLikeEvaluator evaluates StringLike conditions (supports wildcards)
+type StringLikeEvaluator struct{}
+
+func (e *StringLikeEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ patterns := getCachedNormalizedValues(conditionValue)
+ for _, pattern := range patterns {
+ for _, contextValue := range contextValues {
+ if MatchesWildcard(pattern, contextValue) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// StringNotLikeEvaluator evaluates StringNotLike conditions
+type StringNotLikeEvaluator struct{}
+
+func (e *StringNotLikeEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ patterns := getCachedNormalizedValues(conditionValue)
+ for _, pattern := range patterns {
+ for _, contextValue := range contextValues {
+ if MatchesWildcard(pattern, contextValue) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// NumericEqualsEvaluator evaluates NumericEquals conditions
+type NumericEqualsEvaluator struct{}
+
+func (e *NumericEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedFloat, err := strconv.ParseFloat(expected, 64)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextFloat, err := strconv.ParseFloat(contextValue, 64)
+ if err != nil {
+ continue
+ }
+ if expectedFloat == contextFloat {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// NumericNotEqualsEvaluator evaluates NumericNotEquals conditions
+type NumericNotEqualsEvaluator struct{}
+
+func (e *NumericNotEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedFloat, err := strconv.ParseFloat(expected, 64)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextFloat, err := strconv.ParseFloat(contextValue, 64)
+ if err != nil {
+ continue
+ }
+ if expectedFloat == contextFloat {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// NumericLessThanEvaluator evaluates NumericLessThan conditions
+type NumericLessThanEvaluator struct{}
+
+func (e *NumericLessThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedFloat, err := strconv.ParseFloat(expected, 64)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextFloat, err := strconv.ParseFloat(contextValue, 64)
+ if err != nil {
+ continue
+ }
+ if contextFloat < expectedFloat {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// NumericLessThanEqualsEvaluator evaluates NumericLessThanEquals conditions
+type NumericLessThanEqualsEvaluator struct{}
+
+func (e *NumericLessThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedFloat, err := strconv.ParseFloat(expected, 64)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextFloat, err := strconv.ParseFloat(contextValue, 64)
+ if err != nil {
+ continue
+ }
+ if contextFloat <= expectedFloat {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// NumericGreaterThanEvaluator evaluates NumericGreaterThan conditions
+type NumericGreaterThanEvaluator struct{}
+
+func (e *NumericGreaterThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedFloat, err := strconv.ParseFloat(expected, 64)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextFloat, err := strconv.ParseFloat(contextValue, 64)
+ if err != nil {
+ continue
+ }
+ if contextFloat > expectedFloat {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// NumericGreaterThanEqualsEvaluator evaluates NumericGreaterThanEquals conditions
+type NumericGreaterThanEqualsEvaluator struct{}
+
+func (e *NumericGreaterThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedFloat, err := strconv.ParseFloat(expected, 64)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextFloat, err := strconv.ParseFloat(contextValue, 64)
+ if err != nil {
+ continue
+ }
+ if contextFloat >= expectedFloat {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// DateEqualsEvaluator evaluates DateEquals conditions
+type DateEqualsEvaluator struct{}
+
+func (e *DateEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedTime, err := time.Parse(time.RFC3339, expected)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextTime, err := time.Parse(time.RFC3339, contextValue)
+ if err != nil {
+ continue
+ }
+ if expectedTime.Equal(contextTime) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// DateNotEqualsEvaluator evaluates DateNotEquals conditions
+type DateNotEqualsEvaluator struct{}
+
+func (e *DateNotEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedTime, err := time.Parse(time.RFC3339, expected)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextTime, err := time.Parse(time.RFC3339, contextValue)
+ if err != nil {
+ continue
+ }
+ if expectedTime.Equal(contextTime) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// DateLessThanEvaluator evaluates DateLessThan conditions
+type DateLessThanEvaluator struct{}
+
+func (e *DateLessThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedTime, err := time.Parse(time.RFC3339, expected)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextTime, err := time.Parse(time.RFC3339, contextValue)
+ if err != nil {
+ continue
+ }
+ if contextTime.Before(expectedTime) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// DateLessThanEqualsEvaluator evaluates DateLessThanEquals conditions
+type DateLessThanEqualsEvaluator struct{}
+
+func (e *DateLessThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedTime, err := time.Parse(time.RFC3339, expected)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextTime, err := time.Parse(time.RFC3339, contextValue)
+ if err != nil {
+ continue
+ }
+ if contextTime.Before(expectedTime) || contextTime.Equal(expectedTime) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// DateGreaterThanEvaluator evaluates DateGreaterThan conditions
+type DateGreaterThanEvaluator struct{}
+
+func (e *DateGreaterThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedTime, err := time.Parse(time.RFC3339, expected)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextTime, err := time.Parse(time.RFC3339, contextValue)
+ if err != nil {
+ continue
+ }
+ if contextTime.After(expectedTime) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// DateGreaterThanEqualsEvaluator evaluates DateGreaterThanEquals conditions
+type DateGreaterThanEqualsEvaluator struct{}
+
+func (e *DateGreaterThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedTime, err := time.Parse(time.RFC3339, expected)
+ if err != nil {
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextTime, err := time.Parse(time.RFC3339, contextValue)
+ if err != nil {
+ continue
+ }
+ if contextTime.After(expectedTime) || contextTime.Equal(expectedTime) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// BoolEvaluator evaluates Bool conditions
+type BoolEvaluator struct{}
+
+func (e *BoolEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ for _, contextValue := range contextValues {
+ if strings.ToLower(expected) == strings.ToLower(contextValue) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// IpAddressEvaluator evaluates IpAddress conditions
+type IpAddressEvaluator struct{}
+
+func (e *IpAddressEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ _, expectedNet, err := net.ParseCIDR(expected)
+ if err != nil {
+ // Try parsing as single IP
+ expectedIP := net.ParseIP(expected)
+ if expectedIP == nil {
+ glog.V(3).Infof("Failed to parse expected IP address: %s", expected)
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextIP := net.ParseIP(contextValue)
+ if contextIP == nil {
+ glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
+ continue
+ }
+ if contextIP.Equal(expectedIP) {
+ return true
+ }
+ }
+ } else {
+ // CIDR network
+ for _, contextValue := range contextValues {
+ contextIP := net.ParseIP(contextValue)
+ if contextIP == nil {
+ glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
+ continue
+ }
+ if expectedNet.Contains(contextIP) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+// NotIpAddressEvaluator evaluates NotIpAddress conditions
+type NotIpAddressEvaluator struct{}
+
+func (e *NotIpAddressEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ _, expectedNet, err := net.ParseCIDR(expected)
+ if err != nil {
+ // Try parsing as single IP
+ expectedIP := net.ParseIP(expected)
+ if expectedIP == nil {
+ glog.V(3).Infof("Failed to parse expected IP address: %s", expected)
+ continue
+ }
+ for _, contextValue := range contextValues {
+ contextIP := net.ParseIP(contextValue)
+ if contextIP == nil {
+ glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
+ continue
+ }
+ if contextIP.Equal(expectedIP) {
+ return false
+ }
+ }
+ } else {
+ // CIDR network
+ for _, contextValue := range contextValues {
+ contextIP := net.ParseIP(contextValue)
+ if contextIP == nil {
+ glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
+ continue
+ }
+ if expectedNet.Contains(contextIP) {
+ return false
+ }
+ }
+ }
+ }
+ return true
+}
+
+// ArnEqualsEvaluator evaluates ArnEquals conditions
+type ArnEqualsEvaluator struct{}
+
+func (e *ArnEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ for _, contextValue := range contextValues {
+ if expected == contextValue {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// ArnLikeEvaluator evaluates ArnLike conditions
+type ArnLikeEvaluator struct{}
+
+func (e *ArnLikeEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ patterns := getCachedNormalizedValues(conditionValue)
+ for _, pattern := range patterns {
+ for _, contextValue := range contextValues {
+ if MatchesWildcard(pattern, contextValue) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// NullEvaluator evaluates Null conditions
+type NullEvaluator struct{}
+
+func (e *NullEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
+ expectedValues := getCachedNormalizedValues(conditionValue)
+ for _, expected := range expectedValues {
+ expectedBool := strings.ToLower(expected) == "true"
+ contextExists := len(contextValues) > 0
+ if expectedBool && !contextExists {
+ return true // Key should be null and it is
+ }
+ if !expectedBool && contextExists {
+ return true // Key should not be null and it isn't
+ }
+ }
+ return false
+}
+
+// GetConditionEvaluator returns the appropriate evaluator for a condition operator
+func GetConditionEvaluator(operator string) (ConditionEvaluator, error) {
+ switch operator {
+ case "StringEquals":
+ return &StringEqualsEvaluator{}, nil
+ case "StringNotEquals":
+ return &StringNotEqualsEvaluator{}, nil
+ case "StringLike":
+ return &StringLikeEvaluator{}, nil
+ case "StringNotLike":
+ return &StringNotLikeEvaluator{}, nil
+ case "NumericEquals":
+ return &NumericEqualsEvaluator{}, nil
+ case "NumericNotEquals":
+ return &NumericNotEqualsEvaluator{}, nil
+ case "NumericLessThan":
+ return &NumericLessThanEvaluator{}, nil
+ case "NumericLessThanEquals":
+ return &NumericLessThanEqualsEvaluator{}, nil
+ case "NumericGreaterThan":
+ return &NumericGreaterThanEvaluator{}, nil
+ case "NumericGreaterThanEquals":
+ return &NumericGreaterThanEqualsEvaluator{}, nil
+ case "DateEquals":
+ return &DateEqualsEvaluator{}, nil
+ case "DateNotEquals":
+ return &DateNotEqualsEvaluator{}, nil
+ case "DateLessThan":
+ return &DateLessThanEvaluator{}, nil
+ case "DateLessThanEquals":
+ return &DateLessThanEqualsEvaluator{}, nil
+ case "DateGreaterThan":
+ return &DateGreaterThanEvaluator{}, nil
+ case "DateGreaterThanEquals":
+ return &DateGreaterThanEqualsEvaluator{}, nil
+ case "Bool":
+ return &BoolEvaluator{}, nil
+ case "IpAddress":
+ return &IpAddressEvaluator{}, nil
+ case "NotIpAddress":
+ return &NotIpAddressEvaluator{}, nil
+ case "ArnEquals":
+ return &ArnEqualsEvaluator{}, nil
+ case "ArnLike":
+ return &ArnLikeEvaluator{}, nil
+ case "Null":
+ return &NullEvaluator{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported condition operator: %s", operator)
+ }
+}
+
+// EvaluateConditions evaluates all conditions in a policy statement
+func EvaluateConditions(conditions PolicyConditions, contextValues map[string][]string) bool {
+ if len(conditions) == 0 {
+ return true // No conditions means always true
+ }
+
+ for operator, conditionMap := range conditions {
+ conditionEvaluator, err := GetConditionEvaluator(operator)
+ if err != nil {
+ glog.Warningf("Unsupported condition operator: %s", operator)
+ continue
+ }
+
+ for key, value := range conditionMap {
+ contextVals, exists := contextValues[key]
+ if !exists {
+ contextVals = []string{}
+ }
+
+ if !conditionEvaluator.Evaluate(value.Strings(), contextVals) {
+ return false // If any condition fails, the whole condition block fails
+ }
+ }
+ }
+
+ return true
+}
+
+// EvaluateConditionsLegacy evaluates conditions using the old interface{} format for backward compatibility
+func EvaluateConditionsLegacy(conditions map[string]interface{}, contextValues map[string][]string) bool {
+ if len(conditions) == 0 {
+ return true // No conditions means always true
+ }
+
+ for operator, conditionMap := range conditions {
+ conditionEvaluator, err := GetConditionEvaluator(operator)
+ if err != nil {
+ glog.Warningf("Unsupported condition operator: %s", operator)
+ continue
+ }
+
+ conditionMapTyped, ok := conditionMap.(map[string]interface{})
+ if !ok {
+ glog.Warningf("Invalid condition format for operator: %s", operator)
+ continue
+ }
+
+ for key, value := range conditionMapTyped {
+ contextVals, exists := contextValues[key]
+ if !exists {
+ contextVals = []string{}
+ }
+
+ if !conditionEvaluator.Evaluate(value, contextVals) {
+ return false // If any condition fails, the whole condition block fails
+ }
+ }
+ }
+
+ return true
+}