Skip to content

Support positional argument matching in rules to enable rule reuse across different attribute names #2786

@pcloud2

Description

@pcloud2

Is your feature request related to a problem? Please describe.
When I need to apply the same logical condition (e.g., boolean negation) to multiple differently-named attributes across entities, because the current rule system requires the argument name in the call to exactly match the parameter name in the rule definition. This means a rule like negate cannot be reused across attributes with different names — every distinct attribute name requires its own dedicated rule, leading to duplicated logic throughout the schema, and makes schema unnecessary long.

For example, the following does not work today:

entity resource {
    attribute is_private boolean
    attribute is_archived boolean

    permission view   = negate(is_private)
    permission active = negate(is_archived)
}

rule negate(is_private boolean) {
    !is_private
}

Even though the logic is identical, the active permission fails because is_archived does not match the parameter name is_private.

Describe the solution you'd like
Rules should support positional argument matching, so that arguments are bound by their position in the call rather than by name. This would allow a single generic rule to be reused with any attribute of the matching type, regardless of what that attribute is named.

entity resource {
    attribute is_private boolean
    attribute is_archived boolean

    permission view   = negate(is_private)   // passes is_private as first arg
    permission active = negate(is_archived)  // passes is_archived as first arg
}

rule negate(value boolean) {   // "value" is a local parameter name, not tied to attribute name
    !value
}

The rule parameter name would act as a local variable inside the rule expression only, with no requirement to match the caller's attribute name.

Additional context
The root cause of this limitation appears to be in the internal representation of rule arguments as a map[string]base.AttributeType (keyed by name, unordered) in pkg/schema/builder.go. Supporting positional matching would likely require changing this to an ordered structure such as a slice of {name, type} pairs, so that the compiler can bind arguments by index at the call site while still using the declared parameter name as a local variable inside the CEL expression.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions