From ba3a1852f1fe4d2d88a24c248f249573b2d47b76 Mon Sep 17 00:00:00 2001 From: Sean Huh Date: Fri, 31 Jul 2026 14:01:18 -0700 Subject: [PATCH] Add aggregate semantics to Policy Compiler Aggregate walks through all matching rules (including nested ones) and appends them into a list: ```yaml rule: aggregate: - condition: "true" emit: "'FOO'" - condition: "true" emit: "'BAR'" # Output: ['FOO', 'BAR'] ``` Few noteworthy design decisions below. All examples assume all conditions matched: 1. For usability reasons, subrules under an aggregate ancestor will always have their **lists flattened**: ```YAML name: aggregate_flat_flattening_example rule: aggregate: - rule: match: - condition: "resource.is_admin == true" output: "['GDPR_STANDARD', 'EU_B2C_NOTICE']" - condition: "true" emit: "'FALLBACK'" # Output: ['GDPR_STANDARD', 'EU_B2C_NOTICE', 'FALLBACK'] ``` 2. Base case of an aggregate rule is an empty list. Nested conditional rules within an aggregate rule which outputs `optional.none()` are pruned (except in cases where policy output explicitly emits an `optional.none()`): ```YAML name: optional_pruning_example rule: aggregate: - rule: match: - condition: "1 == 2" output: "'EU_NOTICE'" - condition: "true" emit: "'ALWAYS'" # Output: ['ALWAYS'] ``` ```YAML name: explicit_optional_none_example rule: aggregate: - rule: match: - condition: "resource.is_b2c == true" output: "optional.none()" # Explicitly authored by user - condition: "true" emit: "optional.of('ALWAYS')" # Output: [optional.none(), optional.of('ALWAYS')] ``` Note: nesting `aggregate` clauses is currently not allowed, and will result in a compilation error. PiperOrigin-RevId: 957321565 --- conformance/testdata/aggregate/config.yaml | 21 ++++++++ conformance/testdata/aggregate/policy.yaml | 26 ++++++++++ conformance/testdata/aggregate/tests.yaml | 42 ++++++++++++++++ .../policy.yaml | 19 ++++++++ .../aggregate_explicit_list_output/tests.yaml | 22 +++++++++ .../policy.yaml | 19 ++++++++ .../tests.yaml | 22 +++++++++ .../policy.yaml | 21 ++++++++ .../tests.yaml | 22 +++++++++ .../aggregate_shadowed_variables/config.yaml | 21 ++++++++ .../aggregate_shadowed_variables/policy.yaml | 30 ++++++++++++ .../aggregate_shadowed_variables/tests.yaml | 24 ++++++++++ .../aggregate_errors/config.yaml | 19 ++++++++ .../aggregate_errors/policy.yaml | 24 ++++++++++ .../aggregate_false_condition/policy.yaml | 19 ++++++++ .../aggregate_false_condition/tests.yaml | 23 +++++++++ .../policy.yaml | 23 +++++++++ .../tests.yaml | 23 +++++++++ .../aggregate_list_errors/config.yaml | 19 ++++++++ .../aggregate_list_errors/policy.yaml | 24 ++++++++++ .../config.yaml | 20 ++++++++ .../policy.yaml | 25 ++++++++++ .../tests.yaml | 23 +++++++++ .../config.yaml | 21 ++++++++ .../policy.yaml | 23 +++++++++ .../tests.yaml | 23 +++++++++ .../config.yaml | 21 ++++++++ .../policy.yaml | 24 ++++++++++ .../tests.yaml | 24 ++++++++++ .../policy.yaml | 24 ++++++++++ .../tests.yaml | 23 +++++++++ .../first_match_nested_aggregate/config.yaml | 24 ++++++++++ .../first_match_nested_aggregate/policy.yaml | 26 ++++++++++ .../first_match_nested_aggregate/tests.yaml | 48 +++++++++++++++++++ 34 files changed, 812 insertions(+) create mode 100644 conformance/testdata/aggregate/config.yaml create mode 100644 conformance/testdata/aggregate/policy.yaml create mode 100644 conformance/testdata/aggregate/tests.yaml create mode 100644 conformance/testdata/aggregate_explicit_list_output/policy.yaml create mode 100644 conformance/testdata/aggregate_explicit_list_output/tests.yaml create mode 100644 conformance/testdata/aggregate_explicit_optional_none/policy.yaml create mode 100644 conformance/testdata/aggregate_explicit_optional_none/tests.yaml create mode 100644 conformance/testdata/aggregate_nested_explicit_list_double_wrapping/policy.yaml create mode 100644 conformance/testdata/aggregate_nested_explicit_list_double_wrapping/tests.yaml create mode 100644 conformance/testdata/aggregate_shadowed_variables/config.yaml create mode 100644 conformance/testdata/aggregate_shadowed_variables/policy.yaml create mode 100644 conformance/testdata/aggregate_shadowed_variables/tests.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_errors/config.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_errors/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_false_condition/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_false_condition/tests.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/tests.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_list_errors/config.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_list_errors/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/config.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/tests.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/config.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/tests.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/config.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/policy.yaml create mode 100644 conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/tests.yaml create mode 100644 conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/policy.yaml create mode 100644 conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/tests.yaml create mode 100644 conformance/testdata/first_match_nested_aggregate/config.yaml create mode 100644 conformance/testdata/first_match_nested_aggregate/policy.yaml create mode 100644 conformance/testdata/first_match_nested_aggregate/tests.yaml diff --git a/conformance/testdata/aggregate/config.yaml b/conformance/testdata/aggregate/config.yaml new file mode 100644 index 0000000..8345949 --- /dev/null +++ b/conformance/testdata/aggregate/config.yaml @@ -0,0 +1,21 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate" +variables: + - name: "resource" + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/conformance/testdata/aggregate/policy.yaml b/conformance/testdata/aggregate/policy.yaml new file mode 100644 index 0000000..6fa760f --- /dev/null +++ b/conformance/testdata/aggregate/policy.yaml @@ -0,0 +1,26 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate +rule: + aggregate: + - condition: "resource.is_pii == true" + emit: "'PII'" + - condition: "resource.is_confidential == true" + emit: "'CONFIDENTIAL'" + - condition: "true" + rule: + match: + - condition: "resource.nested_cond == true" + output: "'NESTED'" diff --git a/conformance/testdata/aggregate/tests.yaml b/conformance/testdata/aggregate/tests.yaml new file mode 100644 index 0000000..1e4a539 --- /dev/null +++ b/conformance/testdata/aggregate/tests.yaml @@ -0,0 +1,42 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: Aggregate semantic conformance tests +section: + - name: "basic" + tests: + - name: "all_match_nested_triggered" + input: + resource: + expr: "{'is_pii': true, 'is_confidential': true, 'nested_cond': true}" + output: + expr: "['PII', 'CONFIDENTIAL', 'NESTED']" + - name: "all_match_nested_fallback" + input: + resource: + expr: "{'is_pii': true, 'is_confidential': true, 'nested_cond': false}" + output: + expr: "['PII', 'CONFIDENTIAL']" + - name: "some_match" + input: + resource: + expr: "{'is_pii': true, 'is_confidential': false, 'nested_cond': false}" + output: + expr: "['PII']" + - name: "none_match" + input: + resource: + expr: "{'is_pii': false, 'is_confidential': false, 'nested_cond': false}" + output: + expr: "[]" diff --git a/conformance/testdata/aggregate_explicit_list_output/policy.yaml b/conformance/testdata/aggregate_explicit_list_output/policy.yaml new file mode 100644 index 0000000..e75ef8c --- /dev/null +++ b/conformance/testdata/aggregate_explicit_list_output/policy.yaml @@ -0,0 +1,19 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_explicit_list_output +rule: + aggregate: + - condition: "true" + emit: "['tag1', 'tag2']" diff --git a/conformance/testdata/aggregate_explicit_list_output/tests.yaml b/conformance/testdata/aggregate_explicit_list_output/tests.yaml new file mode 100644 index 0000000..b968310 --- /dev/null +++ b/conformance/testdata/aggregate_explicit_list_output/tests.yaml @@ -0,0 +1,22 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: Explicit list output conformance tests +section: + - name: "basic" + tests: + - name: "all_match" + input: {} + output: + expr: "[['tag1', 'tag2']]" diff --git a/conformance/testdata/aggregate_explicit_optional_none/policy.yaml b/conformance/testdata/aggregate_explicit_optional_none/policy.yaml new file mode 100644 index 0000000..dc6ba7f --- /dev/null +++ b/conformance/testdata/aggregate_explicit_optional_none/policy.yaml @@ -0,0 +1,19 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_explicit_optional_none +rule: + aggregate: + - condition: "true" + emit: "optional.none()" diff --git a/conformance/testdata/aggregate_explicit_optional_none/tests.yaml b/conformance/testdata/aggregate_explicit_optional_none/tests.yaml new file mode 100644 index 0000000..d71d854 --- /dev/null +++ b/conformance/testdata/aggregate_explicit_optional_none/tests.yaml @@ -0,0 +1,22 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: Explicit optional none conformance tests +section: + - name: "basic" + tests: + - name: "all_match" + input: {} + output: + expr: "[optional.none()]" diff --git a/conformance/testdata/aggregate_nested_explicit_list_double_wrapping/policy.yaml b/conformance/testdata/aggregate_nested_explicit_list_double_wrapping/policy.yaml new file mode 100644 index 0000000..bf165c9 --- /dev/null +++ b/conformance/testdata/aggregate_nested_explicit_list_double_wrapping/policy.yaml @@ -0,0 +1,21 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_nested_explicit_list_double_wrapping +rule: + aggregate: + - rule: + match: + - condition: "true" + output: "['tag1', 'tag2']" diff --git a/conformance/testdata/aggregate_nested_explicit_list_double_wrapping/tests.yaml b/conformance/testdata/aggregate_nested_explicit_list_double_wrapping/tests.yaml new file mode 100644 index 0000000..2803973 --- /dev/null +++ b/conformance/testdata/aggregate_nested_explicit_list_double_wrapping/tests.yaml @@ -0,0 +1,22 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_nested_explicit_list_double_wrapping" +description: "Tests that aggregate policies cleanly support double-wrapped lists when a nested first_match rule returns an explicit list literal" +sections: +- name: "compile" + tests: + - name: "nested_explicit_list" + output: + value: [["tag1", "tag2"]] diff --git a/conformance/testdata/aggregate_shadowed_variables/config.yaml b/conformance/testdata/aggregate_shadowed_variables/config.yaml new file mode 100644 index 0000000..ecab9d2 --- /dev/null +++ b/conformance/testdata/aggregate_shadowed_variables/config.yaml @@ -0,0 +1,21 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_shadowed_variables" +variables: + - name: "resource" + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/conformance/testdata/aggregate_shadowed_variables/policy.yaml b/conformance/testdata/aggregate_shadowed_variables/policy.yaml new file mode 100644 index 0000000..2785c37 --- /dev/null +++ b/conformance/testdata/aggregate_shadowed_variables/policy.yaml @@ -0,0 +1,30 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_shadowed_variables +rule: + variables: + - name: "x" + expression: "10" + aggregate: + - condition: "resource.cond1 == true" + emit: "variables.x" + - condition: "resource.cond2 == true" + rule: + variables: + - name: "x" + expression: "20" + match: + - condition: "true" + output: "variables.x" diff --git a/conformance/testdata/aggregate_shadowed_variables/tests.yaml b/conformance/testdata/aggregate_shadowed_variables/tests.yaml new file mode 100644 index 0000000..25a41dc --- /dev/null +++ b/conformance/testdata/aggregate_shadowed_variables/tests.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: Shadowed variables conformance tests +section: + - name: "basic" + tests: + - name: "shadowed_in_nested_rule" + input: + resource: + expr: "{'cond1': true, 'cond2': true}" + output: + expr: "[10, 20]" diff --git a/conformance/testdata/compile_errors/aggregate_errors/config.yaml b/conformance/testdata/compile_errors/aggregate_errors/config.yaml new file mode 100644 index 0000000..48f1d35 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_errors/config.yaml @@ -0,0 +1,19 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_errors" +variables: + - name: cond + type: + type_name: "bool" diff --git a/conformance/testdata/compile_errors/aggregate_errors/policy.yaml b/conformance/testdata/compile_errors/aggregate_errors/policy.yaml new file mode 100644 index 0000000..a43455a --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_errors/policy.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_errors +rule: + aggregate: + - condition: "cond" + rule: + match: + - condition: "cond" + output: "optional.of('USER_PII')" + - condition: "true" + output: "403" diff --git a/conformance/testdata/compile_errors/aggregate_false_condition/policy.yaml b/conformance/testdata/compile_errors/aggregate_false_condition/policy.yaml new file mode 100644 index 0000000..a33d8c0 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_false_condition/policy.yaml @@ -0,0 +1,19 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_false_condition +rule: + aggregate: + - condition: "false" + emit: "'FALSE'" diff --git a/conformance/testdata/compile_errors/aggregate_false_condition/tests.yaml b/conformance/testdata/compile_errors/aggregate_false_condition/tests.yaml new file mode 100644 index 0000000..5c35d51 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_false_condition/tests.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_false_condition" +description: "Tests for false condition in aggregate policy" +sections: +- name: "compile" + tests: + - name: "false_condition" + output: + error_set: + - "condition is always false" diff --git a/conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/policy.yaml b/conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/policy.yaml new file mode 100644 index 0000000..b88dac9 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/policy.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_heterogeneous_outputs +rule: + aggregate: + - condition: "true" + emit: "'PII'" + - condition: "true" + emit: "403" + - condition: "true" + emit: "{'reason': 'blocked'}" diff --git a/conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/tests.yaml b/conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/tests.yaml new file mode 100644 index 0000000..1dcf688 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_heterogeneous_outputs/tests.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_heterogeneous_outputs" +description: "Tests for heterogeneous outputs in aggregate policy" +sections: +- name: "compile" + tests: + - name: "incompatible_types" + output: + error_set: + - "incompatible output types: block has output type map(string, string), but previous outputs have type int" diff --git a/conformance/testdata/compile_errors/aggregate_list_errors/config.yaml b/conformance/testdata/compile_errors/aggregate_list_errors/config.yaml new file mode 100644 index 0000000..4361531 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_list_errors/config.yaml @@ -0,0 +1,19 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_list_errors" +variables: + - name: cond + type: + type_name: "bool" diff --git a/conformance/testdata/compile_errors/aggregate_list_errors/policy.yaml b/conformance/testdata/compile_errors/aggregate_list_errors/policy.yaml new file mode 100644 index 0000000..09c81ff --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_list_errors/policy.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_list_errors +rule: + aggregate: + - condition: "cond" + rule: + match: + - condition: "cond" + output: "['tag1', 'tag2']" + - condition: "true" + output: "403" diff --git a/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/config.yaml b/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/config.yaml new file mode 100644 index 0000000..58a3a61 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/config.yaml @@ -0,0 +1,20 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_nested_mixed_semantics" +variables: + - name: "cond1" + type_name: "bool" + - name: "cond2" + type_name: "bool" diff --git a/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/policy.yaml b/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/policy.yaml new file mode 100644 index 0000000..8cdca5a --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/policy.yaml @@ -0,0 +1,25 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_nested_mixed_semantics +rule: + aggregate: + - condition: "cond1" + rule: + match: + - condition: "cond2" + rule: + aggregate: + - condition: "true" + emit: "'nested'" diff --git a/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/tests.yaml b/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/tests.yaml new file mode 100644 index 0000000..e0ac530 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_nested_mixed_semantics/tests.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_nested_mixed_semantics" +description: "Tests that nested aggregate rules under an aggregate ancestor rule raise a compilation error" +sections: +- name: "compile" + tests: + - name: "nested_aggregate_error" + output: + error_set: + - "nested aggregate rules are not allowed" diff --git a/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/config.yaml b/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/config.yaml new file mode 100644 index 0000000..bb0f3aa --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/config.yaml @@ -0,0 +1,21 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +variables: + - name: cond1 + type: + type_name: "bool" + - name: cond2 + type: + type_name: "bool" diff --git a/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/policy.yaml b/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/policy.yaml new file mode 100644 index 0000000..266afc2 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/policy.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_subrule_heterogeneous_outputs +rule: + aggregate: + - rule: + match: + - condition: "cond1" + output: "'PII'" + - condition: "cond2" + output: "403" diff --git a/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/tests.yaml b/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/tests.yaml new file mode 100644 index 0000000..13bdb32 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_subrule_heterogeneous_outputs/tests.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_subrule_heterogeneous_outputs" +description: "Tests that nested first_match subrule under an aggregate outer rule correctly formats its type mismatch errors on raw unwrapped types instead of leaked list wrapper" +sections: +- name: "compile" + tests: + - name: "mixed_semantics_type_error" + output: + error_set: + - "incompatible output types: block has output type int, but previous outputs have type string" diff --git a/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/config.yaml b/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/config.yaml new file mode 100644 index 0000000..04399fe --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/config.yaml @@ -0,0 +1,21 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_unreachable_in_nested_first_match" +variables: + - name: "resource" + type_name: "map" + params: + - type_name: "string" + - type_name: "dyn" diff --git a/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/policy.yaml b/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/policy.yaml new file mode 100644 index 0000000..49ddb7f --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/policy.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: aggregate_unreachable_in_nested_first_match +rule: + aggregate: + - condition: "true" + rule: + match: + - condition: "true" + output: "'PII'" + - condition: "resource.is_admin == true" + output: "'ADMIN'" diff --git a/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/tests.yaml b/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/tests.yaml new file mode 100644 index 0000000..3352795 --- /dev/null +++ b/conformance/testdata/compile_errors/aggregate_unreachable_in_nested_first_match/tests.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "aggregate_unreachable_in_nested_first_match" +description: "Tests for unreachable matches inside nested first_match subrule of aggregate policy" +sections: +- name: "compile" + tests: + - name: "unreachable_match" + output: + error_set: + - "match creates unreachable outputs" + diff --git a/conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/policy.yaml b/conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/policy.yaml new file mode 100644 index 0000000..0ba59c1 --- /dev/null +++ b/conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/policy.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: unreachable_under_unconditional_aggregate_subrule +rule: + match: + - condition: "true" + rule: + aggregate: + - condition: "1 == 2" + emit: "'ADMIN'" + - condition: "true" + output: "['FALLBACK']" diff --git a/conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/tests.yaml b/conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/tests.yaml new file mode 100644 index 0000000..3e7cd72 --- /dev/null +++ b/conformance/testdata/compile_errors/unreachable_under_unconditional_aggregate_subrule/tests.yaml @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "unreachable_under_unconditional_aggregate_subrule" +description: "Tests that dead code is flagged when a first_match rule has an unconditional aggregate subrule followed by another match" +sections: +- name: "compile" + tests: + - name: "unreachable_match" + output: + error_set: + - "rule creates unreachable outputs" diff --git a/conformance/testdata/first_match_nested_aggregate/config.yaml b/conformance/testdata/first_match_nested_aggregate/config.yaml new file mode 100644 index 0000000..c9b688b --- /dev/null +++ b/conformance/testdata/first_match_nested_aggregate/config.yaml @@ -0,0 +1,24 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +variables: + - name: cond1 + type: + type_name: "bool" + - name: cond2 + type: + type_name: "bool" + - name: cond3 + type: + type_name: "bool" diff --git a/conformance/testdata/first_match_nested_aggregate/policy.yaml b/conformance/testdata/first_match_nested_aggregate/policy.yaml new file mode 100644 index 0000000..8db0ca0 --- /dev/null +++ b/conformance/testdata/first_match_nested_aggregate/policy.yaml @@ -0,0 +1,26 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: first_match_nested_aggregate +rule: + match: + - condition: "cond1" + rule: + aggregate: + - condition: "cond2" + emit: "'A'" + - condition: "cond3" + emit: "'B'" + - condition: "true" + output: "['FALLBACK']" diff --git a/conformance/testdata/first_match_nested_aggregate/tests.yaml b/conformance/testdata/first_match_nested_aggregate/tests.yaml new file mode 100644 index 0000000..8cb47df --- /dev/null +++ b/conformance/testdata/first_match_nested_aggregate/tests.yaml @@ -0,0 +1,48 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: Bidirectional scoping conformance tests nesting aggregate inside first_match parent +section: + - name: "basic" + tests: + - name: "all_true" + input: + cond1: + value: true + cond2: + value: true + cond3: + value: true + output: + value: ["A", "B"] + - name: "fallback_outer" + input: + cond1: + value: false + cond2: + value: true + cond3: + value: true + output: + value: ["FALLBACK"] + - name: "nested_failed_to_empty" + input: + cond1: + value: true + cond2: + value: false + cond3: + value: false + output: + value: []