From e12966a4fd0aafcd28d97ce12b6e11679b1bbcbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 14:18:20 +0000 Subject: [PATCH] build(deps): bump github.com/open-policy-agent/opa from 1.18.2 to 1.19.0 Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 1.18.2 to 1.19.0. - [Release notes](https://github.com/open-policy-agent/opa/releases) - [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-policy-agent/opa/compare/v1.18.2...v1.19.0) --- updated-dependencies: - dependency-name: github.com/open-policy-agent/opa dependency-version: 1.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +- go.sum | 20 +- .../github.com/go-logr/logr/context_noslog.go | 1 - .../github.com/go-logr/logr/context_slog.go | 1 - vendor/github.com/go-logr/logr/funcr/funcr.go | 47 +- .../github.com/go-logr/logr/funcr/slogsink.go | 22 +- vendor/github.com/go-logr/logr/sloghandler.go | 1 - vendor/github.com/go-logr/logr/slogr.go | 1 - vendor/github.com/go-logr/logr/slogsink.go | 1 - .../opa/capabilities/v1.19.0.json | 5026 +++++++++++++++++ .../opa/internal/compiler/wasm/opa/opa.wasm | Bin 431796 -> 431796 bytes .../opa/internal/gojsonschema/errors.go | 9 +- .../opa/internal/gojsonschema/schema.go | 5 +- .../opa/internal/jsonv2/jsonv2.go | 79 + .../opa/internal/methodlesstemplate/LICENSE | 27 + .../opa/internal/methodlesstemplate/README.md | 28 + .../opa/internal/methodlesstemplate/doc.go | 502 ++ .../opa/internal/methodlesstemplate/exec.go | 1132 ++++ .../opa/internal/methodlesstemplate/funcs.go | 783 +++ .../internal/fmtsort/sort.go | 154 + .../opa/internal/methodlesstemplate/option.go | 72 + .../internal/methodlesstemplate/template.go | 236 + .../opa/internal/planner/planner.go | 163 +- .../opa/internal/planner/rules.go | 46 +- .../opa/internal/semver/semver.go | 6 +- .../opa/v1/ast/annotations.go | 108 +- .../opa/v1/ast/annotations_json.go | 124 + .../opa/v1/ast/annotations_jsonv2.go | 195 + .../open-policy-agent/opa/v1/ast/builtins.go | 50 +- .../open-policy-agent/opa/v1/ast/check.go | 4 +- .../open-policy-agent/opa/v1/ast/compare.go | 16 +- .../open-policy-agent/opa/v1/ast/compile.go | 284 +- .../open-policy-agent/opa/v1/ast/errors.go | 29 +- .../opa/v1/ast/external_source.go | 69 + .../open-policy-agent/opa/v1/ast/index.go | 315 +- .../opa/v1/ast/location/location.go | 40 - .../opa/v1/ast/location/location_json.go | 47 + .../opa/v1/ast/location/location_jsonv2.go | 50 + .../open-policy-agent/opa/v1/ast/map.go | 2 +- .../open-policy-agent/opa/v1/ast/mermaid.go | 24 +- .../open-policy-agent/opa/v1/ast/parser.go | 297 +- .../open-policy-agent/opa/v1/ast/policy.go | 414 +- .../opa/v1/ast/policy_appenders.go | 18 +- .../opa/v1/ast/policy_json.go | 289 + .../opa/v1/ast/policy_jsonv2.go | 524 ++ .../opa/v1/ast/string_length.go | 17 +- .../open-policy-agent/opa/v1/ast/term.go | 237 +- .../opa/v1/ast/term_appenders.go | 8 + .../open-policy-agent/opa/v1/ast/term_json.go | 95 + .../opa/v1/ast/term_jsonv2.go | 251 + .../opa/v1/ast/version_index.json | 5 + .../open-policy-agent/opa/v1/bundle/bundle.go | 157 +- .../open-policy-agent/opa/v1/bundle/file.go | 5 +- .../opa/v1/bundle/manifest.proto | 6 +- .../open-policy-agent/opa/v1/bundle/proto.go | 434 ++ .../opa/v1/bundle/v1pb/manifest.pb.go | 751 +++ .../open-policy-agent/opa/v1/format/format.go | 7 +- .../open-policy-agent/opa/v1/ir/proto.go | 340 ++ .../opa/v1/ir/v1pb/plan.pb.go | 3449 +++++++++++ .../open-policy-agent/opa/v1/keys/keys.go | 3 + .../open-policy-agent/opa/v1/logging/slog.go | 87 - .../opa/v1/storage/internal/ptr/ptr.go | 14 +- .../opa/v1/topdown/aggregates.go | 83 +- .../opa/v1/topdown/arithmetic.go | 28 + .../opa/v1/topdown/builtins/builtins.go | 15 +- .../open-policy-agent/opa/v1/topdown/cache.go | 57 +- .../copypropagation/copypropagation.go | 68 +- .../opa/v1/topdown/errors_jsonv2.go | 24 + .../open-policy-agent/opa/v1/topdown/eval.go | 508 +- .../open-policy-agent/opa/v1/topdown/query.go | 2 +- .../open-policy-agent/opa/v1/topdown/save.go | 30 +- .../opa/v1/topdown/strings.go | 105 +- .../opa/v1/topdown/template.go | 9 +- .../open-policy-agent/opa/v1/topdown/trace.go | 58 + .../open-policy-agent/opa/v1/util/compare.go | 16 + .../open-policy-agent/opa/v1/util/hashmap.go | 30 +- .../opa/v1/util/performance.go | 89 + .../open-policy-agent/opa/v1/util/queue.go | 91 + .../opa/v1/version/version.go | 2 +- .../vektah/gqlparser/v2/ast/definition.go | 8 +- .../vektah/gqlparser/v2/ast/dumper.go | 6 +- .../vektah/gqlparser/v2/lexer/lexer.go | 6 +- .../vektah/gqlparser/v2/lexer/lexer_test.yml | 6 + .../vektah/gqlparser/v2/parser/schema.go | 14 +- .../vektah/gqlparser/v2/validator/schema.go | 24 + .../gqlparser/v2/validator/schema_test.yml | 31 + .../vektah/gqlparser/v2/validator/vars.go | 19 +- vendor/modules.txt | 11 +- 88 files changed, 17067 insertions(+), 1406 deletions(-) create mode 100644 vendor/github.com/open-policy-agent/opa/capabilities/v1.19.0.json create mode 100644 vendor/github.com/open-policy-agent/opa/internal/jsonv2/jsonv2.go create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/LICENSE create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/README.md create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/doc.go create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/exec.go create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/funcs.go create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort/sort.go create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/option.go create mode 100644 vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/template.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/annotations_json.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/annotations_jsonv2.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/location/location_json.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/location/location_jsonv2.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/policy_json.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/policy_jsonv2.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/term_json.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ast/term_jsonv2.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/bundle/proto.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/bundle/v1pb/manifest.pb.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ir/proto.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/ir/v1pb/plan.pb.go delete mode 100644 vendor/github.com/open-policy-agent/opa/v1/logging/slog.go create mode 100644 vendor/github.com/open-policy-agent/opa/v1/topdown/errors_jsonv2.go diff --git a/go.mod b/go.mod index 53f5f8a0ab..2c7fbaa4ba 100644 --- a/go.mod +++ b/go.mod @@ -61,7 +61,7 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo/v2 v2.32.0 github.com/onsi/gomega v1.42.1 - github.com/open-policy-agent/opa v1.18.2 + github.com/open-policy-agent/opa v1.19.0 github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d github.com/opencloud-eu/reva/v2 v2.47.0 @@ -210,7 +210,7 @@ require ( github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-micro/plugins/v4/events/natsjs v1.2.2 // indirect github.com/go-micro/plugins/v4/store/nats-js v1.2.1 // indirect @@ -362,7 +362,7 @@ require ( github.com/trustelem/zxcvbn v1.0.1 // indirect github.com/urfave/cli/v2 v2.27.7 // indirect github.com/valyala/fastjson v1.6.10 // indirect - github.com/vektah/gqlparser/v2 v2.5.34 // indirect + github.com/vektah/gqlparser/v2 v2.5.36 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/wk8/go-ordered-map v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect diff --git a/go.sum b/go.sum index c026746fe3..efebe28964 100644 --- a/go.sum +++ b/go.sum @@ -195,8 +195,6 @@ github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/ github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 h1:h8Z0hBv5tg/uZMKu8V47+DKWYVQg0lYP8lXDQq7uRpE= github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3/go.mod h1:eE/tD53n3KbVrzrWxKLxdkGw45Fg1qaNLWjpJMvIUF4= -github.com/bytecodealliance/wasmtime-go/v44 v44.0.0 h1:WRZXnLPIer/TWs5aYPaMlmVcOlzmR6Ur6wjLRIQOhTQ= -github.com/bytecodealliance/wasmtime-go/v44 v44.0.0/go.mod h1:GP93piU+39CoFVCQ5xfHrPOUtL0APlMnkbblJ2d3YY0= github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -281,8 +279,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjY github.com/deepmap/oapi-codegen v1.3.11/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dgraph-io/badger/v4 v4.9.2 h1:Wb5qw8gElqwV1a8msHTeQKova9b1V10heFKMIiPd80E= -github.com/dgraph-io/badger/v4 v4.9.2/go.mod h1:nJjaJTUOSsQEBhsq209FmwCvMJzEA3e74RjZw6V2pQI= +github.com/dgraph-io/badger/v4 v4.9.4 h1:bcw+waCpzRZ2nmcSPbnPvDVhiEsn98TKmvnAhK7r7LM= +github.com/dgraph-io/badger/v4 v4.9.4/go.mod h1:nJjaJTUOSsQEBhsq209FmwCvMJzEA3e74RjZw6V2pQI= github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= @@ -412,8 +410,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-micro/plugins/v4/client/grpc v1.2.1 h1:7xAwZRCO6mdUtBHsYIQs1/eCTdhCrnjF70GB+AVd6L0= @@ -936,8 +934,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= -github.com/open-policy-agent/opa v1.18.2 h1:VBiLJpioTuk7XTW1JoQi4ILo+FVxD2/8uD8iP9/OcxY= -github.com/open-policy-agent/opa v1.18.2/go.mod h1:9GY+hER4ZEXtxPlMjftVbqJJY9xLtCD3Q0oufRCfAKo= +github.com/open-policy-agent/opa v1.19.0 h1:+j2OCsjMezZEML2T1lI9giJdGJS/PL1XFKgkHPGIhpo= +github.com/open-policy-agent/opa v1.19.0/go.mod h1:pb6Y6klyf7X7X8uXNDflruA9dQC2gMqWROXI5w/kvv0= github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M= github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY= github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+lP5lUUIzjRGDg93WrQfZJZCaV1ZP3KeyXi8bzY= @@ -1189,6 +1187,8 @@ github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0 github.com/testcontainers/testcontainers-go v0.43.0/go.mod h1:+VxkT2NQnKOZPKi6praMuMKYHYyOGXr0XSBSlSMCzFo= github.com/testcontainers/testcontainers-go/modules/opensearch v0.43.0 h1:a1ipjF7d/VxPX1dgVPIk4F+t6YkgMbE2OtBuRQCHJt8= github.com/testcontainers/testcontainers-go/modules/opensearch v0.43.0/go.mod h1:OWSeUDiGMUy30iMsAltIJIo9uh/CleLv6KyxjYOsgR8= +github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU= +github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0= github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o= github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U= github.com/thejerf/suture/v4 v4.0.6 h1:QsuCEsCqb03xF9tPAsWAj8QOAJBgQI1c0VqJNaingg8= @@ -1227,8 +1227,8 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADT github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/vektah/gqlparser/v2 v2.5.34 h1:MEea5P0qhdcqfBL45ghKE+qr9laidVHTMHjav5h7ckk= -github.com/vektah/gqlparser/v2 v2.5.34/go.mod h1:mFdHLGCio7OGX1fby9ZjTW6FN+qxgmbnBcRIeeScE5s= +github.com/vektah/gqlparser/v2 v2.5.36 h1:CN9mKVHgMkc+XftdOWIhb4HEL8wKSYkFAqhf8booa7s= +github.com/vektah/gqlparser/v2 v2.5.36/go.mod h1:cAJ9qwVgPaUkWv6Gn8vn0mqOE0Ui5Pn56wNy5396XWo= github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= diff --git a/vendor/github.com/go-logr/logr/context_noslog.go b/vendor/github.com/go-logr/logr/context_noslog.go index f012f9a18e..0a3d1a125e 100644 --- a/vendor/github.com/go-logr/logr/context_noslog.go +++ b/vendor/github.com/go-logr/logr/context_noslog.go @@ -1,5 +1,4 @@ //go:build !go1.21 -// +build !go1.21 /* Copyright 2019 The logr Authors. diff --git a/vendor/github.com/go-logr/logr/context_slog.go b/vendor/github.com/go-logr/logr/context_slog.go index 065ef0b828..c69eb01ba1 100644 --- a/vendor/github.com/go-logr/logr/context_slog.go +++ b/vendor/github.com/go-logr/logr/context_slog.go @@ -1,5 +1,4 @@ //go:build go1.21 -// +build go1.21 /* Copyright 2019 The logr Authors. diff --git a/vendor/github.com/go-logr/logr/funcr/funcr.go b/vendor/github.com/go-logr/logr/funcr/funcr.go index b22c57d713..7f4996e9e4 100644 --- a/vendor/github.com/go-logr/logr/funcr/funcr.go +++ b/vendor/github.com/go-logr/logr/funcr/funcr.go @@ -426,7 +426,7 @@ func (f Formatter) colon() byte { } func (f Formatter) pretty(value any) string { - return f.prettyWithFlags(value, 0, 0) + return f.prettyWithFlags(value, 0, 0, 0, nil) } const ( @@ -434,7 +434,13 @@ const ( ) // TODO: This is not fast. Most of the overhead goes here. -func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { +// value: The value to render +// flags: Bitmask of flags (see above) +// depth: The current depth of nested structs, slices, arrays, and maps +// ptrDepth: The current depth of including pointer dereferences +// ptrMap: A map of pointers already seen, to avoid infinite recursion (usually +// nil unless ptrDepth is large) +func (f Formatter) prettyWithFlags(value any, flags uint32, depth int, ptrDepth int, ptrMap map[uintptr]bool) string { if depth > f.opts.MaxLogDepth { return `""` } @@ -504,7 +510,7 @@ func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { // arbitrary keys might need escaping buf.WriteString(prettyString(k)) buf.WriteByte(f.colon()) - buf.WriteString(f.prettyWithFlags(v[i+1], 0, depth+1)) + buf.WriteString(f.prettyWithFlags(v[i+1], 0, depth+1, ptrDepth+1, ptrMap)) } if flags&flagRawStruct == 0 { buf.WriteByte('}') @@ -576,7 +582,7 @@ func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { } printComma = true // if we got here, we are rendering a field if fld.Anonymous && fld.Type.Kind() == reflect.Struct && name == "" { - buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1)) + buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1, ptrDepth+1, ptrMap)) continue } if name == "" { @@ -585,7 +591,7 @@ func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { // field names can't contain characters which need escaping buf.WriteString(f.quoted(name, false)) buf.WriteByte(f.colon()) - buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), 0, depth+1)) + buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), 0, depth+1, ptrDepth+1, ptrMap)) } if flags&flagRawStruct == 0 { buf.WriteByte('}') @@ -612,7 +618,7 @@ func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { buf.WriteByte(f.comma()) } e := v.Index(i) - buf.WriteString(f.prettyWithFlags(e.Interface(), 0, depth+1)) + buf.WriteString(f.prettyWithFlags(e.Interface(), 0, depth+1, ptrDepth+1, ptrMap)) } buf.WriteByte(']') return buf.String() @@ -637,7 +643,8 @@ func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { keystr = prettyString(keystr) } else { // prettyWithFlags will produce already-escaped values - keystr = f.prettyWithFlags(it.Key().Interface(), 0, depth+1) + // key depth is unrelated to overall depth + keystr = f.prettyWithFlags(it.Key().Interface(), 0, 0, ptrDepth, ptrMap) if t.Key().Kind() != reflect.String { // JSON only does string keys. Unlike Go's standard JSON, we'll // convert just about anything to a string. @@ -646,16 +653,34 @@ func (f Formatter) prettyWithFlags(value any, flags uint32, depth int) string { } buf.WriteString(keystr) buf.WriteByte(f.colon()) - buf.WriteString(f.prettyWithFlags(it.Value().Interface(), 0, depth+1)) + buf.WriteString(f.prettyWithFlags(it.Value().Interface(), 0, depth+1, ptrDepth+1, ptrMap)) i++ } buf.WriteByte('}') return buf.String() - case reflect.Ptr, reflect.Interface: + case reflect.Pointer, reflect.Interface: if v.IsNil() { return "null" } - return f.prettyWithFlags(v.Elem().Interface(), 0, depth) + // Special case: recursive pointers. For normal use we do not want to + // count pointer dereferences as depth, but if we see the same pointer + // again we have a recursion and need to stop. After a large number of + // pointer dereferences we will start tracking pointers to avoid the + // perf hit of doing it in the normal path. + // + // This should not happen accidentally (e.g. json decoding should never + // do this) but we can handle it gracefully. + if ptrMap != nil && ptrMap[uintptr(v.Pointer())] { + depth = f.opts.MaxLogDepth + 1 // force a depth error + } + const maxDepthFactor = 4 // arbitrary, but we want it large enough to not false-alert + if ptrDepth > f.opts.MaxLogDepth*maxDepthFactor && ptrMap == nil { + ptrMap = map[uintptr]bool{} + } + if ptrMap != nil { + ptrMap[(uintptr)(v.Pointer())] = true + } + return f.prettyWithFlags(v.Elem().Interface(), 0, depth, ptrDepth+1, ptrMap) } return fmt.Sprintf(`""`, t.Kind().String()) } @@ -697,7 +722,7 @@ func isEmpty(v reflect.Value) bool { return v.Float() == 0 case reflect.Complex64, reflect.Complex128: return v.Complex() == 0 - case reflect.Interface, reflect.Ptr: + case reflect.Interface, reflect.Pointer: return v.IsNil() } return false diff --git a/vendor/github.com/go-logr/logr/funcr/slogsink.go b/vendor/github.com/go-logr/logr/funcr/slogsink.go index 7bd84761e2..8b519c91e1 100644 --- a/vendor/github.com/go-logr/logr/funcr/slogsink.go +++ b/vendor/github.com/go-logr/logr/funcr/slogsink.go @@ -1,5 +1,4 @@ //go:build go1.21 -// +build go1.21 /* Copyright 2023 The logr Authors. @@ -33,7 +32,7 @@ const extraSlogSinkDepth = 3 // 2 for slog, 1 for SlogSink func (l fnlogger) Handle(_ context.Context, record slog.Record) error { kvList := make([]any, 0, 2*record.NumAttrs()) record.Attrs(func(attr slog.Attr) bool { - kvList = attrToKVs(attr, kvList) + kvList = attrToKVs(attr, kvList, l.opts.MaxLogDepth) return true }) @@ -49,7 +48,7 @@ func (l fnlogger) Handle(_ context.Context, record slog.Record) error { func (l fnlogger) WithAttrs(attrs []slog.Attr) logr.SlogSink { kvList := make([]any, 0, 2*len(attrs)) for _, attr := range attrs { - kvList = attrToKVs(attr, kvList) + kvList = attrToKVs(attr, kvList, l.opts.MaxLogDepth) } l.AddValues(kvList) return &l @@ -61,14 +60,25 @@ func (l fnlogger) WithGroup(name string) logr.SlogSink { } // attrToKVs appends a slog.Attr to a logr-style kvList. It handle slog Groups -// and other details of slog. -func attrToKVs(attr slog.Attr, kvList []any) []any { +// and other details of slog. maxDepth bounds recursion into nested groups so a +// deeply-nested slog.Group cannot exhaust the stack; it is decremented per group +// level and starts at the Formatter's MaxLogDepth (past which the formatter would +// truncate the rendering anyway). +func attrToKVs(attr slog.Attr, kvList []any, maxDepth int) []any { attrVal := attr.Value.Resolve() if attrVal.Kind() == slog.KindGroup { + if maxDepth <= 0 { + // Nesting is too deep to build without risking a stack overflow. + // Stop here; the formatter truncates below MaxLogDepth regardless. + if attr.Key != "" { + kvList = append(kvList, attr.Key, "") + } + return kvList + } groupVal := attrVal.Group() grpKVs := make([]any, 0, 2*len(groupVal)) for _, attr := range groupVal { - grpKVs = attrToKVs(attr, grpKVs) + grpKVs = attrToKVs(attr, grpKVs, maxDepth-1) } if attr.Key == "" { // slog says we have to inline these diff --git a/vendor/github.com/go-logr/logr/sloghandler.go b/vendor/github.com/go-logr/logr/sloghandler.go index 82d1ba4948..befaf5510f 100644 --- a/vendor/github.com/go-logr/logr/sloghandler.go +++ b/vendor/github.com/go-logr/logr/sloghandler.go @@ -1,5 +1,4 @@ //go:build go1.21 -// +build go1.21 /* Copyright 2023 The logr Authors. diff --git a/vendor/github.com/go-logr/logr/slogr.go b/vendor/github.com/go-logr/logr/slogr.go index 28a83d0243..bfe80eb8d6 100644 --- a/vendor/github.com/go-logr/logr/slogr.go +++ b/vendor/github.com/go-logr/logr/slogr.go @@ -1,5 +1,4 @@ //go:build go1.21 -// +build go1.21 /* Copyright 2023 The logr Authors. diff --git a/vendor/github.com/go-logr/logr/slogsink.go b/vendor/github.com/go-logr/logr/slogsink.go index 4060fcbc2b..ab76ea99fe 100644 --- a/vendor/github.com/go-logr/logr/slogsink.go +++ b/vendor/github.com/go-logr/logr/slogsink.go @@ -1,5 +1,4 @@ //go:build go1.21 -// +build go1.21 /* Copyright 2023 The logr Authors. diff --git a/vendor/github.com/open-policy-agent/opa/capabilities/v1.19.0.json b/vendor/github.com/open-policy-agent/opa/capabilities/v1.19.0.json new file mode 100644 index 0000000000..1b02dd4ace --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/capabilities/v1.19.0.json @@ -0,0 +1,5026 @@ +{ + "builtins": [ + { + "name": "abs", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "all", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "and", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "\u0026" + }, + { + "name": "any", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "array.concat", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.flatten", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.reverse", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "array.slice", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "assign", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": ":=" + }, + { + "name": "base64.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "base64url.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "base64url.encode_no_pad", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "bits.and", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.lsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.negate", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.or", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.rsh", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "bits.xor", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "cast_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "cast_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "cast_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "null" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "cast_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "cast_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "cast_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "ceil", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "concat", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "count", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.equal", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.md5", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha1", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.hmac.sha512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.md5", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.parse_private_keys", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.sha1", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.sha256", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_and_verify_certificates_with_options", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificate_request", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_certificates", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_keypair", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "crypto.x509.parse_rsa_private_key", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "div", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "/" + }, + { + "name": "endswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "eq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "=" + }, + { + "name": "equal", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "==" + }, + { + "name": "floor", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "format_int", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "glob.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "of": [ + { + "type": "null" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + } + ], + "type": "any" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "glob.quote_meta", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "graph.reachable", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graph.reachable_paths", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "graphql.is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "graphql.parse", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_and_verify", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_query", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.parse_schema", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "graphql.schema_is_valid", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "gt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e" + }, + { + "name": "gte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003e=" + }, + { + "name": "hex.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "hex.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "http.send", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "indexof", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "indexof_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "internal.member_2", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.member_3", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "in" + }, + { + "name": "internal.print", + "decl": { + "args": [ + { + "dynamic": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "internal.template_string", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "internal.test_case", + "decl": { + "args": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "function" + } + }, + { + "name": "intersection", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "static": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "io.jwt.decode_verify", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "array" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.encode_sign_raw", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "io.jwt.verify_eddsa", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_es512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_hs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_ps512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs256", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs384", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "io.jwt.verify_rs512", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_array", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_boolean", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_null", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_number", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_object", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_set", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "is_string", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "json.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "json.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.marshal_with_options", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "indent", + "value": { + "type": "string" + } + }, + { + "key": "prefix", + "value": { + "type": "string" + } + }, + { + "key": "pretty", + "value": { + "type": "boolean" + } + } + ], + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "json.match_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "dynamic": { + "static": [ + { + "key": "desc", + "value": { + "type": "string" + } + }, + { + "key": "error", + "value": { + "type": "string" + } + }, + { + "key": "field", + "value": { + "type": "string" + } + }, + { + "key": "type", + "value": { + "type": "string" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "json.patch", + "decl": { + "args": [ + { + "type": "any" + }, + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "static": [ + { + "key": "op", + "value": { + "type": "string" + } + }, + { + "key": "path", + "value": { + "type": "any" + } + } + ], + "type": "object" + }, + "type": "array" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "json.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "json.verify_schema", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "boolean" + }, + { + "of": [ + { + "type": "null" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "lower", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "lt", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c" + }, + { + "name": "lte", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "\u003c=" + }, + { + "name": "max", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "min", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "minus", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": [ + { + "type": "number" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + "type": "function" + }, + "infix": "-" + }, + { + "name": "mul", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "*" + }, + { + "name": "neq", + "decl": { + "args": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "infix": "!=" + }, + { + "name": "net.cidr_contains", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_contains_matches", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "static": [ + { + "type": "any" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_expand", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_intersects", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "net.cidr_merge", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "of": [ + { + "type": "string" + } + ], + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "net.cidr_overlap", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "net.lookup_ip_addr", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "of": { + "type": "string" + }, + "type": "set" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "numbers.range", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "numbers.range_step", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "object.filter", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "object.get", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "any" + }, + { + "type": "any" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "object.keys", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "object.remove", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "object.subset", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "object.union", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "object.union_n", + "decl": { + "args": [ + { + "dynamic": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "array" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "opa.runtime", + "decl": { + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "or", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "infix": "|" + }, + { + "name": "plus", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "+" + }, + { + "name": "print", + "decl": { + "type": "function", + "variadic": { + "type": "any" + } + } + }, + { + "name": "product", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "providers.aws.sign_req", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "key": { + "type": "any" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rand.intn", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "re_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "regex.find_all_string_submatch_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.find_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.globs_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "regex.replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "regex.split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "regex.template_match", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.chain", + "decl": { + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "rego.metadata.rule", + "decl": { + "result": { + "type": "any" + }, + "type": "function" + } + }, + { + "name": "rego.parse_module", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "rem", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + }, + "infix": "%" + }, + { + "name": "replace", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "round", + "decl": { + "args": [ + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.compare", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "semver.is_valid", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "set_diff", + "decl": { + "args": [ + { + "of": { + "type": "any" + }, + "type": "set" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + }, + "deprecated": true + }, + { + "name": "sort", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "of": { + "type": "any" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "split", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "sprintf", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "any" + }, + "type": "array" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "startswith", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_prefix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.any_suffix_match", + "decl": { + "args": [ + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "strings.count", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "strings.render_template", + "decl": { + "args": [ + { + "type": "string" + }, + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.replace_n", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.reverse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "strings.split_n", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "number" + } + ], + "result": { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + "type": "function" + } + }, + { + "name": "substring", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "sum", + "decl": { + "args": [ + { + "of": [ + { + "dynamic": { + "type": "number" + }, + "type": "array" + }, + { + "of": { + "type": "number" + }, + "type": "set" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.add_date", + "decl": { + "args": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.clock", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.date", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.diff", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + }, + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "static": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ], + "type": "array" + }, + "type": "function" + } + }, + { + "name": "time.format", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "time.now_ns", + "decl": { + "result": { + "type": "number" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "time.parse_duration_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_ns", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.parse_rfc3339_ns", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "time.weekday", + "decl": { + "args": [ + { + "of": [ + { + "type": "number" + }, + { + "static": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "array" + } + ], + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "to_number", + "decl": { + "args": [ + { + "of": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + } + ], + "type": "any" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "trace", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "trim", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_left", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_prefix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_right", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_space", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "trim_suffix", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "type_name", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "union", + "decl": { + "args": [ + { + "of": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "set" + } + ], + "result": { + "of": { + "type": "any" + }, + "type": "set" + }, + "type": "function" + } + }, + { + "name": "units.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "units.parse_bytes", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "number" + }, + "type": "function" + } + }, + { + "name": "upper", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uri.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "uri.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.decode_object", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "dynamic": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "urlquery.encode_object", + "decl": { + "args": [ + { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "of": [ + { + "type": "string" + }, + { + "dynamic": { + "type": "string" + }, + "type": "array" + }, + { + "of": { + "type": "string" + }, + "type": "set" + } + ], + "type": "any" + } + }, + "type": "object" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "uuid.parse", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "dynamic": { + "key": { + "type": "string" + }, + "value": { + "type": "any" + } + }, + "type": "object" + }, + "type": "function" + } + }, + { + "name": "uuid.rfc4122", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "string" + }, + "type": "function" + }, + "nondeterministic": true + }, + { + "name": "walk", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "static": [ + { + "dynamic": { + "type": "any" + }, + "type": "array" + }, + { + "type": "any" + } + ], + "type": "array" + }, + "type": "function" + }, + "relation": true + }, + { + "name": "yaml.is_valid", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, + { + "name": "yaml.marshal", + "decl": { + "args": [ + { + "type": "any" + } + ], + "result": { + "type": "string" + }, + "type": "function" + } + }, + { + "name": "yaml.unmarshal", + "decl": { + "args": [ + { + "type": "string" + } + ], + "result": { + "type": "any" + }, + "type": "function" + } + } + ], + "future_keywords": [ + "not" + ], + "wasm_abi_versions": [ + { + "version": 1, + "minor_version": 1 + }, + { + "version": 1, + "minor_version": 2 + } + ], + "features": [ + "keywords_in_refs", + "rego_v1", + "template_strings" + ] +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/compiler/wasm/opa/opa.wasm b/vendor/github.com/open-policy-agent/opa/internal/compiler/wasm/opa/opa.wasm index a294543e8823f45b8ce4ecfd1387e7a9c8b41663..25d39a83e97bc76efef0300f0473a4d77cf9e22f 100644 GIT binary patch delta 40 qcmdn8R%**ysSVfo8JU`|^S58;X9Qv arg2 + ge + Returns the boolean truth of arg1 >= arg2 + +For simpler multi-way equality tests, eq (only) accepts two or more +arguments and compares the second and subsequent to the first, +returning in effect + + arg1==arg2 || arg1==arg3 || arg1==arg4 ... + +(Unlike with || in Go, however, eq is a function call and all the +arguments will be evaluated.) + +The comparison functions work on any values whose type Go defines as +comparable. For basic types such as integers, the rules are relaxed: +size and exact type are ignored, so any integer value, signed or unsigned, +may be compared with any other integer value. (The arithmetic value is compared, +not the bit pattern, so all negative integers are less than all unsigned integers.) +However, as usual, one may not compare an int with a float32 and so on. + +Associated templates + +Each template is named by a string specified when it is created. Also, each +template is associated with zero or more other templates that it may invoke by +name; such associations are transitive and form a name space of templates. + +A template may use a template invocation to instantiate another associated +template; see the explanation of the "template" action above. The name must be +that of a template associated with the template that contains the invocation. + +Nested template definitions + +When parsing a template, another template may be defined and associated with the +template being parsed. Template definitions must appear at the top level of the +template, much like global variables in a Go program. + +The syntax of such definitions is to surround each template declaration with a +"define" and "end" action. + +The define action names the template being created by providing a string +constant. Here is a simple example: + + {{define "T1"}}ONE{{end}} + {{define "T2"}}TWO{{end}} + {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}} + {{template "T3"}} + +This defines two templates, T1 and T2, and a third T3 that invokes the other two +when it is executed. Finally it invokes T3. If executed this template will +produce the text + + ONE TWO + +By construction, a template may reside in only one association. If it's +necessary to have a template addressable from multiple associations, the +template definition must be parsed multiple times to create distinct *Template +values, or must be copied with [Template.Clone] or [Template.AddParseTree]. + +Parse may be called multiple times to assemble the various associated templates; +see [ParseFiles], [ParseGlob], [Template.ParseFiles] and [Template.ParseGlob] +for simple ways to parse related templates stored in files. + +A template may be executed directly or through [Template.ExecuteTemplate], which executes +an associated template identified by name. To invoke our example above, we +might write, + + err := tmpl.Execute(os.Stdout, "no data needed") + if err != nil { + log.Fatalf("execution failed: %s", err) + } + +or to invoke a particular template explicitly by name, + + err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed") + if err != nil { + log.Fatalf("execution failed: %s", err) + } + +*/ +package template diff --git a/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/exec.go b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/exec.go new file mode 100644 index 0000000000..0ed449b937 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/exec.go @@ -0,0 +1,1132 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "errors" + "fmt" + "io" + "reflect" + "runtime" + "strings" + "text/template/parse" + + "github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort" +) + +// maxExecDepth specifies the maximum stack depth of templates within +// templates. This limit is only practically reached by accidentally +// recursive template invocations. This limit allows us to return +// an error instead of triggering a stack overflow. +var maxExecDepth = initMaxExecDepth() + +func initMaxExecDepth() int { + if runtime.GOARCH == "wasm" { + return 1000 + } + return 100000 +} + +// state represents the state of an execution. It's not part of the +// template so that multiple executions of the same template +// can execute in parallel. +type state struct { + tmpl *Template + wr io.Writer + node parse.Node // current node, for errors + vars []variable // push-down stack of variable values. + depth int // the height of the stack of executing templates. +} + +// variable holds the dynamic value of a variable such as $, $x etc. +type variable struct { + name string + value reflect.Value +} + +// push pushes a new variable on the stack. +func (s *state) push(name string, value reflect.Value) { + s.vars = append(s.vars, variable{name, value}) +} + +// mark returns the length of the variable stack. +func (s *state) mark() int { + return len(s.vars) +} + +// pop pops the variable stack up to the mark. +func (s *state) pop(mark int) { + s.vars = s.vars[0:mark] +} + +// setVar overwrites the last declared variable with the given name. +// Used by variable assignments. +func (s *state) setVar(name string, value reflect.Value) { + for i := s.mark() - 1; i >= 0; i-- { + if s.vars[i].name == name { + s.vars[i].value = value + return + } + } + s.errorf("undefined variable: %s", name) +} + +// setTopVar overwrites the top-nth variable on the stack. Used by range iterations. +func (s *state) setTopVar(n int, value reflect.Value) { + s.vars[len(s.vars)-n].value = value +} + +// varValue returns the value of the named variable. +func (s *state) varValue(name string) reflect.Value { + for i := s.mark() - 1; i >= 0; i-- { + if s.vars[i].name == name { + return s.vars[i].value + } + } + s.errorf("undefined variable: %s", name) + return zero +} + +var zero reflect.Value + +type missingValType struct{} + +var missingVal = reflect.ValueOf(missingValType{}) + +var missingValReflectType = reflect.TypeFor[missingValType]() + +func isMissing(v reflect.Value) bool { + return v.IsValid() && v.Type() == missingValReflectType +} + +// at marks the state to be on node n, for error reporting. +func (s *state) at(node parse.Node) { + s.node = node +} + +// doublePercent returns the string with %'s replaced by %%, if necessary, +// so it can be used safely inside a Printf format string. +func doublePercent(str string) string { + return strings.ReplaceAll(str, "%", "%%") +} + +// TODO: It would be nice if ExecError was more broken down, but +// the way ErrorContext embeds the template name makes the +// processing too clumsy. + +// ExecError is the custom error type returned when Execute has an +// error evaluating its template. (If a write error occurs, the actual +// error is returned; it will not be of type ExecError.) +type ExecError struct { + Name string // Name of template. + Err error // Pre-formatted error. +} + +func (e ExecError) Error() string { + return e.Err.Error() +} + +func (e ExecError) Unwrap() error { + return e.Err +} + +// errorf records an ExecError and terminates processing. +func (s *state) errorf(format string, args ...any) { + name := doublePercent(s.tmpl.Name()) + if s.node == nil { + format = fmt.Sprintf("template: %s: %s", name, format) + } else { + location, context := s.tmpl.ErrorContext(s.node) + format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format) + } + panic(ExecError{ + Name: s.tmpl.Name(), + Err: fmt.Errorf(format, args...), + }) +} + +// writeError is the wrapper type used internally when Execute has an +// error writing to its output. We strip the wrapper in errRecover. +// Note that this is not an implementation of error, so it cannot escape +// from the package as an error value. +type writeError struct { + Err error // Original error. +} + +func (s *state) writeError(err error) { + panic(writeError{ + Err: err, + }) +} + +// errRecover is the handler that turns panics into returns from the top +// level of Parse. +func errRecover(errp *error) { + e := recover() + if e != nil { + switch err := e.(type) { + case runtime.Error: + panic(e) + case writeError: + *errp = err.Err // Strip the wrapper. + case ExecError: + *errp = err // Keep the wrapper. + default: + panic(e) + } + } +} + +// ExecuteTemplate applies the template associated with t that has the given name +// to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { + tmpl := t.Lookup(name) + if tmpl == nil { + return fmt.Errorf("template: no template %q associated with template %q", name, t.name) + } + return tmpl.Execute(wr, data) +} + +// Execute applies a parsed template to the specified data object, +// and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +// +// If data is a [reflect.Value], the template applies to the concrete +// value that the reflect.Value holds, as in [fmt.Print]. +func (t *Template) Execute(wr io.Writer, data any) error { + return t.execute(wr, data) +} + +func (t *Template) execute(wr io.Writer, data any) (err error) { + defer errRecover(&err) + value, ok := data.(reflect.Value) + if !ok { + value = reflect.ValueOf(data) + } + state := &state{ + tmpl: t, + wr: wr, + vars: []variable{{"$", value}}, + } + if t.Tree == nil || t.Root == nil { + state.errorf("%q is an incomplete or empty template", t.Name()) + } + state.walk(value, t.Root) + return +} + +// DefinedTemplates returns a string listing the defined templates, +// prefixed by the string "; defined templates are: ". If there are none, +// it returns the empty string. For generating an error message here +// and in [html/template]. +func (t *Template) DefinedTemplates() string { + if t.common == nil { + return "" + } + var b strings.Builder + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + for name, tmpl := range t.tmpl { + if tmpl.Tree == nil || tmpl.Root == nil { + continue + } + if b.Len() == 0 { + b.WriteString("; defined templates are: ") + } else { + b.WriteString(", ") + } + fmt.Fprintf(&b, "%q", name) + } + return b.String() +} + +// Sentinel errors for use with panic to signal early exits from range loops. +var ( + walkBreak = errors.New("break") + walkContinue = errors.New("continue") +) + +// Walk functions step through the major pieces of the template structure, +// generating output as they go. +func (s *state) walk(dot reflect.Value, node parse.Node) { + s.at(node) + switch node := node.(type) { + case *parse.ActionNode: + // Do not pop variables so they persist until next end. + // Also, if the action declares variables, don't print the result. + val := s.evalPipeline(dot, node.Pipe) + if len(node.Pipe.Decl) == 0 { + s.printValue(node, val) + } + case *parse.BreakNode: + panic(walkBreak) + case *parse.CommentNode: + case *parse.ContinueNode: + panic(walkContinue) + case *parse.IfNode: + s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + case *parse.ListNode: + for _, node := range node.Nodes { + s.walk(dot, node) + } + case *parse.RangeNode: + s.walkRange(dot, node) + case *parse.TemplateNode: + s.walkTemplate(dot, node) + case *parse.TextNode: + if _, err := s.wr.Write(node.Text); err != nil { + s.writeError(err) + } + case *parse.WithNode: + s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) + default: + s.errorf("unknown node: %s", node) + } +} + +// walkIfOrWith walks an 'if' or 'with' node. The two control structures +// are identical in behavior except that 'with' sets dot. +func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) { + defer s.pop(s.mark()) + val := s.evalPipeline(dot, pipe) + truth, ok := isTrue(indirectInterface(val)) + if !ok { + s.errorf("if/with can't use %v", val) + } + if truth { + if typ == parse.NodeWith { + s.walk(val, list) + } else { + s.walk(dot, list) + } + } else if elseList != nil { + s.walk(dot, elseList) + } +} + +// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, +// and whether the value has a meaningful truth value. This is the definition of +// truth used by if and other such actions. +func IsTrue(val any) (truth, ok bool) { + return isTrue(reflect.ValueOf(val)) +} + +func isTrue(val reflect.Value) (truth, ok bool) { + if !val.IsValid() { + // Something like var x interface{}, never set. It's a form of nil. + return false, true + } + switch val.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + truth = val.Len() > 0 + case reflect.Bool: + truth = val.Bool() + case reflect.Complex64, reflect.Complex128: + truth = val.Complex() != 0 + case reflect.Chan, reflect.Func, reflect.Pointer, reflect.UnsafePointer, reflect.Interface: + truth = !val.IsNil() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + truth = val.Int() != 0 + case reflect.Float32, reflect.Float64: + truth = val.Float() != 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + truth = val.Uint() != 0 + case reflect.Struct: + truth = true // Struct values are always true. + default: + return + } + return truth, true +} + +func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { + s.at(r) + defer func() { + if r := recover(); r != nil && r != walkBreak { + panic(r) + } + }() + defer s.pop(s.mark()) + val, _ := indirect(s.evalPipeline(dot, r.Pipe)) + // mark top of stack before any variables in the body are pushed. + mark := s.mark() + oneIteration := func(index, elem reflect.Value) { + if len(r.Pipe.Decl) > 0 { + if r.Pipe.IsAssign { + // With two variables, index comes first. + // With one, we use the element. + if len(r.Pipe.Decl) > 1 { + s.setVar(r.Pipe.Decl[0].Ident[0], index) + } else { + s.setVar(r.Pipe.Decl[0].Ident[0], elem) + } + } else { + // Set top var (lexically the second if there + // are two) to the element. + s.setTopVar(1, elem) + } + } + if len(r.Pipe.Decl) > 1 { + if r.Pipe.IsAssign { + s.setVar(r.Pipe.Decl[1].Ident[0], elem) + } else { + // Set next var (lexically the first if there + // are two) to the index. + s.setTopVar(2, index) + } + } + defer s.pop(mark) + defer func() { + // Consume panic(walkContinue) + if r := recover(); r != nil && r != walkContinue { + panic(r) + } + }() + s.walk(elem, r.List) + } + switch val.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + if len(r.Pipe.Decl) > 1 { + s.errorf("can't use %v to iterate over more than one variable", val) + break + } + run := false + for v := range val.Seq() { + run = true + // Pass element as second value, as we do for channels. + oneIteration(reflect.Value{}, v) + } + if !run { + break + } + return + case reflect.Array, reflect.Slice: + if val.Len() == 0 { + break + } + for i := 0; i < val.Len(); i++ { + oneIteration(reflect.ValueOf(i), val.Index(i)) + } + return + case reflect.Map: + if val.Len() == 0 { + break + } + om := fmtsort.Sort(val) + for _, m := range om { + oneIteration(m.Key, m.Value) + } + return + case reflect.Chan: + if val.IsNil() { + break + } + if val.Type().ChanDir() == reflect.SendDir { + s.errorf("range over send-only channel %v", val) + break + } + i := 0 + for ; ; i++ { + elem, ok := val.Recv() + if !ok { + break + } + oneIteration(reflect.ValueOf(i), elem) + } + if i == 0 { + break + } + return + case reflect.Invalid: + break // An invalid value is likely a nil map, etc. and acts like an empty map. + case reflect.Func: + if val.Type().CanSeq() { + if len(r.Pipe.Decl) > 1 { + s.errorf("can't use %v iterate over more than one variable", val) + break + } + run := false + for v := range val.Seq() { + run = true + // Pass element as second value, + // as we do for channels. + oneIteration(reflect.Value{}, v) + } + if !run { + break + } + return + } + if val.Type().CanSeq2() { + run := false + for i, v := range val.Seq2() { + run = true + if len(r.Pipe.Decl) > 1 { + oneIteration(i, v) + } else { + // If there is only one range variable, + // oneIteration will use the + // second value. + oneIteration(reflect.Value{}, i) + } + } + if !run { + break + } + return + } + fallthrough + default: + s.errorf("range can't iterate over %v", val) + } + if r.ElseList != nil { + s.walk(dot, r.ElseList) + } +} + +func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { + s.at(t) + tmpl := s.tmpl.Lookup(t.Name) + if tmpl == nil { + s.errorf("template %q not defined", t.Name) + } + if s.depth == maxExecDepth { + s.errorf("exceeded maximum template depth (%v)", maxExecDepth) + } + // Variables declared by the pipeline persist. + dot = s.evalPipeline(dot, t.Pipe) + newState := *s + newState.depth++ + newState.tmpl = tmpl + // No dynamic scoping: template invocations inherit no variables. + newState.vars = []variable{{"$", dot}} + newState.walk(dot, tmpl.Root) +} + +// Eval functions evaluate pipelines, commands, and their elements and extract +// values from the data structure by examining fields, calling methods, and so on. +// The printing of those values happens only through walk functions. + +// evalPipeline returns the value acquired by evaluating a pipeline. If the +// pipeline has a variable declaration, the variable will be pushed on the +// stack. Callers should therefore pop the stack after they are finished +// executing commands depending on the pipeline value. +func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) { + if pipe == nil { + return + } + s.at(pipe) + value = missingVal + for _, cmd := range pipe.Cmds { + value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. + // If the object has type interface{}, dig down one level to the thing inside. + if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { + value = value.Elem() + } + } + for _, variable := range pipe.Decl { + if pipe.IsAssign { + s.setVar(variable.Ident[0], value) + } else { + s.push(variable.Ident[0], value) + } + } + return value +} + +func (s *state) notAFunction(args []parse.Node, final reflect.Value) { + if len(args) > 1 || !isMissing(final) { + s.errorf("can't give argument to non-function %s", args[0]) + } +} + +func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value { + firstWord := cmd.Args[0] + switch n := firstWord.(type) { + case *parse.FieldNode: + return s.evalFieldNode(dot, n, cmd.Args, final) + case *parse.ChainNode: + return s.evalChainNode(dot, n, cmd.Args, final) + case *parse.IdentifierNode: + // Must be a function. + return s.evalFunction(dot, n, cmd, cmd.Args, final) + case *parse.PipeNode: + // Parenthesized pipeline. The arguments are all inside the pipeline; final must be absent. + s.notAFunction(cmd.Args, final) + return s.evalPipeline(dot, n) + case *parse.VariableNode: + return s.evalVariableNode(dot, n, cmd.Args, final) + } + s.at(firstWord) + s.notAFunction(cmd.Args, final) + switch word := firstWord.(type) { + case *parse.BoolNode: + return reflect.ValueOf(word.True) + case *parse.DotNode: + return dot + case *parse.NilNode: + s.errorf("nil is not a command") + case *parse.NumberNode: + return s.idealConstant(word) + case *parse.StringNode: + return reflect.ValueOf(word.Text) + } + s.errorf("can't evaluate command %q", firstWord) + panic("not reached") +} + +// idealConstant is called to return the value of a number in a context where +// we don't know the type. In that case, the syntax of the number tells us +// its type, and we use Go rules to resolve. Note there is no such thing as +// a uint ideal constant in this situation - the value must be of int type. +func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value { + // These are ideal constants but we don't know the type + // and we have no context. (If it was a method argument, + // we'd know what we need.) The syntax guides us to some extent. + s.at(constant) + switch { + case constant.IsComplex: + return reflect.ValueOf(constant.Complex128) // incontrovertible. + + case constant.IsFloat && + !isHexInt(constant.Text) && !isRuneInt(constant.Text) && + strings.ContainsAny(constant.Text, ".eEpP"): + return reflect.ValueOf(constant.Float64) + + case constant.IsInt: + n := int(constant.Int64) + if int64(n) != constant.Int64 { + s.errorf("%s overflows int", constant.Text) + } + return reflect.ValueOf(n) + + case constant.IsUint: + s.errorf("%s overflows int", constant.Text) + } + return zero +} + +func isRuneInt(s string) bool { + return len(s) > 0 && s[0] == '\'' +} + +func isHexInt(s string) bool { + return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && !strings.ContainsAny(s, "pP") +} + +func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value { + s.at(field) + return s.evalFieldChain(dot, dot, field, field.Ident, args, final) +} + +func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value { + s.at(chain) + if len(chain.Field) == 0 { + s.errorf("internal error: no fields in evalChainNode") + } + if chain.Node.Type() == parse.NodeNil { + s.errorf("indirection through explicit nil in %s", chain) + } + // (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields. + pipe := s.evalArg(dot, nil, chain.Node) + return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final) +} + +func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value { + // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields. + s.at(variable) + value := s.varValue(variable.Ident[0]) + if len(variable.Ident) == 1 { + s.notAFunction(args, final) + return value + } + return s.evalFieldChain(dot, value, variable, variable.Ident[1:], args, final) +} + +// evalFieldChain evaluates .X.Y.Z possibly followed by arguments. +// dot is the environment in which to evaluate arguments, while +// receiver is the value being walked along the chain. +func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value { + n := len(ident) + for i := 0; i < n-1; i++ { + receiver = s.evalField(dot, ident[i], node, nil, missingVal, receiver) + } + // Now if it's a method, it gets the arguments. + return s.evalField(dot, ident[n-1], node, args, final, receiver) +} + +func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value { + s.at(node) + name := node.Ident + function, isBuiltin, ok := findFunction(name, s.tmpl) + if !ok { + s.errorf("%q is not a defined function", name) + } + return s.evalCall(dot, function, isBuiltin, cmd, name, args, final) +} + +// evalField evaluates an expression like (.Field) or (.Field arg1 arg2). +// The 'final' argument represents the return value from the preceding +// value of the pipeline, if any. +func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value { + if !receiver.IsValid() { + if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key. + s.errorf("nil data; no entry for key %q", fieldName) + } + return zero + } + typ := receiver.Type() + receiver, isNil := indirect(receiver) + if receiver.Kind() == reflect.Interface && isNil { + // Indexing into a nil interface can't work. + s.errorf("nil pointer evaluating %s.%s", typ, fieldName) + return zero + } + + // OPA-DCE (#7903): the upstream text/template resolves methods on the data + // value here via reflect.Value.MethodByName. A reachable non-constant + // MethodByName disables the Go linker's method-level dead-code elimination + // binary-wide (golang/go#72895), so that branch is deliberately removed. + // Rego values (and gojsonschema ErrorDetails) decode to + // map[string]any/[]any/scalars, which have no methods, so field/element + // resolution below is the only path OPA's callers need. + hasArgs := len(args) > 1 || !isMissing(final) + // It's not a method; must be a field of a struct or an element of a map. + switch receiver.Kind() { + case reflect.Struct: + tField, ok := receiver.Type().FieldByName(fieldName) + if ok { + field, err := receiver.FieldByIndexErr(tField.Index) + if !tField.IsExported() { + s.errorf("%s is an unexported field of struct type %s", fieldName, typ) + } + if err != nil { + s.errorf("%v", err) + } + // If it's a function, we must call it. + if hasArgs { + s.errorf("%s has arguments but cannot be invoked as function", fieldName) + } + return field + } + case reflect.Map: + // If it's a map, attempt to use the field name as a key. + nameVal := reflect.ValueOf(fieldName) + if nameVal.Type().AssignableTo(receiver.Type().Key()) { + if hasArgs { + s.errorf("%s is not a method but has arguments", fieldName) + } + result := receiver.MapIndex(nameVal) + if !result.IsValid() { + switch s.tmpl.option.missingKey { + case mapInvalid: + // Just use the invalid value. + case mapZeroValue: + result = reflect.Zero(receiver.Type().Elem()) + case mapError: + s.errorf("map has no entry for key %q", fieldName) + } + } + return result + } + case reflect.Pointer: + etyp := receiver.Type().Elem() + if etyp.Kind() == reflect.Struct { + if _, ok := etyp.FieldByName(fieldName); !ok { + // If there's no such field, say "can't evaluate" + // instead of "nil pointer evaluating". + break + } + } + if isNil { + s.errorf("nil pointer evaluating %s.%s", typ, fieldName) + } + } + s.errorf("can't evaluate field %s in type %s", fieldName, typ) + panic("not reached") +} + +var ( + errorType = reflect.TypeFor[error]() + fmtStringerType = reflect.TypeFor[fmt.Stringer]() + reflectValueType = reflect.TypeFor[reflect.Value]() +) + +// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so +// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0] +// as the function itself. +func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value { + if args != nil { + args = args[1:] // Zeroth arg is function name/node; not passed to function. + } + typ := fun.Type() + numIn := len(args) + if !isMissing(final) { + numIn++ + } + numFixed := len(args) + if typ.IsVariadic() { + numFixed = typ.NumIn() - 1 // last arg is the variadic one. + if numIn < numFixed { + s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args)) + } + } else if numIn != typ.NumIn() { + s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn) + } + if err := goodFunc(name, typ); err != nil { + s.errorf("%v", err) + } + + unwrap := func(v reflect.Value) reflect.Value { + if v.Type() == reflectValueType { + v = v.Interface().(reflect.Value) + } + return v + } + + // Special case for builtin and/or, which short-circuit. + if isBuiltin && (name == "and" || name == "or") { + argType := typ.In(0) + var v reflect.Value + for _, arg := range args { + v = s.evalArg(dot, argType, arg).Interface().(reflect.Value) + if truth(v) == (name == "or") { + // This value was already unwrapped + // by the .Interface().(reflect.Value). + return v + } + } + if !final.Equal(missingVal) { + // The last argument to and/or is coming from + // the pipeline. We didn't short circuit on an earlier + // argument, so we are going to return this one. + // We don't have to evaluate final, but we do + // have to check its type. Then, since we are + // going to return it, we have to unwrap it. + v = unwrap(s.validateType(final, argType)) + } + return v + } + + // Build the arg list. + argv := make([]reflect.Value, numIn) + // Args must be evaluated. Fixed args first. + i := 0 + for ; i < numFixed && i < len(args); i++ { + argv[i] = s.evalArg(dot, typ.In(i), args[i]) + } + // Now the ... args. + if typ.IsVariadic() { + argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice. + for ; i < len(args); i++ { + argv[i] = s.evalArg(dot, argType, args[i]) + } + } + // Add final value if necessary. + if !isMissing(final) { + t := typ.In(typ.NumIn() - 1) + if typ.IsVariadic() { + if numIn-1 < numFixed { + // The added final argument corresponds to a fixed parameter of the function. + // Validate against the type of the actual parameter. + t = typ.In(numIn - 1) + } else { + // The added final argument corresponds to the variadic part. + // Validate against the type of the elements of the variadic slice. + t = t.Elem() + } + } + argv[i] = s.validateType(final, t) + } + + // Special case for the "call" builtin. + // Insert the name of the callee function as the first argument. + if isBuiltin && name == "call" { + var calleeName string + if len(args) == 0 { + // final must be present or we would have errored out above. + calleeName = final.String() + } else { + calleeName = args[0].String() + } + argv = append([]reflect.Value{reflect.ValueOf(calleeName)}, argv...) + fun = reflect.ValueOf(call) + } + + v, err := safeCall(fun, argv) + // If we have an error that is not nil, stop execution and return that + // error to the caller. + if err != nil { + s.at(node) + s.errorf("error calling %s: %w", name, err) + } + return unwrap(v) +} + +// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. +func canBeNil(typ reflect.Type) bool { + switch typ.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: + return true + case reflect.Struct: + return typ == reflectValueType + } + return false +} + +// validateType guarantees that the value is valid and assignable to the type. +func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value { + if !value.IsValid() { + if typ == nil { + // An untyped nil interface{}. Accept as a proper nil value. + return reflect.ValueOf(nil) + } + if canBeNil(typ) { + // Like above, but use the zero value of the non-nil type. + return reflect.Zero(typ) + } + s.errorf("invalid value; expected %s", typ) + } + if typ == reflectValueType && value.Type() != typ { + return reflect.ValueOf(value) + } + if typ != nil && !value.Type().AssignableTo(typ) { + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + if value.Type().AssignableTo(typ) { + return value + } + // fallthrough + } + // Does one dereference or indirection work? We could do more, as we + // do with method receivers, but that gets messy and method receivers + // are much more constrained, so it makes more sense there than here. + // Besides, one is almost always all you need. + switch { + case value.Kind() == reflect.Pointer && value.Type().Elem().AssignableTo(typ): + value = value.Elem() + if !value.IsValid() { + s.errorf("dereference of nil pointer of type %s", typ) + } + case reflect.PointerTo(value.Type()).AssignableTo(typ) && value.CanAddr(): + value = value.Addr() + default: + s.errorf("wrong type for value; expected %s; got %s", typ, value.Type()) + } + } + return value +} + +func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + switch arg := n.(type) { + case *parse.DotNode: + return s.validateType(dot, typ) + case *parse.NilNode: + if canBeNil(typ) { + return reflect.Zero(typ) + } + s.errorf("cannot assign nil to %s", typ) + case *parse.FieldNode: + return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, missingVal), typ) + case *parse.VariableNode: + return s.validateType(s.evalVariableNode(dot, arg, nil, missingVal), typ) + case *parse.PipeNode: + return s.validateType(s.evalPipeline(dot, arg), typ) + case *parse.IdentifierNode: + return s.validateType(s.evalFunction(dot, arg, arg, nil, missingVal), typ) + case *parse.ChainNode: + return s.validateType(s.evalChainNode(dot, arg, nil, missingVal), typ) + } + switch typ.Kind() { + case reflect.Bool: + return s.evalBool(typ, n) + case reflect.Complex64, reflect.Complex128: + return s.evalComplex(typ, n) + case reflect.Float32, reflect.Float64: + return s.evalFloat(typ, n) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return s.evalInteger(typ, n) + case reflect.Interface: + if typ.NumMethod() == 0 { + return s.evalEmptyInterface(dot, n) + } + case reflect.Struct: + if typ == reflectValueType { + return reflect.ValueOf(s.evalEmptyInterface(dot, n)) + } + case reflect.String: + return s.evalString(typ, n) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return s.evalUnsignedInteger(typ, n) + } + s.errorf("can't handle %s for arg of type %s", n, typ) + panic("not reached") +} + +func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.BoolNode); ok { + value := reflect.New(typ).Elem() + value.SetBool(n.True) + return value + } + s.errorf("expected bool; found %s", n) + panic("not reached") +} + +func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.StringNode); ok { + value := reflect.New(typ).Elem() + value.SetString(n.Text) + return value + } + s.errorf("expected string; found %s", n) + panic("not reached") +} + +func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.NumberNode); ok && n.IsInt { + value := reflect.New(typ).Elem() + value.SetInt(n.Int64) + return value + } + s.errorf("expected integer; found %s", n) + panic("not reached") +} + +func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.NumberNode); ok && n.IsUint { + value := reflect.New(typ).Elem() + value.SetUint(n.Uint64) + return value + } + s.errorf("expected unsigned integer; found %s", n) + panic("not reached") +} + +func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value { + s.at(n) + if n, ok := n.(*parse.NumberNode); ok && n.IsFloat { + value := reflect.New(typ).Elem() + value.SetFloat(n.Float64) + return value + } + s.errorf("expected float; found %s", n) + panic("not reached") +} + +func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value { + if n, ok := n.(*parse.NumberNode); ok && n.IsComplex { + value := reflect.New(typ).Elem() + value.SetComplex(n.Complex128) + return value + } + s.errorf("expected complex; found %s", n) + panic("not reached") +} + +func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value { + s.at(n) + switch n := n.(type) { + case *parse.BoolNode: + return reflect.ValueOf(n.True) + case *parse.DotNode: + return dot + case *parse.FieldNode: + return s.evalFieldNode(dot, n, nil, missingVal) + case *parse.IdentifierNode: + return s.evalFunction(dot, n, n, nil, missingVal) + case *parse.NilNode: + // NilNode is handled in evalArg, the only place that calls here. + s.errorf("evalEmptyInterface: nil (can't happen)") + case *parse.NumberNode: + return s.idealConstant(n) + case *parse.StringNode: + return reflect.ValueOf(n.Text) + case *parse.VariableNode: + return s.evalVariableNode(dot, n, nil, missingVal) + case *parse.PipeNode: + return s.evalPipeline(dot, n) + } + s.errorf("can't handle assignment of %s to empty interface argument", n) + panic("not reached") +} + +// indirect returns the item at the end of indirection, and a bool to indicate +// if it's nil. If the returned bool is true, the returned value's kind will be +// either a pointer or interface. +func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { + for ; v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface; v = v.Elem() { + if v.IsNil() { + return v, true + } + } + return v, false +} + +// indirectInterface returns the concrete value in an interface value, +// or else the zero reflect.Value. +// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x): +// the fact that x was an interface value is forgotten. +func indirectInterface(v reflect.Value) reflect.Value { + if v.Kind() != reflect.Interface { + return v + } + if v.IsNil() { + return reflect.Value{} + } + return v.Elem() +} + +// printValue writes the textual representation of the value to the output of +// the template. +func (s *state) printValue(n parse.Node, v reflect.Value) { + s.at(n) + iface, ok := printableValue(v) + if !ok { + s.errorf("can't print %s of type %s", n, v.Type()) + } + _, err := fmt.Fprint(s.wr, iface) + if err != nil { + s.writeError(err) + } +} + +// printableValue returns the, possibly indirected, interface value inside v that +// is best for a call to formatted printer. +func printableValue(v reflect.Value) (any, bool) { + if v.Kind() == reflect.Pointer { + v, _ = indirect(v) // fmt.Fprint handles nil. + } + if !v.IsValid() { + return "", true + } + + if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) { + if v.CanAddr() && (reflect.PointerTo(v.Type()).Implements(errorType) || reflect.PointerTo(v.Type()).Implements(fmtStringerType)) { + v = v.Addr() + } else { + switch v.Kind() { + case reflect.Chan, reflect.Func: + return nil, false + } + } + } + return v.Interface(), true +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/funcs.go b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/funcs.go new file mode 100644 index 0000000000..4d733135fe --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/funcs.go @@ -0,0 +1,783 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "errors" + "fmt" + "io" + "net/url" + "reflect" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// FuncMap is the type of the map defining the mapping from names to functions. +// Each function must have either a single return value, or two return values of +// which the second has type error. In that case, if the second (error) +// return value evaluates to non-nil during execution, execution terminates and +// Execute returns that error. +// +// Errors returned by Execute wrap the underlying error; call [errors.As] to +// unwrap them. +// +// When template execution invokes a function with an argument list, that list +// must be assignable to the function's parameter types. Functions meant to +// apply to arguments of arbitrary type can use parameters of type interface{} or +// of type [reflect.Value]. Similarly, functions meant to return a result of arbitrary +// type can return interface{} or [reflect.Value]. +type FuncMap map[string]any + +// builtins returns the FuncMap. +// It is not a global variable so the linker can dead code eliminate +// more when this isn't called. See golang.org/issue/36021. +// TODO: revert this back to a global map once golang.org/issue/2559 is fixed. +func builtins() FuncMap { + return FuncMap{ + "and": and, + "call": emptyCall, + "html": HTMLEscaper, + "index": index, + "slice": slice, + "js": JSEscaper, + "len": length, + "not": not, + "or": or, + "print": fmt.Sprint, + "printf": fmt.Sprintf, + "println": fmt.Sprintln, + "urlquery": URLQueryEscaper, + + // Comparisons + "eq": eq, // == + "ge": ge, // >= + "gt": gt, // > + "le": le, // <= + "lt": lt, // < + "ne": ne, // != + } +} + +var builtinFuncsOnce struct { + sync.Once + v map[string]reflect.Value +} + +// builtinFuncsOnce lazily computes & caches the builtinFuncs map. +// TODO: revert this back to a global map once golang.org/issue/2559 is fixed. +func builtinFuncs() map[string]reflect.Value { + builtinFuncsOnce.Do(func() { + builtinFuncsOnce.v = createValueFuncs(builtins()) + }) + return builtinFuncsOnce.v +} + +// createValueFuncs turns a FuncMap into a map[string]reflect.Value +func createValueFuncs(funcMap FuncMap) map[string]reflect.Value { + m := make(map[string]reflect.Value) + addValueFuncs(m, funcMap) + return m +} + +// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values. +func addValueFuncs(out map[string]reflect.Value, in FuncMap) { + for name, fn := range in { + if !goodName(name) { + panic(fmt.Errorf("function name %q is not a valid identifier", name)) + } + v := reflect.ValueOf(fn) + if v.Kind() != reflect.Func { + panic("value for " + name + " not a function") + } + if err := goodFunc(name, v.Type()); err != nil { + panic(err) + } + out[name] = v + } +} + +// addFuncs adds to values the functions in funcs. It does no checking of the input - +// call addValueFuncs first. +func addFuncs(out, in FuncMap) { + for name, fn := range in { + out[name] = fn + } +} + +// goodFunc reports whether the function or method has the right result signature. +func goodFunc(name string, typ reflect.Type) error { + // We allow functions with 1 result or 2 results where the second is an error. + switch numOut := typ.NumOut(); { + case numOut == 1: + return nil + case numOut == 2 && typ.Out(1) == errorType: + return nil + case numOut == 2: + return fmt.Errorf("invalid function signature for %s: second return value should be error; is %s", name, typ.Out(1)) + default: + return fmt.Errorf("function %s has %d return values; should be 1 or 2", name, typ.NumOut()) + } +} + +// goodName reports whether the function name is a valid identifier. +func goodName(name string) bool { + if name == "" { + return false + } + for i, r := range name { + switch { + case r == '_': + case i == 0 && !unicode.IsLetter(r): + return false + case !unicode.IsLetter(r) && !unicode.IsDigit(r): + return false + } + } + return true +} + +// findFunction looks for a function in the template, and global map. +func findFunction(name string, tmpl *Template) (v reflect.Value, isBuiltin, ok bool) { + if tmpl != nil && tmpl.common != nil { + tmpl.muFuncs.RLock() + defer tmpl.muFuncs.RUnlock() + if fn := tmpl.execFuncs[name]; fn.IsValid() { + return fn, false, true + } + } + if fn := builtinFuncs()[name]; fn.IsValid() { + return fn, true, true + } + return reflect.Value{}, false, false +} + +// prepareArg checks if value can be used as an argument of type argType, and +// converts an invalid value to appropriate zero if possible. +func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) { + if !value.IsValid() { + if !canBeNil(argType) { + return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType) + } + value = reflect.Zero(argType) + } + if value.Type().AssignableTo(argType) { + return value, nil + } + if intLike(value.Kind()) && intLike(argType.Kind()) && value.Type().ConvertibleTo(argType) { + value = value.Convert(argType) + return value, nil + } + return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType) +} + +func intLike(typ reflect.Kind) bool { + switch typ { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return true + } + return false +} + +// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible. +func indexArg(index reflect.Value, cap int) (int, error) { + var x int64 + switch index.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + x = index.Int() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + x = int64(index.Uint()) + case reflect.Invalid: + return 0, fmt.Errorf("cannot index slice/array with nil") + default: + return 0, fmt.Errorf("cannot index slice/array with type %s", index.Type()) + } + if x < 0 || int(x) < 0 || int(x) > cap { + return 0, fmt.Errorf("index out of range: %d", x) + } + return int(x), nil +} + +// Indexing. + +// index returns the result of indexing its first argument by the following +// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each +// indexed item must be a map, slice, or array. +func index(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) { + item = indirectInterface(item) + if !item.IsValid() { + return reflect.Value{}, fmt.Errorf("index of untyped nil") + } + for _, index := range indexes { + index = indirectInterface(index) + var isNil bool + if item, isNil = indirect(item); isNil { + return reflect.Value{}, fmt.Errorf("index of nil pointer") + } + switch item.Kind() { + case reflect.Array, reflect.Slice, reflect.String: + x, err := indexArg(index, item.Len()) + if err != nil { + return reflect.Value{}, err + } + item = item.Index(x) + case reflect.Map: + index, err := prepareArg(index, item.Type().Key()) + if err != nil { + return reflect.Value{}, err + } + if x := item.MapIndex(index); x.IsValid() { + item = x + } else { + item = reflect.Zero(item.Type().Elem()) + } + case reflect.Invalid: + // the loop holds invariant: item.IsValid() + panic("unreachable") + default: + return reflect.Value{}, fmt.Errorf("can't index item of type %s", item.Type()) + } + } + return item, nil +} + +// Slicing. + +// slice returns the result of slicing its first argument by the remaining +// arguments. Thus "slice x 1 2" is, in Go syntax, x[1:2], while "slice x" +// is x[:], "slice x 1" is x[1:], and "slice x 1 2 3" is x[1:2:3]. The first +// argument must be a string, slice, or array. +func slice(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) { + item = indirectInterface(item) + if !item.IsValid() { + return reflect.Value{}, fmt.Errorf("slice of untyped nil") + } + if len(indexes) > 3 { + return reflect.Value{}, fmt.Errorf("too many slice indexes: %d", len(indexes)) + } + var cap int + switch item.Kind() { + case reflect.String: + if len(indexes) == 3 { + return reflect.Value{}, fmt.Errorf("cannot 3-index slice a string") + } + cap = item.Len() + case reflect.Array, reflect.Slice: + cap = item.Cap() + default: + return reflect.Value{}, fmt.Errorf("can't slice item of type %s", item.Type()) + } + // set default values for cases item[:], item[i:]. + idx := [3]int{0, item.Len()} + for i, index := range indexes { + x, err := indexArg(index, cap) + if err != nil { + return reflect.Value{}, err + } + idx[i] = x + } + // given item[i:j], make sure i <= j. + if idx[0] > idx[1] { + return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[0], idx[1]) + } + if len(indexes) < 3 { + return item.Slice(idx[0], idx[1]), nil + } + // given item[i:j:k], make sure i <= j <= k. + if idx[1] > idx[2] { + return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[1], idx[2]) + } + return item.Slice3(idx[0], idx[1], idx[2]), nil +} + +// Length + +// length returns the length of the item, with an error if it has no defined length. +func length(item reflect.Value) (int, error) { + item, isNil := indirect(item) + if isNil { + return 0, fmt.Errorf("len of nil pointer") + } + switch item.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: + return item.Len(), nil + } + return 0, fmt.Errorf("len of type %s", item.Type()) +} + +// Function invocation + +func emptyCall(fn reflect.Value, args ...reflect.Value) reflect.Value { + panic("unreachable") // implemented as a special case in evalCall +} + +// call returns the result of evaluating the first argument as a function. +// The function must return 1 result, or 2 results, the second of which is an error. +func call(name string, fn reflect.Value, args ...reflect.Value) (reflect.Value, error) { + fn = indirectInterface(fn) + if !fn.IsValid() { + return reflect.Value{}, fmt.Errorf("call of nil") + } + typ := fn.Type() + if typ.Kind() != reflect.Func { + return reflect.Value{}, fmt.Errorf("non-function %s of type %s", name, typ) + } + + if err := goodFunc(name, typ); err != nil { + return reflect.Value{}, err + } + numIn := typ.NumIn() + var dddType reflect.Type + if typ.IsVariadic() { + if len(args) < numIn-1 { + return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want at least %d", name, len(args), numIn-1) + } + dddType = typ.In(numIn - 1).Elem() + } else { + if len(args) != numIn { + return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want %d", name, len(args), numIn) + } + } + argv := make([]reflect.Value, len(args)) + for i, arg := range args { + arg = indirectInterface(arg) + // Compute the expected type. Clumsy because of variadics. + argType := dddType + if !typ.IsVariadic() || i < numIn-1 { + argType = typ.In(i) + } + + var err error + if argv[i], err = prepareArg(arg, argType); err != nil { + return reflect.Value{}, fmt.Errorf("arg %d: %w", i, err) + } + } + return safeCall(fn, argv) +} + +// safeCall runs fun.Call(args), and returns the resulting value and error, if +// any. If the call panics, the panic value is returned as an error. +func safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else { + err = fmt.Errorf("%v", r) + } + } + }() + ret := fun.Call(args) + if len(ret) == 2 && !ret[1].IsNil() { + return ret[0], ret[1].Interface().(error) + } + return ret[0], nil +} + +// Boolean logic. + +func truth(arg reflect.Value) bool { + t, _ := isTrue(indirectInterface(arg)) + return t +} + +// and computes the Boolean AND of its arguments, returning +// the first false argument it encounters, or the last argument. +func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value { + panic("unreachable") // implemented as a special case in evalCall +} + +// or computes the Boolean OR of its arguments, returning +// the first true argument it encounters, or the last argument. +func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value { + panic("unreachable") // implemented as a special case in evalCall +} + +// not returns the Boolean negation of its argument. +func not(arg reflect.Value) bool { + return !truth(arg) +} + +// Comparison. + +// TODO: Perhaps allow comparison between signed and unsigned integers. + +var ( + errBadComparisonType = errors.New("invalid type for comparison") + errNoComparison = errors.New("missing argument for comparison") +) + +type kind int + +const ( + invalidKind kind = iota + boolKind + complexKind + intKind + floatKind + stringKind + uintKind +) + +func basicKind(v reflect.Value) (kind, error) { + switch v.Kind() { + case reflect.Bool: + return boolKind, nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return intKind, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return uintKind, nil + case reflect.Float32, reflect.Float64: + return floatKind, nil + case reflect.Complex64, reflect.Complex128: + return complexKind, nil + case reflect.String: + return stringKind, nil + } + return invalidKind, errBadComparisonType +} + +// isNil returns true if v is the zero reflect.Value, or nil of its type. +func isNil(v reflect.Value) bool { + if !v.IsValid() { + return true + } + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: + return v.IsNil() + } + return false +} + +// canCompare reports whether v1 and v2 are both the same kind, or one is nil. +// Called only when dealing with nillable types, or there's about to be an error. +func canCompare(v1, v2 reflect.Value) bool { + k1 := v1.Kind() + k2 := v2.Kind() + if k1 == k2 { + return true + } + // We know the type can be compared to nil. + return k1 == reflect.Invalid || k2 == reflect.Invalid +} + +// eq evaluates the comparison a == b || a == c || ... +func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) { + arg1 = indirectInterface(arg1) + if len(arg2) == 0 { + return false, errNoComparison + } + k1, _ := basicKind(arg1) + for _, arg := range arg2 { + arg = indirectInterface(arg) + k2, _ := basicKind(arg) + truth := false + if k1 != k2 { + // Special case: Can compare integer values regardless of type's sign. + switch { + case k1 == intKind && k2 == uintKind: + truth = arg1.Int() >= 0 && uint64(arg1.Int()) == arg.Uint() + case k1 == uintKind && k2 == intKind: + truth = arg.Int() >= 0 && arg1.Uint() == uint64(arg.Int()) + default: + if arg1.IsValid() && arg.IsValid() { + return false, fmt.Errorf("incompatible types for comparison: %v and %v", arg1.Type(), arg.Type()) + } + } + } else { + switch k1 { + case boolKind: + truth = arg1.Bool() == arg.Bool() + case complexKind: + truth = arg1.Complex() == arg.Complex() + case floatKind: + truth = arg1.Float() == arg.Float() + case intKind: + truth = arg1.Int() == arg.Int() + case stringKind: + truth = arg1.String() == arg.String() + case uintKind: + truth = arg1.Uint() == arg.Uint() + default: + if !canCompare(arg1, arg) { + return false, fmt.Errorf("non-comparable types %s: %v, %s: %v", arg1, arg1.Type(), arg.Type(), arg) + } + if isNil(arg1) || isNil(arg) { + truth = isNil(arg) == isNil(arg1) + } else { + if !arg.Type().Comparable() { + return false, fmt.Errorf("non-comparable type %s: %v", arg, arg.Type()) + } + truth = arg1.Interface() == arg.Interface() + } + } + } + if truth { + return true, nil + } + } + return false, nil +} + +// ne evaluates the comparison a != b. +func ne(arg1, arg2 reflect.Value) (bool, error) { + // != is the inverse of ==. + equal, err := eq(arg1, arg2) + return !equal, err +} + +// lt evaluates the comparison a < b. +func lt(arg1, arg2 reflect.Value) (bool, error) { + arg1 = indirectInterface(arg1) + k1, err := basicKind(arg1) + if err != nil { + return false, err + } + arg2 = indirectInterface(arg2) + k2, err := basicKind(arg2) + if err != nil { + return false, err + } + truth := false + if k1 != k2 { + // Special case: Can compare integer values regardless of type's sign. + switch { + case k1 == intKind && k2 == uintKind: + truth = arg1.Int() < 0 || uint64(arg1.Int()) < arg2.Uint() + case k1 == uintKind && k2 == intKind: + truth = arg2.Int() >= 0 && arg1.Uint() < uint64(arg2.Int()) + default: + return false, fmt.Errorf("incompatible types for comparison: %v and %v", arg1.Type(), arg2.Type()) + } + } else { + switch k1 { + case boolKind, complexKind: + return false, errBadComparisonType + case floatKind: + truth = arg1.Float() < arg2.Float() + case intKind: + truth = arg1.Int() < arg2.Int() + case stringKind: + truth = arg1.String() < arg2.String() + case uintKind: + truth = arg1.Uint() < arg2.Uint() + default: + panic("invalid kind") + } + } + return truth, nil +} + +// le evaluates the comparison <= b. +func le(arg1, arg2 reflect.Value) (bool, error) { + // <= is < or ==. + lessThan, err := lt(arg1, arg2) + if lessThan || err != nil { + return lessThan, err + } + return eq(arg1, arg2) +} + +// gt evaluates the comparison a > b. +func gt(arg1, arg2 reflect.Value) (bool, error) { + // > is the inverse of <=. + lessOrEqual, err := le(arg1, arg2) + if err != nil { + return false, err + } + return !lessOrEqual, nil +} + +// ge evaluates the comparison a >= b. +func ge(arg1, arg2 reflect.Value) (bool, error) { + // >= is the inverse of <. + lessThan, err := lt(arg1, arg2) + if err != nil { + return false, err + } + return !lessThan, nil +} + +// HTML escaping. + +var ( + htmlQuot = []byte(""") // shorter than """ + htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5 + htmlAmp = []byte("&") + htmlLt = []byte("<") + htmlGt = []byte(">") + htmlNull = []byte("\uFFFD") +) + +// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b. +func HTMLEscape(w io.Writer, b []byte) { + last := 0 + for i, c := range b { + var html []byte + switch c { + case '\000': + html = htmlNull + case '"': + html = htmlQuot + case '\'': + html = htmlApos + case '&': + html = htmlAmp + case '<': + html = htmlLt + case '>': + html = htmlGt + default: + continue + } + w.Write(b[last:i]) + w.Write(html) + last = i + 1 + } + w.Write(b[last:]) +} + +// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. +func HTMLEscapeString(s string) string { + // Avoid allocation if we can. + if !strings.ContainsAny(s, "'\"&<>\000") { + return s + } + var b strings.Builder + HTMLEscape(&b, []byte(s)) + return b.String() +} + +// HTMLEscaper returns the escaped HTML equivalent of the textual +// representation of its arguments. +func HTMLEscaper(args ...any) string { + return HTMLEscapeString(evalArgs(args)) +} + +// JavaScript escaping. + +var ( + jsLowUni = []byte(`\u00`) + hex = []byte("0123456789ABCDEF") + + jsBackslash = []byte(`\\`) + jsApos = []byte(`\'`) + jsQuot = []byte(`\"`) + jsLt = []byte(`\u003C`) + jsGt = []byte(`\u003E`) + jsAmp = []byte(`\u0026`) + jsEq = []byte(`\u003D`) +) + +// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. +func JSEscape(w io.Writer, b []byte) { + last := 0 + for i := 0; i < len(b); i++ { + c := b[i] + + if !jsIsSpecial(rune(c)) { + // fast path: nothing to do + continue + } + w.Write(b[last:i]) + + if c < utf8.RuneSelf { + // Quotes, slashes and angle brackets get quoted. + // Control characters get written as \u00XX. + switch c { + case '\\': + w.Write(jsBackslash) + case '\'': + w.Write(jsApos) + case '"': + w.Write(jsQuot) + case '<': + w.Write(jsLt) + case '>': + w.Write(jsGt) + case '&': + w.Write(jsAmp) + case '=': + w.Write(jsEq) + default: + w.Write(jsLowUni) + t, b := c>>4, c&0x0f + w.Write(hex[t : t+1]) + w.Write(hex[b : b+1]) + } + } else { + // Unicode rune. + r, size := utf8.DecodeRune(b[i:]) + if unicode.IsPrint(r) { + w.Write(b[i : i+size]) + } else { + fmt.Fprintf(w, "\\u%04X", r) + } + i += size - 1 + } + last = i + 1 + } + w.Write(b[last:]) +} + +// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s. +func JSEscapeString(s string) string { + // Avoid allocation if we can. + if strings.IndexFunc(s, jsIsSpecial) < 0 { + return s + } + var b strings.Builder + JSEscape(&b, []byte(s)) + return b.String() +} + +func jsIsSpecial(r rune) bool { + switch r { + case '\\', '\'', '"', '<', '>', '&', '=': + return true + } + return r < ' ' || utf8.RuneSelf <= r +} + +// JSEscaper returns the escaped JavaScript equivalent of the textual +// representation of its arguments. +func JSEscaper(args ...any) string { + return JSEscapeString(evalArgs(args)) +} + +// URLQueryEscaper returns the escaped value of the textual representation of +// its arguments in a form suitable for embedding in a URL query. +func URLQueryEscaper(args ...any) string { + return url.QueryEscape(evalArgs(args)) +} + +// evalArgs formats the list of arguments into a string. It is therefore equivalent to +// +// fmt.Sprint(args...) +// +// except that each argument is indirected (if a pointer), as required, +// using the same rules as the default string evaluation during template +// execution. +func evalArgs(args []any) string { + ok := false + var s string + // Fast path for simple common case. + if len(args) == 1 { + s, ok = args[0].(string) + } + if !ok { + for i, arg := range args { + a, ok := printableValue(reflect.ValueOf(arg)) + if ok { + args[i] = a + } // else let fmt do its thing + } + s = fmt.Sprint(args...) + } + return s +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort/sort.go b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort/sort.go new file mode 100644 index 0000000000..f51cdc7083 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort/sort.go @@ -0,0 +1,154 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package fmtsort provides a general stable ordering mechanism +// for maps, on behalf of the fmt and text/template packages. +// It is not guaranteed to be efficient and works only for types +// that are valid map keys. +package fmtsort + +import ( + "cmp" + "reflect" + "slices" +) + +// Note: Throughout this package we avoid calling reflect.Value.Interface as +// it is not always legal to do so and it's easier to avoid the issue than to face it. + +// SortedMap is a slice of KeyValue pairs that simplifies sorting +// and iterating over map entries. +// +// Each KeyValue pair contains a map key and its corresponding value. +type SortedMap []KeyValue + +// KeyValue holds a single key and value pair found in a map. +type KeyValue struct { + Key, Value reflect.Value +} + +// Sort accepts a map and returns a SortedMap that has the same keys and +// values but in a stable sorted order according to the keys, modulo issues +// raised by unorderable key values such as NaNs. +// +// The ordering rules are more general than with Go's < operator: +// +// - when applicable, nil compares low +// - ints, floats, and strings order by < +// - NaN compares less than non-NaN floats +// - bool compares false before true +// - complex compares real, then imag +// - pointers compare by machine address +// - channel values compare by machine address +// - structs compare each field in turn +// - arrays compare each element in turn. +// Otherwise identical arrays compare by length. +// - interface values compare first by reflect.Type describing the concrete type +// and then by concrete value as described in the previous rules. +func Sort(mapValue reflect.Value) SortedMap { + if mapValue.Type().Kind() != reflect.Map { + return nil + } + // Note: this code is arranged to not panic even in the presence + // of a concurrent map update. The runtime is responsible for + // yelling loudly if that happens. See issue 33275. + n := mapValue.Len() + sorted := make(SortedMap, 0, n) + iter := mapValue.MapRange() + for iter.Next() { + sorted = append(sorted, KeyValue{iter.Key(), iter.Value()}) + } + slices.SortStableFunc(sorted, func(a, b KeyValue) int { + return compare(a.Key, b.Key) + }) + return sorted +} + +// compare compares two values of the same type. It returns -1, 0, 1 +// according to whether a > b (1), a == b (0), or a < b (-1). +// If the types differ, it returns -1. +// See the comment on Sort for the comparison rules. +func compare(aVal, bVal reflect.Value) int { + aType, bType := aVal.Type(), bVal.Type() + if aType != bType { + return -1 // No good answer possible, but don't return 0: they're not equal. + } + switch aVal.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return cmp.Compare(aVal.Int(), bVal.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return cmp.Compare(aVal.Uint(), bVal.Uint()) + case reflect.String: + return cmp.Compare(aVal.String(), bVal.String()) + case reflect.Float32, reflect.Float64: + return cmp.Compare(aVal.Float(), bVal.Float()) + case reflect.Complex64, reflect.Complex128: + a, b := aVal.Complex(), bVal.Complex() + if c := cmp.Compare(real(a), real(b)); c != 0 { + return c + } + return cmp.Compare(imag(a), imag(b)) + case reflect.Bool: + a, b := aVal.Bool(), bVal.Bool() + switch { + case a == b: + return 0 + case a: + return 1 + default: + return -1 + } + case reflect.Pointer, reflect.UnsafePointer: + return cmp.Compare(aVal.Pointer(), bVal.Pointer()) + case reflect.Chan: + if c, ok := nilCompare(aVal, bVal); ok { + return c + } + return cmp.Compare(aVal.Pointer(), bVal.Pointer()) + case reflect.Struct: + for i := 0; i < aVal.NumField(); i++ { + if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { + return c + } + } + return 0 + case reflect.Array: + for i := 0; i < aVal.Len(); i++ { + if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 { + return c + } + } + return 0 + case reflect.Interface: + if c, ok := nilCompare(aVal, bVal); ok { + return c + } + c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type())) + if c != 0 { + return c + } + return compare(aVal.Elem(), bVal.Elem()) + default: + // Certain types cannot appear as keys (maps, funcs, slices), but be explicit. + panic("bad type in compare: " + aType.String()) + } +} + +// nilCompare checks whether either value is nil. If not, the boolean is false. +// If either value is nil, the boolean is true and the integer is the comparison +// value. The comparison is defined to be 0 if both are nil, otherwise the one +// nil value compares low. Both arguments must represent a chan, func, +// interface, map, pointer, or slice. +func nilCompare(aVal, bVal reflect.Value) (int, bool) { + if aVal.IsNil() { + if bVal.IsNil() { + return 0, true + } + return -1, true + } + if bVal.IsNil() { + return 1, true + } + return 0, false +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/option.go b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/option.go new file mode 100644 index 0000000000..ea2fd80c06 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/option.go @@ -0,0 +1,72 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the code to handle template options. + +package template + +import "strings" + +// missingKeyAction defines how to respond to indexing a map with a key that is not present. +type missingKeyAction int + +const ( + mapInvalid missingKeyAction = iota // Return an invalid reflect.Value. + mapZeroValue // Return the zero value for the map element. + mapError // Error out +) + +type option struct { + missingKey missingKeyAction +} + +// Option sets options for the template. Options are described by +// strings, either a simple string or "key=value". There can be at +// most one equals sign in an option string. If the option string +// is unrecognized or otherwise invalid, Option panics. +// +// Known options: +// +// missingkey: Control the behavior during execution if a map is +// indexed with a key that is not present in the map. +// +// "missingkey=default" or "missingkey=invalid" +// The default behavior: Do nothing and continue execution. +// If printed, the result of the index operation is the string +// "". +// "missingkey=zero" +// The operation returns the zero value for the map type's element. +// "missingkey=error" +// Execution stops immediately with an error. +func (t *Template) Option(opt ...string) *Template { + t.init() + for _, s := range opt { + t.setOption(s) + } + return t +} + +func (t *Template) setOption(opt string) { + if opt == "" { + panic("empty option string") + } + // key=value + if key, value, ok := strings.Cut(opt, "="); ok { + switch key { + case "missingkey": + switch value { + case "invalid", "default": + t.option.missingKey = mapInvalid + return + case "zero": + t.option.missingKey = mapZeroValue + return + case "error": + t.option.missingKey = mapError + return + } + } + } + panic("unrecognized option: " + opt) +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/template.go b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/template.go new file mode 100644 index 0000000000..9ae5a6ca5b --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/template.go @@ -0,0 +1,236 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "maps" + "reflect" + "sync" + "text/template/parse" +) + +// common holds the information shared by related templates. +type common struct { + tmpl map[string]*Template // Map from name to defined templates. + muTmpl sync.RWMutex // protects tmpl + option option + // We use two maps, one for parsing and one for execution. + // This separation makes the API cleaner since it doesn't + // expose reflection to the client. + muFuncs sync.RWMutex // protects parseFuncs and execFuncs + parseFuncs FuncMap + execFuncs map[string]reflect.Value +} + +// Template is the representation of a parsed template. The *parse.Tree +// field is exported only for use by [html/template] and should be treated +// as unexported by all other clients. +type Template struct { + name string + *parse.Tree + *common + leftDelim string + rightDelim string +} + +// New allocates a new, undefined template with the given name. +func New(name string) *Template { + t := &Template{ + name: name, + } + t.init() + return t +} + +// Name returns the name of the template. +func (t *Template) Name() string { + return t.name +} + +// New allocates a new, undefined template associated with the given one and with the same +// delimiters. The association, which is transitive, allows one template to +// invoke another with a {{template}} action. +// +// Because associated templates share underlying data, template construction +// cannot be done safely in parallel. Once the templates are constructed, they +// can be executed in parallel. +func (t *Template) New(name string) *Template { + t.init() + nt := &Template{ + name: name, + common: t.common, + leftDelim: t.leftDelim, + rightDelim: t.rightDelim, + } + return nt +} + +// init guarantees that t has a valid common structure. +func (t *Template) init() { + if t.common == nil { + c := new(common) + c.tmpl = make(map[string]*Template) + c.parseFuncs = make(FuncMap) + c.execFuncs = make(map[string]reflect.Value) + t.common = c + } +} + +// Clone returns a duplicate of the template, including all associated +// templates. The actual representation is not copied, but the name space of +// associated templates is, so further calls to [Template.Parse] in the copy will add +// templates to the copy but not to the original. Clone can be used to prepare +// common templates and use them with variant definitions for other templates +// by adding the variants after the clone is made. +func (t *Template) Clone() (*Template, error) { + nt := t.copy(nil) + nt.init() + if t.common == nil { + return nt, nil + } + nt.option = t.option + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + for k, v := range t.tmpl { + if k == t.name { + nt.tmpl[t.name] = nt + continue + } + // The associated templates share nt's common structure. + tmpl := v.copy(nt.common) + nt.tmpl[k] = tmpl + } + t.muFuncs.RLock() + defer t.muFuncs.RUnlock() + maps.Copy(nt.parseFuncs, t.parseFuncs) + maps.Copy(nt.execFuncs, t.execFuncs) + return nt, nil +} + +// copy returns a shallow copy of t, with common set to the argument. +func (t *Template) copy(c *common) *Template { + return &Template{ + name: t.name, + Tree: t.Tree, + common: c, + leftDelim: t.leftDelim, + rightDelim: t.rightDelim, + } +} + +// AddParseTree associates the argument parse tree with the template t, giving +// it the specified name. If the template has not been defined, this tree becomes +// its definition. If it has been defined and already has that name, the existing +// definition is replaced; otherwise a new template is created, defined, and returned. +func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { + t.init() + t.muTmpl.Lock() + defer t.muTmpl.Unlock() + nt := t + if name != t.name { + nt = t.New(name) + } + // Even if nt == t, we need to install it in the common.tmpl map. + if t.associate(nt, tree) || nt.Tree == nil { + nt.Tree = tree + } + return nt, nil +} + +// Templates returns a slice of defined templates associated with t. +func (t *Template) Templates() []*Template { + if t.common == nil { + return nil + } + // Return a slice so we don't expose the map. + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + m := make([]*Template, 0, len(t.tmpl)) + for _, v := range t.tmpl { + m = append(m, v) + } + return m +} + +// Delims sets the action delimiters to the specified strings, to be used in +// subsequent calls to [Template.Parse], [Template.ParseFiles], or [Template.ParseGlob]. Nested template +// definitions will inherit the settings. An empty delimiter stands for the +// corresponding default: {{ or }}. +// The return value is the template, so calls can be chained. +func (t *Template) Delims(left, right string) *Template { + t.init() + t.leftDelim = left + t.rightDelim = right + return t +} + +// Funcs adds the elements of the argument map to the template's function map. +// It must be called before the template is parsed. +// It panics if a value in the map is not a function with appropriate return +// type or if the name cannot be used syntactically as a function in a template. +// It is legal to overwrite elements of the map. The return value is the template, +// so calls can be chained. +func (t *Template) Funcs(funcMap FuncMap) *Template { + t.init() + t.muFuncs.Lock() + defer t.muFuncs.Unlock() + addValueFuncs(t.execFuncs, funcMap) + addFuncs(t.parseFuncs, funcMap) + return t +} + +// Lookup returns the template with the given name that is associated with t. +// It returns nil if there is no such template or the template has no definition. +func (t *Template) Lookup(name string) *Template { + if t.common == nil { + return nil + } + t.muTmpl.RLock() + defer t.muTmpl.RUnlock() + return t.tmpl[name] +} + +// Parse parses text as a template body for t. +// Named template definitions ({{define ...}} or {{block ...}} statements) in text +// define additional templates associated with t and are removed from the +// definition of t itself. +// +// Templates can be redefined in successive calls to Parse. +// A template definition with a body containing only white space and comments +// is considered empty and will not replace an existing template's body. +// This allows using Parse to add new named template definitions without +// overwriting the main template body. +func (t *Template) Parse(text string) (*Template, error) { + t.init() + t.muFuncs.RLock() + trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins()) + t.muFuncs.RUnlock() + if err != nil { + return nil, err + } + // Add the newly parsed trees, including the one for t, into our common structure. + for name, tree := range trees { + if _, err := t.AddParseTree(name, tree); err != nil { + return nil, err + } + } + return t, nil +} + +// associate installs the new template into the group of templates associated +// with t. The two are already known to share the common structure. +// The boolean return value reports whether to store this tree as t.Tree. +func (t *Template) associate(new *Template, tree *parse.Tree) bool { + if new.common != t.common { + panic("internal error: associate not common") + } + if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil { + // If a template by that name exists, + // don't replace it with an empty template. + return false + } + t.tmpl[new.name] = new + return true +} diff --git a/vendor/github.com/open-policy-agent/opa/internal/planner/planner.go b/vendor/github.com/open-policy-agent/opa/internal/planner/planner.go index 9e71e83e72..a7d62542c2 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/planner/planner.go +++ b/vendor/github.com/open-policy-agent/opa/internal/planner/planner.go @@ -648,6 +648,12 @@ func (p *Planner) planExpr(e *ast.Expr, iter planiter) error { case e.IsNegated(): return p.planNot(e, iter) + case e.IsAnd(): + return p.planExprLogicalAnd(e, iter) + + case e.IsOr(): + return p.planExprLogicalOr(e, iter) + case e.IsCall(): return p.planExprCall(e, iter) @@ -659,34 +665,34 @@ func (p *Planner) planExpr(e *ast.Expr, iter planiter) error { } func (p *Planner) planNot(e *ast.Expr, iter planiter) error { - not := &ir.NotStmt{ - Block: &ir.Block{}, - } - - prev := p.curr - p.curr = not.Block - if n, ok := e.Terms.(*ast.Not); ok { - cond := p.newLocal() // success condition + // We're constructing the following plan: + // + // | not + // | | # assigns Local = true at each success point + // | | is_defined &{Source:Local} # aborts inner block if body produced no success + // | iter() # caller's continuation - err := p.planQuery(n.Body, 0, func() error { - p.appendStmt(&ir.AssignVarStmt{ - Source: op(ir.Bool(true)), - Target: cond, - }) - return nil - }) + cond := p.newLocal() + sub, err := p.planBodyAsScope(n.Body, cond) if err != nil { return err } - p.appendStmt(&ir.IsDefinedStmt{ - Source: cond, - }) - } else { - if err := p.planExpr(e.Complement(), func() error { return nil }); err != nil { - return err - } + sub.Stmts = append(sub.Stmts, &ir.IsDefinedStmt{Source: cond}) + p.appendStmt(&ir.NotStmt{Block: sub}) + + return iter() + } + + // Legacy negation + + not := &ir.NotStmt{Block: &ir.Block{}} + prev := p.curr + p.curr = not.Block + + if err := p.planExpr(e.Complement(), func() error { return nil }); err != nil { + return err } p.curr = prev @@ -695,6 +701,119 @@ func (p *Planner) planNot(e *ast.Expr, iter planiter) error { return iter() } +func (p *Planner) planExprLogicalAnd(e *ast.Expr, iter planiter) error { + // We're constructing the following plan: + // + // | reset &{Target:Local} + // | block lhs + // | | + // | | assign_var &{Target:Local} # Local = true on success + // | is_defined &{Source:Local} # aborts outer if LHS produced no success + // | reset &{Target:Local} # clear before RHS + // | block rhs + // | | + // | | assign_var &{Target:Local} # Local = true on success + // | is_defined &{Source:Local} # aborts outer if RHS produced no success + // | iter() # caller's continuation + + and := e.Terms.(*ast.LogicalAnd) + cond := p.newLocal() // success condition + + if err := planLogicalOperand(p, and.Lhs, cond); err != nil { + return err + } + + if err := planLogicalOperand(p, and.Rhs, cond); err != nil { + return err + } + + return iter() +} + +func planLogicalOperand(p *Planner, body ast.Body, cond ir.Local) error { + p.appendStmt(&ir.ResetLocalStmt{Target: cond}) + + sub, err := p.planBodyAsScope(body, cond) + if err != nil { + return err + } + + p.appendStmt(&ir.BlockStmt{Blocks: []*ir.Block{sub}}) + p.appendStmt(&ir.IsDefinedStmt{Source: cond}) + + return nil +} + +func (p *Planner) planExprLogicalOr(e *ast.Expr, iter planiter) error { + // We're constructing the following plan: + // + // | reset &{Target:Local} + // | block lhs + // | | + // | | assign_var &{Target:Local} # Local = true on success + // | block outer + // | | block skip + // | | | is_defined &{Source:Local} # if defined .. + // | | | break &{Index:1} # .. break past RHS + // | | block rhs + // | | | + // | | | assign_var &{Target:Local} # Local = true on success + // | is_defined &{Source:Local} # aborts outer if neither produced a success + // | iter() # caller's continuation + + or := e.Terms.(*ast.LogicalOr) + + cond := p.newLocal() // success condition + p.appendStmt(&ir.ResetLocalStmt{Target: cond}) + + lhsBlock, err := p.planBodyAsScope(or.Lhs, cond) + if err != nil { + return err + } + p.appendStmt(&ir.BlockStmt{Blocks: []*ir.Block{lhsBlock}}) + + rhsBlock, err := p.planBodyAsScope(or.Rhs, cond) + if err != nil { + return err + } + + // skip-rhs-if-lhs-succeeded: if cond is defined, break out past the + // RHS block; otherwise this inner block aborts and the outer block + // falls through into the RHS plan. + skip := &ir.Block{Stmts: []ir.Stmt{ + &ir.IsDefinedStmt{Source: cond}, + &ir.BreakStmt{Index: 1}, + }} + outer := &ir.Block{Stmts: []ir.Stmt{ + &ir.BlockStmt{Blocks: []*ir.Block{skip}}, + &ir.BlockStmt{Blocks: []*ir.Block{rhsBlock}}, + }} + p.appendStmt(&ir.BlockStmt{Blocks: []*ir.Block{outer}}) + + p.appendStmt(&ir.IsDefinedStmt{Source: cond}) + return iter() +} + +func (p *Planner) planBodyAsScope(body ast.Body, cond ir.Local) (*ir.Block, error) { + sub := &ir.Block{} + prev := p.curr + p.curr = sub + p.vars.Push(map[ast.Var]ir.Local{}) + + err := p.planQuery(body, 0, func() error { + p.appendStmt(&ir.AssignVarStmt{ + Source: op(ir.Bool(true)), + Target: cond, + }) + return nil + }) + + p.vars.Pop() + p.curr = prev + + return sub, err +} + func (p *Planner) planWith(e *ast.Expr, iter planiter) error { // Plan the values that will be applied by the `with` modifiers. All values diff --git a/vendor/github.com/open-policy-agent/opa/internal/planner/rules.go b/vendor/github.com/open-policy-agent/opa/internal/planner/rules.go index 9f3d115293..ed4da8571b 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/planner/rules.go +++ b/vendor/github.com/open-policy-agent/opa/internal/planner/rules.go @@ -5,6 +5,7 @@ import ( "sort" "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/util" ) // funcstack implements a simple map structure used to keep track of virtual @@ -270,18 +271,23 @@ func (t *ruletrie) DepthFirst(f func(*ruletrie) bool) { } func (t *ruletrie) Depth() int { - if len(t.Children()) == 0 { - return 0 - } - c := make([]int, 0, len(t.Children())) - for _, nodes := range t.children { - c = append(c, nodes[len(nodes)-1].Depth()) - } + // Avoid Children()'s slice allocation and sort: we only need the max + // depth over the child nodes. A nil last element is a pushed but + // not-yet-inserted node (see Push), matching Children()'s filter. max := 0 - for i := range c { - if max < c[i] { - max = c[i] + found := false + for _, nodes := range t.children { + last := nodes[len(nodes)-1] + if last == nil { + continue } + found = true + if d := last.Depth(); d > max { + max = d + } + } + if !found { + return 0 } return max + 1 } @@ -291,11 +297,9 @@ func (t *ruletrie) String() string { } type functionMocksStack struct { - stack []*functionMocksElem + stack util.GroupStack[frame] } -type functionMocksElem []frame - type frame map[string]*ast.Term func newFunctionMocksStack() *functionMocksStack { @@ -304,30 +308,24 @@ func newFunctionMocksStack() *functionMocksStack { return stack } -func newFunctionMocksElem() *functionMocksElem { - return &functionMocksElem{} -} - func (s *functionMocksStack) Push() { - s.stack = append(s.stack, newFunctionMocksElem()) + s.stack.PushGroup(nil) } func (s *functionMocksStack) Pop() { - s.stack = s.stack[:len(s.stack)-1] + s.stack.PopGroup() } func (s *functionMocksStack) PushFrame(f frame) { - current := s.stack[len(s.stack)-1] - *current = append(*current, f) + s.stack.Push(f) } func (s *functionMocksStack) PopFrame() { - current := s.stack[len(s.stack)-1] - *current = (*current)[:len(*current)-1] + s.stack.Pop() } func (s *functionMocksStack) Lookup(f string) *ast.Term { - current := *s.stack[len(s.stack)-1] + current := s.stack.PeekGroup() for i := len(current) - 1; i >= 0; i-- { if t, ok := current[i][f]; ok { return t diff --git a/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go b/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go index 725f86318a..d46f80aeb8 100644 --- a/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go +++ b/vendor/github.com/open-policy-agent/opa/internal/semver/semver.go @@ -101,10 +101,10 @@ func Compare(a, b string) int { return aV.Compare(bV) } -// AppendText appends the textual representation of the version to b and returns the extended buffer. +// AppendString appends the textual representation of the version to b and returns the extended buffer. // This method conforms to the encoding.TextAppender interface, and is useful for serializing the Version // without allocating, provided the caller has pre-allocated sufficient space in b. -func (v Version) AppendText(b []byte) ([]byte, error) { +func (v Version) AppendString(b []byte) ([]byte, error) { if b == nil { b = make([]byte, 0, length(v)) } @@ -126,7 +126,7 @@ func (v Version) AppendText(b []byte) ([]byte, error) { // String returns the string representation of the version. func (v Version) String() string { bs := make([]byte, 0, length(v)) - bs, _ = v.AppendText(bs) + bs, _ = v.AppendString(bs) return string(bs) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go index 14620a2a48..2b6a83eeeb 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go @@ -13,7 +13,6 @@ import ( "strings" "github.com/open-policy-agent/opa/internal/deepcopy" - astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/util" ) @@ -40,8 +39,8 @@ type ( Labels map[string]any `json:"labels,omitempty"` Location *Location `json:"location,omitempty"` - comments []*Comment - node Node + endLoc *Location + node Node } // SchemaAnnotation contains a schema declaration for the document identified by the path. @@ -108,11 +107,10 @@ func (a *Annotations) SetLoc(l *Location) { // EndLoc returns the location of this annotation's last comment line. func (a *Annotations) EndLoc() *Location { - count := len(a.comments) - if count == 0 { + if a.endLoc == nil { return a.Location } - return a.comments[count-1].Location + return a.endLoc } // Compare returns an integer indicating if a is less than, equal to, or greater @@ -193,64 +191,6 @@ func (a *Annotations) GetTargetPath() Ref { } } -func (a *Annotations) MarshalJSON() ([]byte, error) { - if a == nil { - return []byte(`{"scope":""}`), nil - } - - data := map[string]any{ - "scope": a.Scope, - } - - if a.Title != "" { - data["title"] = a.Title - } - - if a.Description != "" { - data["description"] = a.Description - } - - if a.Entrypoint { - data["entrypoint"] = a.Entrypoint - } - - if len(a.Organizations) > 0 { - data["organizations"] = a.Organizations - } - - if len(a.RelatedResources) > 0 { - data["related_resources"] = a.RelatedResources - } - - if len(a.Authors) > 0 { - data["authors"] = a.Authors - } - - if len(a.Schemas) > 0 { - data["schemas"] = a.Schemas - } - - if a.Compile != nil { - data["compile"] = a.Compile - } - - if len(a.Custom) > 0 { - data["custom"] = a.Custom - } - - if len(a.Labels) > 0 { - data["labels"] = a.Labels - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Annotations { - if a.Location != nil { - data["location"] = a.Location - } - } - - return json.Marshal(data) -} - func NewAnnotationsRef(a *Annotations) *AnnotationsRef { var loc *Location if a.node != nil { @@ -285,34 +225,6 @@ func (ar *AnnotationsRef) GetRule() *Rule { } } -func (ar *AnnotationsRef) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "path": ar.Path, - } - - if ar.Annotations != nil { - data["annotations"] = ar.Annotations - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.AnnotationsRef { - if ar.Location != nil { - data["location"] = ar.Location - } - - // The location set for the schema ref terms is wrong (always set to - // row 1) and not really useful anyway.. so strip it out before marshalling - for _, schema := range ar.Annotations.Schemas { - if schema.Path != nil { - for _, term := range schema.Path { - term.Location = nil - } - } - } - } - - return json.Marshal(data) -} - func scopeCompare(s1, s2 string) int { o1 := scopeOrder(s1) o2 := scopeOrder(s2) @@ -698,18 +610,6 @@ func (rr *RelatedResourceAnnotation) String() string { return string(bs) } -func (rr *RelatedResourceAnnotation) MarshalJSON() ([]byte, error) { - d := map[string]any{ - "ref": rr.Ref.String(), - } - - if len(rr.Description) > 0 { - d["description"] = rr.Description - } - - return json.Marshal(d) -} - // Copy returns a deep copy of s. func (s *SchemaAnnotation) Copy() *SchemaAnnotation { cpy := *s diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/annotations_json.go b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations_json.go new file mode 100644 index 0000000000..420a9f8093 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations_json.go @@ -0,0 +1,124 @@ +//go:build !go1.27 + +package ast + +import ( + "encoding/json" + + astJSON "github.com/open-policy-agent/opa/v1/ast/json" +) + +func (a *Annotations) MarshalJSON() ([]byte, error) { + if a == nil { + return []byte(`{"scope":""}`), nil + } + + data := map[string]any{ + "scope": a.Scope, + } + + if a.Title != "" { + data["title"] = a.Title + } + + if a.Description != "" { + data["description"] = a.Description + } + + if a.Entrypoint { + data["entrypoint"] = a.Entrypoint + } + + if len(a.Organizations) > 0 { + data["organizations"] = a.Organizations + } + + if len(a.RelatedResources) > 0 { + data["related_resources"] = a.RelatedResources + } + + if len(a.Authors) > 0 { + data["authors"] = a.Authors + } + + if len(a.Schemas) > 0 { + data["schemas"] = a.Schemas + } + + if a.Compile != nil { + data["compile"] = a.Compile + } + + if len(a.Custom) > 0 { + data["custom"] = a.Custom + } + + if len(a.Labels) > 0 { + data["labels"] = a.Labels + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Annotations { + if a.Location != nil { + data["location"] = a.Location + } + } + + return json.Marshal(data) +} + +func (rr *RelatedResourceAnnotation) MarshalJSON() ([]byte, error) { + d := map[string]any{ + "ref": rr.Ref.String(), + } + + if len(rr.Description) > 0 { + d["description"] = rr.Description + } + + return json.Marshal(d) +} + +func (ar *AnnotationsRef) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "path": ar.Path, + } + + if ar.Annotations != nil { + data["annotations"] = ar.Annotations + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.AnnotationsRef { + if ar.Location != nil { + data["location"] = ar.Location + } + } + + return json.Marshal(data) +} + +// schemaAnnotationJSON mirrors SchemaAnnotation's JSON tags, with location-free +// path terms. +type schemaAnnotationJSON struct { + Path []termJSON `json:"path"` + Schema Ref `json:"schema,omitempty"` + Definition *any `json:"definition,omitempty"` +} + +func (s *SchemaAnnotation) MarshalJSON() ([]byte, error) { + d := schemaAnnotationJSON{ + Schema: s.Schema, + Definition: s.Definition, + } + + if s.Path != nil { + d.Path = make([]termJSON, len(s.Path)) + for i, t := range s.Path { + // The location is omitted: path terms are parsed on their own from + // the annotation's YAML key, so their locations are offsets into that + // key (always row 1) rather than positions in the module. + d.Path[i] = termJSON{Type: ValueName(t.Value), Value: t.Value} + } + } + + return json.Marshal(d) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/annotations_jsonv2.go b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations_jsonv2.go new file mode 100644 index 0000000000..72e28caec4 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/annotations_jsonv2.go @@ -0,0 +1,195 @@ +//go:build go1.27 + +package ast + +import ( + "encoding/json/jsontext" + "encoding/json/v2" + "fmt" + + "github.com/open-policy-agent/opa/internal/jsonv2" + astJSON "github.com/open-policy-agent/opa/v1/ast/json" +) + +// These are exported types, so losing MarshalJSON here would be a breaking +// API change even though callers should go through json.Marshal, not this +// method directly. +var ( + _ json.Marshaler = &Annotations{} + _ json.Marshaler = &AnnotationsRef{} + _ json.Marshaler = &SchemaAnnotation{} + _ json.Marshaler = &RelatedResourceAnnotation{} +) + +func (a *Annotations) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if a == nil { + e.WriteToken(jsontext.String("scope")) + e.WriteToken(jsontext.String("")) + return e.WriteToken(jsontext.EndObject) + } + + if a.Description != "" { + e.WriteToken(jsontext.String("description")) + e.WriteToken(jsontext.String(a.Description)) + } + + if a.Entrypoint { + e.WriteToken(jsontext.String("entrypoint")) + e.WriteToken(jsontext.True) + } + + if len(a.Organizations) > 0 { + if err := jsonv2.WriteFieldValue(e, "organizations", a.Organizations); err != nil { + return err + } + } + + if len(a.RelatedResources) > 0 { + if err := jsonv2.WriteFieldArray(e, "related_resources", a.RelatedResources); err != nil { + return err + } + } + + if len(a.Authors) > 0 { + if err := jsonv2.WriteFieldValue(e, "authors", a.Authors); err != nil { + return err + } + } + + if len(a.Schemas) > 0 { + if err := jsonv2.WriteFieldArray(e, "schemas", a.Schemas); err != nil { + return err + } + } + + if a.Compile != nil { + if err := jsonv2.WriteFieldValue(e, "compile", a.Compile); err != nil { + return err + } + } + + if len(a.Custom) > 0 { + if err := jsonv2.WriteFieldValue(e, "custom", a.Custom); err != nil { + return err + } + } + + if len(a.Labels) > 0 { + if err := jsonv2.WriteFieldValue(e, "labels", a.Labels); err != nil { + return err + } + } + + e.WriteToken(jsontext.String("scope")) + e.WriteToken(jsontext.String(a.Scope)) + + if a.Title != "" { + e.WriteToken(jsontext.String("title")) + e.WriteToken(jsontext.String(a.Title)) + } + + if a.Location != nil && astJSON.GetOptions().MarshalOptions.IncludeLocation.Annotations { + if err := jsonv2.WriteField(e, "location", a.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (a *Annotations) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(a) +} + +func (ar *AnnotationsRef) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if ar.Annotations != nil { + if err := jsonv2.WriteField(e, "annotations", ar.Annotations); err != nil { + return err + } + } + + if ar.Location != nil && astJSON.GetOptions().MarshalOptions.IncludeLocation.AnnotationsRef { + if err := jsonv2.WriteField(e, "location", ar.Location); err != nil { + return err + } + } + + if err := jsonv2.WriteField(e, "path", ar.Path); err != nil { + return err + } + + return e.WriteToken(jsontext.EndObject) +} + +func (ar *AnnotationsRef) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(ar) +} + +func (s *SchemaAnnotation) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(s) +} + +func (s *SchemaAnnotation) MarshalJSONTo(e *jsontext.Encoder) error { + // Token write errors are unchecked: an unbalanced value fails at the closing + // token. A marshaller can fail having written a balanced value, so is checked. + e.WriteToken(jsontext.BeginObject) + + // Path has no omitempty tag, so it's always written. A nil ref is written + // as null, matching encoding/json v1's treatment of a nil slice. + e.WriteToken(jsontext.String("path")) + if s.Path == nil { + e.WriteToken(jsontext.Null) + } else { + e.WriteToken(jsontext.BeginArray) + for _, t := range s.Path { + // The location is omitted: path terms are parsed on their own from + // the annotation's YAML key, so their locations are offsets into that + // key (always row 1) rather than positions in the module. + e.WriteToken(jsontext.BeginObject) + e.WriteToken(jsontext.String("type")) + e.WriteToken(jsontext.String(ValueName(t.Value))) + e.WriteToken(jsontext.String("value")) + if err := marshalValueTo(e, t.Value); err != nil { + return fmt.Errorf("failed to marshal schema path term of %s: %w", ValueName(t.Value), err) + } + e.WriteToken(jsontext.EndObject) + } + e.WriteToken(jsontext.EndArray) + } + + if len(s.Schema) > 0 { + if err := jsonv2.WriteField(e, "schema", s.Schema); err != nil { + return err + } + } + + if s.Definition != nil { + if err := jsonv2.WriteFieldValue(e, "definition", s.Definition); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (rr *RelatedResourceAnnotation) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(rr) +} + +func (rr *RelatedResourceAnnotation) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + e.WriteToken(jsontext.String("ref")) + e.WriteToken(jsontext.String(rr.Ref.String())) + + if len(rr.Description) > 0 { + e.WriteToken(jsontext.String("description")) + e.WriteToken(jsontext.String(rr.Description)) + } + + return e.WriteToken(jsontext.EndObject) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go b/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go index d557a9bd4b..17ed06035d 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go @@ -141,6 +141,7 @@ var DefaultBuiltins = [...]*Builtin{ StartsWith, EndsWith, Split, + SplitN, Replace, ReplaceN, Trim, @@ -1281,6 +1282,21 @@ var Split = &Builtin{ CanSkipBctx: true, } +var SplitN = &Builtin{ + Name: "strings.split_n", + Description: "Returns an array of at most `n` parts of `x` split on `delimiter`. If `n` is positive, returns the first `n` parts. If `n` is negative, returns the last `abs(n)` parts. If `n` is zero, returns an empty array. If `abs(n)` exceeds the number of parts, all parts are returned.", + Decl: types.NewFunction( + types.Args( + types.Named("x", types.S).Description("string that is split"), + types.Named("delimiter", types.S).Description("delimiter used for splitting"), + types.Named("n", types.N).Description("number of parts to return; positive selects from the left, negative from the right, zero returns an empty array"), + ), + types.Named("ys", types.NewArray(nil, types.S)).Description("split parts"), + ), + Categories: stringsCat, + CanSkipBctx: true, +} + var Replace = &Builtin{ Name: "replace", Description: "Replace replaces all instances of a sub-string.", @@ -1624,7 +1640,10 @@ var JSONFilter = &Builtin{ ), )).Description("JSON string paths"), ), - types.Named("filtered", types.A).Description("remaining data from `object` with only keys specified in `paths`"), + types.Named("filtered", types.NewObject( + nil, + types.NewDynamicProperty(types.A, types.A), + )).Description("remaining data from `object` with only keys specified in `paths`"), ), Categories: objectCat, CanSkipBctx: true, @@ -1663,7 +1682,10 @@ var JSONRemove = &Builtin{ ), )).Description("JSON string paths"), ), - types.Named("output", types.A).Description("result of removing all keys specified in `paths`"), + types.Named("output", types.NewObject( + nil, + types.NewDynamicProperty(types.A, types.A), + )).Description("result of removing all keys specified in `paths`"), ), Categories: objectCat, CanSkipBctx: true, @@ -1724,7 +1746,7 @@ var ObjectSubset = &Builtin{ types.NewArray(nil, types.A), )).Description("object to test if super is a superset of"), ), - types.Named("result", types.A).Description("`true` if `sub` is a subset of `super`"), + types.Named("result", types.B).Description("`true` if `sub` is a subset of `super`, otherwise undefined"), ), CanSkipBctx: true, } @@ -1744,8 +1766,11 @@ var ObjectUnion = &Builtin{ types.NewDynamicProperty(types.A, types.A), )).Description("right-hand object"), ), - types.Named("output", types.A).Description("a new object which is the result of an asymmetric recursive union of two objects where conflicts are resolved by choosing the key from the right-hand object `b`"), - ), // TODO(sr): types.A? ^^^^^^^ (also below) + types.Named("output", types.NewObject( + nil, + types.NewDynamicProperty(types.A, types.A), + )).Description("a new object which is the result of an asymmetric recursive union of two objects where conflicts are resolved by choosing the key from the right-hand object `b`"), + ), CanSkipBctx: true, } @@ -1760,7 +1785,10 @@ var ObjectUnionN = &Builtin{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), )).Description("list of objects to merge"), ), - types.Named("output", types.A).Description("asymmetric recursive union of all objects in `objects`, merged from left to right, where conflicts are resolved by choosing the key from the right-hand object"), + types.Named("output", types.NewObject( + nil, + types.NewDynamicProperty(types.A, types.A), + )).Description("asymmetric recursive union of all objects in `objects`, merged from left to right, where conflicts are resolved by choosing the key from the right-hand object"), ), CanSkipBctx: true, } @@ -1780,7 +1808,10 @@ var ObjectRemove = &Builtin{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), )).Description("keys to remove from x"), ), - types.Named("output", types.A).Description("result of removing the specified `keys` from `object`"), + types.Named("output", types.NewObject( + nil, + types.NewDynamicProperty(types.A, types.A), + )).Description("result of removing the specified `keys` from `object`"), ), CanSkipBctx: true, } @@ -1801,7 +1832,10 @@ var ObjectFilter = &Builtin{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), )).Description("keys to keep in `object`"), ), - types.Named("filtered", types.A).Description("remaining data from `object` with only keys specified in `keys`"), + types.Named("filtered", types.NewObject( + nil, + types.NewDynamicProperty(types.A, types.A), + )).Description("remaining data from `object` with only keys specified in `keys`"), ), CanSkipBctx: true, } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/check.go b/vendor/github.com/open-policy-agent/opa/v1/ast/check.go index 810f38b1d3..ed3d14a15f 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/check.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/check.go @@ -1238,8 +1238,8 @@ func removeDuplicate(list []Value) []Value { return newResult } -func getArgTypes(env *TypeEnv, args []*Term) []types.Type { - pre := make([]types.Type, len(args)) +func getArgTypes(env *TypeEnv, args []*Term) (pre []types.Type) { + pre = make([]types.Type, len(args)) for i := range args { pre[i] = env.GetByValue(args[i].Value) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go b/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go index 1bf990a6ed..ef1ba033fd 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/compare.go @@ -336,26 +336,18 @@ func TermValueCompare(a, b *Term) int { return a.Value.Compare(b.Value) } -func TermValueEqual(a, b *Term) bool { - return ValueEqual(a.Value, b.Value) -} - func ValueEqual(a, b Value) bool { switch v := a.(type) { - case Null: - return v.Equal(b) - case Boolean: - return v.Equal(b) + case Null, Boolean, String, Var: + return v == b case Number: return v.Equal(b) - case String: - return v.Equal(b) - case Var: - return v.Equal(b) case Ref: return v.Equal(b) case *Array: return v.Equal(b) + case *Not: + return v.Equal(b) case *TemplateString: return v.Equal(b) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go b/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go index 8aa60e0f44..c642c508a8 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/compile.go @@ -1344,9 +1344,12 @@ func (c *Compiler) checkRuleConflicts() { kinds := make(map[RuleKind]struct{}, len(rules)) completeRules := 0 partialRules := 0 + // `p contains x` (set) vs `p[k] contains v` (object of sets): a mix is a conflict. + var hasMultiValueSet bool + var hasMultiValueObject bool arities := make(map[int]struct{}, len(rules)) name := "" - var conflicts []Ref + var conflicts []ruleRef defaultRules := make([]*Rule, 0) for _, rule := range rules { @@ -1403,6 +1406,15 @@ func (c *Compiler) checkRuleConflicts() { } else { partialRules++ } + + if r.Head.RuleKind() == MultiValue { + // A ground ref ends at the node (set); a longer one extends past it (object). + if ref.IsGround() { + hasMultiValueSet = true + } else { + hasMultiValueObject = true + } + } } // Functions cannot exist within a rule's dynamic extent, as there is no valid @@ -1422,9 +1434,9 @@ func (c *Compiler) checkRuleConflicts() { switch { case conflicts != nil: - return !c.err(NewError(TypeErr, rules[0].Loc(), "rule %v conflicts with %v", name, conflicts)) + return !c.err(NewError(TypeErr, rules[0].Loc(), "rule %v conflicts with%v", name, formatConflict(conflicts, rw))) - case len(kinds) > 1 || len(arities) > 1 || (completeRules >= 1 && partialRules >= 1): + case len(kinds) > 1 || len(arities) > 1 || (completeRules >= 1 && partialRules >= 1) || (hasMultiValueSet && hasMultiValueObject): return !c.err(NewError(TypeErr, rules[0].Loc(), "conflicting rules %v found", name)) case len(defaultRules) > 1: @@ -1596,11 +1608,15 @@ func (c *Compiler) checkSafetyRuleHeads() { if vars.DiffCount(vis.vars) > 0 { unsafe := vars.Diff(vis.vars) for v := range unsafe { + // vars is keyed by the original name, so the location must be + // read before v is replaced with the rewritten one -- otherwise + // the lookup misses and the error is reported without a location. + loc := vars[v].Location if w, ok := c.RewrittenVars[v]; ok { v = w } if !v.IsGenerated() { - if !c.err(NewError(UnsafeVarErr, vars[v].Location, "var %v is unsafe", v)) { + if !c.err(NewError(UnsafeVarErr, loc, "var %v is unsafe", v)) { return true } } @@ -1701,16 +1717,17 @@ func (parser *schemaParser) parseSchemaWithPropertyKey(schema any, propertyKey s // Handle referenced schemas, returns directly when a $ref is found if subSchema.RefSchema != nil { - if existing, ok := parser.definitionCache[subSchema.Ref.String()]; ok { + subSchemaStr := subSchema.Ref.String() + if existing, ok := parser.definitionCache[subSchemaStr]; ok { if existing.processing { if existing.rec == nil { - existing.rec = types.NewRecursive(subSchema.Ref.String(), nil) + existing.rec = types.NewRecursive(subSchemaStr, nil) } return existing.rec, nil } return existing.typ, nil } - return parser.parseSchemaWithPropertyKey(subSchema.RefSchema, subSchema.Ref.String()) + return parser.parseSchemaWithPropertyKey(subSchema.RefSchema, subSchemaStr) } // Cache this $ref definition and finalize it via defer when parsing @@ -2218,7 +2235,7 @@ func (c *Compiler) resolveAllRefs() { } for v, u := range globals { - if v.Equal(imp.Name()) && !u.used { + if v == imp.Name() && !u.used { if !c.err(NewError(CompileErr, imp.Location, "%s unused", imp.String())) { return } @@ -3327,6 +3344,50 @@ func (c *Compiler) rewriteLocalVarsInRule(rule *Rule, unusedArgs VarSet, argsSta stack := argsStack.Copy() + // A variable shadowing a built-in name (e.g. `count`) is allowed in Rego, + // but if left un-rewritten later stages (type checking, arity, partial + // eval) can mistake it for the built-in, causing spurious, + // map-order-dependent errors (issue #3729). Rewrite such variables to + // fresh locals, like `:=`-declared ones. + // + // Only variables bound in the body are rewritten. Excluded: head-only + // references (stay unsafe-var errors), call operators (SkipRefCallHead), + // and `with` targets/values (possible function mocks). + if len(c.builtins) > 0 { + bodyVis := NewVarVisitor().WithParams(VarVisitorParams{ + SkipRefCallHead: true, + SkipClosures: true, + }) + bodyVis.Walk(rule.Body) + bodyVars := bodyVis.Vars() + + declaredInBody := declaredVars(rule.Body) + + withVars := NewVarSet() + NewGenericVisitor(func(x any) bool { + if w, ok := x.(*With); ok { + WalkVars(w, func(v Var) bool { + withVars.Add(v) + return false + }) + } + return false + }).Walk(rule) + + for _, v := range bodyVars.Sorted() { + if _, ok := c.builtins[v.String()]; !ok { + continue + } + if declaredInBody.Contains(v) || withVars.Contains(v) { + continue + } + if _, ok := stack.Declared(v); ok { + continue + } + stack.Insert(v, gen.Generate(), seenVar) + } + } + body, declared, errs := rewriteLocalVars(gen, stack, used, rule.Body, c.strict) // For rewritten vars use the collection of all variables that @@ -4285,26 +4346,61 @@ func (n *TreeNode) add(path Ref, val any) { } } +// ExternalIndex ties an ExternalRuleSource-provided index to the package Ref it +// serves. It is internal plumbing exported only so the topdown evaluator can +// reach it across the ast/topdown package boundary; it is not part of OPA's +// supported public API and may change without notice. The stable surface for +// implementing external rule sources is the ExternalRuleSource and +// ExternalRuleIndex interfaces. type ExternalIndex struct { Index ExternalRuleIndex Ref Ref } -func (ei *ExternalIndex) Tree(ctx context.Context, rt *TreeNode, prefix Ref, input *Term, m metrics.Metrics, reqMD map[string]any, respMD map[string]any) (*TreeNode, ExternalRuleIndex, error) { - resolver := &termResolver{input: input} +// Tree resolves external rules for prefix, using resolver to resolve references +// while building search queries. Passing a save-set-aware resolver (e.g. the +// topdown evaluator) lets sources that opt into +// ExternalSourceOptions.DistinguishAbsentFromUnknown distinguish absent input +// from values that are unknown under partial evaluation. +// +// params carries the ground key values that followed the registered prefix for +// a parametrized source (see ParametrizedExternalRuleIndex); it is nil for +// conventional sources. The returned subtree is always rooted at prefix (the +// registered ref), regardless of params — the evaluator layers the parameter +// levels back on top. +// +// Like ExternalIndex, Tree is internal plumbing exported only for the topdown +// evaluator. It is not part of OPA's supported public API and may change +// without notice. +func (ei *ExternalIndex) Tree(ctx context.Context, rt *TreeNode, prefix Ref, params []Value, resolver ValueResolver, m metrics.Metrics, reqMD map[string]any, respMD map[string]any) (*TreeNode, ExternalRuleIndex, error) { + o := ei.Index.Opts() + + // Select the resolver handed to the source. By default we wrap the caller's + // resolver so external sources see the legacy behavior (absent and unknown + // both collapse to UnknownValueErr, non-input refs are never resolved). + // Sources that set DistinguishAbsentFromUnknown receive the caller's + // save-set-aware resolver unchanged, letting them tell absent from unknown. + lookupResolver := resolver + switch { + case lookupResolver == nil: + lookupResolver = unknownResolver{} + case o == nil || !o.DistinguishAbsentFromUnknown: + lookupResolver = legacyExternalResolver{inner: lookupResolver} + } rules, updatedIndex, err := ei.Index.Lookup(ctx, - LookupResolver(resolver), + LookupResolver(lookupResolver), LookupMetrics(m), LookupRequestMetadata(reqMD), LookupResponseMetadata(respMD), + LookupParams(params), ) if err != nil { return nil, nil, err } c0 := NewCompiler() - if o := ei.Index.Opts(); o != nil { + if o != nil { if len(o.SkippedStages) > 0 { c0.WithSkipStages(o.SkippedStages...) } @@ -4343,24 +4439,37 @@ func (ei *ExternalIndex) Tree(ctx context.Context, rt *TreeNode, prefix Ref, inp return node, updatedIndex, nil } -type termResolver struct { - input *Term +// legacyExternalResolver reproduces the historical external-source resolver +// behavior on top of an arbitrary (typically save-set-aware) resolver: only +// input references are resolvable, and any input reference that does not +// resolve to a concrete value is reported as UnknownValueErr. This collapses +// "absent from the concrete input" and "symbolic under partial evaluation" +// into a single signal, matching what external sources saw before +// ExternalSourceOptions.DistinguishAbsentFromUnknown existed. +type legacyExternalResolver struct { + inner ValueResolver } -func (r *termResolver) Resolve(ref Ref) (Value, error) { - if ref.HasPrefix(InputRootRef) { - if r.input == nil { - return nil, UnknownValueErr{} - } - v, err := r.input.Value.Find(ref[1:]) - if err != nil { - return nil, UnknownValueErr{} - } - return v, nil +func (r legacyExternalResolver) Resolve(ref Ref) (Value, error) { + if !ref.HasPrefix(InputRootRef) { + return nil, UnknownValueErr{} } - return nil, UnknownValueErr{} + v, err := r.inner.Resolve(ref) + if err != nil { + return nil, err + } + if v == nil { + return nil, UnknownValueErr{} + } + return v, nil } +// unknownResolver treats every reference as unknown. It is used as a safe +// fallback when Tree is invoked without a resolver. +type unknownResolver struct{} + +func (unknownResolver) Resolve(Ref) (Value, error) { return nil, UnknownValueErr{} } + // Size returns the number of rules in the tree. func (n *TreeNode) Size() (s int) { for _, c := range n.Children { @@ -4481,30 +4590,50 @@ func attachValueToNode(node *TreeNode, ref Ref, val any) { } } +type ruleRef struct { + ref Ref + loc *Location +} + // flattenChildren flattens all children's rule refs into a sorted array. -func (n *TreeNode) flattenChildren() []Ref { +func (n *TreeNode) flattenChildren() []ruleRef { return n.flattenMatchingChildren(func(_ *Rule) bool { return true }) } // flattenChildFunctions is like flattenChildren but only collects functions (rules with args). -func (n *TreeNode) flattenChildFunctions() []Ref { +func (n *TreeNode) flattenChildFunctions() []ruleRef { return n.flattenMatchingChildren(func(r *Rule) bool { return r.isFunction() }) } -func (n *TreeNode) flattenMatchingChildren(f func(*Rule) bool) []Ref { - ret := newRefSet() +func (n *TreeNode) flattenMatchingChildren(f func(*Rule) bool) []ruleRef { + var ret ruleRefSet for _, sub := range n.Children { // we only want the children, so don't use n.DepthFirst() right away sub.DepthFirst(func(x *TreeNode) bool { for _, rule := range x.Values { if f(rule) { - ret.AddPrefix(rule.Ref()) + ret.AddPrefix(ruleRef{ref: rule.Ref(), loc: rule.Loc()}) } } return false }) } - return util.SortedFunc(ret.s, RefCompare) + return util.SortedFunc(ret.s, func(a, b ruleRef) int { + return RefCompare(a.ref, b.ref) + }) +} + +func formatConflict(conflicts []ruleRef, rw varRewriter) string { + s := strings.Builder{} + s.WriteString(":\n") + for _, conflict := range conflicts { + s.WriteString(" rule ") + s.WriteString(rw(conflict.ref.Copy()).String()) + s.WriteString(" at ") + s.WriteString(conflict.loc.String()) + s.WriteString("\n") + } + return strings.TrimSuffix(s.String(), "\n") } // Copy creates a shallow copy of the TreeNode suitable for augmentation. @@ -4639,7 +4768,12 @@ func (g *Graph) Sort() (sorted []util.T, ok bool) { temp: map[util.T]struct{}{}, } + nodesList := make([]util.T, 0, len(g.nodes)) for node := range g.nodes { + nodesList = append(nodesList, node) + } + sortGraphNodes(nodesList) + for _, node := range nodesList { if !sorter.Visit(node) { return nil, false } @@ -4687,6 +4821,24 @@ type graphSort struct { temp map[util.T]struct{} } +// sortGraphNodes orders rule nodes deterministically (by location, then ref) +// so the topological sort, and thus the rule type-checking order, doesn't +// depend on Go's randomized map iteration (issue #3729). Head.Ref is used for +// the tie-break rather than Rule.Ref so nodes with a nil Module don't panic. +func sortGraphNodes(nodes []util.T) { + slices.SortStableFunc(nodes, func(a, b util.T) int { + ra, aok := a.(*Rule) + rb, bok := b.(*Rule) + if !aok || !bok { + return 0 + } + if c := ra.Location.Compare(rb.Location); c != 0 { + return c + } + return ra.Head.Ref().Compare(rb.Head.Ref()) + }) +} + func (sort *graphSort) Marked(node util.T) bool { _, marked := sort.marked[node] return marked @@ -4700,7 +4852,13 @@ func (sort *graphSort) Visit(node util.T) (ok bool) { return true } sort.temp[node] = struct{}{} - for other := range sort.deps(node) { + deps := sort.deps(node) + depList := make([]util.T, 0, len(deps)) + for other := range deps { + depList = append(depList, other) + } + sortGraphNodes(depList) + for _, other := range depList { if !sort.Visit(other) { return false } @@ -5249,6 +5407,15 @@ func outputVarsForExprEq(expr *Expr, safe VarSet, output VarSet) VarSet { output = outputVarsForTerms(expr, safe, output) output.Update(safe) + if expr.fromAssignment { + // The LHS of `:=` is a pure output; excluding it from the safe basis + // stops the RHS being made safe by unifying backwards through the LHS. + // See issue #3546. + WalkVars(expr.Operand(0), func(v Var) bool { + delete(output, v) + return false + }) + } output.Update(Unify(output, expr.Operand(0), expr.Operand(1))) diff := output.Diff(safe) @@ -6368,7 +6535,7 @@ func (s localDeclaredVars) Insert(x, y Var, occurrence varOccurrence) { // If the variable has been rewritten (where x != y, with y being // the generated value), store it in the map of rewritten vars. // Assume that the generated values are unique for the compilation. - if !x.Equal(y) { + if x != y { s.rewritten[y] = x } } @@ -6817,6 +6984,7 @@ func rewriteDeclaredAssignment(g *localVarGenerator, stack *localDeclaredVars, e if len(errs) == numErrsBefore { loc := expr.Operator()[0].Location expr.SetOperator(RefTerm(VarTerm(Equality.Name).SetLocation(loc)).SetLocation(loc)) + expr.fromAssignment = true } return expr, errs @@ -6845,7 +7013,7 @@ func rewriteDeclaredVarsInTerm(g *localVarGenerator, stack *localDeclaredVars, t case Call: ref := v[0] WalkVars(ref, func(v Var) bool { - if gv, ok := stack.Declared(v); ok && !gv.Equal(v) { + if gv, ok := stack.Declared(v); ok && gv != v { // We will rewrite the ref of a function call, which is never ok since we don't have first-class functions. errs = append(errs, NewError(CompileErr, term.Location, "called function %s shadowed", ref)) return true @@ -6900,11 +7068,11 @@ func rewriteDeclaredVarsInWithRecursive(g *localVarGenerator, stack *localDeclar if sdwInput, ok := stack.Declared(InputRootDocument.Value.(Var)); ok { // Was "input" shadowed... switch value := w.Target.Value.(type) { case Var: - if sdwInput.Equal(value) { // ...and replaced? If so, fix it + if sdwInput == value { // ...and replaced? If so, fix it w.Target.Value = InputRootRef } case Ref: - if sdwInput.Equal(value[0].Value.(Var)) { + if sdwInput.Equal(value[0].Value) { w.Target.Value.(Ref)[0].Value = InputRootDocument.Value } } @@ -7233,48 +7401,24 @@ func rewriteVarsInRef(vars ...map[Var]Var) varRewriter { } } -// NOTE(sr): This is duplicated with compile/compile.go; but moving it into another location -// would cause a circular dependency -- the refSet definition needs ast.Ref. If we make it -// public in the ast package, the compile package could take it from there, but it would also -// increase our public interface. Let's reconsider if we need it in a third place. -type refSet struct { - s []Ref -} - -func newRefSet(x ...Ref) *refSet { - result := &refSet{} - for i := range x { - result.AddPrefix(x[i]) - } - return result -} - -// ContainsPrefix returns true if r is prefixed by any of the existing refs in the set. -func (rs *refSet) ContainsPrefix(r Ref) bool { - return slices.ContainsFunc(rs.s, r.HasPrefix) +type ruleRefSet struct { + s []ruleRef } // AddPrefix inserts r into the set if r is not prefixed by any existing // refs in the set. If any existing refs are prefixed by r, those existing // refs are removed. -func (rs *refSet) AddPrefix(r Ref) { - if rs.ContainsPrefix(r) { - return - } - cpy := []Ref{r} +func (rs *ruleRefSet) AddPrefix(r ruleRef) { for i := range rs.s { - if !rs.s[i].HasPrefix(r) { + if r.ref.HasPrefix(rs.s[i].ref) { + return + } + } + cpy := []ruleRef{r} + for i := range rs.s { + if !rs.s[i].ref.HasPrefix(r.ref) { cpy = append(cpy, rs.s[i]) } } rs.s = cpy } - -// Sorted returns a sorted slice of terms for refs in the set. -func (rs *refSet) Sorted() []*Term { - terms := make([]*Term, len(rs.s)) - for i := range rs.s { - terms[i] = NewTerm(rs.s[i]) - } - return util.SortedFunc(terms, TermValueCompare) -} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/errors.go b/vendor/github.com/open-policy-agent/opa/v1/ast/errors.go index bf8bca7472..1188cd6e08 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/errors.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/errors.go @@ -87,7 +87,6 @@ type Error struct { } func (e *Error) Error() string { - var prefix string if e.Location != nil { @@ -119,6 +118,34 @@ func (e *Error) Error() string { return sb.String() } +func (e *Error) Equal(other *Error) bool { + if e == other { + return true + } + + if e == nil || other == nil { + return false + } + + if e.Code != other.Code || e.Message != other.Message { + return false + } + + if !e.Location.Equal(other.Location) { + return false + } + + if (e.Details == nil) != (other.Details == nil) { + return false + } + + if e.Details != nil && !slices.Equal(e.Details.Lines(), other.Details.Lines()) { + return false + } + + return true +} + // NewError returns a new Error object. func NewError(code string, loc *Location, f string, a ...any) *Error { return newErrorString(code, loc, fmt.Sprintf(f, a...)) diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/external_source.go b/vendor/github.com/open-policy-agent/opa/v1/ast/external_source.go index ce3433cce0..4669789e11 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/external_source.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/external_source.go @@ -46,6 +46,39 @@ type ExternalRuleIndexCloser interface { Close() error } +// ParametrizedExternalRuleIndex is an optional interface implemented by external +// rule indexes that serve a family of sub-references under their registered +// prefix rather than a single exact ref. The Ref such a source is registered +// under is treated as a PREFIX: the leading elements of a query reference that +// follow the prefix are consumed as ground lookup parameters (handed to Lookup +// via LookupOptions.Params) rather than as descents into a static rule tree. +// This lets one registered source serve an unbounded family of sub-references — +// one distinct set of rules per parameter tuple — without registering each +// concretely, so references whose key only comes into existence at runtime +// resolve without a recompile. +// +// An index that does not implement this interface behaves as a conventional +// exact-ref source (equivalent to an arity of 0). +type ParametrizedExternalRuleIndex interface { + ExternalRuleIndex + + // ParamArity reports how many elements following the registered prefix this + // index consumes as lookup parameters, given the reference tail (the query + // reference elements after the prefix, or an empty Ref when none follow). + // + // The count may vary with the tail's *shape* — e.g. keying off a leading + // discriminator segment — which lets a single prefix back an uneven-depth + // tree. It must NOT depend on parameter *values*: ParamArity is consulted + // before the parameters are plugged, so the tail may contain non-ground + // elements, and the count decides the caching boundary. Returning 0 makes + // the reference resolve as a conventional exact ref. + // + // The parameter elements the count selects must be ground at evaluation + // time. A non-ground parameter yields an undefined result, except under + // partial evaluation where the reference is saved for residualization. + ParamArity(tail Ref) int +} + // ExternalSourceOptions contains options for registering an external rule source. type ExternalSourceOptions struct { // VisibleRefs controls which parts of the surrounding rule tree the external @@ -68,6 +101,25 @@ type ExternalSourceOptions struct { // This is forward-compatible: new compiler stages added in future releases // will be skipped automatically rather than running unexpectedly. SkippedStages []StageID + + // DistinguishAbsentFromUnknown controls how the resolver passed to Lookup + // (via LookupOptions.Resolver) reports references that do not resolve to a + // concrete value. + // + // When false (default), the legacy behavior is preserved for backwards + // compatibility: only input references are resolvable, and any input + // reference that cannot be resolved — whether it is genuinely absent from a + // concrete input or symbolic under partial evaluation — surfaces as + // UnknownValueErr. The two cases are indistinguishable. + // + // When true, the source opts into the same save-set-aware resolver the + // built-in rule indexer uses: a reference that is unknown under partial + // evaluation returns UnknownValueErr, while a reference that is simply + // absent from an otherwise-concrete input resolves to (nil, nil). This lets + // a source tell "deliberately symbolic" apart from "concretely missing" + // on a per-reference basis (e.g. input.foo unknown while input.bar is + // known). See ValueResolver and IsUnknownValueErr. + DistinguishAbsentFromUnknown bool } // LookupOption is a functional option for ExternalRuleIndex.Lookup calls. @@ -79,6 +131,7 @@ type LookupOptions struct { resolver ValueResolver requestMetadata map[string]any responseMetadata map[string]any + params []Value } // Metrics returns the metrics instance from the options, or nil if not set. @@ -101,6 +154,14 @@ func (o *LookupOptions) ResponseMetadata() map[string]any { return o.responseMetadata } +// Params returns the parameter values for a parametrized external source (see +// ParametrizedExternalRuleIndex). The slice holds the ground key values that +// followed the registered prefix in the query reference, in order. It is empty +// for conventional (non-parametrized) sources. +func (o *LookupOptions) Params() []Value { + return o.params +} + // LookupMetrics returns a LookupOption that sets the metrics instance // for the Lookup call. func LookupMetrics(m metrics.Metrics) LookupOption { @@ -126,3 +187,11 @@ func LookupResponseMetadata(m map[string]any) LookupOption { opts.responseMetadata = m } } + +// LookupParams returns a LookupOption that sets the parameter values handed to a +// parametrized external source (see ParametrizedExternalRuleIndex). +func LookupParams(params []Value) LookupOption { + return func(opts *LookupOptions) { + opts.params = params + } +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/index.go b/vendor/github.com/open-policy-agent/opa/v1/ast/index.go index 45c0fa7a81..3502550798 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/index.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/index.go @@ -6,61 +6,12 @@ package ast import ( "slices" - "sort" "strings" "sync" "github.com/open-policy-agent/opa/v1/util" ) -// RuleIndex defines the interface for rule indices. -type RuleIndex interface { - - // Build tries to construct an index for the given rules. If the index was - // constructed, it returns true, otherwise false. - Build(rules []*Rule) bool - - // Lookup searches the index for rules that will match the provided - // resolver. If the resolver returns an error, it is returned via err. - Lookup(resolver ValueResolver) (*IndexResult, error) - - // AllRules traverses the index and returns all rules that will match - // the provided resolver without any optimizations (effectively with - // indexing disabled). If the resolver returns an error, it is returned - // via err. - AllRules(resolver ValueResolver) (*IndexResult, error) -} - -// IndexResult contains the result of an index lookup. -type IndexResult struct { - Rules []*Rule - Else map[*Rule][]*Rule - Default *Rule - Kind RuleKind - EarlyExit bool - OnlyGroundRefs bool -} - -// NewIndexResult returns a new IndexResult object. -func NewIndexResult(kind RuleKind) *IndexResult { - return &IndexResult{ - Kind: kind, - } -} - -// Empty returns true if there are no rules to evaluate. -func (ir *IndexResult) Empty() bool { - return len(ir.Rules) == 0 && ir.Default == nil -} - -type baseDocEqIndex struct { - isVirtual func(Ref) bool - root *trieNode - defaultRule *Rule - kind RuleKind - onlyGroundRefs bool -} - var ( equalityRef = Equality.Ref() equalRef = Equal.Ref() @@ -69,9 +20,59 @@ var ( internalTestCaseRef = InternalTestCase.Ref() internalMemberRef = Member.Ref() + globwildcard = VarTerm("$globwildcard") skipIndexing = NewSet(NewTerm(internalPrintRef), NewTerm(internalTestCaseRef)) + + // anyValue is a fake variable we used to put "naked ref" expressions + // into the rule index + anyValue Value = Var("__any__") ) +type ( + // RuleIndex defines the interface for rule indices. + RuleIndex interface { + // Build tries to construct an index for the given rules. If the index was + // constructed, it returns true, otherwise false. + Build(rules []*Rule) bool + + // Lookup searches the index for rules that will match the provided + // resolver. If the resolver returns an error, it is returned via err. + Lookup(resolver ValueResolver) (*IndexResult, error) + + // AllRules traverses the index and returns all rules that will match + // the provided resolver without any optimizations (effectively with + // indexing disabled). If the resolver returns an error, it is returned + // via err. + AllRules(resolver ValueResolver) (*IndexResult, error) + } + // IndexResult contains the result of an index lookup. + IndexResult struct { + Rules []*Rule + Else map[*Rule][]*Rule + Default *Rule + Kind RuleKind + EarlyExit bool + OnlyGroundRefs bool + } + baseDocEqIndex struct { + isVirtual func(Ref) bool + root *trieNode + defaultRule *Rule + kind RuleKind + onlyGroundRefs bool + } +) + +// NewIndexResult returns a new IndexResult object. +func NewIndexResult(kind RuleKind) *IndexResult { + return &IndexResult{Kind: kind} +} + +// Empty returns true if there are no rules to evaluate. +func (ir *IndexResult) Empty() bool { + return len(ir.Rules) == 0 && ir.Default == nil +} + func newBaseDocEqIndex(isVirtual func(Ref) bool) *baseDocEqIndex { return &baseDocEqIndex{ isVirtual: isVirtual, @@ -99,14 +100,7 @@ func (i *baseDocEqIndex) Build(rules []*Rule) bool { if i.onlyGroundRefs { i.onlyGroundRefs = rule.Head.Reference.IsGround() } - var skip bool - for i := range rule.Body { - if op := rule.Body[i].OperatorTerm(); op != nil && skipIndexing.Contains(op) { - skip = true - break - } - } - if !skip { + if !slices.ContainsFunc(rule.Body, skipIndexingOperator) { clear(values) for i := range rule.Body { indices.Update(rule, rule.Body[i], values) @@ -137,15 +131,7 @@ func (i *baseDocEqIndex) Build(rules []*Rule) bool { } else if len(values) == 1 { node = node.Insert(ref, values[0].Value, values[0].Mapper) } else { - var hasVar bool - for i := range values { - if _, isVar := values[i].Value.(Var); isVar { - hasVar = true - break - } - } - - if hasVar { + if slices.ContainsFunc(values, (*refindex).isVar) { child := node.Insert(ref, anyValue, values[0].Mapper) for i := range values { if values[i].Mapper != nil { @@ -183,7 +169,12 @@ func (i *baseDocEqIndex) Lookup(resolver ValueResolver) (*IndexResult, error) { tr := ttrPool.Get().(*trieTraversalResult) defer func() { - clear(tr.unordered) + // Note(anderseknert): `clear`ing the map is not good enough here, as it'd mean + // resetting each of its slice values, costing us new allocations on each append + // in subsequent lookups + for i := range tr.unordered { + tr.unordered[i] = tr.unordered[i][:0] + } tr.ordering = tr.ordering[:0] tr.multiple = false tr.exist = nil @@ -211,9 +202,10 @@ func (i *baseDocEqIndex) Lookup(resolver ValueResolver) (*IndexResult, error) { clear(result.Else) for _, pos := range tr.ordering { - slices.SortFunc(tr.unordered[pos], func(a, b *ruleNode) int { - return a.prio[1] - b.prio[1] - }) + if len(tr.unordered[pos]) == 0 { + continue + } + slices.SortFunc(tr.unordered[pos], (*ruleNode).prio1Cmp) nodes := tr.unordered[pos] root := nodes[0].rule @@ -267,9 +259,10 @@ func (i *baseDocEqIndex) AllRules(ValueResolver) (*IndexResult, error) { result.Rules = make([]*Rule, 0, len(tr.ordering)) for _, pos := range tr.ordering { - slices.SortFunc(tr.unordered[pos], func(a, b *ruleNode) int { - return a.prio[1] - b.prio[1] - }) + if len(tr.unordered[pos]) == 0 { + continue + } + slices.SortFunc(tr.unordered[pos], (*ruleNode).prio1Cmp) nodes := tr.unordered[pos] root := nodes[0].rule result.Rules = append(result.Rules, root) @@ -326,15 +319,15 @@ func newrefindices(isVirtual func(Ref) bool) *refindices { } } -// anyValue is a fake variable we used to put "naked ref" expressions -// into the rule index -var anyValue = Var("__any__") +func (i *refindex) isVar() bool { + _, isVar := i.Value.(Var) + return isVar +} // Update attempts to update the refindices for the given expression in the // given rule. If the expression cannot be indexed the update does not affect // the indices. func (i *refindices) Update(rule *Rule, expr *Expr, values map[Var]Value) { - if len(expr.With) > 0 { // NOTE(tsandall): In the future, we may need to consider expressions // that have with statements applied to them. @@ -354,8 +347,8 @@ func (i *refindices) Update(rule *Rule, expr *Expr, values map[Var]Value) { // check for type "Var" here. But since it's impossible to call a // function with a undefined argument, there's no point to recording // "needs to be anything" for function args - if ref, ok := ts.Value.(Ref); ok { // "naked ref" - i.updateEq(rule, ref, anyValue, nil) + if _, ok := ts.Value.(Ref); ok { // "naked ref" + i.updateEq(rule, ts.Value, anyValue, nil) } } } @@ -397,27 +390,18 @@ func (i *refindices) isValidIndexRef(ref Ref) bool { // References that appear more frequently in the indexed rules are ordered // before less frequently appearing references. func (i *refindices) Sorted() []Ref { - if i.sorted == nil { - counts := make([]int, 0, i.frequency.Len()) - i.sorted = make([]Ref, 0, i.frequency.Len()) - - i.frequency.Iter(func(k Ref, v int) bool { - counts = append(counts, v) - i.sorted = append(i.sorted, k) - return false - }) - - sort.Slice(i.sorted, func(a, b int) bool { - if counts[a] > counts[b] { - return true - } else if counts[b] > counts[a] { - return false + i.sorted = util.SortedFunc(i.frequency.Keys(), func(a, b Ref) int { + countsA, _ := i.frequency.Get(a) + countsB, _ := i.frequency.Get(b) + if countsA < countsB { // descending, we want highest-freq first + return 1 + } else if countsA > countsB { + return -1 } - return i.sorted[a][0].Loc().Compare(i.sorted[b][0].Loc()) < 0 + return a[0].Loc().Compare(b[0].Loc()) }) } - return i.sorted } @@ -515,12 +499,10 @@ func (i *refindices) updateGlobMatch(rule *Rule, expr *Expr) { } func (i *refindices) updateMember(rule *Rule, expr *Expr, constants map[Var]Value) { - args := rule.Head.Args lhs, rhs := expr.Operand(0), expr.Operand(1) - lvar, ok := lhs.Value.(Var) if ok { - lref := resolveVarToRef(i.rules[rule], args, lvar) + lref := resolveVarToRef(i.rules[rule], rule.Head.Args, lvar) if lref != nil { i.updateMemberRefInValue(rule, lref, rhs, constants) // `ref in value` return @@ -528,7 +510,7 @@ func (i *refindices) updateMember(rule *Rule, expr *Expr, constants map[Var]Valu } // `var0 in var1` case (var0 may be constant, var1 ref) - i.updateMemberValueInRef(rule, args, lhs.Value, rhs, constants) + i.updateMemberValueInRef(rule, rule.Head.Args, lhs.Value, rhs, constants) } func (i *refindices) updateMemberValueInRef(rule *Rule, args []*Term, lval Value, rhs *Term, constants map[Var]Value) { @@ -615,12 +597,12 @@ func (i *refindices) resolveAndValidateRef(rule *Rule, args []*Term, term *Term) // as we're not capturing `var = var` expressions in the index. func resolveVarToRef(ri []*refindex, args []*Term, v Var) Ref { for _, other := range ri { - if ov, ok := other.Value.(Var); ok && ov.Equal(v) { + if v.Equal(other.Value) { return other.Ref } } for j, arg := range args { - if arg.Value.Compare(v) == 0 { + if v.Equal(arg.Value) { return Ref{FunctionArgRootDocument, InternedTerm(j)} } } @@ -636,7 +618,6 @@ func (i *refindices) insert(rule *Rule, index *refindex) { for pos, other := range i.rules[rule] { if other.Ref.Equal(index.Ref) { - if ValueEqual(other.Value, index.Value) { return } @@ -671,7 +652,7 @@ type trieTraversalResult struct { multiple bool } -var ttrPool = sync.Pool{ +var ttrPool = &sync.Pool{ New: func() any { return newTrieTraversalResult() }, @@ -679,21 +660,17 @@ var ttrPool = sync.Pool{ func newTrieTraversalResult() *trieTraversalResult { return &trieTraversalResult{ - unordered: map[int][]*ruleNode{}, + unordered: make(map[int][]*ruleNode, 16), } } func (tr *trieTraversalResult) Add(t *trieNode) { for _, node := range t.rules { root := node.prio[0] - nodes, ok := tr.unordered[root] - if !ok { + if nodes, ok := tr.unordered[root]; !ok || len(nodes) == 0 { tr.ordering = append(tr.ordering, root) - } - // Deduplicate: check if a ruleNode with this priority already exists - if !slices.ContainsFunc(nodes, func(existing *ruleNode) bool { - return existing.prio == node.prio - }) { + tr.unordered[root] = append(nodes, node) + } else if !slices.ContainsFunc(nodes, node.prioEqual) { tr.unordered[root] = append(nodes, node) } } @@ -740,10 +717,16 @@ type ruleNode struct { rule *Rule } +func (a *ruleNode) prio1Cmp(b *ruleNode) int { + return a.prio[1] - b.prio[1] +} + +func (a *ruleNode) prioEqual(b *ruleNode) bool { + return a.prio == b.prio +} + func newTrieNodeImpl() *trieNode { - return &trieNode{ - scalars: util.NewHasherMap[Value, *trieNode](ValueEqual), - } + return &trieNode{} } func (node *trieNode) Do(walker trieWalker) { @@ -768,7 +751,6 @@ func (node *trieNode) Do(walker trieWalker) { } func (node *trieNode) Insert(ref Ref, value Value, mapper *valueMapper) *trieNode { - if node.next == nil { node.next = newTrieNodeImpl() node.next.ref = ref @@ -782,7 +764,6 @@ func (node *trieNode) Insert(ref Ref, value Value, mapper *valueMapper) *trieNod } func (node *trieNode) Traverse(resolver ValueResolver, tr *trieTraversalResult) error { - if node == nil { return nil } @@ -802,54 +783,70 @@ func (node *trieNode) addMapper(mapper *valueMapper) { } func (node *trieNode) insertValue(value Value) *trieNode { - switch value := value.(type) { case nil: - if node.undefined == nil { - node.undefined = newTrieNodeImpl() - } + node.undefined = util.Or(node.undefined, newTrieNodeImpl) return node.undefined case Var: - if node.any == nil { - node.any = newTrieNodeImpl() - } + node.any = util.Or(node.any, newTrieNodeImpl) return node.any case Null, Boolean, Number, String: child, ok := node.scalars.Get(value) if !ok { child = newTrieNodeImpl() + if node.scalars == nil { + node.scalars = util.NewHasherMap[Value, *trieNode](ValueEqual) + } node.scalars.Put(value, child) } return child case *Array: - if node.array == nil { - node.array = newTrieNodeImpl() - } + node.array = util.Or(node.array, newTrieNodeImpl) return node.array.insertArray(value) + + // `x in ` (see updateMemberRefInValue) inserts each element of + // the literal collection as-is, without restricting it to scalars/arrays + // like the equality-based indexing does (see indexValue). A ground + // Object or Set element can't be indexed precisely, so - like Var - it + // falls back to the "any" node: the rule stays a candidate for every + // input value. (The other composite Value types - Ref, comprehensions, + // Call - can't actually reach here: the compiler rewrites them into + // separate statements, bound to a Var, before the index is built.) + case Object, Set: + node.any = util.Or(node.any, newTrieNodeImpl) + return node.any } panic("illegal value") } func (node *trieNode) insertArray(arr *Array) *trieNode { - if arr.Len() == 0 { return node } switch head := arr.Elem(0).Value.(type) { case Var: - if node.any == nil { - node.any = newTrieNodeImpl() - } + node.any = util.Or(node.any, newTrieNodeImpl) return node.any.insertArray(arr.Slice(1, -1)) case Null, Boolean, Number, String: child, ok := node.scalars.Get(head) if !ok { child = newTrieNodeImpl() + if node.scalars == nil { + node.scalars = util.NewHasherMap[Value, *trieNode](ValueEqual) + } node.scalars.Put(head, child) } return child.insertArray(arr.Slice(1, -1)) + + // Same reasoning as in insertValue above: an array element can itself be + // a nested array, object, or set, none of which can be indexed precisely + // at this position, so fall back to "any" and keep indexing the + // remaining elements. + case *Array, Object, Set: + node.any = util.Or(node.any, newTrieNodeImpl) + return node.any.insertArray(arr.Slice(1, -1)) } panic("illegal value") @@ -868,8 +865,7 @@ func (node *trieNode) traverse(resolver ValueResolver, tr *trieTraversalResult) return err } - err = node.undefined.Traverse(resolver, tr) - if err != nil { + if err = node.undefined.Traverse(resolver, tr); err != nil { return err } @@ -877,13 +873,11 @@ func (node *trieNode) traverse(resolver ValueResolver, tr *trieTraversalResult) return nil } - err = node.any.Traverse(resolver, tr) - if err != nil { + if err = node.any.Traverse(resolver, tr); err != nil { return err } - err = node.traverseValue(resolver, tr, v) - if err != nil { + if err = node.traverseValue(resolver, tr, v); err != nil { return err } @@ -900,7 +894,6 @@ func (node *trieNode) traverse(resolver ValueResolver, tr *trieTraversalResult) } func (node *trieNode) traverseValue(resolver ValueResolver, tr *trieTraversalResult, value Value) error { - switch value := value.(type) { case *Array, Set, Object: if node.array != nil { @@ -910,19 +903,13 @@ func (node *trieNode) traverseValue(resolver ValueResolver, tr *trieTraversalRes } } } - if node.scalars.Len() > 0 { return node.traverseCollectionMembership(resolver, tr, value) } - - return nil - case Null, Boolean, Number, String: - child, ok := node.scalars.Get(value) - if !ok { - return nil + if child, ok := node.scalars.Get(value); ok { + return child.Traverse(resolver, tr) } - return child.Traverse(resolver, tr) } return nil @@ -951,7 +938,7 @@ func (node *trieNode) traverseCollectionMembership(resolver ValueResolver, tr *t return nil } -func (node *trieNode) traverseArray(resolver ValueResolver, tr *trieTraversalResult, arr *Array) error { +func (node *trieNode) traverseArray(resolver ValueResolver, tr *trieTraversalResult, arr *Array) (err error) { if node == nil { return nil } @@ -960,24 +947,15 @@ func (node *trieNode) traverseArray(resolver ValueResolver, tr *trieTraversalRes return node.Traverse(resolver, tr) } - err := node.any.traverseArray(resolver, tr, arr.Slice(1, -1)) - if err != nil { - return err + if err = node.any.traverseArray(resolver, tr, arr.Slice(1, -1)); err == nil { + switch head := arr.Elem(0).Value.(type) { + case Null, Boolean, Number, String: + child, _ := node.scalars.Get(head) + return child.traverseArray(resolver, tr, arr.Slice(1, -1)) + } } - head := arr.Elem(0).Value - - if !IsScalar(head) { - return nil - } - - switch head := head.(type) { - case Null, Boolean, Number, String: - child, _ := node.scalars.Get(head) - return child.traverseArray(resolver, tr, arr.Slice(1, -1)) - } - - panic("illegal value") + return err } func (node *trieNode) traverseUnknown(resolver ValueResolver, tr *trieTraversalResult) error { @@ -1105,10 +1083,7 @@ func globDelimiterToString(delim *Term) (string, bool) { return result, true } -var globwildcard = VarTerm("$globwildcard") - func globPatternToArray(pattern *Term, delim string) *Term { - s, ok := pattern.Value.(String) if !ok { return nil @@ -1147,7 +1122,6 @@ func globPatternToArray(pattern *Term, delim string) *Term { // splits s on characters in delim except if delim characters have been escaped // with reverse solidus. func splitStringEscaped(s string, delim string) []string { - var last, curr int var escaped bool var result []string @@ -1171,7 +1145,12 @@ func splitStringEscaped(s string, delim string) []string { func stringSliceToArray(s []string) *Array { arr := make([]*Term, len(s)) for i, v := range s { - arr[i] = StringTerm(v) + arr[i] = InternedTerm(v) } return NewArray(arr...) } + +func skipIndexingOperator(expr *Expr) bool { + op := expr.OperatorTerm() + return op != nil && skipIndexing.Contains(op) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/location/location.go b/vendor/github.com/open-policy-agent/opa/v1/ast/location/location.go index 4e3a080bed..e08088cff1 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/location/location.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/location/location.go @@ -3,12 +3,10 @@ package location import ( "bytes" - "encoding/json" "errors" "fmt" "unicode/utf8" - astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/util" ) @@ -150,41 +148,3 @@ func (loc *Location) Compare(other *Location) int { } return 0 } - -func (loc *Location) MarshalJSON() ([]byte, error) { - // structs are used here to preserve the field ordering of the original Location struct - jsonOptions := astJSON.GetOptions().MarshalOptions - if jsonOptions.ExcludeLocationFile { - data := struct { - Row int `json:"row"` - Col int `json:"col"` - Text []byte `json:"text,omitempty"` - }{ - Row: loc.Row, - Col: loc.Col, - } - - if jsonOptions.IncludeLocationText { - data.Text = loc.Text - } - - return json.Marshal(data) - } - - data := struct { - File string `json:"file"` - Row int `json:"row"` - Col int `json:"col"` - Text []byte `json:"text,omitempty"` - }{ - Row: loc.Row, - Col: loc.Col, - File: loc.File, - } - - if jsonOptions.IncludeLocationText { - data.Text = loc.Text - } - - return json.Marshal(data) -} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/location/location_json.go b/vendor/github.com/open-policy-agent/opa/v1/ast/location/location_json.go new file mode 100644 index 0000000000..441ea86e46 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/location/location_json.go @@ -0,0 +1,47 @@ +//go:build !go1.27 + +package location + +import ( + "encoding/json" + + astJSON "github.com/open-policy-agent/opa/v1/ast/json" +) + +func (loc *Location) MarshalJSON() ([]byte, error) { + // structs are used here to preserve the field ordering of the original Location struct + jsonOptions := astJSON.GetOptions().MarshalOptions + if jsonOptions.ExcludeLocationFile { + data := struct { + Row int `json:"row"` + Col int `json:"col"` + Text []byte `json:"text,omitempty"` + }{ + Row: loc.Row, + Col: loc.Col, + } + + if jsonOptions.IncludeLocationText { + data.Text = loc.Text + } + + return json.Marshal(data) + } + + data := struct { + File string `json:"file"` + Row int `json:"row"` + Col int `json:"col"` + Text []byte `json:"text,omitempty"` + }{ + Row: loc.Row, + Col: loc.Col, + File: loc.File, + } + + if jsonOptions.IncludeLocationText { + data.Text = loc.Text + } + + return json.Marshal(data) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/location/location_jsonv2.go b/vendor/github.com/open-policy-agent/opa/v1/ast/location/location_jsonv2.go new file mode 100644 index 0000000000..1897538a14 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/location/location_jsonv2.go @@ -0,0 +1,50 @@ +// Copyright 2026 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +//go:build go1.27 + +package location + +import ( + "encoding/base64" + "encoding/json/jsontext" + "encoding/json/v2" + + "github.com/open-policy-agent/opa/internal/jsonv2" + astJSON "github.com/open-policy-agent/opa/v1/ast/json" +) + +// Location is an exported type, so losing MarshalJSON here would be a +// breaking API change even though callers should go through json.Marshal, +// not this method directly. +var _ json.Marshaler = &Location{} + +// MarshalJSON returns the JSON encoding of loc. +func (loc *Location) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(loc) +} + +func (loc *Location) MarshalJSONTo(e *jsontext.Encoder) (err error) { + e.WriteToken(jsontext.BeginObject) + + jsonOptions := astJSON.GetOptions().MarshalOptions + if !jsonOptions.ExcludeLocationFile { + e.WriteToken(jsontext.String("file")) + e.WriteToken(jsontext.String(loc.File)) + } + + e.WriteToken(jsontext.String("row")) + e.WriteToken(jsontext.Int(int64(loc.Row))) + e.WriteToken(jsontext.String("col")) + e.WriteToken(jsontext.Int(int64(loc.Col))) + + // NOTE: len check to match the `json:"text,omitempty"` behaviour of the + // pre-go1.27 marshaller. + if jsonOptions.IncludeLocationText && len(loc.Text) > 0 { + e.WriteToken(jsontext.String("text")) + e.WriteToken(jsontext.String(base64.StdEncoding.EncodeToString(loc.Text))) + } + + return e.WriteToken(jsontext.EndObject) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/map.go b/vendor/github.com/open-policy-agent/opa/v1/ast/map.go index 31cad4d611..aa0e655b9e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/map.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/map.go @@ -10,7 +10,7 @@ import ( "github.com/open-policy-agent/opa/v1/util" ) -// ValueMap represents a key/value map between AST term values. Any type of term +// ValueMap represents a key/value map between AST term values. Any type of value // can be used as a key in the map. type ValueMap struct { hashMap *util.TypedHashMap[Value, Value] diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/mermaid.go b/vendor/github.com/open-policy-agent/opa/v1/ast/mermaid.go index 217947bc83..5f0911ec11 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/mermaid.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/mermaid.go @@ -152,7 +152,7 @@ func (rule *Rule) mermaidFormat(b *mermaidBuilder) string { bodyID := b.node("rect", "Body") b.edge(id, bodyID) for i, expr := range rule.Body { - exprID := mermaidFormatExpr(expr, i, b) + exprID := mermaidFormatExpr(expr, b) b.edgeLabeled(bodyID, exprID, strconv.Itoa(i)) } } @@ -188,7 +188,7 @@ func mermaidFormatHead(head *Head, b *mermaidBuilder) string { return id } -func mermaidFormatExpr(expr *Expr, index int, b *mermaidBuilder) string { +func mermaidFormatExpr(expr *Expr, b *mermaidBuilder) string { label := expr.String() id := b.node("hex", label) @@ -245,8 +245,8 @@ func mermaidFormatEvery(every *Every, b *mermaidBuilder) string { b.edgeLabeled(id, domainID, "domain") bodyID := b.node("rect", "Body") b.edge(id, bodyID) - for i, expr := range every.Body { - exprID := mermaidFormatExpr(expr, i, b) + for _, expr := range every.Body { + exprID := mermaidFormatExpr(expr, b) b.edge(bodyID, exprID) } return id @@ -256,14 +256,14 @@ func mermaidFormatLogical(op string, lhs, rhs Body, b *mermaidBuilder) string { id := b.node("rect", op) lhsID := b.node("rect", "Lhs") b.edge(id, lhsID) - for i, expr := range lhs { - exprID := mermaidFormatExpr(expr, i, b) + for _, expr := range lhs { + exprID := mermaidFormatExpr(expr, b) b.edge(lhsID, exprID) } rhsID := b.node("rect", "Rhs") b.edge(id, rhsID) - for i, expr := range rhs { - exprID := mermaidFormatExpr(expr, i, b) + for _, expr := range rhs { + exprID := mermaidFormatExpr(expr, b) b.edge(rhsID, exprID) } return id @@ -283,7 +283,7 @@ func mermaidFormatWith(w *With, b *mermaidBuilder) string { func (not *Not) mermaidFormat(b *mermaidBuilder) string { id := b.node("stadium", "not") for i, expr := range not.Body { - exprID := mermaidFormatExpr(expr, i, b) + exprID := mermaidFormatExpr(expr, b) b.edgeLabeled(id, exprID, strconv.Itoa(i)) } return id @@ -381,7 +381,7 @@ func (ac *ArrayComprehension) mermaidFormat(b *mermaidBuilder) string { bodyID := b.node("rect", "Body") b.edge(id, bodyID) for i, expr := range ac.Body { - exprID := mermaidFormatExpr(expr, i, b) + exprID := mermaidFormatExpr(expr, b) b.edgeLabeled(bodyID, exprID, strconv.Itoa(i)) } return id @@ -396,7 +396,7 @@ func (oc *ObjectComprehension) mermaidFormat(b *mermaidBuilder) string { bodyID := b.node("rect", "Body") b.edge(id, bodyID) for i, expr := range oc.Body { - exprID := mermaidFormatExpr(expr, i, b) + exprID := mermaidFormatExpr(expr, b) b.edgeLabeled(bodyID, exprID, strconv.Itoa(i)) } return id @@ -409,7 +409,7 @@ func (sc *SetComprehension) mermaidFormat(b *mermaidBuilder) string { bodyID := b.node("rect", "Body") b.edge(id, bodyID) for i, expr := range sc.Body { - exprID := mermaidFormatExpr(expr, i, b) + exprID := mermaidFormatExpr(expr, b) b.edgeLabeled(bodyID, exprID, strconv.Itoa(i)) } return id diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go b/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go index 8af16314b9..3ecf654a54 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/parser.go @@ -764,15 +764,15 @@ func (p *Parser) parseImport() *Import { t := r[0] name := string(t.Value.(Var)) if IsKeywordInRegoVersion(name, p.po.EffectiveRegoVersion()) { - p.errorf(t.Location, "unexpected import path, must not end with a keyword, got: %s", name) p.hint("import a different path or use an alias") + p.errorf(t.Location, "unexpected import path, must not end with a keyword, got: %s", name) } } else if !FutureRootDocument.Equal(r[0]) { t := r[len(r)-1] name := string(t.Value.(String)) if IsKeywordInRegoVersion(name, p.po.EffectiveRegoVersion()) { - p.errorf(t.Location, "unexpected import path, must not end with a keyword, got: %s", name) p.hint("import a different path or use an alias") + p.errorf(t.Location, "unexpected import path, must not end with a keyword, got: %s", name) } } @@ -1246,17 +1246,25 @@ func (p *Parser) parseLiteral() (expr *Expr) { if outer == nil { return nil } - if p.s.tok == tokens.With { - if outer.With = p.parseWith(); outer.With == nil { - return nil - } - } - return outer + return p.attachWith(outer) } } p.restore(s) } + // LHS/whole parenthesized group at statement start: `(a or b)`, + // `(a or b) and c`, or `({a}) and c`. parseLogicalGroup only commits when the + // parens hold or precede an and/or; otherwise (`({})`, `({a})`, `(a == b)`) it + // restores and we fall through so parseExpr handles the term. + if p.s.tok == tokens.LParen && p.logicalKeywordsActive() { + if body, explicit, loc, committed := p.parseLogicalGroup(false); committed { + if body == nil { + return nil + } + return p.foldLogicalTail(body, explicit, loc) + } + } + // Check that we're not parsing a ref if p.isAllowedRefKeyword(p.s.tok) { // Scan ahead @@ -1280,14 +1288,10 @@ func (p *Parser) parseLiteral() (expr *Expr) { if negated && p.notBodies && p.s.tok == tokens.LBrace { nb := p.parseNotBody(notLoc) - - if nb != nil && p.s.tok == tokens.With { - if nb.With = p.parseWith(); nb.With == nil { - return nil - } + if nb == nil { + return nil } - - return nb + return p.attachWith(nb) } switch p.s.tok { @@ -1324,6 +1328,22 @@ func (p *Parser) parseLiteralExpr(negated bool, notLoc *Location) *Expr { startOffset := p.s.loc.Offset startLoc := p.s.Loc() s := p.save() + + // Negated parenthesized group: `not (a or b)`. The parens are an operand of + // `not`, so any `{...}` inside is a body. + if negated && p.notBodies && p.s.tok == tokens.LParen && p.logicalKeywordsActive() { + if body, explicit, _, committed := p.parseLogicalGroup(true); committed { + if body == nil { + return nil + } + + spanned := p.extendLoc(notLoc) + not := NewExpr(&Not{Body: body, ExplicitBody: explicit, Location: spanned}).SetLocation(spanned) + + return p.foldLogicalTail(NewBody(not), false, spanned) + } + } + expr := p.parseExpr() if expr != nil { var withLoc *Location @@ -1370,10 +1390,7 @@ func (p *Parser) parseLiteralExpr(negated bool, notLoc *Location) *Expr { if p.s.tok == tokens.LogicalAnd || p.s.tok == tokens.LogicalOr { if withLoc != nil { - kw := p.s.tok.String() - p.errorf(withLoc, - "`with` modifier is not allowed on operand of `%s`; wrap the operand in `{...}` to scope, or move `with` after the %s expression to apply it to the whole expression", - kw, kw) + p.errWithOnOperand(withLoc, p.s.tok.String()) return nil } @@ -1386,12 +1403,7 @@ func (p *Parser) parseLiteralExpr(negated bool, notLoc *Location) *Expr { if outer == nil { return nil } - if p.s.tok == tokens.With { - if outer.With = p.parseWith(); outer.With == nil { - return nil - } - } - return outer + return p.attachWith(outer) } } return expr @@ -1445,6 +1457,35 @@ func (p *Parser) parseWith() []*With { return withs } +func (p *Parser) attachWith(e *Expr) *Expr { + if e != nil && p.s.tok == tokens.With { + if e.With = p.parseWith(); e.With == nil { + return nil + } + } + return e +} + +func (p *Parser) errWithOnOperand(loc *Location, kw string) { + p.hint(fmt.Sprintf( + "Wrap the operand in `(...)` or `{...}` to scope, or move `with` after the `%s` expression to apply it to the whole expression", + kw)) + p.errorf(loc, + "`with` modifier is not allowed on operand of `%s`", + kw) +} + +func (p *Parser) foldLogicalTail(body Body, explicit bool, loc *Location) *Expr { + if p.s.tok == tokens.LogicalAnd || p.s.tok == tokens.LogicalOr { + outer := p.parseLogicalOrChain(body, explicit, loc) + if outer == nil { + return nil + } + return p.attachWith(outer) + } + return p.attachWith(body[0]) +} + func (p *Parser) parseSome() *Expr { decl := &SomeDecl{} @@ -1692,6 +1733,26 @@ func (p *Parser) parseLogicalOperand() (Body, bool, *Location) { return NewBody(nb), false, nb.Location } + // Parenthesized logical group operand: `(a or b)` or, when negated, + // `not (a or b)`. This is an operand of and/or/not, so a `{...}` inside is a + // body. If the parens don't hold a logical group parseLogicalGroup restores + // state and we fall through so parseExpr can handle `(a == b)` as a term. + if p.s.tok == tokens.LParen && p.logicalKeywordsActive() && (!negated || p.notBodies) { + if body, explicit, loc, committed := p.parseLogicalGroup(true); committed { + if body == nil { + return nil, false, nil + } + + if negated { + spanned := p.extendLoc(notLoc) + not := NewExpr(&Not{Body: body, ExplicitBody: explicit, Location: spanned}).SetLocation(spanned) + return NewBody(not), false, spanned + } + + return body, explicit, loc + } + } + startOffset := p.s.loc.Offset startLoc := p.s.Loc() expr := p.parseExpr() @@ -1716,6 +1777,161 @@ func (p *Parser) parseLogicalOperand() (Body, bool, *Location) { return NewBody(expr), false, expr.Location } +// isLogicalBody reports whether b is a single-expression body wrapping a +// LogicalAnd/LogicalOr node, i.e. the result of a parenthesized or nested group. +func isLogicalBody(b Body) bool { + if len(b) != 1 { + return false + } + switch b[0].Terms.(type) { + case *LogicalAnd, *LogicalOr: + return true + } + return false +} + +// isNegatedOperand reports whether b is a single negated operand, e.g. `not a` +// (either a *Not node or an expression with Negated set). +func isNegatedOperand(b Body) bool { + if len(b) != 1 { + return false + } + + if b[0].Negated { + return true + } + + _, ok := b[0].Terms.(*Not) + return ok +} + +// expectRParen consumes the closing `)` of a group, reporting an error if the +// current token is not `)`. +func (p *Parser) expectRParen() bool { + if p.s.tok != tokens.RParen { + p.error(p.s.Loc(), "expected ) to close parenthesized group") + return false + } + p.scan() + return true +} + +// parseLogicalGroup attempts to parse a parenthesized grouping of `and`/`or`/`not` +// operands starting at the current `(`. +// +// operandContext reports whether the `(` is already an operand of `and`/`or`/`not`. +func (p *Parser) parseLogicalGroup(operandContext bool) (Body, bool, *Location, bool) { + if !p.enter() { + return nil, false, nil, true + } + defer p.leave() + + s := p.save() + openLoc := p.s.Loc() + p.scan() // consume `(` + + if p.s.tok == tokens.RParen { + if operandContext { + p.error(openLoc, "empty parenthesized group") + return nil, false, nil, true + } + p.restore(s) + return nil, false, nil, false + } + + // A leading `{` is a body only in an operand context; otherwise it's an + // object/set literal and we backtrack to the term parser. + braceLead := p.s.tok == tokens.LBrace + + lhsBody, lhsExplicit, lhsLoc := p.parseLogicalOperand() + if lhsBody == nil { + // An empty `{}` operand (e.g. `not ({})`) is a body error. + if operandContext && braceLead { + return nil, false, nil, true + } + + p.restore(s) + + return nil, false, nil, false + } + + switch { + case p.s.tok == tokens.LogicalAnd || p.s.tok == tokens.LogicalOr: + expr := p.parseLogicalOrChain(lhsBody, lhsExplicit, lhsLoc) + if expr == nil { + return nil, false, nil, true + } + + // A trailing `with` binds to the whole group, e.g. `(a and b with x)`. + if expr = p.attachWith(expr); expr == nil { + return nil, false, nil, true + } + + if !p.expectRParen() { + return nil, false, nil, true + } + + return NewBody(expr), false, p.extendLoc(openLoc), true + + case p.s.tok == tokens.With && !lhsExplicit && len(lhsBody) == 1: + // Single-operand group carrying a `with`, e.g. `(a with x)`; the `with` + // binds to the sole operand. + withLoc := p.s.Loc() + if p.attachWith(lhsBody[0]) == nil { + return nil, false, nil, true + } + + // A `with` on the operand followed by `and`/`or` is ambiguous. + if p.s.tok == tokens.LogicalAnd || p.s.tok == tokens.LogicalOr { + p.errWithOnOperand(withLoc, p.s.tok.String()) + return nil, false, nil, true + } + + if !p.expectRParen() { + return nil, false, nil, true + } + + if operandContext || p.s.tok == tokens.LogicalAnd || p.s.tok == tokens.LogicalOr { + return lhsBody, false, p.extendLoc(openLoc), true + } + + p.restore(s) + return nil, false, nil, false + + case lhsExplicit: + // `({ body })` + if !p.expectRParen() { + return nil, false, nil, true + } + + if operandContext || p.s.tok == tokens.LogicalAnd || p.s.tok == tokens.LogicalOr { + return lhsBody, true, p.extendLoc(openLoc), true + } + + p.restore(s) + return nil, false, nil, false + + case isLogicalBody(lhsBody): + // `(( ... ))`; redundant parens around a nested group. + if !p.expectRParen() { + return nil, false, nil, true + } + return lhsBody, false, p.extendLoc(openLoc), true + + case isNegatedOperand(lhsBody): + // `(not ...)` + if !p.expectRParen() { + return nil, false, nil, true + } + return lhsBody, false, p.extendLoc(openLoc), true + + default: + // Single non-logical operand, e.g. `(a == b)`: not a group. + p.restore(s) + return nil, false, nil, false + } +} + func (p *Parser) parseEvery() *Expr { qb := &Every{} qb.SetLoc(p.s.Loc()) @@ -3081,6 +3297,16 @@ func (b *metadataParser) Append(c *Comment) { var yamlLineErrRegex = regexp.MustCompile(`^yaml:(?: unmarshal errors:[\n\s]*)? line ([[:digit:]]+):`) +// endLoc returns the location of the last comment in the METADATA block, or nil +// if there are none. Only this location is retained on Annotations (for +// EndLoc), so the comment slice itself is never aliased onto the result. +func endLoc(comments []*Comment) *location.Location { + if len(comments) == 0 { + return nil + } + return comments[len(comments)-1].Location +} + func (b *metadataParser) Parse() (result *Annotations, err error) { if len(bytes.TrimSpace(b.buf.Bytes())) == 0 { return nil, errors.New("expected METADATA block, found whitespace") @@ -3091,8 +3317,7 @@ func (b *metadataParser) Parse() (result *Annotations, err error) { var comment *Comment match := yamlLineErrRegex.FindStringSubmatch(err.Error()) if len(match) == 2 { - index, err2 := strconv.Atoi(match[1]) - if err2 == nil { + if index, ok := util.Atoi(match[1]); ok { if index >= len(b.comments) { comment = b.comments[len(b.comments)-1] } else { @@ -3110,7 +3335,11 @@ func (b *metadataParser) Parse() (result *Annotations, err error) { } result = &Annotations{ - comments: b.comments, + // NOTE: only the last comment's location is retained (as endLoc); the + // comment slice itself is backed by a reused buffer (the metadataParser + // is pooled and Reset truncates rather than reallocates), so it must not + // be aliased here. + endLoc: endLoc(b.comments), Scope: raw.Scope, Entrypoint: raw.Entrypoint, Title: raw.Title, @@ -3173,7 +3402,7 @@ func (b *metadataParser) Parse() (result *Annotations, err error) { switch v := v.(type) { case string: - a.Schema, err = parseSchemaRef(v) + a.Schema, err = ParseSchemaRef(v) if err != nil { return nil, err } @@ -3276,10 +3505,14 @@ func unwrapPair(pair map[string]any) (string, any) { var errInvalidSchemaRef = errors.New("invalid schema reference") +// ParseSchemaRef parses a schema reference string into a Ref. Unlike +// ParseRef, it accepts the bare `schema` Var and Refs prefixed with the +// schema root document. +// // NOTE(tsandall): 'schema' is not registered as a root because it's not // supported by the compiler or evaluator today. Once we fix that, we can remove // this function. -func parseSchemaRef(s string) (Ref, error) { +func ParseSchemaRef(s string) (Ref, error) { term, err := ParseTerm(s) if err == nil { @@ -3507,9 +3740,9 @@ func (p *Parser) futureImport(imp *Import, allowedFutureKeywords map[string]toke if keyword == "not" { p.notBodies = true - } else { - kwds = []string{keyword} // overwrite } + + kwds = []string{keyword} // overwrite } for _, kw := range kwds { diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go b/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go index f3bb43640f..c5592d99b8 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/policy.go @@ -6,7 +6,6 @@ package ast import ( "bytes" - "encoding/json" "fmt" "slices" "strings" @@ -273,6 +272,11 @@ type ( generatedFrom *Expr generates []*Expr + + // fromAssignment marks an equality expression that was rewritten from + // `:=`, so the safety checker can keep the RHS from being made safe + // through the LHS. See reorderBodyForSafety. + fromAssignment bool } // SomeDecl represents a variable declaration statement. The symbols are variables. @@ -397,33 +401,13 @@ func (mod *Module) String() string { func (mod *Module) RuleSet(name Var) RuleSet { rs := NewRuleSet() for _, rule := range mod.Rules { - if rule.Head.Name.Equal(name) { + if rule.Head.Name == name { rs.Add(rule) } } return rs } -// UnmarshalJSON parses bs and stores the result in mod. The rules in the module -// will have their module pointer set to mod. -func (mod *Module) UnmarshalJSON(bs []byte) error { - - // Declare a new type and use a type conversion to avoid recursively calling - // Module#UnmarshalJSON. - type module Module - - if err := util.UnmarshalJSON(bs, (*module)(mod)); err != nil { - return err - } - - WalkRules(mod, func(rule *Rule) bool { - rule.Module = mod - return false - }) - - return nil -} - func (mod *Module) regoV1Compatible() bool { return mod.regoVersion == RegoV1 || mod.regoVersion == RegoV0CompatV1 } @@ -514,20 +498,6 @@ func (pkg *Package) String() string { return util.ByteSliceToString(buf) } -func (pkg *Package) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "path": pkg.Path, - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Package { - if pkg.Location != nil { - data["location"] = pkg.Location - } - } - - return json.Marshal(data) -} - // IsValidImportPath returns an error indicating if the import path is invalid. // If the import path is valid, err is nil. func IsValidImportPath(v Value) (err error) { @@ -618,24 +588,6 @@ func (imp *Import) String() string { return util.ByteSliceToString(buf) } -func (imp *Import) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "path": imp.Path, - } - - if len(imp.Alias) != 0 { - data["alias"] = imp.Alias - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Import { - if imp.Location != nil { - data["location"] = imp.Location - } - } - - return json.Marshal(data) -} - // Compare returns an integer indicating whether rule is less than, equal to, // or greater than other. func (rule *Rule) Compare(other *Rule) int { @@ -749,42 +701,6 @@ func (rule *Rule) isFunction() bool { return len(rule.Head.Args) > 0 } -// ruleJSON is used for JSON serialization of Rule to avoid map allocation overhead. -// Field order is alphabetical to match previous map-based output. -type ruleJSON struct { - Annotations []*Annotations `json:"annotations,omitempty"` - Body Body `json:"body"` - Default bool `json:"default,omitempty"` - Else *Rule `json:"else,omitempty"` - Head *Head `json:"head"` - Location *Location `json:"location,omitempty"` -} - -func (rule *Rule) MarshalJSON() ([]byte, error) { - data := ruleJSON{ - Head: rule.Head, - Body: rule.Body, - } - - if rule.Default { - data.Default = true - } - - if rule.Else != nil { - data.Else = rule.Else - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Rule { - data.Location = rule.Location - } - - if len(rule.Annotations) != 0 { - data.Annotations = rule.Annotations - } - - return json.Marshal(data) -} - // NewHead returns a new Head object. If args are provided, the first will be // used for the key and the second will be used for the value. func NewHead(name Var, args ...*Term) *Head { @@ -947,27 +863,6 @@ func (head *Head) stringWithOpts(opts toStringOpts) string { return util.ByteSliceToString(buf) } -func (head *Head) MarshalJSON() ([]byte, error) { - var loc *Location - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Head && head.Location != nil { - loc = head.Location - } - - // NOTE(sr): we do this to override the rendering of `head.Reference`. - // It's still what'll be used via the default means of encoding/json - // for unmarshaling a json object into a Head struct! - type h Head - return json.Marshal(struct { - h - Ref Ref `json:"ref"` - Location *Location `json:"location,omitempty"` - }{ - h: h(*head), - Ref: head.Ref(), - Location: loc, - }) -} - // Vars returns a set of vars found in the head. func (head *Head) Vars() VarSet { vis := NewVarVisitor() @@ -1046,17 +941,6 @@ func NewBody(exprs ...*Expr) Body { return Body(exprs) } -// MarshalJSON returns JSON encoded bytes representing body. -func (body Body) MarshalJSON() ([]byte, error) { - // Serialize empty Body to empty array. This handles both the empty case and the - // nil case (whereas by default the result would be null if body was nil.) - if len(body) == 0 { - return []byte(`[]`), nil - } - ret, err := json.Marshal([]*Expr(body)) - return ret, err -} - // Append adds the expr to the body and updates the expr's index accordingly. func (body *Body) Append(expr *Expr) { n := len(*body) @@ -1076,19 +960,7 @@ func (body Body) Set(expr *Expr, pos int) { // // If body is a subset of other, it is considered less than (and vice versa). func (body Body) Compare(other Body) int { - minLen := min(len(other), len(body)) - for i := range minLen { - if cmp := body[i].Compare(other[i]); cmp != 0 { - return cmp - } - } - if len(body) < len(other) { - return -1 - } - if len(other) < len(body) { - return 1 - } - return 0 + return slices.CompareFunc(body, other, (*Expr).Compare) } // Copy returns a deep copy of body. @@ -1149,10 +1021,6 @@ func (body Body) String() string { return util.ByteSliceToString(buf) } -func (body Body) AppendText(buf []byte) ([]byte, error) { - return AppendDelimeted(buf, body, "; ") -} - // Vars returns a VarSet containing variables in body. The params can be set to // control which vars are included. func (body Body) Vars(params VarVisitorParams) VarSet { @@ -1528,51 +1396,6 @@ func (expr *Expr) String() string { return util.ByteSliceToString(buf) } -// exprJSON is used for JSON serialization of Expr to avoid map allocation overhead. -// Field order is alphabetical to match previous map-based output. -type exprJSON struct { - Generated bool `json:"generated,omitempty"` - Index int `json:"index"` - Location *Location `json:"location,omitempty"` - Negated bool `json:"negated,omitempty"` - Terms any `json:"terms"` - With []*With `json:"with,omitempty"` -} - -func (expr *Expr) MarshalJSON() ([]byte, error) { - data := exprJSON{ - Index: expr.Index, - Terms: expr.Terms, - } - - if len(expr.With) > 0 { - data.With = expr.With - } - - if expr.Generated { - data.Generated = true - } - - if expr.Negated { - data.Negated = true - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Expr { - data.Location = expr.Location - } - - return json.Marshal(data) -} - -// UnmarshalJSON parses the byte array and stores the result in expr. -func (expr *Expr) UnmarshalJSON(bs []byte) error { - v := map[string]any{} - if err := util.UnmarshalJSON(bs, &v); err != nil { - return err - } - return unmarshalExpr(expr, v) -} - // Vars returns a VarSet containing variables in expr. The params can be set to // control which vars are included. func (expr *Expr) Vars(params VarVisitorParams) VarSet { @@ -1589,6 +1412,7 @@ func NewBuiltinExpr(terms ...*Term) *Expr { func (expr *Expr) CogeneratedExprs() []*Expr { visited := map[*Expr]struct{}{} + var result []*Expr visitCogeneratedExprs(expr, func(e *Expr) bool { if expr.Equal(e) { return true @@ -1597,13 +1421,13 @@ func (expr *Expr) CogeneratedExprs() []*Expr { return true } visited[e] = struct{}{} + // Append during visitation so the result order is deterministic; iterating + // the 'visited' map here would randomize the order and, in turn, make + // dependent output (e.g. PrettyEvent's --var-values) nondeterministic. + result = append(result, e) return false }) - result := make([]*Expr, 0, len(visited)) - for e := range visited { - result = append(result, e) - } return result } @@ -1660,20 +1484,6 @@ func (d *SomeDecl) Hash() int { return termSliceHash(d.Symbols) } -func (d *SomeDecl) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "symbols": d.Symbols, - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.SomeDecl { - if d.Location != nil { - data["location"] = d.Location - } - } - - return json.Marshal(data) -} - func (q *Every) String() string { if q.Key != nil { return fmt.Sprintf("every %s, %s in %s { %s }", @@ -1730,23 +1540,6 @@ func (q *Every) KeyValueVars() VarSet { return vis.vars } -func (q *Every) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "key": q.Key, - "value": q.Value, - "domain": q.Domain, - "body": q.Body, - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Every { - if q.Location != nil { - data["location"] = q.Location - } - } - - return json.Marshal(data) -} - func (a *LogicalAnd) String() string { return formatBinaryLogical("and", a.Lhs, a.Rhs, a.ExplicitLhs, a.ExplicitRhs) } @@ -1780,36 +1573,6 @@ func (a *LogicalAnd) Hash() int { return a.Lhs.Hash() + a.Rhs.Hash() } -func (a *LogicalAnd) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "type": "and", - "lhs": a.Lhs, - "rhs": a.Rhs, - } - if a.ExplicitLhs { - data["explicit_lhs"] = true - } - if a.ExplicitRhs { - data["explicit_rhs"] = true - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.And { - if a.Location != nil { - data["location"] = a.Location - } - } - - return json.Marshal(data) -} - -func (a *LogicalAnd) UnmarshalJSON(bs []byte) error { - v := map[string]any{} - if err := util.UnmarshalJSON(bs, &v); err != nil { - return err - } - return unmarshalLogical("and", &a.Lhs, &a.Rhs, &a.ExplicitLhs, &a.ExplicitRhs, v) -} - func (o *LogicalOr) String() string { return formatBinaryLogical("or", o.Lhs, o.Rhs, o.ExplicitLhs, o.ExplicitRhs) } @@ -1843,86 +1606,64 @@ func (o *LogicalOr) Hash() int { return o.Lhs.Hash() + o.Rhs.Hash() } -func (o *LogicalOr) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "type": "or", - "lhs": o.Lhs, - "rhs": o.Rhs, - } - if o.ExplicitLhs { - data["explicit_lhs"] = true - } - if o.ExplicitRhs { - data["explicit_rhs"] = true - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Or { - if o.Location != nil { - data["location"] = o.Location - } - } - - return json.Marshal(data) -} - -func (o *LogicalOr) UnmarshalJSON(bs []byte) error { - v := map[string]any{} - if err := util.UnmarshalJSON(bs, &v); err != nil { - return err - } - return unmarshalLogical("or", &o.Lhs, &o.Rhs, &o.ExplicitLhs, &o.ExplicitRhs, v) -} - -func unmarshalLogical(typeName string, lhs, rhs *Body, explicitLhs, explicitRhs *bool, v map[string]any) error { - lhsRaw, ok := v["lhs"].([]any) - if !ok { - return fmt.Errorf("ast: unable to unmarshal %s, invalid lhs field type: %T (expected list)", typeName, v["lhs"]) - } - l, err := unmarshalBody(lhsRaw) - if err != nil { - return fmt.Errorf("ast: unable to unmarshal %s lhs: %w", typeName, err) - } - *lhs = l - - rhsRaw, ok := v["rhs"].([]any) - if !ok { - return fmt.Errorf("ast: unable to unmarshal %s, invalid rhs field type: %T (expected list)", typeName, v["rhs"]) - } - r, err := unmarshalBody(rhsRaw) - if err != nil { - return fmt.Errorf("ast: unable to unmarshal %s rhs: %w", typeName, err) - } - *rhs = r - - if x, ok := v["explicit_lhs"]; ok { - b, ok := x.(bool) - if !ok { - return fmt.Errorf("ast: unable to unmarshal %s explicit_lhs field with type: %T (expected true or false)", typeName, x) - } - *explicitLhs = b - } - if x, ok := v["explicit_rhs"]; ok { - b, ok := x.(bool) - if !ok { - return fmt.Errorf("ast: unable to unmarshal %s explicit_rhs field with type: %T (expected true or false)", typeName, x) - } - *explicitRhs = b - } - - return nil -} - func formatBinaryLogical(op string, lhs, rhs Body, explicitLhs, explicitRhs bool) string { - return formatLogicalOperand(lhs, explicitLhs) + " " + op + " " + formatLogicalOperand(rhs, explicitRhs) + return formatLogicalOperand(lhs, explicitLhs, op, false) + " " + op + " " + formatLogicalOperand(rhs, explicitRhs, op, true) } -func formatLogicalOperand(b Body, explicit bool) string { - if explicit { +func formatLogicalOperand(b Body, explicit bool, parentOp string, rhs bool) string { + if explicit || len(b) != 1 { return "{ " + b.String() + " }" } + + if logicalOperandNeedsParens(b, parentOp, rhs) { + return "(" + b.String() + ")" + } + return b.String() } +func logicalOperandNeedsParens(b Body, parentOp string, rhs bool) bool { + if len(b) != 1 { + return false + } + + e := b[0] + if len(e.With) > 0 { + return true + } + + switch e.Terms.(type) { + case *LogicalOr: + // `or` binds looser than `and`: always parenthesize under `and`; under + // `or`, parenthesize only the rhs to preserve right-nesting. + return parentOp == "and" || rhs + case *LogicalAnd: + // `and` binds tighter: no parens under `or`; under `and`, parenthesize + // only the rhs to preserve right-nesting. + return parentOp == "and" && rhs + } + return false +} + +func notBodyNeedsParens(b Body) bool { + if len(b) != 1 { + return false + } + + e := b[0] + if len(e.With) > 0 { + return true + } + + switch e.Terms.(type) { + case *LogicalOr, *LogicalAnd: + // `not` binds tighter than `and`/`or` + return true + } + + return false +} + func (w *With) String() string { buf, _ := w.AppendText(make([]byte, 0, w.StringLength())) return util.ByteSliceToString(buf) @@ -1982,27 +1723,6 @@ func (w *With) SetLoc(loc *Location) { w.Location = loc } -// withJSON is used for JSON serialization of With to avoid map allocation overhead. -// Field order is alphabetical to match previous map-based output. -type withJSON struct { - Location *Location `json:"location,omitempty"` - Target *Term `json:"target"` - Value *Term `json:"value"` -} - -func (w *With) MarshalJSON() ([]byte, error) { - data := withJSON{ - Target: w.Target, - Value: w.Value, - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.With { - data.Location = w.Location - } - - return json.Marshal(data) -} - // Copy returns a deep copy of the AST node x. If x is not an AST node, x is returned unmodified. func Copy(x any) any { switch x := x.(type) { @@ -2136,14 +1856,6 @@ func isGlobalBuiltin(expr *Expr, name Var) bool { return false } - // NOTE(tsandall): do not use Term#Equal or Value#Compare to avoid - // allocation here. ref, ok := terms[0].Value.(Ref) - if !ok || len(ref) != 1 { - return false - } - if head, ok := ref[0].Value.(Var); ok { - return head.Equal(name) - } - return false + return ok && len(ref) == 1 && name.Equal(ref[0].Value) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/policy_appenders.go b/vendor/github.com/open-policy-agent/opa/v1/ast/policy_appenders.go index cead974b16..63b260e0a5 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/policy_appenders.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/policy_appenders.go @@ -223,6 +223,10 @@ func (a Args) AppendText(buf []byte) ([]byte, error) { return append(buf, ')'), nil } +func (body Body) AppendText(buf []byte) ([]byte, error) { + return AppendDelimeted(buf, body, "; ") +} + func (expr *Expr) AppendText(buf []byte) ([]byte, error) { if expr.Negated { buf = append(buf, "not "...) @@ -335,17 +339,25 @@ func (o *LogicalOr) AppendText(buf []byte) ([]byte, error) { func appendLogical(buf []byte, op string, lhs, rhs Body, explicitLhs, explicitRhs bool) ([]byte, error) { var err error - if buf, err = appendLogicalOperand(buf, lhs, explicitLhs); err != nil { + if buf, err = appendLogicalOperand(buf, lhs, explicitLhs, op, false); err != nil { return nil, err } buf = append(buf, ' ') buf = append(buf, op...) buf = append(buf, ' ') - return appendLogicalOperand(buf, rhs, explicitRhs) + return appendLogicalOperand(buf, rhs, explicitRhs, op, true) } -func appendLogicalOperand(buf []byte, b Body, explicit bool) ([]byte, error) { +func appendLogicalOperand(buf []byte, b Body, explicit bool, parentOp string, rhs bool) ([]byte, error) { if !explicit && len(b) == 1 { + if logicalOperandNeedsParens(b, parentOp, rhs) { + buf = append(buf, '(') + var err error + if buf, err = b.AppendText(buf); err != nil { + return nil, err + } + return append(buf, ')'), nil + } return b.AppendText(buf) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/policy_json.go b/vendor/github.com/open-policy-agent/opa/v1/ast/policy_json.go new file mode 100644 index 0000000000..b63c035949 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/policy_json.go @@ -0,0 +1,289 @@ +//go:build !go1.27 + +package ast + +import ( + "encoding/json" + + astJSON "github.com/open-policy-agent/opa/v1/ast/json" + "github.com/open-policy-agent/opa/v1/util" +) + +// ruleJSON is used for JSON serialization of Rule to avoid map allocation overhead. +// Field order is alphabetical to match previous map-based output. +type ruleJSON struct { + Annotations []*Annotations `json:"annotations,omitempty"` + Body Body `json:"body"` + Default bool `json:"default,omitempty"` + Else *Rule `json:"else,omitempty"` + Head *Head `json:"head"` + Location *Location `json:"location,omitempty"` +} + +// exprJSON is used for JSON serialization of Expr to avoid map allocation overhead. +// Field order is alphabetical to match previous map-based output. +type exprJSON struct { + Generated bool `json:"generated,omitempty"` + Index int `json:"index"` + Location *Location `json:"location,omitempty"` + Negated bool `json:"negated,omitempty"` + Terms any `json:"terms"` + With []*With `json:"with,omitempty"` +} + +// withJSON is used for JSON serialization of With to avoid map allocation overhead. +// Field order is alphabetical to match previous map-based output. +type withJSON struct { + Location *Location `json:"location,omitempty"` + Target *Term `json:"target"` + Value *Term `json:"value"` +} + +// UnmarshalJSON parses bs and stores the result in mod. The rules in the module +// will have their module pointer set to mod. +func (mod *Module) UnmarshalJSON(bs []byte) error { + + // Declare a new type and use a type conversion to avoid recursively calling + // Module#UnmarshalJSON. + type module Module + + if err := util.UnmarshalJSON(bs, (*module)(mod)); err != nil { + return err + } + + // The decoded rules have no module pointer, as it isn't part of the JSON + // representation; without this, an unmarshalled module can't be compiled. + WalkRules(mod, func(rule *Rule) bool { + rule.Module = mod + return false + }) + + return nil +} + +func (d *SomeDecl) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "symbols": d.Symbols, + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.SomeDecl { + if d.Location != nil { + data["location"] = d.Location + } + } + + return json.Marshal(data) +} + +func (q *Every) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "key": q.Key, + "value": q.Value, + "domain": q.Domain, + "body": q.Body, + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Every { + if q.Location != nil { + data["location"] = q.Location + } + } + + return json.Marshal(data) +} + +func (a *LogicalAnd) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "type": "and", + "lhs": a.Lhs, + "rhs": a.Rhs, + } + if a.ExplicitLhs { + data["explicit_lhs"] = true + } + if a.ExplicitRhs { + data["explicit_rhs"] = true + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.And { + if a.Location != nil { + data["location"] = a.Location + } + } + + return json.Marshal(data) +} + +func (a *LogicalAnd) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + return unmarshalLogical("and", &a.Lhs, &a.Rhs, &a.ExplicitLhs, &a.ExplicitRhs, v) +} + +func (o *LogicalOr) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "type": "or", + "lhs": o.Lhs, + "rhs": o.Rhs, + } + if o.ExplicitLhs { + data["explicit_lhs"] = true + } + if o.ExplicitRhs { + data["explicit_rhs"] = true + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Or { + if o.Location != nil { + data["location"] = o.Location + } + } + + return json.Marshal(data) +} + +func (o *LogicalOr) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + return unmarshalLogical("or", &o.Lhs, &o.Rhs, &o.ExplicitLhs, &o.ExplicitRhs, v) +} + +// UnmarshalJSON parses the byte array and stores the result in expr. +func (expr *Expr) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + return unmarshalExpr(expr, v) +} + +func (expr *Expr) MarshalJSON() ([]byte, error) { + data := exprJSON{ + Index: expr.Index, + Terms: expr.Terms, + } + + if len(expr.With) > 0 { + data.With = expr.With + } + + if expr.Generated { + data.Generated = true + } + + if expr.Negated { + data.Negated = true + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Expr { + data.Location = expr.Location + } + + return json.Marshal(data) +} + +func (w *With) MarshalJSON() ([]byte, error) { + data := withJSON{ + Target: w.Target, + Value: w.Value, + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.With { + data.Location = w.Location + } + + return json.Marshal(data) +} + +func (pkg *Package) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "path": pkg.Path, + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Package { + if pkg.Location != nil { + data["location"] = pkg.Location + } + } + + return json.Marshal(data) +} + +func (imp *Import) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "path": imp.Path, + } + + if len(imp.Alias) != 0 { + data["alias"] = imp.Alias + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Import { + if imp.Location != nil { + data["location"] = imp.Location + } + } + + return json.Marshal(data) +} + +func (rule *Rule) MarshalJSON() ([]byte, error) { + data := ruleJSON{ + Head: rule.Head, + Body: rule.Body, + } + + if rule.Default { + data.Default = true + } + + if rule.Else != nil { + data.Else = rule.Else + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Rule { + data.Location = rule.Location + } + + if len(rule.Annotations) != 0 { + data.Annotations = rule.Annotations + } + + return json.Marshal(data) +} + +func (head *Head) MarshalJSON() ([]byte, error) { + var loc *Location + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Head && head.Location != nil { + loc = head.Location + } + + // NOTE(sr): we do this to override the rendering of `head.Reference`. + // It's still what'll be used via the default means of encoding/json + // for unmarshaling a json object into a Head struct! + type h Head + return json.Marshal(struct { + h + Ref Ref `json:"ref"` + Location *Location `json:"location,omitempty"` + }{ + h: h(*head), + Ref: head.Ref(), + Location: loc, + }) +} + +// MarshalJSON returns JSON encoded bytes representing body. +func (body Body) MarshalJSON() ([]byte, error) { + // Serialize empty Body to empty array. This handles both the empty case and the + // nil case (whereas by default the result would be null if body was nil.) + if len(body) == 0 { + return []byte(`[]`), nil + } + ret, err := json.Marshal([]*Expr(body)) + return ret, err +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/policy_jsonv2.go b/vendor/github.com/open-policy-agent/opa/v1/ast/policy_jsonv2.go new file mode 100644 index 0000000000..faf1b55df7 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/policy_jsonv2.go @@ -0,0 +1,524 @@ +//go:build go1.27 + +package ast + +import ( + "encoding/base64" + "encoding/json/jsontext" + "encoding/json/v2" + "fmt" + + "github.com/open-policy-agent/opa/internal/jsonv2" + astJSON "github.com/open-policy-agent/opa/v1/ast/json" + "github.com/open-policy-agent/opa/v1/util" +) + +var ( + _ json.Unmarshaler = &Module{} + + // These are exported types, so losing MarshalJSON here would be a breaking + // API change even though callers should go through json.Marshal, not this + // method directly. + _ json.Marshaler = Body{} + _ json.Marshaler = &Expr{} + _ json.Marshaler = &Package{} + _ json.Marshaler = &Import{} + _ json.Marshaler = &Rule{} + _ json.Marshaler = &Head{} + _ json.Marshaler = &With{} + _ json.Marshaler = &SomeDecl{} + _ json.Marshaler = &Every{} + _ json.Marshaler = &LogicalAnd{} + _ json.Marshaler = &LogicalOr{} +) + +// UnmarshalJSON parses bs and stores the result in mod. The rules in the module +// will have their module pointer set to mod. +func (mod *Module) UnmarshalJSON(bs []byte) error { + + // Declare a new type and use a type conversion to avoid recursively calling + // Module#UnmarshalJSON. + type module Module + + if err := util.UnmarshalJSON(bs, (*module)(mod)); err != nil { + return err + } + + // The decoded rules have no module pointer, as it isn't part of the JSON + // representation; without this, an unmarshalled module can't be compiled. + WalkRules(mod, func(rule *Rule) bool { + rule.Module = mod + return false + }) + + return nil +} + +// MarshalJSONTo is here to ensure that we do not fall down to TextAppender, +// which Go 1.27's encoding/json would otherwise use, encoding args as the Rego +// representation of the argument list rather than as a JSON array. +func (a Args) MarshalJSONTo(e *jsontext.Encoder) error { + return jsonv2.WriteMarshalerToArrayOrNull(e, a) +} + +// MarshalJSONTo is here to ensure that we do not fall down to TextAppender, +// which Go 1.27's encoding/json would otherwise use, encoding the module as +// Rego source rather than as JSON. Module's own fields are fully described by +// their struct tags, so the encoding is left to them, as it is pre-1.27. The +// field types provide their own MarshalJSONTo where one is needed. +func (m *Module) MarshalJSONTo(e *jsontext.Encoder) error { + // Declare a new type and use a type conversion to avoid recursively calling + // Module#MarshalJSONTo. It's the highest precedence marshaller, so there is + // nothing below it to fall to, and the new type has no methods of its own. + type module Module + + return json.MarshalEncode(e, (*module)(m)) +} + +func (pkg *Package) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Package && pkg.Location != nil { + if err := jsonv2.WriteField(e, "location", pkg.Location); err != nil { + return err + } + } + + if err := jsonv2.WriteField(e, "path", pkg.Path); err != nil { + return err + } + + return e.WriteToken(jsontext.EndObject) +} + +func (i *Import) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if err := jsonv2.WriteField(e, "path", i.Path); err != nil { + return err + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Import && i.Location != nil { + if err := jsonv2.WriteField(e, "location", i.Location); err != nil { + return err + } + } + + if len(i.Alias) > 0 { + e.WriteToken(jsontext.String("alias")) + e.WriteToken(jsontext.String(string(i.Alias))) + } + + return e.WriteToken(jsontext.EndObject) +} + +func (r *Rule) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if r.Default { + e.WriteToken(jsontext.String("default")) + e.WriteToken(jsontext.True) + } + + if r.Else != nil { + if err := jsonv2.WriteField(e, "else", r.Else); err != nil { + return err + } + } + + if err := jsonv2.WriteField(e, "head", r.Head); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "body", r.Body); err != nil { + return err + } + + if len(r.Annotations) > 0 { + if err := jsonv2.WriteFieldArray(e, "annotations", r.Annotations); err != nil { + return err + } + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Rule && r.Location != nil { + if err := jsonv2.WriteField(e, "location", r.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (h *Head) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if h.Name != "" { + e.WriteToken(jsontext.String("name")) + e.WriteToken(jsontext.String(string(h.Name))) + } + + if err := jsonv2.WriteField(e, "ref", h.Ref()); err != nil { + return err + } + + if len(h.Args) > 0 { + if err := jsonv2.WriteFieldArray(e, "args", h.Args); err != nil { + return err + } + } + + if h.Key != nil { + if err := jsonv2.WriteField(e, "key", h.Key); err != nil { + return err + } + } + + if h.Value != nil { + if err := jsonv2.WriteField(e, "value", h.Value); err != nil { + return err + } + } + + if h.Assign { + e.WriteToken(jsontext.String("assign")) + e.WriteToken(jsontext.True) + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Head && h.Location != nil { + if err := jsonv2.WriteField(e, "location", h.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (c Call) MarshalJSONTo(e *jsontext.Encoder) (err error) { + return jsonv2.WriteMarshalerToArrayOrNull(e, c) +} + +func (c *Comment) MarshalJSONTo(e *jsontext.Encoder) error { + // Token write errors are unchecked: an unbalanced value fails at the closing + // token. A marshaller can fail having written a balanced value, so is checked. + e.WriteToken(jsontext.BeginObject) + + // Comment has no JSON tags, hence the capitalised keys, the base64 encoded + // text, and the location being written even when it's nil. + e.WriteToken(jsontext.String("Text")) + + buf := make([]byte, base64.StdEncoding.EncodedLen(len(c.Text))) + base64.StdEncoding.Encode(buf, c.Text) + + e.WriteValue(append(append(append(e.AvailableBuffer(), '"'), buf...), '"')) + + e.WriteToken(jsontext.String("Location")) + if c.Location != nil { + if err := c.Location.MarshalJSONTo(e); err != nil { + return err + } + } else { + e.WriteToken(jsontext.Null) + } + + return e.WriteToken(jsontext.EndObject) +} + +func (q *Every) MarshalJSONTo(e *jsontext.Encoder) error { + // Token write errors are unchecked: an unbalanced value fails at the closing + // token. A marshaller can fail having written a balanced value, so is checked. + e.WriteToken(jsontext.BeginObject) + + e.WriteToken(jsontext.String("key")) + if q.Key == nil { + e.WriteToken(jsontext.Null) + } else { + if err := q.Key.MarshalJSONTo(e); err != nil { + return err + } + } + + if err := jsonv2.WriteField(e, "value", q.Value); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "domain", q.Domain); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "body", q.Body); err != nil { + return err + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Every && q.Location != nil { + if err := jsonv2.WriteField(e, "location", q.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (b Body) MarshalJSONTo(e *jsontext.Encoder) error { + return jsonv2.WriteMarshalerToArray(e, b) +} + +// MarshalJSON returns JSON encoded bytes representing body. +func (body Body) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(body) +} + +func (expr *Expr) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(expr) +} + +// UnmarshalJSON parses the byte array and stores the result in expr. +func (expr *Expr) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + return unmarshalExpr(expr, v) +} + +func (e *Expr) MarshalJSONTo(enc *jsontext.Encoder) error { + enc.WriteToken(jsontext.BeginObject) + + enc.WriteToken(jsontext.String("index")) + enc.WriteToken(jsontext.Int(int64(e.Index))) + + includeLocation := astJSON.GetOptions().MarshalOptions.IncludeLocation + if e.Location != nil && includeLocation.Expr { + if err := jsonv2.WriteField(enc, "location", e.Location); err != nil { + return err + } + } + + if e.Negated { + enc.WriteToken(jsontext.String("negated")) + enc.WriteToken(jsontext.True) + } + + if e.Generated { + enc.WriteToken(jsontext.String("generated")) + enc.WriteToken(jsontext.True) + } + + enc.WriteToken(jsontext.String("terms")) + var err error + switch t := e.Terms.(type) { + case []*Term: + err = jsonv2.WriteMarshalerToArrayOrNull(enc, t) + case json.MarshalerTo: + err = t.MarshalJSONTo(enc) + default: + return fmt.Errorf("unsupported expr terms type: %T", e.Terms) + } + + if err != nil { + return fmt.Errorf("failed to marshal expr terms: %w", err) + } + + if len(e.With) > 0 { + if err := jsonv2.WriteFieldArray(enc, "with", e.With); err != nil { + return err + } + } + + return enc.WriteToken(jsontext.EndObject) +} + +func (a *LogicalAnd) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + e.WriteToken(jsontext.String("type")) + e.WriteToken(jsontext.String("and")) + if err := jsonv2.WriteField(e, "lhs", a.Lhs); err != nil { + return err + } + if err := jsonv2.WriteField(e, "rhs", a.Rhs); err != nil { + return err + } + + if a.ExplicitLhs { + e.WriteToken(jsontext.String("explicit_lhs")) + e.WriteToken(jsontext.True) + } + if a.ExplicitRhs { + e.WriteToken(jsontext.String("explicit_rhs")) + e.WriteToken(jsontext.True) + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.And && a.Location != nil { + if err := jsonv2.WriteField(e, "location", a.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (a *LogicalAnd) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + return unmarshalLogical("and", &a.Lhs, &a.Rhs, &a.ExplicitLhs, &a.ExplicitRhs, v) +} + +func (o *LogicalOr) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + e.WriteToken(jsontext.String("type")) + e.WriteToken(jsontext.String("or")) + + if err := jsonv2.WriteField(e, "lhs", o.Lhs); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "rhs", o.Rhs); err != nil { + return err + } + + if o.ExplicitLhs { + e.WriteToken(jsontext.String("explicit_lhs")) + e.WriteToken(jsontext.True) + } + if o.ExplicitRhs { + e.WriteToken(jsontext.String("explicit_rhs")) + e.WriteToken(jsontext.True) + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Or && o.Location != nil { + if err := jsonv2.WriteField(e, "location", o.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (o *LogicalOr) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + return unmarshalLogical("or", &o.Lhs, &o.Rhs, &o.ExplicitLhs, &o.ExplicitRhs, v) +} + +func (w *With) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if err := jsonv2.WriteField(e, "target", w.Target); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "value", w.Value); err != nil { + return err + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.With && w.Location != nil { + if err := jsonv2.WriteField(e, "location", w.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (d *SomeDecl) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + e.WriteToken(jsontext.String("symbols")) + if err := jsonv2.WriteMarshalerToArrayOrNull(e, d.Symbols); err != nil { + return err + } + + if d.Location != nil && astJSON.GetOptions().MarshalOptions.IncludeLocation.SomeDecl { + if err := jsonv2.WriteField(e, "location", d.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (ac *ArrayComprehension) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if err := jsonv2.WriteField(e, "term", ac.Term); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "body", ac.Body); err != nil { + return err + } + + return e.WriteToken(jsontext.EndObject) +} + +func (sc *SetComprehension) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if err := jsonv2.WriteField(e, "term", sc.Term); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "body", sc.Body); err != nil { + return err + } + + return e.WriteToken(jsontext.EndObject) +} + +func (oc *ObjectComprehension) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + + if err := jsonv2.WriteField(e, "key", oc.Key); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "value", oc.Value); err != nil { + return err + } + + if err := jsonv2.WriteField(e, "body", oc.Body); err != nil { + return err + } + + return e.WriteToken(jsontext.EndObject) +} + +func (pkg *Package) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(pkg) +} + +func (imp *Import) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(imp) +} + +func (rule *Rule) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(rule) +} + +func (head *Head) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(head) +} + +func (w *With) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(w) +} + +func (d *SomeDecl) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(d) +} + +func (q *Every) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(q) +} + +func (a *LogicalAnd) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(a) +} + +func (o *LogicalOr) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(o) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/string_length.go b/vendor/github.com/open-policy-agent/opa/v1/ast/string_length.go index ccdc7dc7a4..09247effa6 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/string_length.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/string_length.go @@ -365,6 +365,10 @@ func (c *Comment) StringLength() int { func (not *Not) StringLength() int { if !not.ExplicitBody && len(not.Body) == 1 { + if notBodyNeedsParens(not.Body) { + // "not (...)" + return 6 + not.Body.StringLength() + } // "not ..." return 4 + not.Body.StringLength() } @@ -373,19 +377,22 @@ func (not *Not) StringLength() int { } func (a *LogicalAnd) StringLength() int { - return logicalOperandStringLength(a.Lhs, a.ExplicitLhs) + + return logicalOperandStringLength(a.Lhs, a.ExplicitLhs, "and", false) + 5 + // " and " - logicalOperandStringLength(a.Rhs, a.ExplicitRhs) + logicalOperandStringLength(a.Rhs, a.ExplicitRhs, "and", true) } func (o *LogicalOr) StringLength() int { - return logicalOperandStringLength(o.Lhs, o.ExplicitLhs) + + return logicalOperandStringLength(o.Lhs, o.ExplicitLhs, "or", false) + 4 + // " or " - logicalOperandStringLength(o.Rhs, o.ExplicitRhs) + logicalOperandStringLength(o.Rhs, o.ExplicitRhs, "or", true) } -func logicalOperandStringLength(b Body, explicit bool) int { +func logicalOperandStringLength(b Body, explicit bool, parentOp string, rhs bool) int { if !explicit && len(b) == 1 { + if logicalOperandNeedsParens(b, parentOp, rhs) { + return b.StringLength() + 2 // "(" + body + ")" + } return b.StringLength() } return b.StringLength() + 4 // "{ " + body + " }" diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/term.go b/vendor/github.com/open-policy-agent/opa/v1/ast/term.go index 178bc09e38..23820f13bb 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/term.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/term.go @@ -19,7 +19,6 @@ import ( "unicode" "github.com/cespare/xxhash/v2" - astJSON "github.com/open-policy-agent/opa/v1/ast/json" "github.com/open-policy-agent/opa/v1/ast/location" "github.com/open-policy-agent/opa/v1/util" ) @@ -380,15 +379,12 @@ func (term *Term) Copy() *Term { // Equal returns true if this term equals the other term. Equality is // defined for each kind of term, and does not compare the Location. func (term *Term) Equal(other *Term) bool { - if term == nil && other != nil { - return false - } - if term != nil && other == nil { - return false - } if term == other { return true } + if term == nil || other == nil { + return false + } return ValueEqual(term.Value, other.Value) } @@ -423,55 +419,10 @@ func (term *Term) IsGround() bool { return term.Value.IsGround() } -// termJSON is used to serialize Term to JSON without map allocation. -type termJSON struct { - Location *Location `json:"location,omitempty"` - Type string `json:"type"` - Value Value `json:"value"` -} - -// MarshalJSON returns the JSON encoding of the term. -// -// Specialized marshalling logic is required to include a type hint for Value. -func (term *Term) MarshalJSON() ([]byte, error) { - d := termJSON{ - Type: ValueName(term.Value), - Value: term.Value, - } - jsonOptions := astJSON.GetOptions().MarshalOptions - if jsonOptions.IncludeLocation.Term { - d.Location = term.Location - } - return json.Marshal(d) -} - func (term *Term) String() string { return term.Value.String() } -// UnmarshalJSON parses the byte array and stores the result in term. -// Specialized unmarshalling is required to handle Value and Location. -func (term *Term) UnmarshalJSON(bs []byte) error { - v := map[string]any{} - if err := util.UnmarshalJSON(bs, &v); err != nil { - return err - } - val, err := unmarshalValue(v) - if err != nil { - return err - } - term.Value = val - - if loc, ok := v["location"].(map[string]any); ok { - term.Location = &Location{} - err := unmarshalLocation(term.Location, loc) - if err != nil { - return err - } - } - return nil -} - // Vars returns a VarSet with variables contained in this term. func (term *Term) Vars() VarSet { vis := NewVarVisitor() @@ -654,62 +605,15 @@ func (n *Not) IsGround() bool { func (n *Not) String() string { if !n.ExplicitBody && len(n.Body) == 1 { + if notBodyNeedsParens(n.Body) { + return "not (" + n.Body.String() + ")" + } return "not " + n.Body.String() } return "not {" + n.Body.String() + "}" } -func (n *Not) MarshalJSON() ([]byte, error) { - data := map[string]any{ - "type": "not", - "body": n.Body, - "explicit_body": n.ExplicitBody, - } - - if astJSON.GetOptions().MarshalOptions.IncludeLocation.Not { - if n.Location != nil { - data["location"] = n.Location - } - } - - return json.Marshal(data) -} - -func (n *Not) UnmarshalJSON(bs []byte) error { - v := map[string]any{} - if err := util.UnmarshalJSON(bs, &v); err != nil { - return err - } - - return unmarshalNot(n, v) -} - -func unmarshalNot(n *Not, v map[string]any) error { - var eb bool - if x, ok := v["explicit_body"]; ok { - eb, ok = x.(bool) - if !ok { - return fmt.Errorf("ast: unable to unmarshal explicit_body field with type: %T (expected true or false)", v["explicit_body"]) - } - } - - b, ok := v["body"].([]any) - if !ok { - return fmt.Errorf("ast: unable to unmarshal not, invalid body field type: %T (expected list)", v["body"]) - } - - body, err := unmarshalBody(b) - if err != nil { - return fmt.Errorf("ast: unable to unmarshal not body: %w", err) - } - - n.ExplicitBody = eb - n.Body = body - - return nil -} - // Null represents the null value defined by JSON. type Null struct{} @@ -874,7 +778,7 @@ func (num Number) Find(path Ref) (Value, error) { // Hash returns the hash code for the Value. func (num Number) Hash() int { if len(num) < 4 { - if i, err := strconv.Atoi(string(num)); err == nil { + if i, ok := util.Atoi(string(num)); ok { return i } } @@ -892,11 +796,7 @@ func (num Number) Int() (int, bool) { // Int64 returns the int64 representation of num if possible. func (num Number) Int64() (int64, bool) { - i, err := json.Number(num).Int64() - if err != nil { - return 0, false - } - return i, true + return util.Atoi64(string(num)) } // Float64 returns the float64 representation of num if possible. @@ -913,11 +813,6 @@ func (Number) IsGround() bool { return true } -// MarshalJSON returns JSON encoded bytes representing num. -func (num Number) MarshalJSON() ([]byte, error) { - return json.Marshal(json.Number(num)) -} - func (num Number) String() string { return string(num) } @@ -1696,14 +1591,6 @@ func (arr *Array) IsGround() bool { return arr.ground } -// MarshalJSON returns JSON encoded bytes representing arr. -func (arr *Array) MarshalJSON() ([]byte, error) { - if len(arr.elems) == 0 { - return []byte(`[]`), nil - } - return json.Marshal(arr.elems) -} - func (arr *Array) String() string { buf, _ := arr.AppendText(make([]byte, 0, arr.StringLength())) return util.ByteSliceToString(buf) @@ -2052,14 +1939,6 @@ func (s *set) Len() int { return len(s.keys) } -// MarshalJSON returns JSON encoded bytes representing s. -func (s *set) MarshalJSON() ([]byte, error) { - if s.keys == nil { - return []byte(`[]`), nil - } - return json.Marshal(s.sortedKeys()) -} - // Sorted returns an Array that contains the sorted elements of s. func (s *set) Sorted() *Array { cpy := make([]*Term, len(s.keys)) @@ -2228,10 +2107,6 @@ func (l *lazyObj) Map(f func(*Term, *Term) (*Term, *Term, error)) (Object, error return l.force().Map(f) } -func (l *lazyObj) MarshalJSON() ([]byte, error) { - return l.force().(*object).MarshalJSON() -} - func (l *lazyObj) Merge(other Object) (Object, bool) { return l.force().Merge(other) } @@ -2609,15 +2484,6 @@ func (obj *object) KeysIterator() ObjectKeysIterator { return newobjectKeysIterator(obj) } -// MarshalJSON returns JSON encoded bytes representing obj. -func (obj *object) MarshalJSON() ([]byte, error) { - sl := make([][2]*Term, obj.Len()) - for i, node := range obj.sortedKeys() { - sl[i] = Item(node.key, node.value) - } - return json.Marshal(sl) -} - // Merge returns a new Object containing the non-overlapping keys of obj and other. If there are // overlapping keys between obj and other, the values of associated with the keys are merged. Only // objects can be merged with other objects. If the values cannot be merged, the second turn value @@ -3191,6 +3057,29 @@ func isControlOrBackslash(r rune) bool { // on the happy path and treats all errors the same. If better error // reporting is needed, the error paths will need to be fleshed out. +// UnmarshalJSON parses the byte array and stores the result in term. +// Specialized unmarshalling is required to handle Value and Location. +func (term *Term) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + val, err := unmarshalValue(v) + if err != nil { + return err + } + term.Value = val + + if loc, ok := v["location"].(map[string]any); ok { + term.Location = &Location{} + err := unmarshalLocation(term.Location, loc) + if err != nil { + return err + } + } + return nil +} + func unmarshalBody(b []any) (Body, error) { buf := Body{} for _, e := range b { @@ -3395,6 +3284,45 @@ func unmarshalWith(i any) (*With, error) { return nil, errors.New(`ast: unable to unmarshal with modifier (expected {"target": {...}, "value": {...}})`) } +func unmarshalLogical(typeName string, lhs, rhs *Body, explicitLhs, explicitRhs *bool, v map[string]any) error { + lhsRaw, ok := v["lhs"].([]any) + if !ok { + return fmt.Errorf("ast: unable to unmarshal %s, invalid lhs field type: %T (expected list)", typeName, v["lhs"]) + } + l, err := unmarshalBody(lhsRaw) + if err != nil { + return fmt.Errorf("ast: unable to unmarshal %s lhs: %w", typeName, err) + } + *lhs = l + + rhsRaw, ok := v["rhs"].([]any) + if !ok { + return fmt.Errorf("ast: unable to unmarshal %s, invalid rhs field type: %T (expected list)", typeName, v["rhs"]) + } + r, err := unmarshalBody(rhsRaw) + if err != nil { + return fmt.Errorf("ast: unable to unmarshal %s rhs: %w", typeName, err) + } + *rhs = r + + if x, ok := v["explicit_lhs"]; ok { + b, ok := x.(bool) + if !ok { + return fmt.Errorf("ast: unable to unmarshal %s explicit_lhs field with type: %T (expected true or false)", typeName, x) + } + *explicitLhs = b + } + if x, ok := v["explicit_rhs"]; ok { + b, ok := x.(bool) + if !ok { + return fmt.Errorf("ast: unable to unmarshal %s explicit_rhs field with type: %T (expected true or false)", typeName, x) + } + *explicitRhs = b + } + + return nil +} + func unmarshalValue(d map[string]any) (Value, error) { v := d["value"] switch d["type"] { @@ -3512,3 +3440,28 @@ func unmarshalValue(d map[string]any) (Value, error) { unmarshal_error: return nil, errors.New("ast: unable to unmarshal term") } + +func unmarshalNot(n *Not, v map[string]any) error { + var eb bool + if x, ok := v["explicit_body"]; ok { + eb, ok = x.(bool) + if !ok { + return fmt.Errorf("ast: unable to unmarshal explicit_body field with type: %T (expected true or false)", v["explicit_body"]) + } + } + + b, ok := v["body"].([]any) + if !ok { + return fmt.Errorf("ast: unable to unmarshal not, invalid body field type: %T (expected list)", v["body"]) + } + + body, err := unmarshalBody(b) + if err != nil { + return fmt.Errorf("ast: unable to unmarshal not body: %w", err) + } + + n.ExplicitBody = eb + n.Body = body + + return nil +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/term_appenders.go b/vendor/github.com/open-policy-agent/opa/v1/ast/term_appenders.go index 63c3973b3f..60a9a088d7 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/term_appenders.go +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/term_appenders.go @@ -289,6 +289,14 @@ func appendComprehensionTerm(buf []byte, term *Term) ([]byte, error) { func (not *Not) AppendText(buf []byte) ([]byte, error) { if !not.ExplicitBody && len(not.Body) == 1 { + if notBodyNeedsParens(not.Body) { + buf = append(buf, "not ("...) + var err error + if buf, err = not.Body.AppendText(buf); err != nil { + return nil, err + } + return append(buf, ')'), nil + } buf = append(buf, "not "...) return not.Body.AppendText(buf) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/term_json.go b/vendor/github.com/open-policy-agent/opa/v1/ast/term_json.go new file mode 100644 index 0000000000..685801b66d --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/term_json.go @@ -0,0 +1,95 @@ +// Copyright 2026 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +//go:build !go1.27 + +package ast + +import ( + "encoding/json" + + astJSON "github.com/open-policy-agent/opa/v1/ast/json" + "github.com/open-policy-agent/opa/v1/util" +) + +// termJSON is used to serialize Term to JSON without map allocation. +type termJSON struct { + Location *Location `json:"location,omitempty"` + Type string `json:"type"` + Value Value `json:"value"` +} + +// MarshalJSON returns the JSON encoding of the term. +// +// Specialized marshalling logic is required to include a type hint for Value. +func (term *Term) MarshalJSON() ([]byte, error) { + d := termJSON{ + Type: ValueName(term.Value), + Value: term.Value, + } + jsonOptions := astJSON.GetOptions().MarshalOptions + if jsonOptions.IncludeLocation.Term { + d.Location = term.Location + } + return json.Marshal(d) +} + +// MarshalJSON returns JSON encoded bytes representing arr. +func (arr *Array) MarshalJSON() ([]byte, error) { + if len(arr.elems) == 0 { + return []byte(`[]`), nil + } + return json.Marshal(arr.elems) +} + +// MarshalJSON returns JSON encoded bytes representing num. +func (num Number) MarshalJSON() ([]byte, error) { + return json.Marshal(json.Number(num)) +} + +// MarshalJSON returns JSON encoded bytes representing obj. +func (obj *object) MarshalJSON() ([]byte, error) { + sl := make([][2]*Term, obj.Len()) + for i, node := range obj.sortedKeys() { + sl[i] = Item(node.key, node.value) + } + return json.Marshal(sl) +} + +// MarshalJSON returns JSON encoded bytes representing s. +func (s *set) MarshalJSON() ([]byte, error) { + if s.keys == nil { + return []byte(`[]`), nil + } + return json.Marshal(s.sortedKeys()) +} + +func (l *lazyObj) MarshalJSON() ([]byte, error) { + return l.force().(*object).MarshalJSON() +} + +func (n *Not) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "type": "not", + "body": n.Body, + "explicit_body": n.ExplicitBody, + } + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Not { + if n.Location != nil { + data["location"] = n.Location + } + } + + return json.Marshal(data) +} + +func (n *Not) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + + return unmarshalNot(n, v) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/term_jsonv2.go b/vendor/github.com/open-policy-agent/opa/v1/ast/term_jsonv2.go new file mode 100644 index 0000000000..62189c3729 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/term_jsonv2.go @@ -0,0 +1,251 @@ +//go:build go1.27 + +package ast + +import ( + "encoding" + "encoding/json/jsontext" + "encoding/json/v2" + "fmt" + + "github.com/open-policy-agent/opa/internal/jsonv2" + astJSON "github.com/open-policy-agent/opa/v1/ast/json" + "github.com/open-policy-agent/opa/v1/util" +) + +var ( + _ json.MarshalerTo = &Term{} + _ json.Unmarshaler = &LogicalOr{} + _ json.MarshalerTo = &LogicalOr{} + _ json.MarshalerTo = &Not{} + _ json.MarshalerTo = &Array{} + _ json.MarshalerTo = &set{} + _ json.MarshalerTo = &object{} + _ json.MarshalerTo = &TemplateString{} + _ json.MarshalerTo = &Ref{} + _ json.MarshalerTo = &lazyObj{} + _ json.MarshalerTo = Args{} + _ json.MarshalerTo = Boolean(false) + _ json.MarshalerTo = Null{} + _ json.MarshalerTo = Number("") + _ json.MarshalerTo = String("") + _ json.MarshalerTo = Var("") + _ json.Unmarshaler = &Not{} + + // These are exported types, so losing MarshalJSON here would be a breaking + // API change even though callers should go through json.Marshal, not this + // method directly. + _ json.Marshaler = Number("") + _ json.Marshaler = &Term{} + _ json.Marshaler = &Not{} + _ json.Marshaler = &lazyObj{} + _ json.Marshaler = &object{} + _ json.Marshaler = &Array{} + _ json.Marshaler = &set{} +) + +// These are here to ensure that we do not fall down to TextAppender, which +// Go 1.27's encoding/json would otherwise use, encoding these as JSON strings. + +func (b Boolean) MarshalJSONTo(e *jsontext.Encoder) error { + return e.WriteToken(jsontext.Bool(bool(b))) +} + +func (Null) MarshalJSONTo(e *jsontext.Encoder) error { + // Encoded as an empty object rather than null, as that's the representation + // callers have come to expect. See also [marshalValueTo]. + return e.WriteValue([]byte("{}")) +} + +func (v Var) MarshalJSONTo(e *jsontext.Encoder) error { + // Must produce the var name as a JSON string, wildcard vars included: that's + // what encoding/json v1 does for a type whose underlying kind is string. + return e.WriteToken(jsontext.String(string(v))) +} + +func (num Number) MarshalJSONTo(e *jsontext.Encoder) error { + if num == "" { + // Matches encoding/json v1, which encodes an empty json.Number as 0. + return e.WriteToken(jsontext.Int(0)) + } + return e.WriteValue(jsontext.Value(num)) +} + +// MarshalJSON returns JSON encoded bytes representing num. +func (num Number) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(num) +} + +func (str String) MarshalJSONTo(e *jsontext.Encoder) error { + return e.WriteToken(jsontext.String(string(str))) +} + +func (t *Term) MarshalJSONTo(e *jsontext.Encoder) (err error) { + // Token write errors are unchecked: an unbalanced value fails at the closing + // token. A marshaller can fail having written a balanced value, so is checked. + e.WriteToken(jsontext.BeginObject) + + includeLocation := astJSON.GetOptions().MarshalOptions.IncludeLocation + if t.Location != nil && includeLocation.Term { + if err := jsonv2.WriteField(e, "location", t.Location); err != nil { + return err + } + } + + e.WriteToken(jsontext.String("type")) + e.WriteToken(jsontext.String(ValueName(t.Value))) + + e.WriteToken(jsontext.String("value")) + if err = marshalValueTo(e, t.Value); err != nil { + return fmt.Errorf("failed to marshal term of %s: %w", ValueName(t.Value), err) + } + + return e.WriteToken(jsontext.EndObject) +} + +// MarshalJSON returns the JSON encoding of the term. +func (term *Term) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(term) +} + +func (r Ref) MarshalJSONTo(e *jsontext.Encoder) (err error) { + return jsonv2.WriteMarshalerToArrayOrNull(e, r) +} + +func (t *TemplateString) MarshalJSONTo(e *jsontext.Encoder) (err error) { + // Token write errors are unchecked: an unbalanced value fails at the closing + // token. A marshaller can fail having written a balanced value, so is checked. + e.WriteToken(jsontext.BeginObject) + e.WriteToken(jsontext.String("parts")) + if t.Parts == nil { + // Parts has no omitempty tag, so it's always written. Matches + // encoding/json v1, which encodes a nil slice as null rather than as an + // empty array. + e.WriteToken(jsontext.Null) + } else { + e.WriteToken(jsontext.BeginArray) + for _, p := range t.Parts { + switch v := p.(type) { + case *Expr: + if err := v.MarshalJSONTo(e); err != nil { + return err + } + case *Term: + if err := v.MarshalJSONTo(e); err != nil { + return err + } + } + } + e.WriteToken(jsontext.EndArray) + } + + e.WriteToken(jsontext.String("multi_line")) + e.WriteToken(jsontext.Bool(t.MultiLine)) + + return e.WriteToken(jsontext.EndObject) +} + +func (n *Not) MarshalJSONTo(e *jsontext.Encoder) error { + e.WriteToken(jsontext.BeginObject) + e.WriteToken(jsontext.String("type")) + e.WriteToken(jsontext.String("not")) + + if err := jsonv2.WriteField(e, "body", n.Body); err != nil { + return err + } + + e.WriteToken(jsontext.String("explicit_body")) + e.WriteToken(jsontext.Bool(n.ExplicitBody)) + + if astJSON.GetOptions().MarshalOptions.IncludeLocation.Not && n.Location != nil { + if err := jsonv2.WriteField(e, "location", n.Location); err != nil { + return err + } + } + + return e.WriteToken(jsontext.EndObject) +} + +func (n *Not) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(n) +} + +func (n *Not) UnmarshalJSON(bs []byte) error { + v := map[string]any{} + if err := util.UnmarshalJSON(bs, &v); err != nil { + return err + } + + return unmarshalNot(n, v) +} + +func (obj *object) MarshalJSONTo(e *jsontext.Encoder) error { + // Token write errors are unchecked: an unbalanced value fails at the closing + // token. A marshaller can fail having written a balanced value, so is checked. + e.WriteToken(jsontext.BeginArray) + + for _, node := range obj.sortedKeys() { + e.WriteToken(jsontext.BeginArray) + if err := node.key.MarshalJSONTo(e); err != nil { + return err + } + if err := node.value.MarshalJSONTo(e); err != nil { + return err + } + e.WriteToken(jsontext.EndArray) + } + return e.WriteToken(jsontext.EndArray) +} + +func (l *lazyObj) MarshalJSONTo(e *jsontext.Encoder) error { + return l.force().(*object).MarshalJSONTo(e) +} + +func (l *lazyObj) MarshalJSON() ([]byte, error) { + return l.force().(*object).MarshalJSON() +} + +// MarshalJSON returns JSON encoded bytes representing obj. +func (obj *object) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(obj) +} + +func (a *Array) MarshalJSONTo(e *jsontext.Encoder) error { + return jsonv2.WriteMarshalerToArray(e, a.elems) +} + +// MarshalJSON returns JSON encoded bytes representing arr. +func (arr *Array) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(arr) +} + +func (s *set) MarshalJSONTo(e *jsontext.Encoder) error { + return jsonv2.WriteMarshalerToArray(e, s.sortedKeys()) +} + +// MarshalJSON returns JSON encoded bytes representing s. +func (s *set) MarshalJSON() ([]byte, error) { + return jsonv2.MarshalMarshalerTo(s) +} + +func marshalValueTo(e *jsontext.Encoder, val Value) (err error) { + switch v := val.(type) { + case json.MarshalerTo: + err = v.MarshalJSONTo(e) + case encoding.TextAppender: + var text []byte + if text, err = v.AppendText(nil); err != nil { + return err + } + + if text, err = jsontext.AppendQuote(e.AvailableBuffer(), text); err != nil { + return err + } + + err = e.WriteValue(text) + default: + err = json.MarshalEncode(e, v) + } + + return err +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json b/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json index 4e5442604c..91e4d09ff3 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json +++ b/vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json @@ -845,6 +845,11 @@ "Minor": 36, "Patch": 0 }, + "strings.split_n": { + "Major": 1, + "Minor": 19, + "Patch": 0 + }, "substring": { "Major": 0, "Minor": 17, diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go index b717a5a718..f697e336d5 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go @@ -23,11 +23,13 @@ import ( "github.com/gobwas/glob" "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" "github.com/open-policy-agent/opa/internal/file/archive" "github.com/open-policy-agent/opa/internal/merge" "github.com/open-policy-agent/opa/v1/ast" astJSON "github.com/open-policy-agent/opa/v1/ast/json" + pb "github.com/open-policy-agent/opa/v1/bundle/v1pb" "github.com/open-policy-agent/opa/v1/format" "github.com/open-policy-agent/opa/v1/metrics" "github.com/open-policy-agent/opa/v1/storage" @@ -39,7 +41,9 @@ const ( RegoExt = ".rego" WasmFile = "policy.wasm" PlanFile = "plan.json" + PlanProtoFile = "plan.pb" ManifestExt = ".manifest" + ManifestProtoExt = ".manifest.pb" SignaturesFile = "signatures.json" patchFile = "patch.json" dataFile = "data.json" @@ -70,6 +74,13 @@ type Bundle struct { lazyLoadingMode bool sizeLimitBytes int64 + manifestProto bool +} + +// SetManifestProto configures the bundle to serialize its manifest as +// protobuf at /.manifest.pb instead of JSON at /.manifest. +func (b *Bundle) SetManifestProto(yes bool) { + b.manifestProto = yes } // Raw contains raw bytes representing the bundle's content @@ -213,7 +224,7 @@ func (m Manifest) Equal(other Manifest) bool { // If both are nil, or both are empty, we consider them equal. if !(len(m.FileRegoVersions) == 0 && len(other.FileRegoVersions) == 0) && - !reflect.DeepEqual(m.FileRegoVersions, other.FileRegoVersions) { + !maps.Equal(m.FileRegoVersions, other.FileRegoVersions) { return false } @@ -641,6 +652,7 @@ func (r *Reader) Read() (Bundle, error) { } var modules []ModuleFile + var manifestPath string for _, f := range descriptors { buf, err := readFile(f, r.sizeLimitBytes) if err != nil { @@ -695,7 +707,7 @@ func (r *Reader) Read() (Bundle, error) { Path: r.fullPath(path), Raw: buf.Bytes(), }) - } else if filepath.Base(path) == PlanFile { + } else if filepath.Base(path) == PlanFile || filepath.Base(path) == PlanProtoFile { bundle.PlanModules = append(bundle.PlanModules, PlanModuleFile{ URL: f.URL(), Path: r.fullPath(path), @@ -741,7 +753,26 @@ func (r *Reader) Read() (Bundle, error) { return empty, err } + } else if strings.HasSuffix(path, ManifestProtoExt) { + if manifestPath != "" { + return empty, fmt.Errorf("bundle contains multiple manifest files: %q and %q", manifestPath, path) + } + manifestPath = path + pbManifest := &pb.Manifest{} + if err := proto.Unmarshal(buf.Bytes(), pbManifest); err != nil { + return empty, fmt.Errorf("bundle load failed on manifest decode: %w", err) + } + m, err := ManifestFromProto(pbManifest) + if err != nil { + return empty, fmt.Errorf("bundle load failed on manifest decode: %w", err) + } + bundle.Manifest = *m + bundle.manifestProto = true } else if strings.HasSuffix(path, ManifestExt) { + if manifestPath != "" { + return empty, fmt.Errorf("bundle contains multiple manifest files: %q and %q", manifestPath, path) + } + manifestPath = path if err := util.NewJSONDecoder(&buf).Decode(&bundle.Manifest); err != nil { return empty, fmt.Errorf("bundle load failed on manifest decode: %w", err) } @@ -935,6 +966,9 @@ func (w *Writer) DisableFormat(yes bool) *Writer { // Write writes the bundle to the writer's output stream. func (w *Writer) Write(bundle Bundle) error { + if err := validateBundleFormat(&bundle); err != nil { + return err + } tw := archive.NewTarGzWriter(w.w) if bundle.Type() == SnapshotBundleType { @@ -971,8 +1005,18 @@ func (w *Writer) Write(bundle Bundle) error { } if !bundle.Manifest.Empty() { - if err := tw.WriteJSONFile("/.manifest", bundle.Manifest); err != nil { - return err + if bundle.manifestProto { + bs, err := marshalManifestProto(&bundle.Manifest) + if err != nil { + return err + } + if err := tw.WriteFile(util.WithPrefix(ManifestProtoExt, "/"), bs); err != nil { + return err + } + } else { + if err := tw.WriteJSONFile("/.manifest", bundle.Manifest); err != nil { + return err + } } } @@ -1060,32 +1104,74 @@ func hashBundleFiles(hash SignatureHasher, b *Bundle) ([]FileInfo, error) { files = append(files, NewFile(strings.TrimPrefix(planmodule.Path, "/"), hex.EncodeToString(bs), defaultHashingAlg)) } - // If the manifest is essentially empty, don't add it to the signatures since it - // won't be written to the bundle. Otherwise: - // parse the manifest into a JSON structure; - // then recursively order the fields of all objects alphabetically and then apply - // the hash function to result to compute the hash. + // Skip empty manifest — Writer.Write skips it too, so no entry to hash. + // Proto manifest is hashed as raw deterministic-marshal bytes (matches + // what VerifyBundleFile sees, since IsStructuredDoc is false for /.manifest.pb). if !b.Manifest.Empty() { - mbs, err := json.Marshal(b.Manifest) - if err != nil { - return files, err - } + if b.manifestProto { + pbBytes, err := marshalManifestProto(&b.Manifest) + if err != nil { + return files, err + } + if bs, err = hash.HashFile(pbBytes); err != nil { + return files, err + } + files = append(files, NewFile(strings.TrimPrefix(ManifestProtoExt, "/"), hex.EncodeToString(bs), defaultHashingAlg)) + } else { + mbs, err := json.Marshal(b.Manifest) + if err != nil { + return files, err + } - var result map[string]any - if err := util.Unmarshal(mbs, &result); err != nil { - return files, err - } + var result map[string]any + if err := util.Unmarshal(mbs, &result); err != nil { + return files, err + } - if bs, err = hash.HashFile(result); err != nil { - return files, err - } + if bs, err = hash.HashFile(result); err != nil { + return files, err + } - files = append(files, NewFile(strings.TrimPrefix(ManifestExt, "/"), hex.EncodeToString(bs), defaultHashingAlg)) + files = append(files, NewFile(strings.TrimPrefix(ManifestExt, "/"), hex.EncodeToString(bs), defaultHashingAlg)) + } } return files, err } +// marshalManifestProto returns the deterministic protobuf wire form so +// signer and writer produce byte-identical output (sign/verify on +// /.manifest.pb depends on it). +func marshalManifestProto(m *Manifest) ([]byte, error) { + pbManifest, err := ManifestToProto(m) + if err != nil { + return nil, err + } + return proto.MarshalOptions{Deterministic: true}.Marshal(pbManifest) +} + +// validateBundleFormat rejects bundles whose plan format disagrees with +// the manifest format (e.g. /plan.pb + /.manifest). +func validateBundleFormat(b *Bundle) error { + if b.Manifest.Empty() { + return nil + } + for _, pm := range b.PlanModules { + base := filepath.Base(pm.Path) + switch base { + case PlanFile: + if b.manifestProto { + return fmt.Errorf("bundle has proto manifest but JSON plan %q; SetManifestProto must agree with plan format", pm.Path) + } + case PlanProtoFile: + if !b.manifestProto { + return fmt.Errorf("bundle has JSON manifest but proto plan %q; SetManifestProto(true) required", pm.Path) + } + } + } + return nil +} + // FormatModules formats Rego modules // Modules will be formatted to comply with [ast.DefaultRegoVersion], but Rego compatibility of individual parsed modules will be respected (e.g. if 'rego.v1' is imported). func (b *Bundle) FormatModules(useModulePath bool) error { @@ -1473,11 +1559,34 @@ func MergeWithRegoVersion(bundles []*Bundle, regoVersion ast.RegoVersion, usePat var roots []string var result Bundle + var planFile string + var manifestProto bool + var manifestProtoSet bool + for _, b := range bundles { if b.Manifest.Roots == nil { return nil, errors.New("bundle manifest not initialized") } + for _, pm := range b.PlanModules { + base := filepath.Base(pm.Path) + if base != PlanFile && base != PlanProtoFile { + continue + } + if planFile == "" { + planFile = base + } else if planFile != base { + return nil, fmt.Errorf("cannot merge bundles with mixed plan formats (%s and %s)", planFile, base) + } + } + + if !manifestProtoSet { + manifestProto = b.manifestProto + manifestProtoSet = true + } else if manifestProto != b.manifestProto { + return nil, errors.New("cannot merge bundles with mixed manifest formats") + } + roots = append(roots, *b.Manifest.Roots...) result.Modules = append(result.Modules, b.Modules...) @@ -1508,6 +1617,8 @@ func MergeWithRegoVersion(bundles []*Bundle, regoVersion ast.RegoVersion, usePat } } + result.manifestProto = manifestProto + // We respect the bundle rego-version, defaulting to the provided rego version if not set. result.SetRegoVersion(result.RegoVersion(regoVersion)) @@ -1666,7 +1777,9 @@ func modulePathWithPrefix(bundleName string, modulePath string) string { return path.Join(bundleName, modulePath) } -// IsStructuredDoc checks if the file name equals a structured file extension ex. ".json" +// IsStructuredDoc checks if the file name equals a structured file extension ex. ".json". +// Note: ManifestProtoExt (".manifest.pb") is intentionally absent — proto manifests are +// hashed as raw wire bytes on both the sign and verify paths. func IsStructuredDoc(name string) bool { base := filepath.Base(name) return base == dataFile || base == yamlDataFile || base == SignaturesFile || base == ManifestExt diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go index 4897ee7b91..e4f74cc0e4 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/file.go @@ -200,7 +200,10 @@ func formatPath(fileName string, root string, pathFormat PathFormat) string { case Chrooted: // Trim off the root directory and return path as if chrooted result := strings.TrimPrefix(fileName, filepath.FromSlash(root)) - if root == "." && filepath.Base(fileName) == ManifestExt { + // TrimPrefix at root="." strips the leading dot from dotfile manifests + // (".manifest" → "manifest"), which then misses the Reader's HasSuffix + // check. Restore the original name for both manifest forms. + if root == "." && (filepath.Base(fileName) == ManifestExt || filepath.Base(fileName) == ManifestProtoExt) { result = fileName } if !strings.HasPrefix(result, string(filepath.Separator)) { diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/manifest.proto b/vendor/github.com/open-policy-agent/opa/v1/bundle/manifest.proto index 96a79a707a..ed3c1498ce 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/bundle/manifest.proto +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/manifest.proto @@ -16,7 +16,7 @@ message Manifest { // Bundle revision string. string revision = 1; - // Root paths the bundle owns. + // Root paths the bundle owns. See `roots_set` for nil-vs-empty. repeated string roots = 2; // Wasm resolvers attached to the bundle. JSON key is `wasm`. @@ -31,6 +31,10 @@ message Manifest { // Free-form metadata object. Modeled as `Struct` because the Go field // is `map[string]any`. google.protobuf.Struct metadata = 6; + + // True if `bundle.Manifest.Roots` was non-nil. `repeated string` can't + // distinguish nil (default to [""]) from explicit-empty (owns no paths). + bool roots_set = 7; } // WasmResolver mirrors `bundle.WasmResolver` in v1/bundle/bundle.go. diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/proto.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/proto.go new file mode 100644 index 0000000000..500be418d5 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/proto.go @@ -0,0 +1,434 @@ +// Copyright 2026 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package bundle + +import ( + "encoding/json" + "fmt" + "net/url" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/ast/location" + pb "github.com/open-policy-agent/opa/v1/bundle/v1pb" +) + +// ManifestToProto converts a bundle Manifest to its protobuf wire-form, +// defined in v1/bundle/manifest.proto. The compiled-only fileRegoVersions +// cache is intentionally not modeled. Roots presence (nil vs explicit-empty) +// is preserved via the `roots_set` wire field. +func ManifestToProto(m *Manifest) (*pb.Manifest, error) { + if m == nil { + return nil, nil + } + out := &pb.Manifest{ + Revision: proto.String(m.Revision), + } + if m.Roots != nil { + out.Roots = append([]string(nil), (*m.Roots)...) + out.RootsSet = proto.Bool(true) + } + if len(m.WasmResolvers) > 0 { + out.Wasm = make([]*pb.WasmResolver, len(m.WasmResolvers)) + for i := range m.WasmResolvers { + wr, err := wasmResolverToProto(&m.WasmResolvers[i]) + if err != nil { + return nil, fmt.Errorf("manifest wasm[%d]: %w", i, err) + } + out.Wasm[i] = wr + } + } + if m.RegoVersion != nil { + out.RegoVersion = proto.Int32(int32(*m.RegoVersion)) + } + if len(m.FileRegoVersions) > 0 { + out.FileRegoVersions = make(map[string]int32, len(m.FileRegoVersions)) + for k, v := range m.FileRegoVersions { + out.FileRegoVersions[k] = int32(v) + } + } + if len(m.Metadata) > 0 { + s, err := jsonNormalizeStruct(m.Metadata) + if err != nil { + return nil, fmt.Errorf("manifest metadata: %w", err) + } + out.Metadata = s + } + return out, nil +} + +func wasmResolverToProto(w *WasmResolver) (*pb.WasmResolver, error) { + if w == nil { + return nil, nil + } + out := &pb.WasmResolver{ + Entrypoint: proto.String(w.Entrypoint), + Module: proto.String(w.Module), + } + if len(w.Annotations) > 0 { + out.Annotations = make([]*pb.Annotations, len(w.Annotations)) + for i, a := range w.Annotations { + ap, err := annotationsToProto(a) + if err != nil { + return nil, fmt.Errorf("annotations[%d]: %w", i, err) + } + out.Annotations[i] = ap + } + } + return out, nil +} + +func annotationsToProto(a *ast.Annotations) (*pb.Annotations, error) { + if a == nil { + return nil, nil + } + out := &pb.Annotations{ + Scope: proto.String(a.Scope), + Title: proto.String(a.Title), + Entrypoint: proto.Bool(a.Entrypoint), + Description: proto.String(a.Description), + Organizations: append([]string(nil), a.Organizations...), + } + if len(a.RelatedResources) > 0 { + out.RelatedResources = make([]*pb.RelatedResourceAnnotation, len(a.RelatedResources)) + for i, r := range a.RelatedResources { + out.RelatedResources[i] = relatedResourceToProto(r) + } + } + if len(a.Authors) > 0 { + out.Authors = make([]*pb.AuthorAnnotation, len(a.Authors)) + for i, au := range a.Authors { + out.Authors[i] = authorToProto(au) + } + } + if len(a.Schemas) > 0 { + out.Schemas = make([]*pb.SchemaAnnotation, len(a.Schemas)) + for i, s := range a.Schemas { + sa, err := schemaToProto(s) + if err != nil { + return nil, fmt.Errorf("schemas[%d]: %w", i, err) + } + out.Schemas[i] = sa + } + } + if a.Compile != nil { + out.Compile = compileToProto(a.Compile) + } + if len(a.Custom) > 0 { + s, err := jsonNormalizeStruct(a.Custom) + if err != nil { + return nil, fmt.Errorf("custom: %w", err) + } + out.Custom = s + } + if len(a.Labels) > 0 { + s, err := jsonNormalizeStruct(a.Labels) + if err != nil { + return nil, fmt.Errorf("labels: %w", err) + } + out.Labels = s + } + if a.Location != nil { + out.Location = locationToProto(a.Location) + } + return out, nil +} + +func relatedResourceToProto(r *ast.RelatedResourceAnnotation) *pb.RelatedResourceAnnotation { + if r == nil { + return nil + } + return &pb.RelatedResourceAnnotation{ + Ref: proto.String(r.Ref.String()), + Description: proto.String(r.Description), + } +} + +func authorToProto(a *ast.AuthorAnnotation) *pb.AuthorAnnotation { + if a == nil { + return nil + } + return &pb.AuthorAnnotation{ + Name: proto.String(a.Name), + Email: proto.String(a.Email), + } +} + +func schemaToProto(s *ast.SchemaAnnotation) (*pb.SchemaAnnotation, error) { + if s == nil { + return nil, nil + } + out := &pb.SchemaAnnotation{ + Path: proto.String(s.Path.String()), + Schema: proto.String(s.Schema.String()), + } + if s.Definition != nil { + v, err := jsonNormalizeValue(*s.Definition) + if err != nil { + return nil, fmt.Errorf("definition: %w", err) + } + out.Definition = v + } + return out, nil +} + +func compileToProto(c *ast.CompileAnnotation) *pb.CompileAnnotation { + if c == nil { + return nil + } + out := &pb.CompileAnnotation{ + MaskRule: proto.String(c.MaskRule.String()), + } + if len(c.Unknowns) > 0 { + out.Unknowns = make([]string, len(c.Unknowns)) + for i, u := range c.Unknowns { + out.Unknowns[i] = u.String() + } + } + return out +} + +func locationToProto(l *location.Location) *pb.Location { + if l == nil { + return nil + } + return &pb.Location{ + File: proto.String(l.File), + Row: proto.Int32(int32(l.Row)), + Col: proto.Int32(int32(l.Col)), + } +} + +// ManifestFromProto is the inverse of ManifestToProto. +func ManifestFromProto(m *pb.Manifest) (*Manifest, error) { + if m == nil { + return nil, nil + } + out := &Manifest{ + Revision: m.GetRevision(), + } + if m.GetRootsSet() { + roots := make([]string, len(m.Roots)) + copy(roots, m.Roots) + out.Roots = &roots + } + if len(m.Wasm) > 0 { + out.WasmResolvers = make([]WasmResolver, len(m.Wasm)) + for i, wr := range m.Wasm { + converted, err := wasmResolverFromProto(wr) + if err != nil { + return nil, fmt.Errorf("manifest wasm[%d]: %w", i, err) + } + out.WasmResolvers[i] = converted + } + } + if m.RegoVersion != nil { + v := int(*m.RegoVersion) + out.RegoVersion = &v + } + if len(m.FileRegoVersions) > 0 { + out.FileRegoVersions = make(map[string]int, len(m.FileRegoVersions)) + for k, v := range m.FileRegoVersions { + out.FileRegoVersions[k] = int(v) + } + } + if m.Metadata != nil { + out.Metadata = m.Metadata.AsMap() + } + return out, nil +} + +func wasmResolverFromProto(w *pb.WasmResolver) (WasmResolver, error) { + out := WasmResolver{ + Entrypoint: w.GetEntrypoint(), + Module: w.GetModule(), + } + if len(w.Annotations) > 0 { + out.Annotations = make([]*ast.Annotations, len(w.Annotations)) + for i, a := range w.Annotations { + converted, err := annotationsFromProto(a) + if err != nil { + return WasmResolver{}, fmt.Errorf("annotations[%d]: %w", i, err) + } + out.Annotations[i] = converted + } + } + return out, nil +} + +func annotationsFromProto(a *pb.Annotations) (*ast.Annotations, error) { + if a == nil { + return nil, nil + } + out := &ast.Annotations{ + Scope: a.GetScope(), + Title: a.GetTitle(), + Entrypoint: a.GetEntrypoint(), + Description: a.GetDescription(), + } + if len(a.Organizations) > 0 { + out.Organizations = append([]string(nil), a.Organizations...) + } + if len(a.RelatedResources) > 0 { + out.RelatedResources = make([]*ast.RelatedResourceAnnotation, len(a.RelatedResources)) + for i, r := range a.RelatedResources { + converted, err := relatedResourceFromProto(r) + if err != nil { + return nil, fmt.Errorf("related_resources[%d]: %w", i, err) + } + out.RelatedResources[i] = converted + } + } + if len(a.Authors) > 0 { + out.Authors = make([]*ast.AuthorAnnotation, len(a.Authors)) + for i, au := range a.Authors { + out.Authors[i] = authorFromProto(au) + } + } + if len(a.Schemas) > 0 { + out.Schemas = make([]*ast.SchemaAnnotation, len(a.Schemas)) + for i, s := range a.Schemas { + converted, err := schemaFromProto(s) + if err != nil { + return nil, fmt.Errorf("schemas[%d]: %w", i, err) + } + out.Schemas[i] = converted + } + } + if a.Compile != nil { + converted, err := compileFromProto(a.Compile) + if err != nil { + return nil, fmt.Errorf("compile: %w", err) + } + out.Compile = converted + } + if a.Custom != nil { + out.Custom = a.Custom.AsMap() + } + if a.Labels != nil { + out.Labels = a.Labels.AsMap() + } + if a.Location != nil { + out.Location = locationFromProto(a.Location) + } + return out, nil +} + +func relatedResourceFromProto(r *pb.RelatedResourceAnnotation) (*ast.RelatedResourceAnnotation, error) { + if r == nil { + return nil, nil + } + out := &ast.RelatedResourceAnnotation{ + Description: r.GetDescription(), + } + if ref := r.GetRef(); ref != "" { + u, err := url.Parse(ref) + if err != nil { + return nil, fmt.Errorf("ref %q: %w", ref, err) + } + out.Ref = *u + } + return out, nil +} + +func authorFromProto(a *pb.AuthorAnnotation) *ast.AuthorAnnotation { + if a == nil { + return nil + } + return &ast.AuthorAnnotation{ + Name: a.GetName(), + Email: a.GetEmail(), + } +} + +func schemaFromProto(s *pb.SchemaAnnotation) (*ast.SchemaAnnotation, error) { + if s == nil { + return nil, nil + } + out := &ast.SchemaAnnotation{} + if p := s.GetPath(); p != "" { + ref, err := ast.ParseRef(p) + if err != nil { + return nil, fmt.Errorf("path %q: %w", p, err) + } + out.Path = ref + } + if sc := s.GetSchema(); sc != "" { + ref, err := ast.ParseSchemaRef(sc) + if err != nil { + return nil, fmt.Errorf("schema %q: %w", sc, err) + } + out.Schema = ref + } + if s.Definition != nil { + def := s.Definition.AsInterface() + out.Definition = &def + } + return out, nil +} + +func compileFromProto(c *pb.CompileAnnotation) (*ast.CompileAnnotation, error) { + if c == nil { + return nil, nil + } + out := &ast.CompileAnnotation{} + if mr := c.GetMaskRule(); mr != "" { + ref, err := ast.ParseRef(mr) + if err != nil { + return nil, fmt.Errorf("mask_rule %q: %w", mr, err) + } + out.MaskRule = ref + } + if len(c.Unknowns) > 0 { + out.Unknowns = make([]ast.Ref, len(c.Unknowns)) + for i, u := range c.Unknowns { + ref, err := ast.ParseRef(u) + if err != nil { + return nil, fmt.Errorf("unknowns[%d] %q: %w", i, u, err) + } + out.Unknowns[i] = ref + } + } + return out, nil +} + +func locationFromProto(l *pb.Location) *location.Location { + if l == nil { + return nil + } + return &location.Location{ + File: l.GetFile(), + Row: int(l.GetRow()), + Col: int(l.GetCol()), + } +} + +// jsonNormalizeStruct routes a map through JSON before structpb.NewStruct +// so the proto path accepts the same value types the JSON path does. +func jsonNormalizeStruct(m map[string]any) (*structpb.Struct, error) { + bs, err := json.Marshal(m) + if err != nil { + return nil, err + } + var normalized map[string]any + if err := json.Unmarshal(bs, &normalized); err != nil { + return nil, err + } + return structpb.NewStruct(normalized) +} + +func jsonNormalizeValue(v any) (*structpb.Value, error) { + bs, err := json.Marshal(v) + if err != nil { + return nil, err + } + var normalized any + if err := json.Unmarshal(bs, &normalized); err != nil { + return nil, err + } + return structpb.NewValue(normalized) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/bundle/v1pb/manifest.pb.go b/vendor/github.com/open-policy-agent/opa/v1/bundle/v1pb/manifest.pb.go new file mode 100644 index 0000000000..018001f2d9 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/bundle/v1pb/manifest.pb.go @@ -0,0 +1,751 @@ +// Copyright 2026 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.35.1 +// source: v1/bundle/manifest.proto + +package v1pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Manifest mirrors `bundle.Manifest` in v1/bundle/bundle.go. +type Manifest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Bundle revision string. + Revision *string `protobuf:"bytes,1,opt,name=revision" json:"revision,omitempty"` + // Root paths the bundle owns. See `roots_set` for nil-vs-empty. + Roots []string `protobuf:"bytes,2,rep,name=roots" json:"roots,omitempty"` + // Wasm resolvers attached to the bundle. JSON key is `wasm`. + Wasm []*WasmResolver `protobuf:"bytes,3,rep,name=wasm" json:"wasm,omitempty"` + // Global Rego version for the bundle. Currently 0 (RegoV0) or 1 (RegoV1). + RegoVersion *int32 `protobuf:"varint,4,opt,name=rego_version,json=regoVersion" json:"rego_version,omitempty"` + // Per-file Rego version overrides keyed by file path. + FileRegoVersions map[string]int32 `protobuf:"bytes,5,rep,name=file_rego_versions,json=fileRegoVersions" json:"file_rego_versions,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + // Free-form metadata object. Modeled as `Struct` because the Go field + // is `map[string]any`. + Metadata *structpb.Struct `protobuf:"bytes,6,opt,name=metadata" json:"metadata,omitempty"` + // True iff `bundle.Manifest.Roots` was non-nil. `repeated string` can't + // distinguish nil (default to [""]) from explicit-empty (owns no paths). + RootsSet *bool `protobuf:"varint,7,opt,name=roots_set,json=rootsSet" json:"roots_set,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Manifest) Reset() { + *x = Manifest{} + mi := &file_v1_bundle_manifest_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Manifest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Manifest) ProtoMessage() {} + +func (x *Manifest) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Manifest.ProtoReflect.Descriptor instead. +func (*Manifest) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{0} +} + +func (x *Manifest) GetRevision() string { + if x != nil && x.Revision != nil { + return *x.Revision + } + return "" +} + +func (x *Manifest) GetRoots() []string { + if x != nil { + return x.Roots + } + return nil +} + +func (x *Manifest) GetWasm() []*WasmResolver { + if x != nil { + return x.Wasm + } + return nil +} + +func (x *Manifest) GetRegoVersion() int32 { + if x != nil && x.RegoVersion != nil { + return *x.RegoVersion + } + return 0 +} + +func (x *Manifest) GetFileRegoVersions() map[string]int32 { + if x != nil { + return x.FileRegoVersions + } + return nil +} + +func (x *Manifest) GetMetadata() *structpb.Struct { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *Manifest) GetRootsSet() bool { + if x != nil && x.RootsSet != nil { + return *x.RootsSet + } + return false +} + +// WasmResolver mirrors `bundle.WasmResolver` in v1/bundle/bundle.go. +type WasmResolver struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Entrypoint policy ref this resolver targets. + Entrypoint *string `protobuf:"bytes,1,opt,name=entrypoint" json:"entrypoint,omitempty"` + // Path to the wasm module within the bundle. + Module *string `protobuf:"bytes,2,opt,name=module" json:"module,omitempty"` + // Rego annotations attached to the entrypoint. + Annotations []*Annotations `protobuf:"bytes,3,rep,name=annotations" json:"annotations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WasmResolver) Reset() { + *x = WasmResolver{} + mi := &file_v1_bundle_manifest_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WasmResolver) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WasmResolver) ProtoMessage() {} + +func (x *WasmResolver) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WasmResolver.ProtoReflect.Descriptor instead. +func (*WasmResolver) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{1} +} + +func (x *WasmResolver) GetEntrypoint() string { + if x != nil && x.Entrypoint != nil { + return *x.Entrypoint + } + return "" +} + +func (x *WasmResolver) GetModule() string { + if x != nil && x.Module != nil { + return *x.Module + } + return "" +} + +func (x *WasmResolver) GetAnnotations() []*Annotations { + if x != nil { + return x.Annotations + } + return nil +} + +// Annotations mirrors `ast.Annotations` in v1/ast/annotations.go. +type Annotations struct { + state protoimpl.MessageState `protogen:"open.v1"` + Scope *string `protobuf:"bytes,1,opt,name=scope" json:"scope,omitempty"` + Title *string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` + Entrypoint *bool `protobuf:"varint,3,opt,name=entrypoint" json:"entrypoint,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + Organizations []string `protobuf:"bytes,5,rep,name=organizations" json:"organizations,omitempty"` + RelatedResources []*RelatedResourceAnnotation `protobuf:"bytes,6,rep,name=related_resources,json=relatedResources" json:"related_resources,omitempty"` + Authors []*AuthorAnnotation `protobuf:"bytes,7,rep,name=authors" json:"authors,omitempty"` + Schemas []*SchemaAnnotation `protobuf:"bytes,8,rep,name=schemas" json:"schemas,omitempty"` + Compile *CompileAnnotation `protobuf:"bytes,9,opt,name=compile" json:"compile,omitempty"` + // `custom` and `labels` are `map[string]any` in Go — genuinely + // free-form, so `Struct` is the right model. + Custom *structpb.Struct `protobuf:"bytes,10,opt,name=custom" json:"custom,omitempty"` + Labels *structpb.Struct `protobuf:"bytes,11,opt,name=labels" json:"labels,omitempty"` + Location *Location `protobuf:"bytes,12,opt,name=location" json:"location,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Annotations) Reset() { + *x = Annotations{} + mi := &file_v1_bundle_manifest_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Annotations) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Annotations) ProtoMessage() {} + +func (x *Annotations) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Annotations.ProtoReflect.Descriptor instead. +func (*Annotations) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{2} +} + +func (x *Annotations) GetScope() string { + if x != nil && x.Scope != nil { + return *x.Scope + } + return "" +} + +func (x *Annotations) GetTitle() string { + if x != nil && x.Title != nil { + return *x.Title + } + return "" +} + +func (x *Annotations) GetEntrypoint() bool { + if x != nil && x.Entrypoint != nil { + return *x.Entrypoint + } + return false +} + +func (x *Annotations) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *Annotations) GetOrganizations() []string { + if x != nil { + return x.Organizations + } + return nil +} + +func (x *Annotations) GetRelatedResources() []*RelatedResourceAnnotation { + if x != nil { + return x.RelatedResources + } + return nil +} + +func (x *Annotations) GetAuthors() []*AuthorAnnotation { + if x != nil { + return x.Authors + } + return nil +} + +func (x *Annotations) GetSchemas() []*SchemaAnnotation { + if x != nil { + return x.Schemas + } + return nil +} + +func (x *Annotations) GetCompile() *CompileAnnotation { + if x != nil { + return x.Compile + } + return nil +} + +func (x *Annotations) GetCustom() *structpb.Struct { + if x != nil { + return x.Custom + } + return nil +} + +func (x *Annotations) GetLabels() *structpb.Struct { + if x != nil { + return x.Labels + } + return nil +} + +func (x *Annotations) GetLocation() *Location { + if x != nil { + return x.Location + } + return nil +} + +// SchemaAnnotation mirrors `ast.SchemaAnnotation`. Path/Schema are +// `ast.Ref` in Go (a list of terms); the wire form is the canonical +// dotted ref string (e.g. `data.foo.bar`). Modeling the term tree +// faithfully would pull most of the AST into this schema and isn't +// worth the cost for annotations. +type SchemaAnnotation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Path *string `protobuf:"bytes,1,opt,name=path" json:"path,omitempty"` + Schema *string `protobuf:"bytes,2,opt,name=schema" json:"schema,omitempty"` + // `*any` on the Go side — a parsed JSON Schema document or any + // JSON value. `Value` (not `Struct`) because the top level may be + // a scalar, list, or null, not just an object. + Definition *structpb.Value `protobuf:"bytes,3,opt,name=definition" json:"definition,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SchemaAnnotation) Reset() { + *x = SchemaAnnotation{} + mi := &file_v1_bundle_manifest_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SchemaAnnotation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SchemaAnnotation) ProtoMessage() {} + +func (x *SchemaAnnotation) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SchemaAnnotation.ProtoReflect.Descriptor instead. +func (*SchemaAnnotation) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{3} +} + +func (x *SchemaAnnotation) GetPath() string { + if x != nil && x.Path != nil { + return *x.Path + } + return "" +} + +func (x *SchemaAnnotation) GetSchema() string { + if x != nil && x.Schema != nil { + return *x.Schema + } + return "" +} + +func (x *SchemaAnnotation) GetDefinition() *structpb.Value { + if x != nil { + return x.Definition + } + return nil +} + +// CompileAnnotation mirrors `ast.CompileAnnotation`. Refs are the +// canonical dotted form; see SchemaAnnotation for the trade-off. +type CompileAnnotation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Unknowns []string `protobuf:"bytes,1,rep,name=unknowns" json:"unknowns,omitempty"` + MaskRule *string `protobuf:"bytes,2,opt,name=mask_rule,json=maskRule" json:"mask_rule,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompileAnnotation) Reset() { + *x = CompileAnnotation{} + mi := &file_v1_bundle_manifest_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompileAnnotation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompileAnnotation) ProtoMessage() {} + +func (x *CompileAnnotation) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompileAnnotation.ProtoReflect.Descriptor instead. +func (*CompileAnnotation) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{4} +} + +func (x *CompileAnnotation) GetUnknowns() []string { + if x != nil { + return x.Unknowns + } + return nil +} + +func (x *CompileAnnotation) GetMaskRule() string { + if x != nil && x.MaskRule != nil { + return *x.MaskRule + } + return "" +} + +// AuthorAnnotation mirrors `ast.AuthorAnnotation`. +type AuthorAnnotation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Email *string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthorAnnotation) Reset() { + *x = AuthorAnnotation{} + mi := &file_v1_bundle_manifest_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthorAnnotation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthorAnnotation) ProtoMessage() {} + +func (x *AuthorAnnotation) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthorAnnotation.ProtoReflect.Descriptor instead. +func (*AuthorAnnotation) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{5} +} + +func (x *AuthorAnnotation) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *AuthorAnnotation) GetEmail() string { + if x != nil && x.Email != nil { + return *x.Email + } + return "" +} + +// RelatedResourceAnnotation mirrors `ast.RelatedResourceAnnotation`. +// `Ref` is a `url.URL` in Go, serialized to its `String()` form. +type RelatedResourceAnnotation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ref *string `protobuf:"bytes,1,opt,name=ref" json:"ref,omitempty"` + Description *string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RelatedResourceAnnotation) Reset() { + *x = RelatedResourceAnnotation{} + mi := &file_v1_bundle_manifest_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RelatedResourceAnnotation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelatedResourceAnnotation) ProtoMessage() {} + +func (x *RelatedResourceAnnotation) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelatedResourceAnnotation.ProtoReflect.Descriptor instead. +func (*RelatedResourceAnnotation) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{6} +} + +func (x *RelatedResourceAnnotation) GetRef() string { + if x != nil && x.Ref != nil { + return *x.Ref + } + return "" +} + +func (x *RelatedResourceAnnotation) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +// Location mirrors `ast.Location` (= `location.Location`). Only the +// File/Row/Col triple is wire-relevant; `Text`, `Offset`, and `Tabs` +// are tagged `json:"-"` and intentionally absent. +// +// Distinct from `ir.Location`, which is promoted onto the `Stmt` +// envelope in plan.proto. The two are independent Go types. +type Location struct { + state protoimpl.MessageState `protogen:"open.v1"` + File *string `protobuf:"bytes,1,opt,name=file" json:"file,omitempty"` + Row *int32 `protobuf:"varint,2,opt,name=row" json:"row,omitempty"` + Col *int32 `protobuf:"varint,3,opt,name=col" json:"col,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Location) Reset() { + *x = Location{} + mi := &file_v1_bundle_manifest_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Location) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Location) ProtoMessage() {} + +func (x *Location) ProtoReflect() protoreflect.Message { + mi := &file_v1_bundle_manifest_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Location.ProtoReflect.Descriptor instead. +func (*Location) Descriptor() ([]byte, []int) { + return file_v1_bundle_manifest_proto_rawDescGZIP(), []int{7} +} + +func (x *Location) GetFile() string { + if x != nil && x.File != nil { + return *x.File + } + return "" +} + +func (x *Location) GetRow() int32 { + if x != nil && x.Row != nil { + return *x.Row + } + return 0 +} + +func (x *Location) GetCol() int32 { + if x != nil && x.Col != nil { + return *x.Col + } + return 0 +} + +var File_v1_bundle_manifest_proto protoreflect.FileDescriptor + +const file_v1_bundle_manifest_proto_rawDesc = "" + + "\n" + + "\x18v1/bundle/manifest.proto\x12\ropa.bundle.v1\x1a\x1cgoogle/protobuf/struct.proto\"\x84\x03\n" + + "\bManifest\x12\x1a\n" + + "\brevision\x18\x01 \x01(\tR\brevision\x12\x14\n" + + "\x05roots\x18\x02 \x03(\tR\x05roots\x12/\n" + + "\x04wasm\x18\x03 \x03(\v2\x1b.opa.bundle.v1.WasmResolverR\x04wasm\x12!\n" + + "\frego_version\x18\x04 \x01(\x05R\vregoVersion\x12[\n" + + "\x12file_rego_versions\x18\x05 \x03(\v2-.opa.bundle.v1.Manifest.FileRegoVersionsEntryR\x10fileRegoVersions\x123\n" + + "\bmetadata\x18\x06 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x12\x1b\n" + + "\troots_set\x18\a \x01(\bR\brootsSet\x1aC\n" + + "\x15FileRegoVersionsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\x05R\x05value:\x028\x01\"\x84\x01\n" + + "\fWasmResolver\x12\x1e\n" + + "\n" + + "entrypoint\x18\x01 \x01(\tR\n" + + "entrypoint\x12\x16\n" + + "\x06module\x18\x02 \x01(\tR\x06module\x12<\n" + + "\vannotations\x18\x03 \x03(\v2\x1a.opa.bundle.v1.AnnotationsR\vannotations\"\xc1\x04\n" + + "\vAnnotations\x12\x14\n" + + "\x05scope\x18\x01 \x01(\tR\x05scope\x12\x14\n" + + "\x05title\x18\x02 \x01(\tR\x05title\x12\x1e\n" + + "\n" + + "entrypoint\x18\x03 \x01(\bR\n" + + "entrypoint\x12 \n" + + "\vdescription\x18\x04 \x01(\tR\vdescription\x12$\n" + + "\rorganizations\x18\x05 \x03(\tR\rorganizations\x12U\n" + + "\x11related_resources\x18\x06 \x03(\v2(.opa.bundle.v1.RelatedResourceAnnotationR\x10relatedResources\x129\n" + + "\aauthors\x18\a \x03(\v2\x1f.opa.bundle.v1.AuthorAnnotationR\aauthors\x129\n" + + "\aschemas\x18\b \x03(\v2\x1f.opa.bundle.v1.SchemaAnnotationR\aschemas\x12:\n" + + "\acompile\x18\t \x01(\v2 .opa.bundle.v1.CompileAnnotationR\acompile\x12/\n" + + "\x06custom\x18\n" + + " \x01(\v2\x17.google.protobuf.StructR\x06custom\x12/\n" + + "\x06labels\x18\v \x01(\v2\x17.google.protobuf.StructR\x06labels\x123\n" + + "\blocation\x18\f \x01(\v2\x17.opa.bundle.v1.LocationR\blocation\"v\n" + + "\x10SchemaAnnotation\x12\x12\n" + + "\x04path\x18\x01 \x01(\tR\x04path\x12\x16\n" + + "\x06schema\x18\x02 \x01(\tR\x06schema\x126\n" + + "\n" + + "definition\x18\x03 \x01(\v2\x16.google.protobuf.ValueR\n" + + "definition\"L\n" + + "\x11CompileAnnotation\x12\x1a\n" + + "\bunknowns\x18\x01 \x03(\tR\bunknowns\x12\x1b\n" + + "\tmask_rule\x18\x02 \x01(\tR\bmaskRule\"<\n" + + "\x10AuthorAnnotation\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05email\x18\x02 \x01(\tR\x05email\"O\n" + + "\x19RelatedResourceAnnotation\x12\x10\n" + + "\x03ref\x18\x01 \x01(\tR\x03ref\x12 \n" + + "\vdescription\x18\x02 \x01(\tR\vdescription\"B\n" + + "\bLocation\x12\x12\n" + + "\x04file\x18\x01 \x01(\tR\x04file\x12\x10\n" + + "\x03row\x18\x02 \x01(\x05R\x03row\x12\x10\n" + + "\x03col\x18\x03 \x01(\x05R\x03colB3P\x01Z/github.com/open-policy-agent/opa/v1/bundle/v1pbb\beditionsp\xe8\a" + +var ( + file_v1_bundle_manifest_proto_rawDescOnce sync.Once + file_v1_bundle_manifest_proto_rawDescData []byte +) + +func file_v1_bundle_manifest_proto_rawDescGZIP() []byte { + file_v1_bundle_manifest_proto_rawDescOnce.Do(func() { + file_v1_bundle_manifest_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_v1_bundle_manifest_proto_rawDesc), len(file_v1_bundle_manifest_proto_rawDesc))) + }) + return file_v1_bundle_manifest_proto_rawDescData +} + +var file_v1_bundle_manifest_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_v1_bundle_manifest_proto_goTypes = []any{ + (*Manifest)(nil), // 0: opa.bundle.v1.Manifest + (*WasmResolver)(nil), // 1: opa.bundle.v1.WasmResolver + (*Annotations)(nil), // 2: opa.bundle.v1.Annotations + (*SchemaAnnotation)(nil), // 3: opa.bundle.v1.SchemaAnnotation + (*CompileAnnotation)(nil), // 4: opa.bundle.v1.CompileAnnotation + (*AuthorAnnotation)(nil), // 5: opa.bundle.v1.AuthorAnnotation + (*RelatedResourceAnnotation)(nil), // 6: opa.bundle.v1.RelatedResourceAnnotation + (*Location)(nil), // 7: opa.bundle.v1.Location + nil, // 8: opa.bundle.v1.Manifest.FileRegoVersionsEntry + (*structpb.Struct)(nil), // 9: google.protobuf.Struct + (*structpb.Value)(nil), // 10: google.protobuf.Value +} +var file_v1_bundle_manifest_proto_depIdxs = []int32{ + 1, // 0: opa.bundle.v1.Manifest.wasm:type_name -> opa.bundle.v1.WasmResolver + 8, // 1: opa.bundle.v1.Manifest.file_rego_versions:type_name -> opa.bundle.v1.Manifest.FileRegoVersionsEntry + 9, // 2: opa.bundle.v1.Manifest.metadata:type_name -> google.protobuf.Struct + 2, // 3: opa.bundle.v1.WasmResolver.annotations:type_name -> opa.bundle.v1.Annotations + 6, // 4: opa.bundle.v1.Annotations.related_resources:type_name -> opa.bundle.v1.RelatedResourceAnnotation + 5, // 5: opa.bundle.v1.Annotations.authors:type_name -> opa.bundle.v1.AuthorAnnotation + 3, // 6: opa.bundle.v1.Annotations.schemas:type_name -> opa.bundle.v1.SchemaAnnotation + 4, // 7: opa.bundle.v1.Annotations.compile:type_name -> opa.bundle.v1.CompileAnnotation + 9, // 8: opa.bundle.v1.Annotations.custom:type_name -> google.protobuf.Struct + 9, // 9: opa.bundle.v1.Annotations.labels:type_name -> google.protobuf.Struct + 7, // 10: opa.bundle.v1.Annotations.location:type_name -> opa.bundle.v1.Location + 10, // 11: opa.bundle.v1.SchemaAnnotation.definition:type_name -> google.protobuf.Value + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_v1_bundle_manifest_proto_init() } +func file_v1_bundle_manifest_proto_init() { + if File_v1_bundle_manifest_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_v1_bundle_manifest_proto_rawDesc), len(file_v1_bundle_manifest_proto_rawDesc)), + NumEnums: 0, + NumMessages: 9, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_v1_bundle_manifest_proto_goTypes, + DependencyIndexes: file_v1_bundle_manifest_proto_depIdxs, + MessageInfos: file_v1_bundle_manifest_proto_msgTypes, + }.Build() + File_v1_bundle_manifest_proto = out.File + file_v1_bundle_manifest_proto_goTypes = nil + file_v1_bundle_manifest_proto_depIdxs = nil +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/format/format.go b/vendor/github.com/open-policy-agent/opa/v1/format/format.go index dfb4746334..1f25938bae 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/format/format.go +++ b/vendor/github.com/open-policy-agent/opa/v1/format/format.go @@ -640,7 +640,12 @@ func (w *writer) writeRule(rule *ast.Rule, isElse bool, comments []*ast.Comment) if (w.fmtOpts.regoV1 || w.fmtOpts.ifs) && partialSetException { w.write(" if") if len(rule.Body) == 1 { - if rule.Body[0].Location.Row == rule.Head.Location.Row { + // Keep `if ` on one line when the single body term sits on the + // same line as the end of the head. Comparing against the head's + // start row would wrongly expand the condition into a block whenever + // the head value spans multiple lines (e.g. a multi-line call). + headEndRow := rule.Head.Location.Row + strings.Count(string(rule.Head.Location.Text), "\n") + if rule.Body[0].Location.Row == headEndRow { w.write(" ") var err error comments, err = w.writeExpr(rule.Body[0], comments) diff --git a/vendor/github.com/open-policy-agent/opa/v1/ir/proto.go b/vendor/github.com/open-policy-agent/opa/v1/ir/proto.go new file mode 100644 index 0000000000..0c89dcb105 --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ir/proto.go @@ -0,0 +1,340 @@ +// Copyright 2026 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package ir + +import ( + "fmt" + "math" + + "google.golang.org/protobuf/proto" + + pb "github.com/open-policy-agent/opa/v1/ir/v1pb" +) + +// PolicyToProto converts an IR Policy to its protobuf wire-form, +// defined in v1/ir/plan.proto. Returns an error if the policy contains +// a Stmt or Val kind not yet covered by the encoder switch. +func PolicyToProto(p *Policy) (out *pb.Policy, err error) { + if p == nil { + return nil, nil + } + defer func() { + if r := recover(); r != nil { + out = nil + err = fmt.Errorf("ir: PolicyToProto: %v", r) + } + }() + return &pb.Policy{ + Static: staticToProto(p.Static), + Plans: plansToProto(p.Plans), + Funcs: funcsToProto(p.Funcs), + }, nil +} + +func staticToProto(s *Static) *pb.Static { + if s == nil { + return nil + } + out := &pb.Static{ + Strings: make([]*pb.StringConst, len(s.Strings)), + BuiltinFuncs: make([]*pb.BuiltinFunc, len(s.BuiltinFuncs)), + Files: make([]*pb.StringConst, len(s.Files)), + } + for i, sc := range s.Strings { + out.Strings[i] = stringConstToProto(sc) + } + for i, bf := range s.BuiltinFuncs { + out.BuiltinFuncs[i] = builtinFuncToProto(bf) + } + for i, f := range s.Files { + out.Files[i] = stringConstToProto(f) + } + return out +} + +func stringConstToProto(s *StringConst) *pb.StringConst { + if s == nil { + return nil + } + return &pb.StringConst{Value: proto.String(s.Value)} +} + +func builtinFuncToProto(b *BuiltinFunc) *pb.BuiltinFunc { + if b == nil { + return nil + } + return &pb.BuiltinFunc{Name: proto.String(b.Name)} +} + +func plansToProto(p *Plans) *pb.Plans { + if p == nil { + return nil + } + out := &pb.Plans{Plans: make([]*pb.Plan, len(p.Plans))} + for i, pl := range p.Plans { + out.Plans[i] = planToProto(pl) + } + return out +} + +func planToProto(p *Plan) *pb.Plan { + if p == nil { + return nil + } + out := &pb.Plan{Name: proto.String(p.Name), Blocks: make([]*pb.Block, len(p.Blocks))} + for i, b := range p.Blocks { + out.Blocks[i] = blockToProto(b) + } + return out +} + +func funcsToProto(f *Funcs) *pb.Funcs { + if f == nil { + return nil + } + out := &pb.Funcs{Funcs: make([]*pb.Func, len(f.Funcs))} + for i, fn := range f.Funcs { + out.Funcs[i] = funcToProto(fn) + } + return out +} + +func funcToProto(f *Func) *pb.Func { + if f == nil { + return nil + } + out := &pb.Func{ + Name: proto.String(f.Name), + Params: localsToInt32s(f.Params), + Result: proto.Int32(toInt32(f.Return)), + Blocks: make([]*pb.Block, len(f.Blocks)), + Path: f.Path, + } + for i, b := range f.Blocks { + out.Blocks[i] = blockToProto(b) + } + return out +} + +func blockToProto(b *Block) *pb.Block { + if b == nil { + return nil + } + out := &pb.Block{Stmts: make([]*pb.Stmt, len(b.Stmts))} + for i, s := range b.Stmts { + out.Stmts[i] = stmtToProto(s) + } + return out +} + +func operandToProto(o Operand) *pb.Operand { + return &pb.Operand{Value: valToProto(o.Value)} +} + +func operandsToProto(os []Operand) []*pb.Operand { + out := make([]*pb.Operand, len(os)) + for i, o := range os { + out[i] = operandToProto(o) + } + return out +} + +func valToProto(v Val) *pb.Val { + if v == nil { + return nil + } + switch x := v.(type) { + case Local: + return &pb.Val{Kind: &pb.Val_Local{Local: toInt32(x)}} + case StringIndex: + return &pb.Val{Kind: &pb.Val_StringIndex{StringIndex: toInt32(x)}} + case Bool: + return &pb.Val{Kind: &pb.Val_Bool{Bool: bool(x)}} + default: + panic(fmt.Sprintf("unsupported Val type %T", v)) + } +} + +// toInt32 narrows an int-based value to int32, panicking if it would +// overflow. PolicyToProto recovers from the panic and returns it as an +// error, so callers don't need to check the bound themselves. +func toInt32[T ~int](v T) int32 { + if int64(v) > math.MaxInt32 || int64(v) < math.MinInt32 { + panic(fmt.Sprintf("value %d overflows int32", int64(v))) + } + return int32(v) +} + +func localsToInt32s(ls []Local) []int32 { + out := make([]int32, len(ls)) + for i, l := range ls { + out[i] = toInt32(l) + } + return out +} + +func intsToInt32s(is []int) []int32 { + out := make([]int32, len(is)) + for i, v := range is { + out[i] = toInt32(v) + } + return out +} + +func stmtToProto(s Stmt) *pb.Stmt { + if s == nil { + return nil + } + loc := s.GetLocation() + out := &pb.Stmt{ + File: proto.Int32(toInt32(loc.File)), + Col: proto.Int32(toInt32(loc.Col)), + Row: proto.Int32(toInt32(loc.Row)), + } + switch x := s.(type) { + case *ArrayAppendStmt: + out.Kind = &pb.Stmt_ArrayAppendStmt{ArrayAppendStmt: &pb.ArrayAppendStmt{ + Value: operandToProto(x.Value), + Array: proto.Int32(toInt32(x.Array)), + }} + case *AssignIntStmt: + out.Kind = &pb.Stmt_AssignIntStmt{AssignIntStmt: &pb.AssignIntStmt{ + Value: proto.Int64(x.Value), + Target: proto.Int32(toInt32(x.Target)), + }} + case *AssignVarOnceStmt: + out.Kind = &pb.Stmt_AssignVarOnceStmt{AssignVarOnceStmt: &pb.AssignVarOnceStmt{ + Source: operandToProto(x.Source), + Target: proto.Int32(toInt32(x.Target)), + }} + case *AssignVarStmt: + out.Kind = &pb.Stmt_AssignVarStmt{AssignVarStmt: &pb.AssignVarStmt{ + Source: operandToProto(x.Source), + Target: proto.Int32(toInt32(x.Target)), + }} + case *BlockStmt: + body := &pb.BlockStmt{Blocks: make([]*pb.Block, len(x.Blocks))} + for i, b := range x.Blocks { + body.Blocks[i] = blockToProto(b) + } + out.Kind = &pb.Stmt_BlockStmt{BlockStmt: body} + case *BreakStmt: + out.Kind = &pb.Stmt_BreakStmt{BreakStmt: &pb.BreakStmt{Index: proto.Uint32(x.Index)}} + case *CallDynamicStmt: + out.Kind = &pb.Stmt_CallDynamicStmt{CallDynamicStmt: &pb.CallDynamicStmt{ + Args: localsToInt32s(x.Args), + Result: proto.Int32(toInt32(x.Result)), + Path: operandsToProto(x.Path), + }} + case *CallStmt: + out.Kind = &pb.Stmt_CallStmt{CallStmt: &pb.CallStmt{ + Function: proto.String(x.Func), + Args: operandsToProto(x.Args), + Result: proto.Int32(toInt32(x.Result)), + }} + case *DotStmt: + out.Kind = &pb.Stmt_DotStmt{DotStmt: &pb.DotStmt{ + Source: operandToProto(x.Source), + Key: operandToProto(x.Key), + Target: proto.Int32(toInt32(x.Target)), + }} + case *EqualStmt: + out.Kind = &pb.Stmt_EqualStmt{EqualStmt: &pb.EqualStmt{ + A: operandToProto(x.A), + B: operandToProto(x.B), + }} + case *IsArrayStmt: + out.Kind = &pb.Stmt_IsArrayStmt{IsArrayStmt: &pb.IsArrayStmt{Source: operandToProto(x.Source)}} + case *IsDefinedStmt: + out.Kind = &pb.Stmt_IsDefinedStmt{IsDefinedStmt: &pb.IsDefinedStmt{Source: proto.Int32(toInt32(x.Source))}} + case *IsObjectStmt: + out.Kind = &pb.Stmt_IsObjectStmt{IsObjectStmt: &pb.IsObjectStmt{Source: operandToProto(x.Source)}} + case *IsSetStmt: + out.Kind = &pb.Stmt_IsSetStmt{IsSetStmt: &pb.IsSetStmt{Source: operandToProto(x.Source)}} + case *IsUndefinedStmt: + out.Kind = &pb.Stmt_IsUndefinedStmt{IsUndefinedStmt: &pb.IsUndefinedStmt{Source: proto.Int32(toInt32(x.Source))}} + case *LenStmt: + out.Kind = &pb.Stmt_LenStmt{LenStmt: &pb.LenStmt{ + Source: operandToProto(x.Source), + Target: proto.Int32(toInt32(x.Target)), + }} + case *MakeArrayStmt: + out.Kind = &pb.Stmt_MakeArrayStmt{MakeArrayStmt: &pb.MakeArrayStmt{ + Capacity: proto.Int32(x.Capacity), + Target: proto.Int32(toInt32(x.Target)), + }} + case *MakeNullStmt: + out.Kind = &pb.Stmt_MakeNullStmt{MakeNullStmt: &pb.MakeNullStmt{Target: proto.Int32(toInt32(x.Target))}} + case *MakeNumberIntStmt: + out.Kind = &pb.Stmt_MakeNumberIntStmt{MakeNumberIntStmt: &pb.MakeNumberIntStmt{ + Value: proto.Int64(x.Value), + Target: proto.Int32(toInt32(x.Target)), + }} + case *MakeNumberRefStmt: + out.Kind = &pb.Stmt_MakeNumberRefStmt{MakeNumberRefStmt: &pb.MakeNumberRefStmt{ + Index: proto.Int32(toInt32(x.Index)), + Target: proto.Int32(toInt32(x.Target)), + }} + case *MakeObjectStmt: + out.Kind = &pb.Stmt_MakeObjectStmt{MakeObjectStmt: &pb.MakeObjectStmt{Target: proto.Int32(toInt32(x.Target))}} + case *MakeSetStmt: + out.Kind = &pb.Stmt_MakeSetStmt{MakeSetStmt: &pb.MakeSetStmt{Target: proto.Int32(toInt32(x.Target))}} + case *NopStmt: + out.Kind = &pb.Stmt_NopStmt{NopStmt: &pb.NopStmt{}} + case *NotEqualStmt: + out.Kind = &pb.Stmt_NotEqualStmt{NotEqualStmt: &pb.NotEqualStmt{ + A: operandToProto(x.A), + B: operandToProto(x.B), + }} + case *NotStmt: + out.Kind = &pb.Stmt_NotStmt{NotStmt: &pb.NotStmt{Block: blockToProto(x.Block)}} + case *ObjectInsertOnceStmt: + out.Kind = &pb.Stmt_ObjectInsertOnceStmt{ObjectInsertOnceStmt: &pb.ObjectInsertOnceStmt{ + Key: operandToProto(x.Key), + Value: operandToProto(x.Value), + Object: proto.Int32(toInt32(x.Object)), + }} + case *ObjectInsertStmt: + out.Kind = &pb.Stmt_ObjectInsertStmt{ObjectInsertStmt: &pb.ObjectInsertStmt{ + Key: operandToProto(x.Key), + Value: operandToProto(x.Value), + Object: proto.Int32(toInt32(x.Object)), + }} + case *ObjectMergeStmt: + out.Kind = &pb.Stmt_ObjectMergeStmt{ObjectMergeStmt: &pb.ObjectMergeStmt{ + A: proto.Int32(toInt32(x.A)), + B: proto.Int32(toInt32(x.B)), + Target: proto.Int32(toInt32(x.Target)), + }} + case *ResetLocalStmt: + out.Kind = &pb.Stmt_ResetLocalStmt{ResetLocalStmt: &pb.ResetLocalStmt{Target: proto.Int32(toInt32(x.Target))}} + case *ResultSetAddStmt: + out.Kind = &pb.Stmt_ResultSetAddStmt{ResultSetAddStmt: &pb.ResultSetAddStmt{Value: proto.Int32(toInt32(x.Value))}} + case *ReturnLocalStmt: + out.Kind = &pb.Stmt_ReturnLocalStmt{ReturnLocalStmt: &pb.ReturnLocalStmt{Source: proto.Int32(toInt32(x.Source))}} + case *ScanStmt: + out.Kind = &pb.Stmt_ScanStmt{ScanStmt: &pb.ScanStmt{ + Source: proto.Int32(toInt32(x.Source)), + Key: proto.Int32(toInt32(x.Key)), + Value: proto.Int32(toInt32(x.Value)), + Block: blockToProto(x.Block), + }} + case *SetAddStmt: + out.Kind = &pb.Stmt_SetAddStmt{SetAddStmt: &pb.SetAddStmt{ + Value: operandToProto(x.Value), + Set: proto.Int32(toInt32(x.Set)), + }} + case *WithStmt: + out.Kind = &pb.Stmt_WithStmt{WithStmt: &pb.WithStmt{ + Local: proto.Int32(toInt32(x.Local)), + Path: intsToInt32s(x.Path), + Value: operandToProto(x.Value), + Block: blockToProto(x.Block), + }} + default: + panic(fmt.Sprintf("unsupported Stmt type %T", s)) + } + return out +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/ir/v1pb/plan.pb.go b/vendor/github.com/open-policy-agent/opa/v1/ir/v1pb/plan.pb.go new file mode 100644 index 0000000000..a47afbcc0f --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/ir/v1pb/plan.pb.go @@ -0,0 +1,3449 @@ +// Copyright 2026 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.35.1 +// source: v1/ir/plan.proto + +package v1pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Policy mirrors `ir.Policy` in v1/ir/ir.go. +type Policy struct { + state protoimpl.MessageState `protogen:"open.v1"` + Static *Static `protobuf:"bytes,1,opt,name=static" json:"static,omitempty"` + Plans *Plans `protobuf:"bytes,2,opt,name=plans" json:"plans,omitempty"` + Funcs *Funcs `protobuf:"bytes,3,opt,name=funcs" json:"funcs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Policy) Reset() { + *x = Policy{} + mi := &file_v1_ir_plan_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Policy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Policy) ProtoMessage() {} + +func (x *Policy) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Policy.ProtoReflect.Descriptor instead. +func (*Policy) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{0} +} + +func (x *Policy) GetStatic() *Static { + if x != nil { + return x.Static + } + return nil +} + +func (x *Policy) GetPlans() *Plans { + if x != nil { + return x.Plans + } + return nil +} + +func (x *Policy) GetFuncs() *Funcs { + if x != nil { + return x.Funcs + } + return nil +} + +// Static mirrors `ir.Static` in v1/ir/ir.go. +type Static struct { + state protoimpl.MessageState `protogen:"open.v1"` + Strings []*StringConst `protobuf:"bytes,1,rep,name=strings" json:"strings,omitempty"` + BuiltinFuncs []*BuiltinFunc `protobuf:"bytes,2,rep,name=builtin_funcs,json=builtinFuncs" json:"builtin_funcs,omitempty"` + Files []*StringConst `protobuf:"bytes,3,rep,name=files" json:"files,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Static) Reset() { + *x = Static{} + mi := &file_v1_ir_plan_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Static) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Static) ProtoMessage() {} + +func (x *Static) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Static.ProtoReflect.Descriptor instead. +func (*Static) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{1} +} + +func (x *Static) GetStrings() []*StringConst { + if x != nil { + return x.Strings + } + return nil +} + +func (x *Static) GetBuiltinFuncs() []*BuiltinFunc { + if x != nil { + return x.BuiltinFuncs + } + return nil +} + +func (x *Static) GetFiles() []*StringConst { + if x != nil { + return x.Files + } + return nil +} + +// BuiltinFunc mirrors `ir.BuiltinFunc` in v1/ir/ir.go. +// +// `ir.BuiltinFunc.Decl` (the function's `types.Function` signature) is +// intentionally not modeled. Consumers that execute plans need their +// own builtin registry to dispatch host-language implementations, and +// that registry is the source of truth for signatures — bundling +// `Decl` here would be redundant and prone to drift. +type BuiltinFunc struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BuiltinFunc) Reset() { + *x = BuiltinFunc{} + mi := &file_v1_ir_plan_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BuiltinFunc) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BuiltinFunc) ProtoMessage() {} + +func (x *BuiltinFunc) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BuiltinFunc.ProtoReflect.Descriptor instead. +func (*BuiltinFunc) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{2} +} + +func (x *BuiltinFunc) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +// Plans mirrors `ir.Plans` in v1/ir/ir.go. +type Plans struct { + state protoimpl.MessageState `protogen:"open.v1"` + Plans []*Plan `protobuf:"bytes,1,rep,name=plans" json:"plans,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Plans) Reset() { + *x = Plans{} + mi := &file_v1_ir_plan_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Plans) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Plans) ProtoMessage() {} + +func (x *Plans) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Plans.ProtoReflect.Descriptor instead. +func (*Plans) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{3} +} + +func (x *Plans) GetPlans() []*Plan { + if x != nil { + return x.Plans + } + return nil +} + +// Funcs mirrors `ir.Funcs` in v1/ir/ir.go. +type Funcs struct { + state protoimpl.MessageState `protogen:"open.v1"` + Funcs []*Func `protobuf:"bytes,1,rep,name=funcs" json:"funcs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Funcs) Reset() { + *x = Funcs{} + mi := &file_v1_ir_plan_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Funcs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Funcs) ProtoMessage() {} + +func (x *Funcs) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Funcs.ProtoReflect.Descriptor instead. +func (*Funcs) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{4} +} + +func (x *Funcs) GetFuncs() []*Func { + if x != nil { + return x.Funcs + } + return nil +} + +// Func mirrors `ir.Func` in v1/ir/ir.go. +// +// Each parameter and the return slot are local-variable indices; see +// `ir.Local` in v1/ir/ir.go. +type Func struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Params []int32 `protobuf:"varint,2,rep,packed,name=params" json:"params,omitempty"` + // The local that holds the function's return value. Renamed from + // `return` (the Go field is `Func.Return Local`, JSON-tagged `return`) + // to avoid colliding with a reserved keyword in many target languages + // when this proto is fed to protoc plugins. The JSON wire form + // continues to use `return`; only the proto-side identifier differs. + Result *int32 `protobuf:"varint,3,opt,name=result" json:"result,omitempty"` + Blocks []*Block `protobuf:"bytes,4,rep,name=blocks" json:"blocks,omitempty"` + Path []string `protobuf:"bytes,5,rep,name=path" json:"path,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Func) Reset() { + *x = Func{} + mi := &file_v1_ir_plan_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Func) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Func) ProtoMessage() {} + +func (x *Func) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Func.ProtoReflect.Descriptor instead. +func (*Func) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{5} +} + +func (x *Func) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *Func) GetParams() []int32 { + if x != nil { + return x.Params + } + return nil +} + +func (x *Func) GetResult() int32 { + if x != nil && x.Result != nil { + return *x.Result + } + return 0 +} + +func (x *Func) GetBlocks() []*Block { + if x != nil { + return x.Blocks + } + return nil +} + +func (x *Func) GetPath() []string { + if x != nil { + return x.Path + } + return nil +} + +// Plan mirrors `ir.Plan` in v1/ir/ir.go. +type Plan struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Blocks []*Block `protobuf:"bytes,2,rep,name=blocks" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Plan) Reset() { + *x = Plan{} + mi := &file_v1_ir_plan_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Plan) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Plan) ProtoMessage() {} + +func (x *Plan) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Plan.ProtoReflect.Descriptor instead. +func (*Plan) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{6} +} + +func (x *Plan) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *Plan) GetBlocks() []*Block { + if x != nil { + return x.Blocks + } + return nil +} + +// Block mirrors `ir.Block` in v1/ir/ir.go. +type Block struct { + state protoimpl.MessageState `protogen:"open.v1"` + Stmts []*Stmt `protobuf:"bytes,1,rep,name=stmts" json:"stmts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Block) Reset() { + *x = Block{} + mi := &file_v1_ir_plan_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Block) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Block) ProtoMessage() {} + +func (x *Block) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Block.ProtoReflect.Descriptor instead. +func (*Block) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{7} +} + +func (x *Block) GetStmts() []*Stmt { + if x != nil { + return x.Stmts + } + return nil +} + +// StringConst mirrors `ir.StringConst` in v1/ir/ir.go. +type StringConst struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StringConst) Reset() { + *x = StringConst{} + mi := &file_v1_ir_plan_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StringConst) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StringConst) ProtoMessage() {} + +func (x *StringConst) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StringConst.ProtoReflect.Descriptor instead. +func (*StringConst) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{8} +} + +func (x *StringConst) GetValue() string { + if x != nil && x.Value != nil { + return *x.Value + } + return "" +} + +// Operand mirrors `ir.Operand` in v1/ir/ir.go. The `value` field is a +// polymorphic `Val` union; see the `Val` message below. +type Operand struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *Val `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Operand) Reset() { + *x = Operand{} + mi := &file_v1_ir_plan_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Operand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Operand) ProtoMessage() {} + +func (x *Operand) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Operand.ProtoReflect.Descriptor instead. +func (*Operand) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{9} +} + +func (x *Operand) GetValue() *Val { + if x != nil { + return x.Value + } + return nil +} + +// Val mirrors the `ir.Val` interface in v1/ir/ir.go. Each oneof case +// corresponds to a concrete `Val` implementation; the case names match +// the JSON discriminator strings emitted by `*Operand.MarshalJSON`. +// +// Case-number assignments are a stability commitment. New cases must +// be added with the next unused number; existing numbers must never +// be repurposed. +type Val struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Kind: + // + // *Val_Bool + // *Val_Local + // *Val_StringIndex + Kind isVal_Kind `protobuf_oneof:"kind"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Val) Reset() { + *x = Val{} + mi := &file_v1_ir_plan_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Val) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Val) ProtoMessage() {} + +func (x *Val) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Val.ProtoReflect.Descriptor instead. +func (*Val) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{10} +} + +func (x *Val) GetKind() isVal_Kind { + if x != nil { + return x.Kind + } + return nil +} + +func (x *Val) GetBool() bool { + if x != nil { + if x, ok := x.Kind.(*Val_Bool); ok { + return x.Bool + } + } + return false +} + +func (x *Val) GetLocal() int32 { + if x != nil { + if x, ok := x.Kind.(*Val_Local); ok { + return x.Local + } + } + return 0 +} + +func (x *Val) GetStringIndex() int32 { + if x != nil { + if x, ok := x.Kind.(*Val_StringIndex); ok { + return x.StringIndex + } + } + return 0 +} + +type isVal_Kind interface { + isVal_Kind() +} + +type Val_Bool struct { + Bool bool `protobuf:"varint,1,opt,name=bool,oneof"` +} + +type Val_Local struct { + Local int32 `protobuf:"varint,2,opt,name=local,oneof"` +} + +type Val_StringIndex struct { + StringIndex int32 `protobuf:"varint,3,opt,name=string_index,json=stringIndex,oneof"` +} + +func (*Val_Bool) isVal_Kind() {} + +func (*Val_Local) isVal_Kind() {} + +func (*Val_StringIndex) isVal_Kind() {} + +// Stmt mirrors the `ir.Stmt` interface in v1/ir/ir.go. Every Stmt carries +// the source-location triple (file, col, row) on this envelope; the body +// messages below describe only the kind-specific payload. +// +// On the Go side, `ir.Location` is embedded into every concrete Stmt +// implementation, so `encoding/json` flattens File/Col/Row into the +// emitted JSON body. The proto promotes those fields to the envelope +// because that's both more idiomatic protobuf and lets every body +// message start its own field numbering at 1. +// +// Case-number assignments (4–37) are a stability commitment. Field +// numbers 1–3 are reserved for the location triple. New cases must be +// added with the next unused number; existing numbers must never be +// repurposed. +type Stmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + File *int32 `protobuf:"varint,1,opt,name=file" json:"file,omitempty"` + Col *int32 `protobuf:"varint,2,opt,name=col" json:"col,omitempty"` + Row *int32 `protobuf:"varint,3,opt,name=row" json:"row,omitempty"` + // Types that are valid to be assigned to Kind: + // + // *Stmt_ArrayAppendStmt + // *Stmt_AssignIntStmt + // *Stmt_AssignVarOnceStmt + // *Stmt_AssignVarStmt + // *Stmt_BlockStmt + // *Stmt_BreakStmt + // *Stmt_CallDynamicStmt + // *Stmt_CallStmt + // *Stmt_DotStmt + // *Stmt_EqualStmt + // *Stmt_IsArrayStmt + // *Stmt_IsDefinedStmt + // *Stmt_IsObjectStmt + // *Stmt_IsSetStmt + // *Stmt_IsUndefinedStmt + // *Stmt_LenStmt + // *Stmt_MakeArrayStmt + // *Stmt_MakeNullStmt + // *Stmt_MakeNumberIntStmt + // *Stmt_MakeNumberRefStmt + // *Stmt_MakeObjectStmt + // *Stmt_MakeSetStmt + // *Stmt_NopStmt + // *Stmt_NotEqualStmt + // *Stmt_NotStmt + // *Stmt_ObjectInsertOnceStmt + // *Stmt_ObjectInsertStmt + // *Stmt_ObjectMergeStmt + // *Stmt_ResetLocalStmt + // *Stmt_ResultSetAddStmt + // *Stmt_ReturnLocalStmt + // *Stmt_ScanStmt + // *Stmt_SetAddStmt + // *Stmt_WithStmt + Kind isStmt_Kind `protobuf_oneof:"kind"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Stmt) Reset() { + *x = Stmt{} + mi := &file_v1_ir_plan_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Stmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Stmt) ProtoMessage() {} + +func (x *Stmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Stmt.ProtoReflect.Descriptor instead. +func (*Stmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{11} +} + +func (x *Stmt) GetFile() int32 { + if x != nil && x.File != nil { + return *x.File + } + return 0 +} + +func (x *Stmt) GetCol() int32 { + if x != nil && x.Col != nil { + return *x.Col + } + return 0 +} + +func (x *Stmt) GetRow() int32 { + if x != nil && x.Row != nil { + return *x.Row + } + return 0 +} + +func (x *Stmt) GetKind() isStmt_Kind { + if x != nil { + return x.Kind + } + return nil +} + +func (x *Stmt) GetArrayAppendStmt() *ArrayAppendStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ArrayAppendStmt); ok { + return x.ArrayAppendStmt + } + } + return nil +} + +func (x *Stmt) GetAssignIntStmt() *AssignIntStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_AssignIntStmt); ok { + return x.AssignIntStmt + } + } + return nil +} + +func (x *Stmt) GetAssignVarOnceStmt() *AssignVarOnceStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_AssignVarOnceStmt); ok { + return x.AssignVarOnceStmt + } + } + return nil +} + +func (x *Stmt) GetAssignVarStmt() *AssignVarStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_AssignVarStmt); ok { + return x.AssignVarStmt + } + } + return nil +} + +func (x *Stmt) GetBlockStmt() *BlockStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_BlockStmt); ok { + return x.BlockStmt + } + } + return nil +} + +func (x *Stmt) GetBreakStmt() *BreakStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_BreakStmt); ok { + return x.BreakStmt + } + } + return nil +} + +func (x *Stmt) GetCallDynamicStmt() *CallDynamicStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_CallDynamicStmt); ok { + return x.CallDynamicStmt + } + } + return nil +} + +func (x *Stmt) GetCallStmt() *CallStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_CallStmt); ok { + return x.CallStmt + } + } + return nil +} + +func (x *Stmt) GetDotStmt() *DotStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_DotStmt); ok { + return x.DotStmt + } + } + return nil +} + +func (x *Stmt) GetEqualStmt() *EqualStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_EqualStmt); ok { + return x.EqualStmt + } + } + return nil +} + +func (x *Stmt) GetIsArrayStmt() *IsArrayStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_IsArrayStmt); ok { + return x.IsArrayStmt + } + } + return nil +} + +func (x *Stmt) GetIsDefinedStmt() *IsDefinedStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_IsDefinedStmt); ok { + return x.IsDefinedStmt + } + } + return nil +} + +func (x *Stmt) GetIsObjectStmt() *IsObjectStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_IsObjectStmt); ok { + return x.IsObjectStmt + } + } + return nil +} + +func (x *Stmt) GetIsSetStmt() *IsSetStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_IsSetStmt); ok { + return x.IsSetStmt + } + } + return nil +} + +func (x *Stmt) GetIsUndefinedStmt() *IsUndefinedStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_IsUndefinedStmt); ok { + return x.IsUndefinedStmt + } + } + return nil +} + +func (x *Stmt) GetLenStmt() *LenStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_LenStmt); ok { + return x.LenStmt + } + } + return nil +} + +func (x *Stmt) GetMakeArrayStmt() *MakeArrayStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_MakeArrayStmt); ok { + return x.MakeArrayStmt + } + } + return nil +} + +func (x *Stmt) GetMakeNullStmt() *MakeNullStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_MakeNullStmt); ok { + return x.MakeNullStmt + } + } + return nil +} + +func (x *Stmt) GetMakeNumberIntStmt() *MakeNumberIntStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_MakeNumberIntStmt); ok { + return x.MakeNumberIntStmt + } + } + return nil +} + +func (x *Stmt) GetMakeNumberRefStmt() *MakeNumberRefStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_MakeNumberRefStmt); ok { + return x.MakeNumberRefStmt + } + } + return nil +} + +func (x *Stmt) GetMakeObjectStmt() *MakeObjectStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_MakeObjectStmt); ok { + return x.MakeObjectStmt + } + } + return nil +} + +func (x *Stmt) GetMakeSetStmt() *MakeSetStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_MakeSetStmt); ok { + return x.MakeSetStmt + } + } + return nil +} + +func (x *Stmt) GetNopStmt() *NopStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_NopStmt); ok { + return x.NopStmt + } + } + return nil +} + +func (x *Stmt) GetNotEqualStmt() *NotEqualStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_NotEqualStmt); ok { + return x.NotEqualStmt + } + } + return nil +} + +func (x *Stmt) GetNotStmt() *NotStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_NotStmt); ok { + return x.NotStmt + } + } + return nil +} + +func (x *Stmt) GetObjectInsertOnceStmt() *ObjectInsertOnceStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ObjectInsertOnceStmt); ok { + return x.ObjectInsertOnceStmt + } + } + return nil +} + +func (x *Stmt) GetObjectInsertStmt() *ObjectInsertStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ObjectInsertStmt); ok { + return x.ObjectInsertStmt + } + } + return nil +} + +func (x *Stmt) GetObjectMergeStmt() *ObjectMergeStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ObjectMergeStmt); ok { + return x.ObjectMergeStmt + } + } + return nil +} + +func (x *Stmt) GetResetLocalStmt() *ResetLocalStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ResetLocalStmt); ok { + return x.ResetLocalStmt + } + } + return nil +} + +func (x *Stmt) GetResultSetAddStmt() *ResultSetAddStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ResultSetAddStmt); ok { + return x.ResultSetAddStmt + } + } + return nil +} + +func (x *Stmt) GetReturnLocalStmt() *ReturnLocalStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ReturnLocalStmt); ok { + return x.ReturnLocalStmt + } + } + return nil +} + +func (x *Stmt) GetScanStmt() *ScanStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_ScanStmt); ok { + return x.ScanStmt + } + } + return nil +} + +func (x *Stmt) GetSetAddStmt() *SetAddStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_SetAddStmt); ok { + return x.SetAddStmt + } + } + return nil +} + +func (x *Stmt) GetWithStmt() *WithStmt { + if x != nil { + if x, ok := x.Kind.(*Stmt_WithStmt); ok { + return x.WithStmt + } + } + return nil +} + +type isStmt_Kind interface { + isStmt_Kind() +} + +type Stmt_ArrayAppendStmt struct { + ArrayAppendStmt *ArrayAppendStmt `protobuf:"bytes,4,opt,name=array_append_stmt,json=arrayAppendStmt,oneof"` +} + +type Stmt_AssignIntStmt struct { + AssignIntStmt *AssignIntStmt `protobuf:"bytes,5,opt,name=assign_int_stmt,json=assignIntStmt,oneof"` +} + +type Stmt_AssignVarOnceStmt struct { + AssignVarOnceStmt *AssignVarOnceStmt `protobuf:"bytes,6,opt,name=assign_var_once_stmt,json=assignVarOnceStmt,oneof"` +} + +type Stmt_AssignVarStmt struct { + AssignVarStmt *AssignVarStmt `protobuf:"bytes,7,opt,name=assign_var_stmt,json=assignVarStmt,oneof"` +} + +type Stmt_BlockStmt struct { + BlockStmt *BlockStmt `protobuf:"bytes,8,opt,name=block_stmt,json=blockStmt,oneof"` +} + +type Stmt_BreakStmt struct { + BreakStmt *BreakStmt `protobuf:"bytes,9,opt,name=break_stmt,json=breakStmt,oneof"` +} + +type Stmt_CallDynamicStmt struct { + CallDynamicStmt *CallDynamicStmt `protobuf:"bytes,10,opt,name=call_dynamic_stmt,json=callDynamicStmt,oneof"` +} + +type Stmt_CallStmt struct { + CallStmt *CallStmt `protobuf:"bytes,11,opt,name=call_stmt,json=callStmt,oneof"` +} + +type Stmt_DotStmt struct { + DotStmt *DotStmt `protobuf:"bytes,12,opt,name=dot_stmt,json=dotStmt,oneof"` +} + +type Stmt_EqualStmt struct { + EqualStmt *EqualStmt `protobuf:"bytes,13,opt,name=equal_stmt,json=equalStmt,oneof"` +} + +type Stmt_IsArrayStmt struct { + IsArrayStmt *IsArrayStmt `protobuf:"bytes,14,opt,name=is_array_stmt,json=isArrayStmt,oneof"` +} + +type Stmt_IsDefinedStmt struct { + IsDefinedStmt *IsDefinedStmt `protobuf:"bytes,15,opt,name=is_defined_stmt,json=isDefinedStmt,oneof"` +} + +type Stmt_IsObjectStmt struct { + IsObjectStmt *IsObjectStmt `protobuf:"bytes,16,opt,name=is_object_stmt,json=isObjectStmt,oneof"` +} + +type Stmt_IsSetStmt struct { + IsSetStmt *IsSetStmt `protobuf:"bytes,17,opt,name=is_set_stmt,json=isSetStmt,oneof"` +} + +type Stmt_IsUndefinedStmt struct { + IsUndefinedStmt *IsUndefinedStmt `protobuf:"bytes,18,opt,name=is_undefined_stmt,json=isUndefinedStmt,oneof"` +} + +type Stmt_LenStmt struct { + LenStmt *LenStmt `protobuf:"bytes,19,opt,name=len_stmt,json=lenStmt,oneof"` +} + +type Stmt_MakeArrayStmt struct { + MakeArrayStmt *MakeArrayStmt `protobuf:"bytes,20,opt,name=make_array_stmt,json=makeArrayStmt,oneof"` +} + +type Stmt_MakeNullStmt struct { + MakeNullStmt *MakeNullStmt `protobuf:"bytes,21,opt,name=make_null_stmt,json=makeNullStmt,oneof"` +} + +type Stmt_MakeNumberIntStmt struct { + MakeNumberIntStmt *MakeNumberIntStmt `protobuf:"bytes,22,opt,name=make_number_int_stmt,json=makeNumberIntStmt,oneof"` +} + +type Stmt_MakeNumberRefStmt struct { + MakeNumberRefStmt *MakeNumberRefStmt `protobuf:"bytes,23,opt,name=make_number_ref_stmt,json=makeNumberRefStmt,oneof"` +} + +type Stmt_MakeObjectStmt struct { + MakeObjectStmt *MakeObjectStmt `protobuf:"bytes,24,opt,name=make_object_stmt,json=makeObjectStmt,oneof"` +} + +type Stmt_MakeSetStmt struct { + MakeSetStmt *MakeSetStmt `protobuf:"bytes,25,opt,name=make_set_stmt,json=makeSetStmt,oneof"` +} + +type Stmt_NopStmt struct { + NopStmt *NopStmt `protobuf:"bytes,26,opt,name=nop_stmt,json=nopStmt,oneof"` +} + +type Stmt_NotEqualStmt struct { + NotEqualStmt *NotEqualStmt `protobuf:"bytes,27,opt,name=not_equal_stmt,json=notEqualStmt,oneof"` +} + +type Stmt_NotStmt struct { + NotStmt *NotStmt `protobuf:"bytes,28,opt,name=not_stmt,json=notStmt,oneof"` +} + +type Stmt_ObjectInsertOnceStmt struct { + ObjectInsertOnceStmt *ObjectInsertOnceStmt `protobuf:"bytes,29,opt,name=object_insert_once_stmt,json=objectInsertOnceStmt,oneof"` +} + +type Stmt_ObjectInsertStmt struct { + ObjectInsertStmt *ObjectInsertStmt `protobuf:"bytes,30,opt,name=object_insert_stmt,json=objectInsertStmt,oneof"` +} + +type Stmt_ObjectMergeStmt struct { + ObjectMergeStmt *ObjectMergeStmt `protobuf:"bytes,31,opt,name=object_merge_stmt,json=objectMergeStmt,oneof"` +} + +type Stmt_ResetLocalStmt struct { + ResetLocalStmt *ResetLocalStmt `protobuf:"bytes,32,opt,name=reset_local_stmt,json=resetLocalStmt,oneof"` +} + +type Stmt_ResultSetAddStmt struct { + ResultSetAddStmt *ResultSetAddStmt `protobuf:"bytes,33,opt,name=result_set_add_stmt,json=resultSetAddStmt,oneof"` +} + +type Stmt_ReturnLocalStmt struct { + ReturnLocalStmt *ReturnLocalStmt `protobuf:"bytes,34,opt,name=return_local_stmt,json=returnLocalStmt,oneof"` +} + +type Stmt_ScanStmt struct { + ScanStmt *ScanStmt `protobuf:"bytes,35,opt,name=scan_stmt,json=scanStmt,oneof"` +} + +type Stmt_SetAddStmt struct { + SetAddStmt *SetAddStmt `protobuf:"bytes,36,opt,name=set_add_stmt,json=setAddStmt,oneof"` +} + +type Stmt_WithStmt struct { + WithStmt *WithStmt `protobuf:"bytes,37,opt,name=with_stmt,json=withStmt,oneof"` +} + +func (*Stmt_ArrayAppendStmt) isStmt_Kind() {} + +func (*Stmt_AssignIntStmt) isStmt_Kind() {} + +func (*Stmt_AssignVarOnceStmt) isStmt_Kind() {} + +func (*Stmt_AssignVarStmt) isStmt_Kind() {} + +func (*Stmt_BlockStmt) isStmt_Kind() {} + +func (*Stmt_BreakStmt) isStmt_Kind() {} + +func (*Stmt_CallDynamicStmt) isStmt_Kind() {} + +func (*Stmt_CallStmt) isStmt_Kind() {} + +func (*Stmt_DotStmt) isStmt_Kind() {} + +func (*Stmt_EqualStmt) isStmt_Kind() {} + +func (*Stmt_IsArrayStmt) isStmt_Kind() {} + +func (*Stmt_IsDefinedStmt) isStmt_Kind() {} + +func (*Stmt_IsObjectStmt) isStmt_Kind() {} + +func (*Stmt_IsSetStmt) isStmt_Kind() {} + +func (*Stmt_IsUndefinedStmt) isStmt_Kind() {} + +func (*Stmt_LenStmt) isStmt_Kind() {} + +func (*Stmt_MakeArrayStmt) isStmt_Kind() {} + +func (*Stmt_MakeNullStmt) isStmt_Kind() {} + +func (*Stmt_MakeNumberIntStmt) isStmt_Kind() {} + +func (*Stmt_MakeNumberRefStmt) isStmt_Kind() {} + +func (*Stmt_MakeObjectStmt) isStmt_Kind() {} + +func (*Stmt_MakeSetStmt) isStmt_Kind() {} + +func (*Stmt_NopStmt) isStmt_Kind() {} + +func (*Stmt_NotEqualStmt) isStmt_Kind() {} + +func (*Stmt_NotStmt) isStmt_Kind() {} + +func (*Stmt_ObjectInsertOnceStmt) isStmt_Kind() {} + +func (*Stmt_ObjectInsertStmt) isStmt_Kind() {} + +func (*Stmt_ObjectMergeStmt) isStmt_Kind() {} + +func (*Stmt_ResetLocalStmt) isStmt_Kind() {} + +func (*Stmt_ResultSetAddStmt) isStmt_Kind() {} + +func (*Stmt_ReturnLocalStmt) isStmt_Kind() {} + +func (*Stmt_ScanStmt) isStmt_Kind() {} + +func (*Stmt_SetAddStmt) isStmt_Kind() {} + +func (*Stmt_WithStmt) isStmt_Kind() {} + +// ArrayAppendStmt mirrors `ir.ArrayAppendStmt` in v1/ir/ir.go. +type ArrayAppendStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *Operand `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Array *int32 `protobuf:"varint,2,opt,name=array" json:"array,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ArrayAppendStmt) Reset() { + *x = ArrayAppendStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ArrayAppendStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ArrayAppendStmt) ProtoMessage() {} + +func (x *ArrayAppendStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ArrayAppendStmt.ProtoReflect.Descriptor instead. +func (*ArrayAppendStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{12} +} + +func (x *ArrayAppendStmt) GetValue() *Operand { + if x != nil { + return x.Value + } + return nil +} + +func (x *ArrayAppendStmt) GetArray() int32 { + if x != nil && x.Array != nil { + return *x.Array + } + return 0 +} + +// AssignIntStmt mirrors `ir.AssignIntStmt` in v1/ir/ir.go. +type AssignIntStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *int64 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AssignIntStmt) Reset() { + *x = AssignIntStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AssignIntStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignIntStmt) ProtoMessage() {} + +func (x *AssignIntStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignIntStmt.ProtoReflect.Descriptor instead. +func (*AssignIntStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{13} +} + +func (x *AssignIntStmt) GetValue() int64 { + if x != nil && x.Value != nil { + return *x.Value + } + return 0 +} + +func (x *AssignIntStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// AssignVarOnceStmt mirrors `ir.AssignVarOnceStmt` in v1/ir/ir.go. +type AssignVarOnceStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AssignVarOnceStmt) Reset() { + *x = AssignVarOnceStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AssignVarOnceStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignVarOnceStmt) ProtoMessage() {} + +func (x *AssignVarOnceStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignVarOnceStmt.ProtoReflect.Descriptor instead. +func (*AssignVarOnceStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{14} +} + +func (x *AssignVarOnceStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +func (x *AssignVarOnceStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// AssignVarStmt mirrors `ir.AssignVarStmt` in v1/ir/ir.go. +type AssignVarStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AssignVarStmt) Reset() { + *x = AssignVarStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AssignVarStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignVarStmt) ProtoMessage() {} + +func (x *AssignVarStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignVarStmt.ProtoReflect.Descriptor instead. +func (*AssignVarStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{15} +} + +func (x *AssignVarStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +func (x *AssignVarStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// BlockStmt mirrors `ir.BlockStmt` in v1/ir/ir.go. +type BlockStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Blocks []*Block `protobuf:"bytes,1,rep,name=blocks" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BlockStmt) Reset() { + *x = BlockStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BlockStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockStmt) ProtoMessage() {} + +func (x *BlockStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockStmt.ProtoReflect.Descriptor instead. +func (*BlockStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{16} +} + +func (x *BlockStmt) GetBlocks() []*Block { + if x != nil { + return x.Blocks + } + return nil +} + +// BreakStmt mirrors `ir.BreakStmt` in v1/ir/ir.go. +type BreakStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Index *uint32 `protobuf:"varint,1,opt,name=index" json:"index,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BreakStmt) Reset() { + *x = BreakStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BreakStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BreakStmt) ProtoMessage() {} + +func (x *BreakStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BreakStmt.ProtoReflect.Descriptor instead. +func (*BreakStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{17} +} + +func (x *BreakStmt) GetIndex() uint32 { + if x != nil && x.Index != nil { + return *x.Index + } + return 0 +} + +// CallDynamicStmt mirrors `ir.CallDynamicStmt` in v1/ir/ir.go. +type CallDynamicStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Args []int32 `protobuf:"varint,1,rep,packed,name=args" json:"args,omitempty"` + Result *int32 `protobuf:"varint,2,opt,name=result" json:"result,omitempty"` + Path []*Operand `protobuf:"bytes,3,rep,name=path" json:"path,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CallDynamicStmt) Reset() { + *x = CallDynamicStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CallDynamicStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallDynamicStmt) ProtoMessage() {} + +func (x *CallDynamicStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CallDynamicStmt.ProtoReflect.Descriptor instead. +func (*CallDynamicStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{18} +} + +func (x *CallDynamicStmt) GetArgs() []int32 { + if x != nil { + return x.Args + } + return nil +} + +func (x *CallDynamicStmt) GetResult() int32 { + if x != nil && x.Result != nil { + return *x.Result + } + return 0 +} + +func (x *CallDynamicStmt) GetPath() []*Operand { + if x != nil { + return x.Path + } + return nil +} + +// CallStmt mirrors `ir.CallStmt` in v1/ir/ir.go. +type CallStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Renamed from `func` (Go field `CallStmt.Func`, JSON-tagged `func`) + // to avoid colliding with reserved keywords in target languages, + // mirroring the Func.return → result rename above. + Function *string `protobuf:"bytes,1,opt,name=function" json:"function,omitempty"` + Args []*Operand `protobuf:"bytes,2,rep,name=args" json:"args,omitempty"` + Result *int32 `protobuf:"varint,3,opt,name=result" json:"result,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CallStmt) Reset() { + *x = CallStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CallStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallStmt) ProtoMessage() {} + +func (x *CallStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CallStmt.ProtoReflect.Descriptor instead. +func (*CallStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{19} +} + +func (x *CallStmt) GetFunction() string { + if x != nil && x.Function != nil { + return *x.Function + } + return "" +} + +func (x *CallStmt) GetArgs() []*Operand { + if x != nil { + return x.Args + } + return nil +} + +func (x *CallStmt) GetResult() int32 { + if x != nil && x.Result != nil { + return *x.Result + } + return 0 +} + +// DotStmt mirrors `ir.DotStmt` in v1/ir/ir.go. +type DotStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + Key *Operand `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"` + Target *int32 `protobuf:"varint,3,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DotStmt) Reset() { + *x = DotStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DotStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DotStmt) ProtoMessage() {} + +func (x *DotStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DotStmt.ProtoReflect.Descriptor instead. +func (*DotStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{20} +} + +func (x *DotStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +func (x *DotStmt) GetKey() *Operand { + if x != nil { + return x.Key + } + return nil +} + +func (x *DotStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// EqualStmt mirrors `ir.EqualStmt` in v1/ir/ir.go. +type EqualStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + A *Operand `protobuf:"bytes,1,opt,name=a" json:"a,omitempty"` + B *Operand `protobuf:"bytes,2,opt,name=b" json:"b,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EqualStmt) Reset() { + *x = EqualStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EqualStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EqualStmt) ProtoMessage() {} + +func (x *EqualStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EqualStmt.ProtoReflect.Descriptor instead. +func (*EqualStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{21} +} + +func (x *EqualStmt) GetA() *Operand { + if x != nil { + return x.A + } + return nil +} + +func (x *EqualStmt) GetB() *Operand { + if x != nil { + return x.B + } + return nil +} + +// IsArrayStmt mirrors `ir.IsArrayStmt` in v1/ir/ir.go. +type IsArrayStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IsArrayStmt) Reset() { + *x = IsArrayStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IsArrayStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsArrayStmt) ProtoMessage() {} + +func (x *IsArrayStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsArrayStmt.ProtoReflect.Descriptor instead. +func (*IsArrayStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{22} +} + +func (x *IsArrayStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +// IsDefinedStmt mirrors `ir.IsDefinedStmt` in v1/ir/ir.go. +type IsDefinedStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *int32 `protobuf:"varint,1,opt,name=source" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IsDefinedStmt) Reset() { + *x = IsDefinedStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IsDefinedStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsDefinedStmt) ProtoMessage() {} + +func (x *IsDefinedStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsDefinedStmt.ProtoReflect.Descriptor instead. +func (*IsDefinedStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{23} +} + +func (x *IsDefinedStmt) GetSource() int32 { + if x != nil && x.Source != nil { + return *x.Source + } + return 0 +} + +// IsObjectStmt mirrors `ir.IsObjectStmt` in v1/ir/ir.go. +type IsObjectStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IsObjectStmt) Reset() { + *x = IsObjectStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IsObjectStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsObjectStmt) ProtoMessage() {} + +func (x *IsObjectStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsObjectStmt.ProtoReflect.Descriptor instead. +func (*IsObjectStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{24} +} + +func (x *IsObjectStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +// IsSetStmt mirrors `ir.IsSetStmt` in v1/ir/ir.go. +type IsSetStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IsSetStmt) Reset() { + *x = IsSetStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IsSetStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsSetStmt) ProtoMessage() {} + +func (x *IsSetStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsSetStmt.ProtoReflect.Descriptor instead. +func (*IsSetStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{25} +} + +func (x *IsSetStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +// IsUndefinedStmt mirrors `ir.IsUndefinedStmt` in v1/ir/ir.go. +type IsUndefinedStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *int32 `protobuf:"varint,1,opt,name=source" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IsUndefinedStmt) Reset() { + *x = IsUndefinedStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IsUndefinedStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsUndefinedStmt) ProtoMessage() {} + +func (x *IsUndefinedStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsUndefinedStmt.ProtoReflect.Descriptor instead. +func (*IsUndefinedStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{26} +} + +func (x *IsUndefinedStmt) GetSource() int32 { + if x != nil && x.Source != nil { + return *x.Source + } + return 0 +} + +// LenStmt mirrors `ir.LenStmt` in v1/ir/ir.go. +type LenStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *Operand `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LenStmt) Reset() { + *x = LenStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LenStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LenStmt) ProtoMessage() {} + +func (x *LenStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LenStmt.ProtoReflect.Descriptor instead. +func (*LenStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{27} +} + +func (x *LenStmt) GetSource() *Operand { + if x != nil { + return x.Source + } + return nil +} + +func (x *LenStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// MakeArrayStmt mirrors `ir.MakeArrayStmt` in v1/ir/ir.go. +type MakeArrayStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Capacity *int32 `protobuf:"varint,1,opt,name=capacity" json:"capacity,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MakeArrayStmt) Reset() { + *x = MakeArrayStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MakeArrayStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MakeArrayStmt) ProtoMessage() {} + +func (x *MakeArrayStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MakeArrayStmt.ProtoReflect.Descriptor instead. +func (*MakeArrayStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{28} +} + +func (x *MakeArrayStmt) GetCapacity() int32 { + if x != nil && x.Capacity != nil { + return *x.Capacity + } + return 0 +} + +func (x *MakeArrayStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// MakeNullStmt mirrors `ir.MakeNullStmt` in v1/ir/ir.go. +type MakeNullStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Target *int32 `protobuf:"varint,1,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MakeNullStmt) Reset() { + *x = MakeNullStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MakeNullStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MakeNullStmt) ProtoMessage() {} + +func (x *MakeNullStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MakeNullStmt.ProtoReflect.Descriptor instead. +func (*MakeNullStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{29} +} + +func (x *MakeNullStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// MakeNumberIntStmt mirrors `ir.MakeNumberIntStmt` in v1/ir/ir.go. +type MakeNumberIntStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *int64 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MakeNumberIntStmt) Reset() { + *x = MakeNumberIntStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MakeNumberIntStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MakeNumberIntStmt) ProtoMessage() {} + +func (x *MakeNumberIntStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MakeNumberIntStmt.ProtoReflect.Descriptor instead. +func (*MakeNumberIntStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{30} +} + +func (x *MakeNumberIntStmt) GetValue() int64 { + if x != nil && x.Value != nil { + return *x.Value + } + return 0 +} + +func (x *MakeNumberIntStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// MakeNumberRefStmt mirrors `ir.MakeNumberRefStmt` in v1/ir/ir.go. +// +// The Go field is named `Index` (no `json` tag). The historical JSON +// shape emitted both `index` and `Index`; the canonical key going +// forward is `index` and the deprecated `Index` alias will be removed +// in a future major release. This proto models only the canonical +// `index` field. +type MakeNumberRefStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Index *int32 `protobuf:"varint,1,opt,name=index" json:"index,omitempty"` + Target *int32 `protobuf:"varint,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MakeNumberRefStmt) Reset() { + *x = MakeNumberRefStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MakeNumberRefStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MakeNumberRefStmt) ProtoMessage() {} + +func (x *MakeNumberRefStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[31] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MakeNumberRefStmt.ProtoReflect.Descriptor instead. +func (*MakeNumberRefStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{31} +} + +func (x *MakeNumberRefStmt) GetIndex() int32 { + if x != nil && x.Index != nil { + return *x.Index + } + return 0 +} + +func (x *MakeNumberRefStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// MakeObjectStmt mirrors `ir.MakeObjectStmt` in v1/ir/ir.go. +type MakeObjectStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Target *int32 `protobuf:"varint,1,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MakeObjectStmt) Reset() { + *x = MakeObjectStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MakeObjectStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MakeObjectStmt) ProtoMessage() {} + +func (x *MakeObjectStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[32] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MakeObjectStmt.ProtoReflect.Descriptor instead. +func (*MakeObjectStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{32} +} + +func (x *MakeObjectStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// MakeSetStmt mirrors `ir.MakeSetStmt` in v1/ir/ir.go. +type MakeSetStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Target *int32 `protobuf:"varint,1,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MakeSetStmt) Reset() { + *x = MakeSetStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MakeSetStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MakeSetStmt) ProtoMessage() {} + +func (x *MakeSetStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MakeSetStmt.ProtoReflect.Descriptor instead. +func (*MakeSetStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{33} +} + +func (x *MakeSetStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// NopStmt mirrors `ir.NopStmt` in v1/ir/ir.go. +type NopStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NopStmt) Reset() { + *x = NopStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NopStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NopStmt) ProtoMessage() {} + +func (x *NopStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NopStmt.ProtoReflect.Descriptor instead. +func (*NopStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{34} +} + +// NotEqualStmt mirrors `ir.NotEqualStmt` in v1/ir/ir.go. +type NotEqualStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + A *Operand `protobuf:"bytes,1,opt,name=a" json:"a,omitempty"` + B *Operand `protobuf:"bytes,2,opt,name=b" json:"b,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NotEqualStmt) Reset() { + *x = NotEqualStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NotEqualStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotEqualStmt) ProtoMessage() {} + +func (x *NotEqualStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotEqualStmt.ProtoReflect.Descriptor instead. +func (*NotEqualStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{35} +} + +func (x *NotEqualStmt) GetA() *Operand { + if x != nil { + return x.A + } + return nil +} + +func (x *NotEqualStmt) GetB() *Operand { + if x != nil { + return x.B + } + return nil +} + +// NotStmt mirrors `ir.NotStmt` in v1/ir/ir.go. +type NotStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Block *Block `protobuf:"bytes,1,opt,name=block" json:"block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NotStmt) Reset() { + *x = NotStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NotStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotStmt) ProtoMessage() {} + +func (x *NotStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotStmt.ProtoReflect.Descriptor instead. +func (*NotStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{36} +} + +func (x *NotStmt) GetBlock() *Block { + if x != nil { + return x.Block + } + return nil +} + +// ObjectInsertOnceStmt mirrors `ir.ObjectInsertOnceStmt` in v1/ir/ir.go. +type ObjectInsertOnceStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Key *Operand `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value *Operand `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` + Object *int32 `protobuf:"varint,3,opt,name=object" json:"object,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectInsertOnceStmt) Reset() { + *x = ObjectInsertOnceStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectInsertOnceStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectInsertOnceStmt) ProtoMessage() {} + +func (x *ObjectInsertOnceStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectInsertOnceStmt.ProtoReflect.Descriptor instead. +func (*ObjectInsertOnceStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{37} +} + +func (x *ObjectInsertOnceStmt) GetKey() *Operand { + if x != nil { + return x.Key + } + return nil +} + +func (x *ObjectInsertOnceStmt) GetValue() *Operand { + if x != nil { + return x.Value + } + return nil +} + +func (x *ObjectInsertOnceStmt) GetObject() int32 { + if x != nil && x.Object != nil { + return *x.Object + } + return 0 +} + +// ObjectInsertStmt mirrors `ir.ObjectInsertStmt` in v1/ir/ir.go. +type ObjectInsertStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Key *Operand `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value *Operand `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` + Object *int32 `protobuf:"varint,3,opt,name=object" json:"object,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectInsertStmt) Reset() { + *x = ObjectInsertStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectInsertStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectInsertStmt) ProtoMessage() {} + +func (x *ObjectInsertStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectInsertStmt.ProtoReflect.Descriptor instead. +func (*ObjectInsertStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{38} +} + +func (x *ObjectInsertStmt) GetKey() *Operand { + if x != nil { + return x.Key + } + return nil +} + +func (x *ObjectInsertStmt) GetValue() *Operand { + if x != nil { + return x.Value + } + return nil +} + +func (x *ObjectInsertStmt) GetObject() int32 { + if x != nil && x.Object != nil { + return *x.Object + } + return 0 +} + +// ObjectMergeStmt mirrors `ir.ObjectMergeStmt` in v1/ir/ir.go. +type ObjectMergeStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + A *int32 `protobuf:"varint,1,opt,name=a" json:"a,omitempty"` + B *int32 `protobuf:"varint,2,opt,name=b" json:"b,omitempty"` + Target *int32 `protobuf:"varint,3,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectMergeStmt) Reset() { + *x = ObjectMergeStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectMergeStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectMergeStmt) ProtoMessage() {} + +func (x *ObjectMergeStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[39] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectMergeStmt.ProtoReflect.Descriptor instead. +func (*ObjectMergeStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{39} +} + +func (x *ObjectMergeStmt) GetA() int32 { + if x != nil && x.A != nil { + return *x.A + } + return 0 +} + +func (x *ObjectMergeStmt) GetB() int32 { + if x != nil && x.B != nil { + return *x.B + } + return 0 +} + +func (x *ObjectMergeStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// ResetLocalStmt mirrors `ir.ResetLocalStmt` in v1/ir/ir.go. +type ResetLocalStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Target *int32 `protobuf:"varint,1,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResetLocalStmt) Reset() { + *x = ResetLocalStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResetLocalStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResetLocalStmt) ProtoMessage() {} + +func (x *ResetLocalStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[40] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetLocalStmt.ProtoReflect.Descriptor instead. +func (*ResetLocalStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{40} +} + +func (x *ResetLocalStmt) GetTarget() int32 { + if x != nil && x.Target != nil { + return *x.Target + } + return 0 +} + +// ResultSetAddStmt mirrors `ir.ResultSetAddStmt` in v1/ir/ir.go. +type ResultSetAddStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *int32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResultSetAddStmt) Reset() { + *x = ResultSetAddStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResultSetAddStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResultSetAddStmt) ProtoMessage() {} + +func (x *ResultSetAddStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResultSetAddStmt.ProtoReflect.Descriptor instead. +func (*ResultSetAddStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{41} +} + +func (x *ResultSetAddStmt) GetValue() int32 { + if x != nil && x.Value != nil { + return *x.Value + } + return 0 +} + +// ReturnLocalStmt mirrors `ir.ReturnLocalStmt` in v1/ir/ir.go. +type ReturnLocalStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *int32 `protobuf:"varint,1,opt,name=source" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReturnLocalStmt) Reset() { + *x = ReturnLocalStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReturnLocalStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReturnLocalStmt) ProtoMessage() {} + +func (x *ReturnLocalStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[42] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReturnLocalStmt.ProtoReflect.Descriptor instead. +func (*ReturnLocalStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{42} +} + +func (x *ReturnLocalStmt) GetSource() int32 { + if x != nil && x.Source != nil { + return *x.Source + } + return 0 +} + +// ScanStmt mirrors `ir.ScanStmt` in v1/ir/ir.go. +type ScanStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Source *int32 `protobuf:"varint,1,opt,name=source" json:"source,omitempty"` + Key *int32 `protobuf:"varint,2,opt,name=key" json:"key,omitempty"` + Value *int32 `protobuf:"varint,3,opt,name=value" json:"value,omitempty"` + Block *Block `protobuf:"bytes,4,opt,name=block" json:"block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScanStmt) Reset() { + *x = ScanStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScanStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScanStmt) ProtoMessage() {} + +func (x *ScanStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[43] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScanStmt.ProtoReflect.Descriptor instead. +func (*ScanStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{43} +} + +func (x *ScanStmt) GetSource() int32 { + if x != nil && x.Source != nil { + return *x.Source + } + return 0 +} + +func (x *ScanStmt) GetKey() int32 { + if x != nil && x.Key != nil { + return *x.Key + } + return 0 +} + +func (x *ScanStmt) GetValue() int32 { + if x != nil && x.Value != nil { + return *x.Value + } + return 0 +} + +func (x *ScanStmt) GetBlock() *Block { + if x != nil { + return x.Block + } + return nil +} + +// SetAddStmt mirrors `ir.SetAddStmt` in v1/ir/ir.go. +type SetAddStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *Operand `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Set *int32 `protobuf:"varint,2,opt,name=set" json:"set,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetAddStmt) Reset() { + *x = SetAddStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetAddStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetAddStmt) ProtoMessage() {} + +func (x *SetAddStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[44] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetAddStmt.ProtoReflect.Descriptor instead. +func (*SetAddStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{44} +} + +func (x *SetAddStmt) GetValue() *Operand { + if x != nil { + return x.Value + } + return nil +} + +func (x *SetAddStmt) GetSet() int32 { + if x != nil && x.Set != nil { + return *x.Set + } + return 0 +} + +// WithStmt mirrors `ir.WithStmt` in v1/ir/ir.go. +type WithStmt struct { + state protoimpl.MessageState `protogen:"open.v1"` + Local *int32 `protobuf:"varint,1,opt,name=local" json:"local,omitempty"` + Path []int32 `protobuf:"varint,2,rep,packed,name=path" json:"path,omitempty"` + Value *Operand `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"` + Block *Block `protobuf:"bytes,4,opt,name=block" json:"block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WithStmt) Reset() { + *x = WithStmt{} + mi := &file_v1_ir_plan_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WithStmt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithStmt) ProtoMessage() {} + +func (x *WithStmt) ProtoReflect() protoreflect.Message { + mi := &file_v1_ir_plan_proto_msgTypes[45] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithStmt.ProtoReflect.Descriptor instead. +func (*WithStmt) Descriptor() ([]byte, []int) { + return file_v1_ir_plan_proto_rawDescGZIP(), []int{45} +} + +func (x *WithStmt) GetLocal() int32 { + if x != nil && x.Local != nil { + return *x.Local + } + return 0 +} + +func (x *WithStmt) GetPath() []int32 { + if x != nil { + return x.Path + } + return nil +} + +func (x *WithStmt) GetValue() *Operand { + if x != nil { + return x.Value + } + return nil +} + +func (x *WithStmt) GetBlock() *Block { + if x != nil { + return x.Block + } + return nil +} + +var File_v1_ir_plan_proto protoreflect.FileDescriptor + +const file_v1_ir_plan_proto_rawDesc = "" + + "\n" + + "\x10v1/ir/plan.proto\x12\topa.ir.v1\"\x83\x01\n" + + "\x06Policy\x12)\n" + + "\x06static\x18\x01 \x01(\v2\x11.opa.ir.v1.StaticR\x06static\x12&\n" + + "\x05plans\x18\x02 \x01(\v2\x10.opa.ir.v1.PlansR\x05plans\x12&\n" + + "\x05funcs\x18\x03 \x01(\v2\x10.opa.ir.v1.FuncsR\x05funcs\"\xa5\x01\n" + + "\x06Static\x120\n" + + "\astrings\x18\x01 \x03(\v2\x16.opa.ir.v1.StringConstR\astrings\x12;\n" + + "\rbuiltin_funcs\x18\x02 \x03(\v2\x16.opa.ir.v1.BuiltinFuncR\fbuiltinFuncs\x12,\n" + + "\x05files\x18\x03 \x03(\v2\x16.opa.ir.v1.StringConstR\x05files\"!\n" + + "\vBuiltinFunc\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\".\n" + + "\x05Plans\x12%\n" + + "\x05plans\x18\x01 \x03(\v2\x0f.opa.ir.v1.PlanR\x05plans\".\n" + + "\x05Funcs\x12%\n" + + "\x05funcs\x18\x01 \x03(\v2\x0f.opa.ir.v1.FuncR\x05funcs\"\x88\x01\n" + + "\x04Func\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" + + "\x06params\x18\x02 \x03(\x05R\x06params\x12\x16\n" + + "\x06result\x18\x03 \x01(\x05R\x06result\x12(\n" + + "\x06blocks\x18\x04 \x03(\v2\x10.opa.ir.v1.BlockR\x06blocks\x12\x12\n" + + "\x04path\x18\x05 \x03(\tR\x04path\"D\n" + + "\x04Plan\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12(\n" + + "\x06blocks\x18\x02 \x03(\v2\x10.opa.ir.v1.BlockR\x06blocks\".\n" + + "\x05Block\x12%\n" + + "\x05stmts\x18\x01 \x03(\v2\x0f.opa.ir.v1.StmtR\x05stmts\"#\n" + + "\vStringConst\x12\x14\n" + + "\x05value\x18\x01 \x01(\tR\x05value\"/\n" + + "\aOperand\x12$\n" + + "\x05value\x18\x01 \x01(\v2\x0e.opa.ir.v1.ValR\x05value\"`\n" + + "\x03Val\x12\x14\n" + + "\x04bool\x18\x01 \x01(\bH\x00R\x04bool\x12\x16\n" + + "\x05local\x18\x02 \x01(\x05H\x00R\x05local\x12#\n" + + "\fstring_index\x18\x03 \x01(\x05H\x00R\vstringIndexB\x06\n" + + "\x04kind\"\xf5\x11\n" + + "\x04Stmt\x12\x12\n" + + "\x04file\x18\x01 \x01(\x05R\x04file\x12\x10\n" + + "\x03col\x18\x02 \x01(\x05R\x03col\x12\x10\n" + + "\x03row\x18\x03 \x01(\x05R\x03row\x12H\n" + + "\x11array_append_stmt\x18\x04 \x01(\v2\x1a.opa.ir.v1.ArrayAppendStmtH\x00R\x0farrayAppendStmt\x12B\n" + + "\x0fassign_int_stmt\x18\x05 \x01(\v2\x18.opa.ir.v1.AssignIntStmtH\x00R\rassignIntStmt\x12O\n" + + "\x14assign_var_once_stmt\x18\x06 \x01(\v2\x1c.opa.ir.v1.AssignVarOnceStmtH\x00R\x11assignVarOnceStmt\x12B\n" + + "\x0fassign_var_stmt\x18\a \x01(\v2\x18.opa.ir.v1.AssignVarStmtH\x00R\rassignVarStmt\x125\n" + + "\n" + + "block_stmt\x18\b \x01(\v2\x14.opa.ir.v1.BlockStmtH\x00R\tblockStmt\x125\n" + + "\n" + + "break_stmt\x18\t \x01(\v2\x14.opa.ir.v1.BreakStmtH\x00R\tbreakStmt\x12H\n" + + "\x11call_dynamic_stmt\x18\n" + + " \x01(\v2\x1a.opa.ir.v1.CallDynamicStmtH\x00R\x0fcallDynamicStmt\x122\n" + + "\tcall_stmt\x18\v \x01(\v2\x13.opa.ir.v1.CallStmtH\x00R\bcallStmt\x12/\n" + + "\bdot_stmt\x18\f \x01(\v2\x12.opa.ir.v1.DotStmtH\x00R\adotStmt\x125\n" + + "\n" + + "equal_stmt\x18\r \x01(\v2\x14.opa.ir.v1.EqualStmtH\x00R\tequalStmt\x12<\n" + + "\ris_array_stmt\x18\x0e \x01(\v2\x16.opa.ir.v1.IsArrayStmtH\x00R\visArrayStmt\x12B\n" + + "\x0fis_defined_stmt\x18\x0f \x01(\v2\x18.opa.ir.v1.IsDefinedStmtH\x00R\risDefinedStmt\x12?\n" + + "\x0eis_object_stmt\x18\x10 \x01(\v2\x17.opa.ir.v1.IsObjectStmtH\x00R\fisObjectStmt\x126\n" + + "\vis_set_stmt\x18\x11 \x01(\v2\x14.opa.ir.v1.IsSetStmtH\x00R\tisSetStmt\x12H\n" + + "\x11is_undefined_stmt\x18\x12 \x01(\v2\x1a.opa.ir.v1.IsUndefinedStmtH\x00R\x0fisUndefinedStmt\x12/\n" + + "\blen_stmt\x18\x13 \x01(\v2\x12.opa.ir.v1.LenStmtH\x00R\alenStmt\x12B\n" + + "\x0fmake_array_stmt\x18\x14 \x01(\v2\x18.opa.ir.v1.MakeArrayStmtH\x00R\rmakeArrayStmt\x12?\n" + + "\x0emake_null_stmt\x18\x15 \x01(\v2\x17.opa.ir.v1.MakeNullStmtH\x00R\fmakeNullStmt\x12O\n" + + "\x14make_number_int_stmt\x18\x16 \x01(\v2\x1c.opa.ir.v1.MakeNumberIntStmtH\x00R\x11makeNumberIntStmt\x12O\n" + + "\x14make_number_ref_stmt\x18\x17 \x01(\v2\x1c.opa.ir.v1.MakeNumberRefStmtH\x00R\x11makeNumberRefStmt\x12E\n" + + "\x10make_object_stmt\x18\x18 \x01(\v2\x19.opa.ir.v1.MakeObjectStmtH\x00R\x0emakeObjectStmt\x12<\n" + + "\rmake_set_stmt\x18\x19 \x01(\v2\x16.opa.ir.v1.MakeSetStmtH\x00R\vmakeSetStmt\x12/\n" + + "\bnop_stmt\x18\x1a \x01(\v2\x12.opa.ir.v1.NopStmtH\x00R\anopStmt\x12?\n" + + "\x0enot_equal_stmt\x18\x1b \x01(\v2\x17.opa.ir.v1.NotEqualStmtH\x00R\fnotEqualStmt\x12/\n" + + "\bnot_stmt\x18\x1c \x01(\v2\x12.opa.ir.v1.NotStmtH\x00R\anotStmt\x12X\n" + + "\x17object_insert_once_stmt\x18\x1d \x01(\v2\x1f.opa.ir.v1.ObjectInsertOnceStmtH\x00R\x14objectInsertOnceStmt\x12K\n" + + "\x12object_insert_stmt\x18\x1e \x01(\v2\x1b.opa.ir.v1.ObjectInsertStmtH\x00R\x10objectInsertStmt\x12H\n" + + "\x11object_merge_stmt\x18\x1f \x01(\v2\x1a.opa.ir.v1.ObjectMergeStmtH\x00R\x0fobjectMergeStmt\x12E\n" + + "\x10reset_local_stmt\x18 \x01(\v2\x19.opa.ir.v1.ResetLocalStmtH\x00R\x0eresetLocalStmt\x12L\n" + + "\x13result_set_add_stmt\x18! \x01(\v2\x1b.opa.ir.v1.ResultSetAddStmtH\x00R\x10resultSetAddStmt\x12H\n" + + "\x11return_local_stmt\x18\" \x01(\v2\x1a.opa.ir.v1.ReturnLocalStmtH\x00R\x0freturnLocalStmt\x122\n" + + "\tscan_stmt\x18# \x01(\v2\x13.opa.ir.v1.ScanStmtH\x00R\bscanStmt\x129\n" + + "\fset_add_stmt\x18$ \x01(\v2\x15.opa.ir.v1.SetAddStmtH\x00R\n" + + "setAddStmt\x122\n" + + "\twith_stmt\x18% \x01(\v2\x13.opa.ir.v1.WithStmtH\x00R\bwithStmtB\x06\n" + + "\x04kind\"Q\n" + + "\x0fArrayAppendStmt\x12(\n" + + "\x05value\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x05value\x12\x14\n" + + "\x05array\x18\x02 \x01(\x05R\x05array\"=\n" + + "\rAssignIntStmt\x12\x14\n" + + "\x05value\x18\x01 \x01(\x03R\x05value\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"W\n" + + "\x11AssignVarOnceStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"S\n" + + "\rAssignVarStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"5\n" + + "\tBlockStmt\x12(\n" + + "\x06blocks\x18\x01 \x03(\v2\x10.opa.ir.v1.BlockR\x06blocks\"!\n" + + "\tBreakStmt\x12\x14\n" + + "\x05index\x18\x01 \x01(\rR\x05index\"e\n" + + "\x0fCallDynamicStmt\x12\x12\n" + + "\x04args\x18\x01 \x03(\x05R\x04args\x12\x16\n" + + "\x06result\x18\x02 \x01(\x05R\x06result\x12&\n" + + "\x04path\x18\x03 \x03(\v2\x12.opa.ir.v1.OperandR\x04path\"f\n" + + "\bCallStmt\x12\x1a\n" + + "\bfunction\x18\x01 \x01(\tR\bfunction\x12&\n" + + "\x04args\x18\x02 \x03(\v2\x12.opa.ir.v1.OperandR\x04args\x12\x16\n" + + "\x06result\x18\x03 \x01(\x05R\x06result\"s\n" + + "\aDotStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\x12$\n" + + "\x03key\x18\x02 \x01(\v2\x12.opa.ir.v1.OperandR\x03key\x12\x16\n" + + "\x06target\x18\x03 \x01(\x05R\x06target\"O\n" + + "\tEqualStmt\x12 \n" + + "\x01a\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x01a\x12 \n" + + "\x01b\x18\x02 \x01(\v2\x12.opa.ir.v1.OperandR\x01b\"9\n" + + "\vIsArrayStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\"'\n" + + "\rIsDefinedStmt\x12\x16\n" + + "\x06source\x18\x01 \x01(\x05R\x06source\":\n" + + "\fIsObjectStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\"7\n" + + "\tIsSetStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\")\n" + + "\x0fIsUndefinedStmt\x12\x16\n" + + "\x06source\x18\x01 \x01(\x05R\x06source\"M\n" + + "\aLenStmt\x12*\n" + + "\x06source\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x06source\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"C\n" + + "\rMakeArrayStmt\x12\x1a\n" + + "\bcapacity\x18\x01 \x01(\x05R\bcapacity\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"&\n" + + "\fMakeNullStmt\x12\x16\n" + + "\x06target\x18\x01 \x01(\x05R\x06target\"A\n" + + "\x11MakeNumberIntStmt\x12\x14\n" + + "\x05value\x18\x01 \x01(\x03R\x05value\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"A\n" + + "\x11MakeNumberRefStmt\x12\x14\n" + + "\x05index\x18\x01 \x01(\x05R\x05index\x12\x16\n" + + "\x06target\x18\x02 \x01(\x05R\x06target\"(\n" + + "\x0eMakeObjectStmt\x12\x16\n" + + "\x06target\x18\x01 \x01(\x05R\x06target\"%\n" + + "\vMakeSetStmt\x12\x16\n" + + "\x06target\x18\x01 \x01(\x05R\x06target\"\t\n" + + "\aNopStmt\"R\n" + + "\fNotEqualStmt\x12 \n" + + "\x01a\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x01a\x12 \n" + + "\x01b\x18\x02 \x01(\v2\x12.opa.ir.v1.OperandR\x01b\"1\n" + + "\aNotStmt\x12&\n" + + "\x05block\x18\x01 \x01(\v2\x10.opa.ir.v1.BlockR\x05block\"~\n" + + "\x14ObjectInsertOnceStmt\x12$\n" + + "\x03key\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x03key\x12(\n" + + "\x05value\x18\x02 \x01(\v2\x12.opa.ir.v1.OperandR\x05value\x12\x16\n" + + "\x06object\x18\x03 \x01(\x05R\x06object\"z\n" + + "\x10ObjectInsertStmt\x12$\n" + + "\x03key\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x03key\x12(\n" + + "\x05value\x18\x02 \x01(\v2\x12.opa.ir.v1.OperandR\x05value\x12\x16\n" + + "\x06object\x18\x03 \x01(\x05R\x06object\"E\n" + + "\x0fObjectMergeStmt\x12\f\n" + + "\x01a\x18\x01 \x01(\x05R\x01a\x12\f\n" + + "\x01b\x18\x02 \x01(\x05R\x01b\x12\x16\n" + + "\x06target\x18\x03 \x01(\x05R\x06target\"(\n" + + "\x0eResetLocalStmt\x12\x16\n" + + "\x06target\x18\x01 \x01(\x05R\x06target\"(\n" + + "\x10ResultSetAddStmt\x12\x14\n" + + "\x05value\x18\x01 \x01(\x05R\x05value\")\n" + + "\x0fReturnLocalStmt\x12\x16\n" + + "\x06source\x18\x01 \x01(\x05R\x06source\"r\n" + + "\bScanStmt\x12\x16\n" + + "\x06source\x18\x01 \x01(\x05R\x06source\x12\x10\n" + + "\x03key\x18\x02 \x01(\x05R\x03key\x12\x14\n" + + "\x05value\x18\x03 \x01(\x05R\x05value\x12&\n" + + "\x05block\x18\x04 \x01(\v2\x10.opa.ir.v1.BlockR\x05block\"H\n" + + "\n" + + "SetAddStmt\x12(\n" + + "\x05value\x18\x01 \x01(\v2\x12.opa.ir.v1.OperandR\x05value\x12\x10\n" + + "\x03set\x18\x02 \x01(\x05R\x03set\"\x86\x01\n" + + "\bWithStmt\x12\x14\n" + + "\x05local\x18\x01 \x01(\x05R\x05local\x12\x12\n" + + "\x04path\x18\x02 \x03(\x05R\x04path\x12(\n" + + "\x05value\x18\x03 \x01(\v2\x12.opa.ir.v1.OperandR\x05value\x12&\n" + + "\x05block\x18\x04 \x01(\v2\x10.opa.ir.v1.BlockR\x05blockB/P\x01Z+github.com/open-policy-agent/opa/v1/ir/v1pbb\beditionsp\xe8\a" + +var ( + file_v1_ir_plan_proto_rawDescOnce sync.Once + file_v1_ir_plan_proto_rawDescData []byte +) + +func file_v1_ir_plan_proto_rawDescGZIP() []byte { + file_v1_ir_plan_proto_rawDescOnce.Do(func() { + file_v1_ir_plan_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_v1_ir_plan_proto_rawDesc), len(file_v1_ir_plan_proto_rawDesc))) + }) + return file_v1_ir_plan_proto_rawDescData +} + +var file_v1_ir_plan_proto_msgTypes = make([]protoimpl.MessageInfo, 46) +var file_v1_ir_plan_proto_goTypes = []any{ + (*Policy)(nil), // 0: opa.ir.v1.Policy + (*Static)(nil), // 1: opa.ir.v1.Static + (*BuiltinFunc)(nil), // 2: opa.ir.v1.BuiltinFunc + (*Plans)(nil), // 3: opa.ir.v1.Plans + (*Funcs)(nil), // 4: opa.ir.v1.Funcs + (*Func)(nil), // 5: opa.ir.v1.Func + (*Plan)(nil), // 6: opa.ir.v1.Plan + (*Block)(nil), // 7: opa.ir.v1.Block + (*StringConst)(nil), // 8: opa.ir.v1.StringConst + (*Operand)(nil), // 9: opa.ir.v1.Operand + (*Val)(nil), // 10: opa.ir.v1.Val + (*Stmt)(nil), // 11: opa.ir.v1.Stmt + (*ArrayAppendStmt)(nil), // 12: opa.ir.v1.ArrayAppendStmt + (*AssignIntStmt)(nil), // 13: opa.ir.v1.AssignIntStmt + (*AssignVarOnceStmt)(nil), // 14: opa.ir.v1.AssignVarOnceStmt + (*AssignVarStmt)(nil), // 15: opa.ir.v1.AssignVarStmt + (*BlockStmt)(nil), // 16: opa.ir.v1.BlockStmt + (*BreakStmt)(nil), // 17: opa.ir.v1.BreakStmt + (*CallDynamicStmt)(nil), // 18: opa.ir.v1.CallDynamicStmt + (*CallStmt)(nil), // 19: opa.ir.v1.CallStmt + (*DotStmt)(nil), // 20: opa.ir.v1.DotStmt + (*EqualStmt)(nil), // 21: opa.ir.v1.EqualStmt + (*IsArrayStmt)(nil), // 22: opa.ir.v1.IsArrayStmt + (*IsDefinedStmt)(nil), // 23: opa.ir.v1.IsDefinedStmt + (*IsObjectStmt)(nil), // 24: opa.ir.v1.IsObjectStmt + (*IsSetStmt)(nil), // 25: opa.ir.v1.IsSetStmt + (*IsUndefinedStmt)(nil), // 26: opa.ir.v1.IsUndefinedStmt + (*LenStmt)(nil), // 27: opa.ir.v1.LenStmt + (*MakeArrayStmt)(nil), // 28: opa.ir.v1.MakeArrayStmt + (*MakeNullStmt)(nil), // 29: opa.ir.v1.MakeNullStmt + (*MakeNumberIntStmt)(nil), // 30: opa.ir.v1.MakeNumberIntStmt + (*MakeNumberRefStmt)(nil), // 31: opa.ir.v1.MakeNumberRefStmt + (*MakeObjectStmt)(nil), // 32: opa.ir.v1.MakeObjectStmt + (*MakeSetStmt)(nil), // 33: opa.ir.v1.MakeSetStmt + (*NopStmt)(nil), // 34: opa.ir.v1.NopStmt + (*NotEqualStmt)(nil), // 35: opa.ir.v1.NotEqualStmt + (*NotStmt)(nil), // 36: opa.ir.v1.NotStmt + (*ObjectInsertOnceStmt)(nil), // 37: opa.ir.v1.ObjectInsertOnceStmt + (*ObjectInsertStmt)(nil), // 38: opa.ir.v1.ObjectInsertStmt + (*ObjectMergeStmt)(nil), // 39: opa.ir.v1.ObjectMergeStmt + (*ResetLocalStmt)(nil), // 40: opa.ir.v1.ResetLocalStmt + (*ResultSetAddStmt)(nil), // 41: opa.ir.v1.ResultSetAddStmt + (*ReturnLocalStmt)(nil), // 42: opa.ir.v1.ReturnLocalStmt + (*ScanStmt)(nil), // 43: opa.ir.v1.ScanStmt + (*SetAddStmt)(nil), // 44: opa.ir.v1.SetAddStmt + (*WithStmt)(nil), // 45: opa.ir.v1.WithStmt +} +var file_v1_ir_plan_proto_depIdxs = []int32{ + 1, // 0: opa.ir.v1.Policy.static:type_name -> opa.ir.v1.Static + 3, // 1: opa.ir.v1.Policy.plans:type_name -> opa.ir.v1.Plans + 4, // 2: opa.ir.v1.Policy.funcs:type_name -> opa.ir.v1.Funcs + 8, // 3: opa.ir.v1.Static.strings:type_name -> opa.ir.v1.StringConst + 2, // 4: opa.ir.v1.Static.builtin_funcs:type_name -> opa.ir.v1.BuiltinFunc + 8, // 5: opa.ir.v1.Static.files:type_name -> opa.ir.v1.StringConst + 6, // 6: opa.ir.v1.Plans.plans:type_name -> opa.ir.v1.Plan + 5, // 7: opa.ir.v1.Funcs.funcs:type_name -> opa.ir.v1.Func + 7, // 8: opa.ir.v1.Func.blocks:type_name -> opa.ir.v1.Block + 7, // 9: opa.ir.v1.Plan.blocks:type_name -> opa.ir.v1.Block + 11, // 10: opa.ir.v1.Block.stmts:type_name -> opa.ir.v1.Stmt + 10, // 11: opa.ir.v1.Operand.value:type_name -> opa.ir.v1.Val + 12, // 12: opa.ir.v1.Stmt.array_append_stmt:type_name -> opa.ir.v1.ArrayAppendStmt + 13, // 13: opa.ir.v1.Stmt.assign_int_stmt:type_name -> opa.ir.v1.AssignIntStmt + 14, // 14: opa.ir.v1.Stmt.assign_var_once_stmt:type_name -> opa.ir.v1.AssignVarOnceStmt + 15, // 15: opa.ir.v1.Stmt.assign_var_stmt:type_name -> opa.ir.v1.AssignVarStmt + 16, // 16: opa.ir.v1.Stmt.block_stmt:type_name -> opa.ir.v1.BlockStmt + 17, // 17: opa.ir.v1.Stmt.break_stmt:type_name -> opa.ir.v1.BreakStmt + 18, // 18: opa.ir.v1.Stmt.call_dynamic_stmt:type_name -> opa.ir.v1.CallDynamicStmt + 19, // 19: opa.ir.v1.Stmt.call_stmt:type_name -> opa.ir.v1.CallStmt + 20, // 20: opa.ir.v1.Stmt.dot_stmt:type_name -> opa.ir.v1.DotStmt + 21, // 21: opa.ir.v1.Stmt.equal_stmt:type_name -> opa.ir.v1.EqualStmt + 22, // 22: opa.ir.v1.Stmt.is_array_stmt:type_name -> opa.ir.v1.IsArrayStmt + 23, // 23: opa.ir.v1.Stmt.is_defined_stmt:type_name -> opa.ir.v1.IsDefinedStmt + 24, // 24: opa.ir.v1.Stmt.is_object_stmt:type_name -> opa.ir.v1.IsObjectStmt + 25, // 25: opa.ir.v1.Stmt.is_set_stmt:type_name -> opa.ir.v1.IsSetStmt + 26, // 26: opa.ir.v1.Stmt.is_undefined_stmt:type_name -> opa.ir.v1.IsUndefinedStmt + 27, // 27: opa.ir.v1.Stmt.len_stmt:type_name -> opa.ir.v1.LenStmt + 28, // 28: opa.ir.v1.Stmt.make_array_stmt:type_name -> opa.ir.v1.MakeArrayStmt + 29, // 29: opa.ir.v1.Stmt.make_null_stmt:type_name -> opa.ir.v1.MakeNullStmt + 30, // 30: opa.ir.v1.Stmt.make_number_int_stmt:type_name -> opa.ir.v1.MakeNumberIntStmt + 31, // 31: opa.ir.v1.Stmt.make_number_ref_stmt:type_name -> opa.ir.v1.MakeNumberRefStmt + 32, // 32: opa.ir.v1.Stmt.make_object_stmt:type_name -> opa.ir.v1.MakeObjectStmt + 33, // 33: opa.ir.v1.Stmt.make_set_stmt:type_name -> opa.ir.v1.MakeSetStmt + 34, // 34: opa.ir.v1.Stmt.nop_stmt:type_name -> opa.ir.v1.NopStmt + 35, // 35: opa.ir.v1.Stmt.not_equal_stmt:type_name -> opa.ir.v1.NotEqualStmt + 36, // 36: opa.ir.v1.Stmt.not_stmt:type_name -> opa.ir.v1.NotStmt + 37, // 37: opa.ir.v1.Stmt.object_insert_once_stmt:type_name -> opa.ir.v1.ObjectInsertOnceStmt + 38, // 38: opa.ir.v1.Stmt.object_insert_stmt:type_name -> opa.ir.v1.ObjectInsertStmt + 39, // 39: opa.ir.v1.Stmt.object_merge_stmt:type_name -> opa.ir.v1.ObjectMergeStmt + 40, // 40: opa.ir.v1.Stmt.reset_local_stmt:type_name -> opa.ir.v1.ResetLocalStmt + 41, // 41: opa.ir.v1.Stmt.result_set_add_stmt:type_name -> opa.ir.v1.ResultSetAddStmt + 42, // 42: opa.ir.v1.Stmt.return_local_stmt:type_name -> opa.ir.v1.ReturnLocalStmt + 43, // 43: opa.ir.v1.Stmt.scan_stmt:type_name -> opa.ir.v1.ScanStmt + 44, // 44: opa.ir.v1.Stmt.set_add_stmt:type_name -> opa.ir.v1.SetAddStmt + 45, // 45: opa.ir.v1.Stmt.with_stmt:type_name -> opa.ir.v1.WithStmt + 9, // 46: opa.ir.v1.ArrayAppendStmt.value:type_name -> opa.ir.v1.Operand + 9, // 47: opa.ir.v1.AssignVarOnceStmt.source:type_name -> opa.ir.v1.Operand + 9, // 48: opa.ir.v1.AssignVarStmt.source:type_name -> opa.ir.v1.Operand + 7, // 49: opa.ir.v1.BlockStmt.blocks:type_name -> opa.ir.v1.Block + 9, // 50: opa.ir.v1.CallDynamicStmt.path:type_name -> opa.ir.v1.Operand + 9, // 51: opa.ir.v1.CallStmt.args:type_name -> opa.ir.v1.Operand + 9, // 52: opa.ir.v1.DotStmt.source:type_name -> opa.ir.v1.Operand + 9, // 53: opa.ir.v1.DotStmt.key:type_name -> opa.ir.v1.Operand + 9, // 54: opa.ir.v1.EqualStmt.a:type_name -> opa.ir.v1.Operand + 9, // 55: opa.ir.v1.EqualStmt.b:type_name -> opa.ir.v1.Operand + 9, // 56: opa.ir.v1.IsArrayStmt.source:type_name -> opa.ir.v1.Operand + 9, // 57: opa.ir.v1.IsObjectStmt.source:type_name -> opa.ir.v1.Operand + 9, // 58: opa.ir.v1.IsSetStmt.source:type_name -> opa.ir.v1.Operand + 9, // 59: opa.ir.v1.LenStmt.source:type_name -> opa.ir.v1.Operand + 9, // 60: opa.ir.v1.NotEqualStmt.a:type_name -> opa.ir.v1.Operand + 9, // 61: opa.ir.v1.NotEqualStmt.b:type_name -> opa.ir.v1.Operand + 7, // 62: opa.ir.v1.NotStmt.block:type_name -> opa.ir.v1.Block + 9, // 63: opa.ir.v1.ObjectInsertOnceStmt.key:type_name -> opa.ir.v1.Operand + 9, // 64: opa.ir.v1.ObjectInsertOnceStmt.value:type_name -> opa.ir.v1.Operand + 9, // 65: opa.ir.v1.ObjectInsertStmt.key:type_name -> opa.ir.v1.Operand + 9, // 66: opa.ir.v1.ObjectInsertStmt.value:type_name -> opa.ir.v1.Operand + 7, // 67: opa.ir.v1.ScanStmt.block:type_name -> opa.ir.v1.Block + 9, // 68: opa.ir.v1.SetAddStmt.value:type_name -> opa.ir.v1.Operand + 9, // 69: opa.ir.v1.WithStmt.value:type_name -> opa.ir.v1.Operand + 7, // 70: opa.ir.v1.WithStmt.block:type_name -> opa.ir.v1.Block + 71, // [71:71] is the sub-list for method output_type + 71, // [71:71] is the sub-list for method input_type + 71, // [71:71] is the sub-list for extension type_name + 71, // [71:71] is the sub-list for extension extendee + 0, // [0:71] is the sub-list for field type_name +} + +func init() { file_v1_ir_plan_proto_init() } +func file_v1_ir_plan_proto_init() { + if File_v1_ir_plan_proto != nil { + return + } + file_v1_ir_plan_proto_msgTypes[10].OneofWrappers = []any{ + (*Val_Bool)(nil), + (*Val_Local)(nil), + (*Val_StringIndex)(nil), + } + file_v1_ir_plan_proto_msgTypes[11].OneofWrappers = []any{ + (*Stmt_ArrayAppendStmt)(nil), + (*Stmt_AssignIntStmt)(nil), + (*Stmt_AssignVarOnceStmt)(nil), + (*Stmt_AssignVarStmt)(nil), + (*Stmt_BlockStmt)(nil), + (*Stmt_BreakStmt)(nil), + (*Stmt_CallDynamicStmt)(nil), + (*Stmt_CallStmt)(nil), + (*Stmt_DotStmt)(nil), + (*Stmt_EqualStmt)(nil), + (*Stmt_IsArrayStmt)(nil), + (*Stmt_IsDefinedStmt)(nil), + (*Stmt_IsObjectStmt)(nil), + (*Stmt_IsSetStmt)(nil), + (*Stmt_IsUndefinedStmt)(nil), + (*Stmt_LenStmt)(nil), + (*Stmt_MakeArrayStmt)(nil), + (*Stmt_MakeNullStmt)(nil), + (*Stmt_MakeNumberIntStmt)(nil), + (*Stmt_MakeNumberRefStmt)(nil), + (*Stmt_MakeObjectStmt)(nil), + (*Stmt_MakeSetStmt)(nil), + (*Stmt_NopStmt)(nil), + (*Stmt_NotEqualStmt)(nil), + (*Stmt_NotStmt)(nil), + (*Stmt_ObjectInsertOnceStmt)(nil), + (*Stmt_ObjectInsertStmt)(nil), + (*Stmt_ObjectMergeStmt)(nil), + (*Stmt_ResetLocalStmt)(nil), + (*Stmt_ResultSetAddStmt)(nil), + (*Stmt_ReturnLocalStmt)(nil), + (*Stmt_ScanStmt)(nil), + (*Stmt_SetAddStmt)(nil), + (*Stmt_WithStmt)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_v1_ir_plan_proto_rawDesc), len(file_v1_ir_plan_proto_rawDesc)), + NumEnums: 0, + NumMessages: 46, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_v1_ir_plan_proto_goTypes, + DependencyIndexes: file_v1_ir_plan_proto_depIdxs, + MessageInfos: file_v1_ir_plan_proto_msgTypes, + }.Build() + File_v1_ir_plan_proto = out.File + file_v1_ir_plan_proto_goTypes = nil + file_v1_ir_plan_proto_depIdxs = nil +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/keys/keys.go b/vendor/github.com/open-policy-agent/opa/v1/keys/keys.go index fba7a9c939..0581317172 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/keys/keys.go +++ b/vendor/github.com/open-policy-agent/opa/v1/keys/keys.go @@ -33,6 +33,9 @@ type Config struct { // Equal returns true if this key config is equal to the other. func (k *Config) Equal(other *Config) bool { + if k == other { + return true + } return other != nil && *k == *other } diff --git a/vendor/github.com/open-policy-agent/opa/v1/logging/slog.go b/vendor/github.com/open-policy-agent/opa/v1/logging/slog.go deleted file mode 100644 index b6ee1c7c71..0000000000 --- a/vendor/github.com/open-policy-agent/opa/v1/logging/slog.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2026 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package logging - -import ( - "context" - "log/slog" -) - -// AsSlogLogger returns a *slog.Logger that forwards log records to the given Logger. -// Structured fields are forwarded via WithFields; log levels map to the equivalent -// Logger methods. Groups are not supported and are ignored. -func AsSlogLogger(logger Logger) *slog.Logger { - return slog.New(slogHandler{logger: logger}) -} - -// AsSlogLoggerWithPinnedLevel returns a *slog.Logger that forwards all log records -// to the given Logger at the specified fixed level, ignoring the slog record's own level. -// This is useful when bridging a library that uses slog into OPA's logger at a fixed verbosity. -func AsSlogLoggerWithPinnedLevel(logger Logger, level Level) *slog.Logger { - return slog.New(slogHandler{logger: logger, pinnedLevel: &level}) -} - -type slogHandler struct { - logger Logger - pinnedLevel *Level -} - -func (slogHandler) Enabled(_ context.Context, _ slog.Level) bool { return true } - -func (h slogHandler) Handle(_ context.Context, r slog.Record) error { - fields := make(map[string]any, r.NumAttrs()) - - r.Attrs(func(a slog.Attr) bool { - fields[a.Key] = a.Value.Any() - - return true - }) - - l := h.logger.WithFields(fields) - - if h.pinnedLevel != nil { - dispatchAtLevel(l, *h.pinnedLevel, r.Message) - return nil - } - - // slog.Level is int; cascade from most-severe so custom levels between named ones route correctly. - switch { - case r.Level >= slog.LevelError: - l.Error(r.Message) - case r.Level >= slog.LevelWarn: - l.Warn(r.Message) - case r.Level >= slog.LevelInfo: - l.Info(r.Message) - default: - l.Debug(r.Message) - } - - return nil -} - -func (h slogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { - fields := make(map[string]any, len(attrs)) - - for _, a := range attrs { - fields[a.Key] = a.Value.Any() - } - - return slogHandler{logger: h.logger.WithFields(fields), pinnedLevel: h.pinnedLevel} -} - -func (h slogHandler) WithGroup(_ string) slog.Handler { return h } - -func dispatchAtLevel(l Logger, level Level, msg string) { - switch level { - case Error: - l.Error(msg) - case Warn: - l.Warn(msg) - case Info: - l.Info(msg) - default: - l.Debug(msg) - } -} diff --git a/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go b/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go index bef39ebf49..62c3a51e90 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go +++ b/vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go @@ -6,11 +6,10 @@ package ptr import ( - "strconv" - "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/storage" "github.com/open-policy-agent/opa/v1/storage/internal/errors" + "github.com/open-policy-agent/opa/v1/util" ) func Ptr(data any, path storage.Path) (any, error) { @@ -92,7 +91,7 @@ func ValuePtr(data ast.Value, path storage.Path) (ast.Value, error) { } func ValidateArrayIndex(arr []any, s string, path storage.Path) (int, error) { - idx, ok := isInt(s) + idx, ok := util.Atoi(s) if !ok { return 0, errors.NewNotFoundErrorWithHint(path, errors.ArrayIndexTypeMsg) } @@ -100,7 +99,7 @@ func ValidateArrayIndex(arr []any, s string, path storage.Path) (int, error) { } func ValidateASTArrayIndex(arr *ast.Array, s string, path storage.Path) (int, error) { - idx, ok := isInt(s) + idx, ok := util.Atoi(s) if !ok { return 0, errors.NewNotFoundErrorWithHint(path, errors.ArrayIndexTypeMsg) } @@ -111,18 +110,13 @@ func ValidateASTArrayIndex(arr *ast.Array, s string, path storage.Path) (int, er // array element like `ValidateArrayIndex`, but returns a `resource_conflict` error // if it is not. func ValidateArrayIndexForWrite(arr []any, s string, i int, path storage.Path) (int, error) { - idx, ok := isInt(s) + idx, ok := util.Atoi(s) if !ok { return 0, errors.NewWriteConflictError(path[:i-1]) } return inRange(idx, arr, path) } -func isInt(s string) (int, bool) { - idx, err := strconv.Atoi(s) - return idx, err == nil -} - func inRange(i int, arr any, path storage.Path) (int, error) { var arrLen int diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go index 356e7b38b0..f018057213 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go @@ -25,6 +25,44 @@ func builtinCount(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) e return builtins.NewOperandTypeErr(1, operands[0].Value, "array", "object", "set", "string") } +// termIterable is satisfied by both *ast.Array and ast.Set. +type termIterable interface { + Iter(func(*ast.Term) error) error +} + +// exactIntAccumulate accumulates the numbers in a with op on exact big.Ints, reporting false if +// any element is not an integer, in which case the caller falls back to the float path. +// +// That float path accumulates in a big.Float carrying the default mantissa, so integers needing +// more significant bits are silently rounded. +func exactIntAccumulate(a termIterable, init int64, op func(z, x, y *big.Int) *big.Int) (ast.Number, bool) { + acc := big.NewInt(init) + exact := true + + _ = a.Iter(func(x *ast.Term) error { + if !exact { + return nil + } + n, ok := x.Value.(ast.Number) + if !ok { + exact = false + return nil + } + i, err := builtins.NumberToInt(n) + if err != nil { + exact = false + return nil + } + op(acc, acc, i) + return nil + }) + + if !exact { + return "", false + } + return builtins.IntToNumber(acc), true +} + func builtinSum(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { switch a := operands[0].Value.(type) { case *ast.Array: @@ -44,6 +82,10 @@ func builtinSum(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) err } // Non-integer values found, so we need to sum as floats. + if n, ok := exactIntAccumulate(a, 0, (*big.Int).Add); ok { + return iter(ast.NewTerm(n)) + } + sum := big.NewFloat(0) tmp := new(big.Float) err := a.Iter(func(x *ast.Term) error { @@ -74,6 +116,10 @@ func builtinSum(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) err return iter(ast.InternedTerm(is)) } + if n, ok := exactIntAccumulate(a, 0, (*big.Int).Add); ok { + return iter(ast.NewTerm(n)) + } + sum := big.NewFloat(0) tmp := new(big.Float) err := a.Iter(func(x *ast.Term) error { @@ -95,6 +141,10 @@ func builtinSum(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) err func builtinProduct(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { switch a := operands[0].Value.(type) { case *ast.Array: + if n, ok := exactIntAccumulate(a, 1, (*big.Int).Mul); ok { + return iter(ast.NewTerm(n)) + } + product := big.NewFloat(1) tmp := new(big.Float) err := a.Iter(func(x *ast.Term) error { @@ -110,6 +160,10 @@ func builtinProduct(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) } return iter(ast.NewTerm(builtins.FloatToNumber(product))) case ast.Set: + if n, ok := exactIntAccumulate(a, 1, (*big.Int).Mul); ok { + return iter(ast.NewTerm(n)) + } + product := big.NewFloat(1) tmp := new(big.Float) err := a.Iter(func(x *ast.Term) error { @@ -260,34 +314,29 @@ func builtinAny(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) err } func builtinMember(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - containee := operands[0] switch c := operands[1].Value.(type) { case ast.Set: - return iter(ast.InternedTerm(c.Contains(containee))) + return iter(ast.InternedTerm(c.Contains(operands[0]))) case *ast.Array: - for i := range c.Len() { - if c.Elem(i).Value.Compare(containee.Value) == 0 { - return iter(ast.InternedTerm(true)) - } - } - return iter(ast.InternedTerm(false)) + return iter(ast.InternedTerm(c.Until(operands[0].Equal))) case ast.Object: return iter(ast.InternedTerm(c.Until(func(_, v *ast.Term) bool { - return v.Value.Compare(containee.Value) == 0 + return operands[0].Equal(v) }))) } return iter(ast.InternedTerm(false)) } func builtinMemberWithKey(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - key, val := operands[0], operands[1] - switch c := operands[2].Value.(type) { - case interface{ Get(*ast.Term) *ast.Term }: - ret := false - if act := c.Get(key); act != nil { - ret = act.Value.Compare(val.Value) == 0 - } - return iter(ast.InternedTerm(ret)) + type getter interface { + Get(*ast.Term) *ast.Term + } + col, key, val := operands[2], operands[0], operands[1] + switch c := col.Value.(type) { + case ast.Set: + return iter(ast.InternedTerm(c.Contains(key) && key.Equal(val))) + case getter: + return iter(ast.InternedTerm(val.Equal(c.Get(key)))) } return iter(ast.InternedTerm(false)) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/arithmetic.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/arithmetic.go index 91190330fa..ce870904f5 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/arithmetic.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/arithmetic.go @@ -53,6 +53,22 @@ func arithFloor(a *big.Float) (*big.Float, error) { return new(big.Float).Sub(f, big.NewFloat(1.0)), nil } +// exactIntArith applies op to n1 and n2 as exact big.Ints when both are integers. +// +// The big.Float path used otherwise carries the default mantissa, so integers needing more +// significant bits than that are silently rounded before the operation is applied. +func exactIntArith(n1, n2 ast.Number, op func(z, x, y *big.Int) *big.Int) (ast.Number, bool) { + x, err := builtins.NumberToInt(n1) + if err != nil { + return "", false + } + y, err := builtins.NumberToInt(n2) + if err != nil { + return "", false + } + return builtins.IntToNumber(op(new(big.Int), x, y)), true +} + func builtinPlus(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { n1, err := builtins.NumberOperand(operands[0].Value, 1) if err != nil { @@ -70,6 +86,10 @@ func builtinPlus(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) er return iter(ast.InternedTerm(x + y)) } + if n, ok := exactIntArith(n1, n2, (*big.Int).Add); ok { + return iter(ast.NewTerm(n)) + } + f := new(big.Float).Add(builtins.NumberToFloat(n1), builtins.NumberToFloat(n2)) return iter(ast.NewTerm(builtins.FloatToNumber(f))) @@ -92,6 +112,10 @@ func builtinMultiply(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term return iter(ast.InternedTerm(x * y)) } + if n, ok := exactIntArith(n1, n2, (*big.Int).Mul); ok { + return iter(ast.NewTerm(n)) + } + f := new(big.Float).Mul(builtins.NumberToFloat(n1), builtins.NumberToFloat(n2)) return iter(ast.NewTerm(builtins.FloatToNumber(f))) @@ -158,6 +182,10 @@ func builtinMinus(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) e return iter(ast.InternedTerm(x - y)) } + if n, ok := exactIntArith(n1, n2, (*big.Int).Sub); ok { + return iter(ast.NewTerm(n)) + } + f := new(big.Float).Sub(builtins.NumberToFloat(n1), builtins.NumberToFloat(n2)) return iter(ast.NewTerm(builtins.FloatToNumber(f))) diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/builtins/builtins.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/builtins/builtins.go index 0f02021f24..8726284279 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/builtins/builtins.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/builtins/builtins.go @@ -269,12 +269,19 @@ func FloatToNumber(f *big.Float) ast.Number { // NumberToInt converts n to a big int. // If n cannot be converted to an big int, an error is returned. func NumberToInt(n ast.Number) (*big.Int, error) { - f := NumberToFloat(n) - r, accuracy := f.Int(nil) - if accuracy != big.Exact { + // Integer literals are parsed exactly. Going through NumberToFloat first would round any + // value needing more than the big.Float default mantissa, and because the rounded value is + // itself an integer, the accuracy check below cannot detect that it happened. + if i, ok := new(big.Int).SetString(string(n), 10); ok { + return i, nil + } + // Fractional and exponent forms. big.Rat parses both exactly, so a value such as 1e30 stays + // exact, and a genuinely fractional value is rejected rather than silently truncated. + r, ok := new(big.Rat).SetString(string(n)) + if !ok || !r.IsInt() { return nil, errors.New("illegal value") } - return r, nil + return new(big.Int).Set(r.Num()), nil } // IntToNumber converts i to a number. diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/cache.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/cache.go index a6c89b4537..9a162e2a57 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/cache.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/cache.go @@ -41,7 +41,7 @@ type BaseCache interface { } type virtualCache struct { - stack []*virtualCacheElem + stack util.SliceStack[*virtualCacheElem] } type virtualCacheElem struct { @@ -57,11 +57,11 @@ func NewVirtualCache() VirtualCache { } func (c *virtualCache) Push() { - c.stack = append(c.stack, newVirtualCacheElem()) + c.stack.Push(newVirtualCacheElem()) } func (c *virtualCache) Pop() { - c.stack = c.stack[:len(c.stack)-1] + c.stack.Pop() } // Returns the resolved value of the AST term and a flag indicating if the value @@ -72,7 +72,7 @@ func (c *virtualCache) Pop() { // nil, false indicates the ref has not been cached // ast.Term, true is impossible func (c *virtualCache) Get(ref ast.Ref) (*ast.Term, bool) { - node := c.stack[len(c.stack)-1] + node := c.stack.Peek() for i := range ref { x, ok := node.children.Get(ref[i]) if !ok { @@ -90,7 +90,7 @@ func (c *virtualCache) Get(ref ast.Ref) (*ast.Term, bool) { // If value is a nil pointer, set the 'undefined' flag on the cache element to // indicate that the Ref has resolved to undefined. func (c *virtualCache) Put(ref ast.Ref, value *ast.Term) { - node := c.stack[len(c.stack)-1] + node := c.stack.Peek() for i := range ref { x, ok := node.children.Get(ref[i]) if ok { @@ -109,7 +109,7 @@ func (c *virtualCache) Put(ref ast.Ref, value *ast.Term) { } func (c *virtualCache) Keys() []ast.Ref { - node := c.stack[len(c.stack)-1] + node := c.stack.Peek() return keysRecursive(nil, node) } @@ -133,7 +133,7 @@ func newVirtualCacheElem() *virtualCacheElem { } func newVirtualCacheHashMap() *util.HasherMap[*ast.Term, *virtualCacheElem] { - return util.NewHasherMap[*ast.Term, *virtualCacheElem](ast.TermValueEqual) + return util.NewHasherMap[*ast.Term, *virtualCacheElem]((*ast.Term).Equal) } // baseCache implements a trie structure to cache base documents read out of @@ -204,7 +204,7 @@ func (e *baseCacheElem) set(value ast.Value) { } type refStack struct { - sl []refStackElem + sl util.SliceStack[refStackElem] } type refStackElem struct { @@ -216,20 +216,21 @@ func newRefStack() *refStack { } func (s *refStack) Push(refs []ast.Ref) { - s.sl = append(s.sl, refStackElem{refs: refs}) + s.sl.Push(refStackElem{refs: refs}) } func (s *refStack) Pop() { if s == nil { return } - s.sl = s.sl[:len(s.sl)-1] + s.sl.Pop() } func (s *refStack) Prefixed(ref ast.Ref) bool { if s != nil { - for i := len(s.sl) - 1; i >= 0; i-- { - if slices.ContainsFunc(s.sl[i].refs, ref.HasPrefix) { + sl := s.sl.Slice() + for i := len(sl) - 1; i >= 0; i-- { + if slices.ContainsFunc(sl[i].refs, ref.HasPrefix) { return true } } @@ -238,7 +239,7 @@ func (s *refStack) Prefixed(ref ast.Ref) bool { } type comprehensionCache struct { - stack []map[*ast.Term]*comprehensionCacheElem + stack util.SliceStack[map[*ast.Term]*comprehensionCacheElem] } type comprehensionCacheElem struct { @@ -253,20 +254,20 @@ func newComprehensionCache() *comprehensionCache { } func (c *comprehensionCache) Push() { - c.stack = append(c.stack, map[*ast.Term]*comprehensionCacheElem{}) + c.stack.Push(map[*ast.Term]*comprehensionCacheElem{}) } func (c *comprehensionCache) Pop() { - c.stack = c.stack[:len(c.stack)-1] + c.stack.Pop() } func (c *comprehensionCache) Elem(t *ast.Term) (*comprehensionCacheElem, bool) { - elem, ok := c.stack[len(c.stack)-1][t] + elem, ok := c.stack.Peek()[t] return elem, ok } func (c *comprehensionCache) Set(t *ast.Term, elem *comprehensionCacheElem) { - c.stack[len(c.stack)-1][t] = elem + c.stack.Peek()[t] = elem } func newComprehensionCacheElem() *comprehensionCacheElem { @@ -301,15 +302,13 @@ func (c *comprehensionCacheElem) Put(key []*ast.Term, value *ast.Term) { } func newComprehensionCacheHashMap() *util.HasherMap[*ast.Term, *comprehensionCacheElem] { - return util.NewHasherMap[*ast.Term, *comprehensionCacheElem](ast.TermValueEqual) + return util.NewHasherMap[*ast.Term, *comprehensionCacheElem]((*ast.Term).Equal) } type functionMocksStack struct { - stack []*functionMocksElem + stack util.GroupStack[frame] } -type functionMocksElem []frame - type frame map[string]*ast.Term func newFunctionMocksStack() *functionMocksStack { @@ -318,21 +317,16 @@ func newFunctionMocksStack() *functionMocksStack { return stack } -func newFunctionMocksElem() *functionMocksElem { - return &functionMocksElem{} -} - func (s *functionMocksStack) Push() { - s.stack = append(s.stack, newFunctionMocksElem()) + s.stack.PushGroup(nil) } func (s *functionMocksStack) Pop() { - s.stack = s.stack[:len(s.stack)-1] + s.stack.PopGroup() } func (s *functionMocksStack) PopPairs() { - current := s.stack[len(s.stack)-1] - *current = (*current)[:len(*current)-1] + s.stack.Pop() } func (s *functionMocksStack) PutPairs(mocks [][2]*ast.Term) { @@ -344,8 +338,7 @@ func (s *functionMocksStack) PutPairs(mocks [][2]*ast.Term) { } func (s *functionMocksStack) Put(el frame) { - current := s.stack[len(s.stack)-1] - *current = append(*current, el) + s.stack.Push(el) } func (s *functionMocksStack) Get(f ast.Ref) (*ast.Term, bool) { @@ -353,7 +346,7 @@ func (s *functionMocksStack) Get(f ast.Ref) (*ast.Term, bool) { return nil, false } - current := *s.stack[len(s.stack)-1] + current := s.stack.PeekGroup() for i := len(current) - 1; i >= 0; i-- { if r, ok := current[i][f.String()]; ok { return r, true diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go index ae30723dfb..799a716136 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go @@ -34,6 +34,9 @@ type CopyPropagator struct { ensureNonEmptyBody bool compiler *ast.Compiler localvargen *localVarGenerator + // placeholders holds vars synthesized to keep a ref alive for its definedness. + // They appear nowhere else, so their bindings can be emitted as the bare ref. + placeholders ast.VarSet } type localVarGenerator struct { @@ -47,10 +50,17 @@ func (l *localVarGenerator) Generate() ast.Var { } +// generatePlaceholder returns a fresh local variable, recorded as a placeholder. +func (p *CopyPropagator) generatePlaceholder() ast.Var { + v := p.localvargen.Generate() + p.placeholders.Add(v) + return v +} + // New returns a new CopyPropagator that optimizes queries while preserving vars // in the livevars set. func New(livevars ast.VarSet) *CopyPropagator { - return &CopyPropagator{livevars: livevars, sorted: util.KeysSorted(livevars), localvargen: &localVarGenerator{}} + return &CopyPropagator{livevars: livevars, sorted: util.KeysSorted(livevars), localvargen: &localVarGenerator{}, placeholders: ast.NewVarSet()} } // WithEnsureNonEmptyBody configures p to ensure that results are always non-empty. @@ -188,7 +198,14 @@ func (p *CopyPropagator) Apply(query ast.Body) ast.Body { } if providesSafety || (!safevarRef && !containedIn(b.v, result)) { - result.Append(removedEq) + // For a placeholder key, emit the bare ref rather than `__localcp0__ = + // input.project`: both only require the ref to be defined, but the + // equality leaks the internal var into results (#6378). + if expr := p.placeholderRef(b); expr != nil { + result.Append(expr) + } else { + result.Append(removedEq) + } safe.Update(outputVars) } } @@ -244,11 +261,10 @@ func (t bindingPlugTransform) Transform(x any) (any, error) { } func (bindingPlugTransform) plugBindingsVar(pctx *plugContext, v ast.Var) ast.Value { - var result ast.Value = v // Apply union-find to remove redundant variables from input. - root, ok := pctx.uf.Find(v) + root, ok := pctx.uf.Find(result) if ok { result = root.Value() } @@ -258,7 +274,7 @@ func (bindingPlugTransform) plugBindingsVar(pctx *plugContext, v ast.Var) ast.Va if !ok { return result } - b := pctx.removedEqs.Get(v) + b := pctx.removedEqs.Get(result) if b == nil { return result } @@ -266,7 +282,7 @@ func (bindingPlugTransform) plugBindingsVar(pctx *plugContext, v ast.Var) ast.Va return result } - if r, ok := b.(ast.Ref); ok && r.OutputVars().Contains(v) { + if ast.NewTerm(b).Vars().Contains(v) { return result } @@ -311,7 +327,7 @@ func (p *CopyPropagator) updateBindings(pctx *plugContext, expr *ast.Expr) bool a, b := expr.Operand(0), expr.Operand(1) if a.Equal(b) { if p.livevarRef(a) { - pctx.removedEqs.Put(p.localvargen.Generate(), a.Value) + pctx.removedEqs.Put(p.generatePlaceholder(), a.Value) } return false } @@ -351,6 +367,20 @@ func (p *CopyPropagator) livevarRef(a *ast.Term) bool { return false } +// placeholderRef returns the ref a placeholder binding maps to, wrapped as a +// bare expression, or nil if b is not a placeholder-to-ref binding. +func (p *CopyPropagator) placeholderRef(b *binding) *ast.Expr { + k, ok := b.k.(ast.Var) + if !ok || !p.placeholders.Contains(k) { + return nil + } + ref, ok := b.v.(ast.Ref) + if !ok { + return nil + } + return ast.NewExpr(ast.NewTerm(ref)) +} + func (p *CopyPropagator) updateBindingsEq(a, b *ast.Term) (ast.Var, ast.Value, bool) { k, v, keep := p.updateBindingsEqAsymmetric(a, b) if !keep { @@ -498,18 +528,20 @@ func makeDisjointSets(livevars ast.VarSet, query ast.Body) (*unionFind, bool) { func isNoop(expr *ast.Expr) bool { - if !expr.IsCall() && !expr.IsEvery() { - term := expr.Terms.(*ast.Term) - if !ast.IsConstant(term.Value) { + switch t := expr.Terms.(type) { + case []*ast.Term: + // A==A can be ignored + if expr.Operator().Equal(ast.Equal.Ref()) { + return expr.Operand(0).Equal(expr.Operand(1)) + } + return false + case *ast.Term: + if !ast.IsConstant(t.Value) { return false } - return !ast.Boolean(false).Equal(term.Value) + return !ast.Boolean(false).Equal(t.Value) + default: + // *ast.Every, *ast.Not, *ast.LogicalAnd, *ast.LogicalOr — none are no-ops. + return false } - - // A==A can be ignored - if expr.Operator().Equal(ast.Equal.Ref()) { - return expr.Operand(0).Equal(expr.Operand(1)) - } - - return false } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/errors_jsonv2.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/errors_jsonv2.go new file mode 100644 index 0000000000..29b6f3761e --- /dev/null +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/errors_jsonv2.go @@ -0,0 +1,24 @@ +//go:build go1.27 + +package topdown + +import ( + "encoding/json/jsontext" + "errors" + + "github.com/open-policy-agent/opa/internal/jsonv2" +) + +func (e *Error) MarshalJSONTo(enc *jsontext.Encoder) (err error) { + enc.WriteToken(jsontext.BeginObject) + enc.WriteToken(jsontext.String("code")) + enc.WriteToken(jsontext.String(e.Code)) + enc.WriteToken(jsontext.String("message")) + enc.WriteToken(jsontext.String(e.Message)) + + if e.Location != nil { + err = jsonv2.WriteField(enc, "location", e.Location) + } + + return errors.Join(err, enc.WriteToken(jsontext.EndObject)) +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go index b6700549de..f22af29267 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go @@ -8,7 +8,6 @@ import ( "slices" "strconv" "strings" - "sync" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/metrics" @@ -130,52 +129,13 @@ type eval struct { responseMetadata map[string]any } -type ( - evfp struct{ pool sync.Pool } - evbp struct{ pool sync.Pool } -) - -func (ep *evfp) Put(e *evalFunc) { - if e != nil { - e.e, e.terms, e.ir = nil, nil, nil - ep.pool.Put(e) - } -} - -func (ep *evfp) Get() *evalFunc { - return ep.pool.Get().(*evalFunc) -} - -func (ep *evbp) Put(e *evalBuiltin) { - if e != nil { - e.e, e.bi, e.bctx, e.f, e.terms = nil, nil, nil, nil, nil - ep.pool.Put(e) - } -} - -func (ep *evbp) Get() *evalBuiltin { - return ep.pool.Get().(*evalBuiltin) -} - var ( - evalPool = util.NewSyncPool[eval]() - deecPool = util.NewSyncPool[deferredEarlyExitContainer]() - resolverPool = util.NewSyncPool[evalResolver]() - arraysRecPool = util.NewSyncPool[biunifyArraysRecParams]() - evalFuncPool = &evfp{ - pool: sync.Pool{ - New: func() any { - return &evalFunc{} - }, - }, - } - evalBuiltinPool = &evbp{ - pool: sync.Pool{ - New: func() any { - return &evalBuiltin{} - }, - }, - } + evalPool = util.NewSyncPool[eval]() + deecPool = util.NewSyncPool[deferredEarlyExitContainer]() + resolverPool = util.NewSyncPool[evalResolver]() + arraysRecPool = util.NewSyncPool[biunifyArraysRecParams]() + evalFuncPool = util.NewResettablePool[evalFunc, *evalFunc]() + evalBuiltinPool = util.NewResettablePool[evalBuiltin, *evalBuiltin]() ) func (e *eval) Run(iter evalIterator) error { @@ -545,6 +505,30 @@ func (e *eval) evalStep(iter evalIterator) error { return err }) + case *ast.LogicalAnd: + ea := evalLogicalAnd{ + e: e, + and: terms, + } + err = ea.eval(func(e *eval) error { + defined = true + err := iter(e) + e.traceRedo(expr) + return err + }) + + case *ast.LogicalOr: + eo := evalLogicalOr{ + e: e, + or: terms, + } + err = eo.eval(func(e *eval) error { + defined = true + err := iter(e) + e.traceRedo(expr) + return err + }) + default: // guard-rail for adding extra (Expr).Terms types return fmt.Errorf("got %T terms: %[1]v", terms) } @@ -604,6 +588,24 @@ func (e *eval) evalStep(iter evalIterator) error { return iter(e) }) + case *ast.LogicalAnd: + ea := evalLogicalAnd{ + e: e, + and: terms, + } + err = ea.eval(func(e *eval) error { + return iter(e) + }) + + case *ast.LogicalOr: + eo := evalLogicalOr{ + e: e, + or: terms, + } + err = eo.eval(func(e *eval) error { + return iter(e) + }) + default: // guard-rail for adding extra (Expr).Terms types return fmt.Errorf("got %T terms: %[1]v", terms) } @@ -2063,6 +2065,12 @@ type evalBuiltin struct { terms []*ast.Term } +// Reset clears the fields before this evalBuiltin is returned to its pool, +// so pooling it doesn't keep terms/bindings from the previous call alive. +func (e *evalBuiltin) Reset() { + e.e, e.bi, e.bctx, e.f, e.terms = nil, nil, nil, nil, nil +} + // Is this builtin non-deterministic, and did the caller provide an NDBCache? func (e *evalBuiltin) canUseNDBCache(bi *ast.Builtin) bool { return bi.Nondeterministic && e.bctx != nil && e.bctx.NDBuiltinCache != nil @@ -2178,6 +2186,12 @@ type evalFunc struct { terms []*ast.Term } +// Reset clears the fields before this evalFunc is returned to its pool, +// so pooling it doesn't keep terms/index results from the previous call alive. +func (e *evalFunc) Reset() { + e.e, e.terms, e.ir = nil, nil, nil +} + func (e *evalFunc) eval(iter unifyIterator) error { if e.ir.Empty() { return nil @@ -2587,30 +2601,104 @@ func (e evalTree) next(iter unifyIterator, plugged *ast.Term) error { externalRef := node.External.Ref externalIndex := node.External.Index - // Initialize externalTreeStack if needed - if e.e.externalTreeStack == nil { - e.e.externalTreeStack = newExternalTreeStack(e.e) + // For a parametrized (prefix) external source, the leading + // elements of the reference after the prefix are lookup + // parameters rather than tree descents. The source reports how + // many via ParamArity, keyed off the reference tail's shape (so + // one prefix can back an uneven-depth tree). They must be ground; + // the resolved sub-tree is cached under the full reference + // (prefix + params) so distinct parameters do not collide within + // a single evaluation. + arity := 0 + if p, ok := externalIndex.(ast.ParametrizedExternalRuleIndex); ok { + arity = p.ParamArity(e.ref[e.pos+1:]) + } + var params []ast.Value + cacheRef := externalRef + expand := true + + if arity > 0 { + params = make([]ast.Value, 0, arity) + cacheRef = make(ast.Ref, len(externalRef), len(externalRef)+arity) + copy(cacheRef, externalRef) + for i := 1; i <= arity; i++ { + idx := e.pos + i + if idx >= len(e.ref) { + expand = false + break + } + k := e.bindings.Plug(e.ref[idx]) + if !k.IsGround() { + expand = false + break + } + params = append(params, k.Value) + cacheRef = append(cacheRef, k) + } + + if !expand { + // The parameter key(s) are not ground, so we cannot + // select a concrete sub-source. Under partial evaluation + // the reference is unknown and must be residualized; + // otherwise it is simply undefined and we fall through + // with the bare (rule-less) external node. + if e.e.partial() { + saved := make(ast.Ref, len(e.ref)) + for i := range e.ref { + saved[i] = e.bindings.Plug(e.ref[i]) + } + return e.e.saveUnify(ast.NewTerm(saved), e.rterm, e.bindings, e.rbindings, iter) + } + } } - // Check cache first - cachedNode, _, found := e.e.externalTreeStack.findCached(externalRef) - if found { - node = cachedNode - } else { - // Call Tree() and cache the result - e.e.instr.startTimer(evalOpExternalRuleSource) - tree, updatedIndex, err := node.External.Tree(e.e.ctx, e.e.compiler.RuleTree, externalRef, e.e.input, e.e.metrics, e.e.requestMetadata, e.e.responseMetadata) - e.e.instr.stopTimer(evalOpExternalRuleSource) - if err != nil { - return err + if expand { + // Initialize externalTreeStack if needed + if e.e.externalTreeStack == nil { + e.e.externalTreeStack = newExternalTreeStack(e.e) } - if tree != nil { - if updatedIndex != nil { - externalIndex = updatedIndex + + // Check cache first + cachedNode, _, found := e.e.externalTreeStack.findCached(cacheRef) + var tree *ast.TreeNode + if found { + tree = cachedNode + } else { + // Call Tree() and cache the result. + e.e.instr.startTimer(evalOpExternalRuleSource) + // Pass the eval itself as the resolver: it is save-set + // aware, so external sources that opt into + // ExternalSourceOptions.DistinguishAbsentFromUnknown can + // tell references that are unknown under partial evaluation + // apart from references that are simply absent from the + // concrete input. The parameter terms (params) select the + // concrete sub-source for a parametrized prefix. + t, updatedIndex, err := node.External.Tree(e.e.ctx, e.e.compiler.RuleTree, externalRef, params, e.e, e.e.metrics, e.e.requestMetadata, e.e.responseMetadata) + e.e.instr.stopTimer(evalOpExternalRuleSource) + if err != nil { + return err + } + if t != nil { + if updatedIndex != nil { + externalIndex = updatedIndex + } + e.e.externalTreeStack.Push(cacheRef, t, externalIndex, e.e.input) + pushedExternalTree = true + } + tree = t + } + + if tree != nil { + if arity > 0 { + // The resolved sub-tree is rooted at the prefix, but + // the walk still has to consume the parameter + // element(s). Re-insert them as ordinary tree levels + // so the descent below (and any further descent into + // rules) proceeds unchanged. + node = wrapExternalParams(cacheRef[len(externalRef):], tree) + } else { + node = tree } - e.e.externalTreeStack.Push(externalRef, tree, externalIndex, e.e.input) - node = tree - pushedExternalTree = true } } } @@ -3295,7 +3383,7 @@ func (e evalVirtualPartial) partialEvalSupportRule(rule *ast.Rule, _ ast.Ref) (b head.Key = ruleRef[len(ruleRef)-1] } - if head.Name.Equal(ast.Var("")) && (len(ruleRef) == 1 || (len(ruleRef) == 2 && rule.Head.RuleKind() == ast.SingleValue)) { + if head.Name == "" && (len(ruleRef) == 1 || (len(ruleRef) == 2 && rule.Head.RuleKind() == ast.SingleValue)) { head.Name = ruleRef[0].Value.(ast.Var) } @@ -4214,7 +4302,7 @@ func (e *evalEvery) save(iter unifyIterator) error { func (e *evalEvery) plug(expr *ast.Expr) (*ast.Expr, error) { cpy := expr.Copy() every := cpy.Terms.(*ast.Every) - if err := e.plugBody(every.Body); err != nil { + if err := plugBody(e.e, every.Body); err != nil { return nil, err } @@ -4225,45 +4313,6 @@ func (e *evalEvery) plug(expr *ast.Expr) (*ast.Expr, error) { return cpy, nil } -func (e *evalEvery) plugBody(body ast.Body) error { - for i := range body { - switch t := body[i].Terms.(type) { - case *ast.Term: - plugged, err := e.plugTerm(t) - if err != nil { - return err - } - body[i].Terms = plugged - case []*ast.Term: - for j := 1; j < len(t); j++ { // don't plug operator, t[0] - plugged, err := e.plugTerm(t[j]) - if err != nil { - return err - } - t[j] = plugged - } - case *ast.Every: - plugged, err := e.plug(body[i]) - if err != nil { - return err - } - body[i] = plugged - case *ast.Not: - if err := e.plugBody(t.Body); err != nil { - return err - } - } - } - return nil -} - -func (e *evalEvery) plugTerm(t *ast.Term) (*ast.Term, error) { - if ast.IsComprehension(t.Value) { - return e.e.amendComprehension(t, e.e.bindings) - } - return e.e.bindings.PlugNamespaced(t, e.e.caller.bindings), nil -} - type evalNot struct { e *eval not *ast.Not @@ -4364,6 +4413,212 @@ func (e evalNot) evalPartial(iter evalIterator) error { return e.e.evalNotPartial(expr, unNegate, ast.Complement, supportTerms, iter) } +type evalLogicalAnd struct { + e *eval + and *ast.LogicalAnd +} + +func (e evalLogicalAnd) eval(iter evalIterator) error { + if e.e.partial() && (e.e.unknown(e.and.Lhs, e.e.bindings) || e.e.unknown(e.and.Rhs, e.e.bindings)) { + return e.evalPartial(iter) + } + + lhsDefined, err := evalLogicalOperand(e.e, e.and.Lhs) + if err != nil { + return err + } + if !lhsDefined { + // short-circuit: RHS is not evaluated if LHS is undefined + return nil + } + + rhsDefined, err := evalLogicalOperand(e.e, e.and.Rhs) + if err != nil { + return err + } + if !rhsDefined { + return nil + } + + return iter(e.e) +} + +func (e evalLogicalAnd) evalPartial(iter evalIterator) error { + // Plug and save the expression to produce a valid, but non-optimized PE result + expr := e.e.query[e.e.index] + + plugged, err := e.plug(expr) + if err != nil { + return err + } + + return e.e.saveExpr(plugged, e.e.bindings, func() error { + return iter(e.e) + }) +} + +func (e evalLogicalAnd) plug(expr *ast.Expr) (*ast.Expr, error) { + cpy := expr.Copy() + and := cpy.Terms.(*ast.LogicalAnd) + + if err := plugBody(e.e, and.Lhs); err != nil { + return nil, err + } + if err := plugBody(e.e, and.Rhs); err != nil { + return nil, err + } + + cpy.Terms = and + return cpy, nil +} + +type evalLogicalOr struct { + e *eval + or *ast.LogicalOr +} + +func (e evalLogicalOr) eval(iter evalIterator) error { + if e.e.partial() && (e.e.unknown(e.or.Lhs, e.e.bindings) || e.e.unknown(e.or.Rhs, e.e.bindings)) { + return e.evalPartial(iter) + } + + lhsDefined, err := evalLogicalOperand(e.e, e.or.Lhs) + if err != nil { + return err + } + if lhsDefined { + // short-circuit: RHS is not evaluated if LHS is defined + return iter(e.e) + } + + rhsDefined, err := evalLogicalOperand(e.e, e.or.Rhs) + if err != nil { + return err + } + if !rhsDefined { + return nil + } + + return iter(e.e) +} + +func (e evalLogicalOr) evalPartial(iter evalIterator) error { + // Plug and save the expression to produce a valid, but non-optimized PE result + expr := e.e.query[e.e.index] + + plugged, err := e.plug(expr) + if err != nil { + return err + } + + return e.e.saveExpr(plugged, e.e.bindings, func() error { + return iter(e.e) + }) +} + +func (e evalLogicalOr) plug(expr *ast.Expr) (*ast.Expr, error) { + cpy := expr.Copy() + or := cpy.Terms.(*ast.LogicalOr) + + if err := plugBody(e.e, or.Lhs); err != nil { + return nil, err + } + if err := plugBody(e.e, or.Rhs); err != nil { + return nil, err + } + + cpy.Terms = or + return cpy, nil +} + +// evalLogicalOperand runs body as a closed scope that contributes at most one +// success. Returns whether the body succeeded; bindings introduced inside body +// do not propagate to the caller. +func evalLogicalOperand(parent *eval, body ast.Body) (bool, error) { + child := evalPool.Get() + defer evalPool.Put(child) + + parent.closure(body, child) + child.findOne = true + + if parent.traceEnabled { + child.traceEnter(body) + } + + defined := false + err := child.eval(func(*eval) error { + if parent.traceEnabled { + child.traceExit(body) + child.traceRedo(body) + } + defined = true + return nil + }) + + // findOne raises an earlyExitError once the iter callback fires; that's + // our signal to stop, not an error to propagate to the caller. + if err := suppressEarlyExit(err); err != nil { + return false, err + } + + return defined, nil +} + +func plugBody(e *eval, body ast.Body) error { + for i := range body { + switch t := body[i].Terms.(type) { + case *ast.Term: + plugged, err := plugTerm(e, t) + if err != nil { + return err + } + body[i].Terms = plugged + case []*ast.Term: + for j := 1; j < len(t); j++ { // don't plug operator, t[0] + plugged, err := plugTerm(e, t[j]) + if err != nil { + return err + } + t[j] = plugged + } + case *ast.Every: + ev := evalEvery{e: e, every: t, expr: body[i]} + plugged, err := ev.plug(body[i]) + if err != nil { + return err + } + body[i] = plugged + case *ast.Not: + if err := plugBody(e, t.Body); err != nil { + return err + } + case *ast.LogicalAnd: + if err := plugBody(e, t.Lhs); err != nil { + return err + } + if err := plugBody(e, t.Rhs); err != nil { + return err + } + case *ast.LogicalOr: + if err := plugBody(e, t.Lhs); err != nil { + return err + } + if err := plugBody(e, t.Rhs); err != nil { + return err + } + } + } + + return nil +} + +func plugTerm(e *eval, t *ast.Term) (*ast.Term, error) { + if ast.IsComprehension(t.Value) { + return e.amendComprehension(t, e.bindings) + } + return e.bindings.PlugNamespaced(t, e.caller.bindings), nil +} + func (e *eval) comprehensionIndex(term *ast.Term) *ast.ComprehensionIndex { if e.queryCompiler != nil { return e.queryCompiler.ComprehensionIndex(term) @@ -4518,17 +4773,29 @@ func containsNestedRefOrCall(vis *nestedCheckVisitor, expr *ast.Expr) bool { } if n, ok := expr.Terms.(*ast.Not); ok { - for _, nExpr := range n.Body { - if containsNestedRefOrCall(vis, nExpr) { - return true - } - } - return false + return containsNestedRefOrCallInBody(vis, n.Body) + } + + if a, ok := expr.Terms.(*ast.LogicalAnd); ok { + return containsNestedRefOrCallInBody(vis, a.Lhs) || containsNestedRefOrCallInBody(vis, a.Rhs) + } + + if o, ok := expr.Terms.(*ast.LogicalOr); ok { + return containsNestedRefOrCallInBody(vis, o.Lhs) || containsNestedRefOrCallInBody(vis, o.Rhs) } return containsNestedRefOrCallInTerm(vis, expr.Terms.(*ast.Term)) } +func containsNestedRefOrCallInBody(vis *nestedCheckVisitor, body ast.Body) bool { + for _, expr := range body { + if containsNestedRefOrCall(vis, expr) { + return true + } + } + return false +} + func containsNestedRefOrCallInTerm(vis *nestedCheckVisitor, term *ast.Term) bool { switch v := term.Value.(type) { case ast.Ref: @@ -4690,6 +4957,21 @@ func (e *eval) updateSavedMocks(withs []*ast.With) []*ast.With { return ret } +// wrapExternalParams re-inserts the parameter levels consumed by a +// parametrized external source (see ast.ParametrizedExternalRuleIndex) on +// top of the resolved sub-tree, which is rooted at the registered prefix. The +// evaluator's descent can then consume the parameter element(s) as ordinary +// tree levels. keys are the ground parameter terms in reference order. +func wrapExternalParams(keys []*ast.Term, tree *ast.TreeNode) *ast.TreeNode { + node := tree + for i := len(keys) - 1; i >= 0; i-- { + node = &ast.TreeNode{ + Children: map[ast.Value]*ast.TreeNode{keys[i].Value: node}, + } + } + return node +} + // simpleTreeNode provides minimal tree structure for navigation type simpleTreeNode struct { tree *ast.TreeNode diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go index 85b3ed9e93..971d62b33b 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/query.go @@ -479,7 +479,7 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support [] // Build output from saved expressions. body := ast.NewBody() - for _, elem := range e.saveStack.Stack[len(e.saveStack.Stack)-1] { + for _, elem := range e.saveStack.Peek() { body.Append(elem.Plug(e.bindings)) } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/save.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/save.go index 7a922b5f7b..a1c0fdd65a 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/save.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/save.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/open-policy-agent/opa/v1/ast" + "github.com/open-policy-agent/opa/v1/util" ) // saveSet contains a stack of terms that are considered 'unknown' during @@ -183,40 +184,33 @@ func (sse *saveSetElem) containsVar(t *ast.Term, b *bindings) bool { // partially evaluated. In this case, the partially evaluated rule will be // output in the support module. type saveStack struct { - Stack []saveStackQuery + Stack util.GroupStack[saveStackElem] } func newSaveStack() *saveStack { - return &saveStack{ - Stack: []saveStackQuery{ - {}, - }, - } + s := &saveStack{} + s.Stack.PushGroup(nil) + return s } func (s *saveStack) PushQuery(query saveStackQuery) { - s.Stack = append(s.Stack, query) + s.Stack.PushGroup(query) } func (s *saveStack) PopQuery() saveStackQuery { - last := s.Stack[len(s.Stack)-1] - s.Stack = s.Stack[:len(s.Stack)-1] - return last + return s.Stack.PopGroup() } func (s *saveStack) Peek() saveStackQuery { - return s.Stack[len(s.Stack)-1] + return s.Stack.PeekGroup() } func (s *saveStack) Push(expr *ast.Expr, b1 *bindings, b2 *bindings) { - idx := len(s.Stack) - 1 - s.Stack[idx] = append(s.Stack[idx], saveStackElem{expr, b1, b2}) + s.Stack.Push(saveStackElem{expr, b1, b2}) } func (s *saveStack) Pop() { - idx := len(s.Stack) - 1 - query := s.Stack[idx] - s.Stack[idx] = query[:len(query)-1] + s.Stack.Pop() } type saveStackQuery []saveStackElem @@ -298,7 +292,7 @@ func (s *saveSupport) Exists(path ast.Ref) bool { if len(ruleRef) == 1 { name := ruleRef[0].Value.(ast.Var) for _, rule := range module.Rules { - if rule.Head.Name.Equal(name) { + if rule.Head.Name == name { return true } } @@ -586,7 +580,7 @@ func (i *inliningControl) DisabledVar(v ast.Var, ignoreInternal bool) bool { } for _, frame := range i.disable { - if (!frame.internal || !ignoreInternal) && frame.v.Equal(v) { + if (!frame.internal || !ignoreInternal) && frame.v == v { return true } } diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go index b0b5684a8c..4ffd307c78 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go @@ -129,11 +129,14 @@ func builtinFormatInt(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Ter } var format string + var radix int switch base { case ast.Number("2"): format = "%b" + radix = 2 case ast.Number("8"): format = "%o" + radix = 8 case ast.Number("10"): // Fast path: for numbers whose decimal string is already interned (e.g. // "0"–"100"), we can skip strconv.ParseInt entirely. @@ -144,12 +147,23 @@ func builtinFormatInt(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Ter return iter(ast.InternedIntegerString(i)) } format = "%d" + radix = 10 case ast.Number("16"): format = "%x" + radix = 16 default: return builtins.NewOperandEnumErr(2, "2", "8", "10", "16") } + // For integer inputs, format the exact big.Int. Routing integers through a + // float (as the fractional path below does) loses precision for values that + // need more than a float64's 53-bit mantissa, e.g. 18446744073709551617. + if i, ok := new(big.Int).SetString(string(input), 10); ok { + return iter(ast.InternedTerm(i.Text(radix))) + } + + // Fractional inputs (e.g. 15.9) are truncated toward zero, matching the + // historical behaviour: format_int(15.9, 16) == "f", format_int(-15.9, 16) == "-f". f := builtins.NumberToFloat(input) i, _ := f.Int(nil) @@ -543,6 +557,55 @@ func builtinSplit(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) e return iter(ast.ArrayTerm(util.SplitMap(text, delim, ast.InternedTerm)...)) } +func builtinSplitN(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) + if err != nil { + return err + } + + d, err := builtins.StringOperand(operands[1].Value, 2) + if err != nil { + return err + } + + n, err := builtins.IntOperand(operands[2].Value, 3) + if err != nil { + return err + } + + text, delim := string(s), string(d) + + var result []*ast.Term + if n >= 0 { + // n+1 may overflow for very large n; a negative limit means no limit. + limit := n + 1 + if limit < 0 { + limit = -1 + } + parts := strings.SplitN(text, delim, limit) + end := n + if end > len(parts) { + end = len(parts) + } + result = make([]*ast.Term, end) + for i := range result { + result[i] = ast.InternedTerm(parts[i]) + } + } else { + parts := strings.Split(text, delim) + start := len(parts) + n + if start < 0 { + start = 0 + } + result = make([]*ast.Term, len(parts)-start) + for i, p := range parts[start:] { + result[i] = ast.InternedTerm(p) + } + } + + return iter(ast.ArrayTerm(result...)) +} + func builtinReplace(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { @@ -722,15 +785,15 @@ func builtinSprintf(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) return err } - astArr, ok := operands[1].Value.(*ast.Array) - if !ok { - return builtins.NewOperandTypeErr(2, operands[1].Value, "array") + a, err := builtins.ArrayOperand(operands[1].Value, 2) + if err != nil { + return err } // Optimized path for where sprintf is used as a "to_string" function for // a single integer, i.e. sprintf("%d", [x]) where x is an integer. - if s == "%d" && astArr.Len() == 1 { - if n, ok := astArr.Elem(0).Value.(ast.Number); ok { + if s == "%d" && a.Len() == 1 { + if n, ok := a.Elem(0).Value.(ast.Number); ok { if i, ok := n.Int(); ok { if interned := ast.InternedIntegerString(i); interned != nil { return iter(interned) @@ -740,24 +803,35 @@ func builtinSprintf(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) } } - args := make([]any, astArr.Len()) + args := make([]any, a.Len()) for i := range args { - switch v := astArr.Elem(i).Value.(type) { + t := a.Elem(i) + switch v := t.Value.(type) { case ast.Number: - if n, ok := v.Int(); ok { - args[i] = n - } else if b, ok := new(big.Int).SetString(v.String(), 10); ok { - args[i] = b - } else if f, ok := v.Float64(); ok { - args[i] = f + ns := string(v) + if x, ok := util.Atoi64(ns); ok { + args[i] = x } else { - args[i] = v.String() + if strings.ContainsRune(ns, '.') { + if f, ok := v.Float64(); ok { + args[i] = f + continue + } else { + args[i] = ns + } + } else { + if b, ok := new(big.Int).SetString(ns, 10); ok { + args[i] = b + } else { + args[i] = ns + } + } } case ast.String: args[i] = string(v) default: - args[i] = astArr.Elem(i).String() + args[i] = t.Value.String() } } @@ -806,6 +880,7 @@ func init() { RegisterBuiltinFunc(ast.Upper.Name, builtinUpper) RegisterBuiltinFunc(ast.Lower.Name, builtinLower) RegisterBuiltinFunc(ast.Split.Name, builtinSplit) + RegisterBuiltinFunc(ast.SplitN.Name, builtinSplitN) RegisterBuiltinFunc(ast.Replace.Name, builtinReplace) RegisterBuiltinFunc(ast.ReplaceN.Name, builtinReplaceN) RegisterBuiltinFunc(ast.Trim.Name, builtinTrim) diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/template.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/template.go index 524c5bde0d..940fa85c34 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/template.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/template.go @@ -3,7 +3,14 @@ package topdown import ( "bytes" "strings" - "text/template" + + // A method-less copy of text/template (see internal/methodlesstemplate). Rego values + // decode to map[string]any/[]any/scalars, which have no methods, so eliding + // method calls is a no-op here; it keeps text/template's evalField + // MethodByName off the reachable graph, which otherwise disables the Go + // linker's method-level dead-code elimination binary-wide (golang/go#72895, + // #7903). + template "github.com/open-policy-agent/opa/internal/methodlesstemplate" "github.com/open-policy-agent/opa/v1/ast" "github.com/open-policy-agent/opa/v1/topdown/builtins" diff --git a/vendor/github.com/open-policy-agent/opa/v1/topdown/trace.go b/vendor/github.com/open-policy-agent/opa/v1/topdown/trace.go index 52451dc6bd..8b672da54e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/topdown/trace.go +++ b/vendor/github.com/open-policy-agent/opa/v1/topdown/trace.go @@ -598,6 +598,49 @@ type varInfo struct { col int // 0-indexed column } +// resolveLocalRef resolves a ground ref whose base is a local variable (e.g. 'tc.data') +// against the given local bindings, returning the selected value. It returns nil if the +// ref can't be resolved: the base isn't a bound local, a path element isn't ground (after +// resolving any variable keys), or the path doesn't exist in the value. +func resolveLocalRef(ref ast.Ref, locals *ast.ValueMap) ast.Value { + if len(ref) < 2 || locals == nil { + return nil + } + + base, ok := ref[0].Value.(ast.Var) + if !ok { + return nil + } + + baseVal := locals.Get(base) + if baseVal == nil { + return nil + } + + path := make(ast.Ref, 0, len(ref)-1) + for _, t := range ref[1:] { + if key, ok := t.Value.(ast.Var); ok { + // A variable key (e.g. 'y[i]') must itself be resolved from the local bindings. + keyVal := locals.Get(key) + if keyVal == nil { + return nil + } + path = append(path, ast.NewTerm(keyVal)) + continue + } + if !t.IsGround() { + return nil + } + path = append(path, t) + } + + val, err := baseVal.Find(path) + if err != nil { + return nil + } + return val +} + func (v varInfo) Value() string { if v.val != nil { return v.val.String() @@ -691,6 +734,21 @@ func PrettyEvent(w io.Writer, e *Event, opts PrettyEventOpts) error { case *ast.ArrayComprehension, *ast.SetComprehension, *ast.ObjectComprehension: // we don't report on the internals of a comprehension, as it's already evaluated, and we won't have the local vars. return true + case ast.Ref: + // For a ref that selects into a local variable (e.g. 'tc.data'), report the + // selected value rather than only the base variable's (potentially large) value. + // We keep descending (return false) so the base variable is still reported too. + if val := resolveLocalRef(v, e.Locals); val != nil { + info := varInfo{ + VarMetadata: VarMetadata{Name: ast.Var(term.Location.Text)}, + val: val, + exprLoc: term.Location, + col: term.Location.Col, + } + if existing, exists := exprVars[info.Title()]; !exists || existing.val == nil { + exprVars[info.Title()] = info + } + } case ast.Var: var info *varInfo if meta, ok := e.LocalMetadata[v]; ok { diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/compare.go b/vendor/github.com/open-policy-agent/opa/v1/util/compare.go index a930db21c5..ec12210c6e 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/compare.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/compare.go @@ -19,6 +19,22 @@ const ( objectSort ) +// Or works like [cmp.Or] but allows supplier functions to be tried rather than +// alternative values. This allows deferring computation of the alternatives to +// only when needed. +func Or[T comparable](val T, suppliers ...func() T) T { + var zero T + if val == zero { + for _, f := range suppliers { + if alt := f(); alt != zero { + return alt + } + } + } + + return val +} + // SliceLenCompare is a convenience function for comparing / sorting // slices by their length using the various slices.SortX functions. func SliceLenCompare[T any, S ~[]T](a, b S) int { diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/hashmap.go b/vendor/github.com/open-policy-agent/opa/v1/util/hashmap.go index 69a90cbb53..b90ea85169 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/hashmap.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/hashmap.go @@ -208,9 +208,11 @@ func NewHasherMap[K Hasher, V any](keq func(K, K) bool) *HasherMap[K, V] { // Get returns the value for k. func (h *HasherMap[K, V]) Get(k K) (V, bool) { - for entry := h.table[k.Hash()]; entry != nil; entry = entry.next { - if h.keq(entry.k, k) { - return entry.v, true + if h != nil { + for entry := h.table[k.Hash()]; entry != nil; entry = entry.next { + if h.keq(entry.k, k) { + return entry.v, true + } } } var zero V @@ -250,11 +252,28 @@ func (h *HasherMap[K, V]) Delete(k K) { } } +// Keys returns a slice containing all keys in the HasherMap. +func (h *HasherMap[K, V]) Keys() []K { + if h == nil { + return nil + } + keys := make([]K, 0, h.size) + for _, entry := range h.table { + for ; entry != nil; entry = entry.next { + keys = append(keys, entry.k) + } + } + return keys +} + // Iter invokes the iter function for each element in the HasherMap. // If the iter function returns true, iteration stops and the return value is true. // If the iter function never returns true, iteration proceeds through all elements // and the return value is false. func (h *HasherMap[K, V]) Iter(iter func(K, V) bool) bool { + if h == nil { + return false + } for _, entry := range h.table { for ; entry != nil; entry = entry.next { if iter(entry.k, entry.v) { @@ -265,7 +284,10 @@ func (h *HasherMap[K, V]) Iter(iter func(K, V) bool) bool { return false } -// Len returns the current size of this HashMap. +// Len returns the current size of this HashMap, or 0 if the HasherMap is nil. func (h *HasherMap[K, V]) Len() int { + if h == nil { + return 0 + } return h.size } diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/performance.go b/vendor/github.com/open-policy-agent/opa/v1/util/performance.go index 3c852638e2..f269a2e1d7 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/performance.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/performance.go @@ -36,6 +36,43 @@ func (p *SyncPool[T]) Put(x *T) { } } +// resettable is implemented by *T when used with [ResettablePool], allowing +// pooled values to clear their internal state (e.g. drop pointers so they +// don't outlive their useful life) before being returned to the pool. +type resettable[T any] interface { + *T + Reset() +} + +// ResettablePool is like [SyncPool], but for types whose pointer clears its +// own fields via a Reset method before being pooled. Unlike a runtime +// interface check on every Put, the PT type parameter is resolved at compile +// time, so there's no extra dispatch cost over a hand-written pool. +type ResettablePool[T any, PT resettable[T]] struct { + pool sync.Pool +} + +func NewResettablePool[T any, PT resettable[T]]() *ResettablePool[T, PT] { + return &ResettablePool[T, PT]{ + pool: sync.Pool{ + New: func() any { + return new(T) + }, + }, + } +} + +func (p *ResettablePool[T, PT]) Get() *T { + return p.pool.Get().(*T) +} + +func (p *ResettablePool[T, PT]) Put(x *T) { + if x != nil { + PT(x).Reset() + p.pool.Put(x) + } +} + // NewPtrSlice returns a slice of pointers to T with length n, // with only 2 allocations performed no matter the size of n. // See: @@ -114,6 +151,58 @@ func AppendInt(buf []byte, n int) []byte { return strconv.AppendInt(buf, int64(n), 10) } +// Atoi is a convenience function for [Atoi64] where an int is preferable to an int64. +// See the documentation of [Atoi64] for details on the performance benefits of this +// function over strconv.Atoi. +func Atoi(s string) (int, bool) { + if i, ok := Atoi64(s); ok { + return int(i), true + } + return 0, false +} + +// Atoi64 is an alternative implementation of strconv.Atoi which is slightly faster for the +// (for our use case) common case of a successful conversion, and crucially — *much* faster +// for the failure case, as this function allocates nothing for any given input string, while +// strconv.Atoi performs 1-2 allocations on failure in its error handling. The callers in this +// codebase — most notably ast.Number's Int() and Int64() methods — have no interest in the +// details of the failure, and keeping this allocation free means both methods can be used +// not only for conversion, but as a most efficient "IsInt64" check. +func Atoi64(s string) (int64, bool) { + sLen := len(s) + if sLen > 0 { + negative := s[0] == '-' + if negative || s[0] == '+' { + s = s[1:] + sLen-- + } + if sLen == 0 || sLen > 19 { + return 0, false + } + + var n int64 + for _, ch := range []byte(s) { + ch -= '0' + if ch > 9 { + return 0, false + } + n = n*10 + int64(ch) + } + if !negative && n < 0 { + return 0, false // overflow + } + if negative { + n = -n + if n > 0 { + return 0, false // underflow + } + } + return n, true + } + + return 0, false +} + // SplitMap calls fn for each delim-separated part of text and returns a slice of the results. // Cheaper than calling fn on strings.Split(text, delim), as it avoids allocating an intermediate slice of strings. func SplitMap[T any](text string, delim string, fn func(string) T) []T { diff --git a/vendor/github.com/open-policy-agent/opa/v1/util/queue.go b/vendor/github.com/open-policy-agent/opa/v1/util/queue.go index 63a2ffc16a..9208ecdbec 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/util/queue.go +++ b/vendor/github.com/open-policy-agent/opa/v1/util/queue.go @@ -111,3 +111,94 @@ func (s *FIFO) Pop() (T, bool) { func (s *FIFO) Size() int { return s.size } + +// SliceStack is a generic LIFO stack backed by a slice. +type SliceStack[T any] struct { + s []T +} + +// Push adds v to the top of the stack. +func (s *SliceStack[T]) Push(v T) { + s.s = append(s.s, v) +} + +// Pop removes and returns the top element of the stack. +// It panics if the stack is empty. +func (s *SliceStack[T]) Pop() T { + idx := len(s.s) - 1 + v := s.s[idx] + var zero T + s.s[idx] = zero // avoid retaining a reference to v in the backing array + s.s = s.s[:idx] + return v +} + +// Peek returns the top element of the stack without removing it. +// It panics if the stack is empty. +func (s *SliceStack[T]) Peek() T { + return s.s[len(s.s)-1] +} + +// PeekPtr returns a pointer to the top element, so callers can mutate it in place. +// It panics if the stack is empty. +func (s *SliceStack[T]) PeekPtr() *T { + return &s.s[len(s.s)-1] +} + +// Slice returns the stack's underlying slice, bottom-to-top. +func (s *SliceStack[T]) Slice() []T { + return s.s +} + +// Len returns the number of elements on the stack. +func (s *SliceStack[T]) Len() int { + return len(s.s) +} + +// GroupStack is a two-level stack: a stack of groups, where each group is a +// slice of T. Whole groups are pushed and popped with PushGroup/PopGroup, +// while individual elements are pushed and popped onto the top group with +// Push/Pop. Element lookups (Peek) always target the top group. +// +// Both levels zero their vacated slots when popping, so a popped group or +// element isn't kept alive by the backing arrays. +type GroupStack[T any] struct { + groups SliceStack[[]T] +} + +// PushGroup pushes a new group onto the stack. Pass nil for an empty group. +func (g *GroupStack[T]) PushGroup(group []T) { + g.groups.Push(group) +} + +// PopGroup removes and returns the top group. It panics if there are no groups. +func (g *GroupStack[T]) PopGroup() []T { + return g.groups.Pop() +} + +// PeekGroup returns the top group without removing it. It panics if there are +// no groups. +func (g *GroupStack[T]) PeekGroup() []T { + return g.groups.Peek() +} + +// Push appends v to the top group. It panics if there are no groups. +func (g *GroupStack[T]) Push(v T) { + top := g.groups.PeekPtr() + *top = append(*top, v) +} + +// Pop removes the top element of the top group. It panics if there are no +// groups or the top group is empty. +func (g *GroupStack[T]) Pop() { + top := g.groups.PeekPtr() + idx := len(*top) - 1 + var zero T + (*top)[idx] = zero // avoid retaining a reference in the backing array + *top = (*top)[:idx] +} + +// Len returns the number of groups on the stack. +func (g *GroupStack[T]) Len() int { + return g.groups.Len() +} diff --git a/vendor/github.com/open-policy-agent/opa/v1/version/version.go b/vendor/github.com/open-policy-agent/opa/v1/version/version.go index 92bf2fdaf2..cb30f722fc 100644 --- a/vendor/github.com/open-policy-agent/opa/v1/version/version.go +++ b/vendor/github.com/open-policy-agent/opa/v1/version/version.go @@ -10,7 +10,7 @@ import ( "runtime/debug" ) -var Version = "1.18.2" +var Version = "1.19.0" // GoVersion is the version of Go this was built with var GoVersion = runtime.Version() diff --git a/vendor/github.com/vektah/gqlparser/v2/ast/definition.go b/vendor/github.com/vektah/gqlparser/v2/ast/definition.go index 426db7588c..a8760c15f1 100644 --- a/vendor/github.com/vektah/gqlparser/v2/ast/definition.go +++ b/vendor/github.com/vektah/gqlparser/v2/ast/definition.go @@ -32,7 +32,13 @@ type Definition struct { EnumValues EnumValueList // enum Position *Position `dump:"-" json:"-"` - BuiltIn bool `dump:"-"` + // TypePositions holds the source position of each Types entry (a union's + // member types), parallel to Types. The parser populates it so that + // validation can point at the offending member; when populated its length + // equals len(Types). It is empty for definitions built programmatically, in + // which case validators fall back to the definition's own Position. + TypePositions []*Position `dump:"-" json:"-"` + BuiltIn bool `dump:"-"` BeforeDescriptionComment *CommentGroup AfterDescriptionComment *CommentGroup diff --git a/vendor/github.com/vektah/gqlparser/v2/ast/dumper.go b/vendor/github.com/vektah/gqlparser/v2/ast/dumper.go index 26cf693d9c..201688183a 100644 --- a/vendor/github.com/vektah/gqlparser/v2/ast/dumper.go +++ b/vendor/github.com/vektah/gqlparser/v2/ast/dumper.go @@ -58,7 +58,7 @@ func (d *dumper) dump(v reflect.Value) { case reflect.Array, reflect.Slice: d.dumpArray(v) - case reflect.Interface, reflect.Ptr: + case reflect.Interface, reflect.Pointer: d.dumpPtr(v) case reflect.Struct: @@ -79,7 +79,7 @@ func (d *dumper) nl() { } func typeName(t reflect.Type) string { - if t.Kind() == reflect.Ptr { + if t.Kind() == reflect.Pointer { return typeName(t.Elem()) } return t.Name() @@ -122,7 +122,7 @@ func (d *dumper) dumpStruct(v reflect.Value) { func isZero(v reflect.Value) bool { switch v.Kind() { - case reflect.Ptr, reflect.Interface: + case reflect.Pointer, reflect.Interface: return v.IsNil() case reflect.Func, reflect.Map: return v.IsNil() diff --git a/vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go index 7a82a42b33..1af14c6a48 100644 --- a/vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go +++ b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go @@ -193,7 +193,7 @@ func (s *Lexer) ReadToken() (Token, error) { s.endRunes-- if r < 0x0020 && r != 0x0009 && r != 0x000a && r != 0x000d { - return s.makeError(`Cannot contain the invalid character "\u%04d"`, r) + return s.makeError(`Cannot contain the invalid character "\u%04x"`, r) } if r == '\'' { @@ -365,7 +365,7 @@ func (s *Lexer) readString() (Token, error) { break } if r < 0x0020 && r != '\t' { - return s.makeError(`Invalid character within String: "\u%04d".`, r) + return s.makeError(`Invalid character within String: "\u%04x".`, r) } switch r { default: @@ -505,7 +505,7 @@ func (s *Lexer) readBlockString() (Token, error) { // SourceCharacter if r < 0x0020 && r != '\t' && r != '\n' && r != '\r' { - return s.makeError(`Invalid character within String: "\u%04d".`, r) + return s.makeError(`Invalid character within String: "\u%04x".`, r) } switch { diff --git a/vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml index 0899f4ca9b..22956b84cd 100644 --- a/vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml +++ b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml @@ -231,6 +231,12 @@ lex reports useful string errors: message: 'Invalid character within String: "\u0000".' locations: [{ line: 1, column: 19 }] + - name: control character codepoint reported in hex + input: "\"contains \u000e sub char\"" + error: + message: 'Invalid character within String: "\u000e".' + locations: [{ line: 1, column: 11 }] + - name: unterminated newline input: "\"multi\nline\"" error: diff --git a/vendor/github.com/vektah/gqlparser/v2/parser/schema.go b/vendor/github.com/vektah/gqlparser/v2/parser/schema.go index a004a0f6c0..7152963332 100644 --- a/vendor/github.com/vektah/gqlparser/v2/parser/schema.go +++ b/vendor/github.com/vektah/gqlparser/v2/parser/schema.go @@ -329,22 +329,26 @@ func (p *parser) parseUnionTypeDefinition(description descriptionWithComment) *D def.AfterDescriptionComment = comment def.Name = p.parseName() def.Directives = p.parseDirectives(true) - def.Types = p.parseUnionMemberTypes() + def.Types, def.TypePositions = p.parseUnionMemberTypes() return &def } -func (p *parser) parseUnionMemberTypes() []string { - var types []string +// parseUnionMemberTypes parses a union's member type list. It returns the member +// type names alongside their source positions; the two slices have equal length +// (one position per name), so callers can report errors at a specific member. +func (p *parser) parseUnionMemberTypes() (types []string, positions []*Position) { if p.skip(lexer.Equals) { // optional leading pipe p.skip(lexer.Pipe) + positions = append(positions, p.peekPos()) types = append(types, p.parseName()) for p.skip(lexer.Pipe) && p.err == nil { + positions = append(positions, p.peekPos()) types = append(types, p.parseName()) } } - return types + return types, positions } func (p *parser) parseEnumTypeDefinition(description descriptionWithComment) *Definition { @@ -506,7 +510,7 @@ func (p *parser) parseUnionTypeExtension(comment *CommentGroup) *Definition { def.Kind = Union def.Name = p.parseName() def.Directives = p.parseDirectives(true) - def.Types = p.parseUnionMemberTypes() + def.Types, def.TypePositions = p.parseUnionMemberTypes() if len(def.Directives) == 0 && len(def.Types) == 0 { p.unexpectedError() diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/schema.go b/vendor/github.com/vektah/gqlparser/v2/validator/schema.go index b1049aaf28..f8d9472754 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/schema.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/schema.go @@ -62,6 +62,7 @@ func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) { def.Interfaces = append(def.Interfaces, ext.Interfaces...) def.Fields = append(def.Fields, ext.Fields...) def.Types = append(def.Types, ext.Types...) + def.TypePositions = append(def.TypePositions, ext.TypePositions...) def.EnumValues = append(def.EnumValues, ext.EnumValues...) } @@ -421,6 +422,29 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error { } } + // Reject duplicate union member types, pointing at the duplicate member's + // position when it is known. TypePositions is parallel to Types (populated by + // the parser); when it is absent or not aligned, fall back to the + // definition's own position. + memberPosAligned := len(def.TypePositions) == len(def.Types) + for i, typ1 := range def.Types { + for j := i + 1; j < len(def.Types); j++ { + if typ1 != def.Types[j] { + continue + } + pos := def.Position + if memberPosAligned && def.TypePositions[j] != nil { + pos = def.TypePositions[j] + } + return gqlerror.ErrorPosf( + pos, + "Union type %s can only include type %s once.", + def.Name, + def.Types[j], + ) + } + } + if !def.BuiltIn { // GraphQL spec has reserved type names a lot! err := validateName(def.Position, def.Name) diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml b/vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml index 5b59711ffc..b66e1e3d5a 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml +++ b/vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml @@ -494,6 +494,37 @@ unions: error: message: "UNION type \"Baz\" must be OBJECT." locations: [{line: 1, column: 7}] + - name: cannot include same union member twice at same definition + input: | + union Foo = Bar | Bar + type Bar { + id: ID + } + error: + message: "Union type Foo can only include type Bar once." + locations: [{line: 1, column: 19}] + - name: cannot include same union member twice across extension + input: | + union Foo = Bar + extend union Foo = Bar + type Bar { + id: ID + } + error: + message: "Union type Foo can only include type Bar once." + locations: [{line: 2, column: 20}] + - name: reports the second occurrence among multiple members + input: | + union Foo = Bar | Baz | Bar + type Bar { + id: ID + } + type Baz { + id: ID + } + error: + message: "Union type Foo can only include type Bar once." + locations: [{line: 1, column: 25}] - name: unions of pure type extensions are valid input: | diff --git a/vendor/github.com/vektah/gqlparser/v2/validator/vars.go b/vendor/github.com/vektah/gqlparser/v2/validator/vars.go index 50e2cdb295..8d3534d940 100644 --- a/vendor/github.com/vektah/gqlparser/v2/validator/vars.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/vars.go @@ -86,7 +86,7 @@ func VariableValues( rv = reflect.ValueOf(f) } } - if rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface { + if rv.Kind() == reflect.Pointer || rv.Kind() == reflect.Interface { rv = rv.Elem() } @@ -117,6 +117,14 @@ func (v *varValidator) validateVarType( v.path = currentPath } defer resetPath() + + if !val.IsValid() { + if typ.NonNull { + return val, gqlerror.ErrorPathf(v.path, "cannot be null") + } + return val, nil + } + if typ.Elem != nil { if val.Kind() != reflect.Slice { // GraphQL spec says that non-null values should be coerced to an array when possible. @@ -129,7 +137,7 @@ func (v *varValidator) validateVarType( resetPath() v.path = append(v.path, ast.PathIndex(i)) field := val.Index(i) - if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { + if field.Kind() == reflect.Pointer || field.Kind() == reflect.Interface { if typ.Elem.NonNull && field.IsNil() { return val, gqlerror.ErrorPathf(v.path, "cannot be null") } @@ -147,11 +155,6 @@ func (v *varValidator) validateVarType( panic(fmt.Errorf("missing def for %s", typ.NamedType)) } - if !typ.NonNull && !val.IsValid() { - // If the type is not null and we got a invalid value namely null/nil, then it's valid - return val, nil - } - switch def.Kind { case ast.Enum: kind := val.Type().Kind() @@ -245,7 +248,7 @@ func (v *varValidator) validateVarType( continue } - if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { + if field.Kind() == reflect.Pointer || field.Kind() == reflect.Interface { if fieldDef.Type.NonNull && field.IsNil() { return val, gqlerror.ErrorPathf(v.path, "cannot be null") } diff --git a/vendor/modules.txt b/vendor/modules.txt index f03b6ecb59..64f125c0d9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -548,7 +548,7 @@ github.com/go-ldap/ldif # github.com/go-logfmt/logfmt v0.5.1 ## explicit; go 1.17 github.com/go-logfmt/logfmt -# github.com/go-logr/logr v1.4.3 +# github.com/go-logr/logr v1.4.4 ## explicit; go 1.18 github.com/go-logr/logr github.com/go-logr/logr/funcr @@ -1274,7 +1274,7 @@ github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types -# github.com/open-policy-agent/opa v1.18.2 +# github.com/open-policy-agent/opa v1.19.0 ## explicit; go 1.25.0 github.com/open-policy-agent/opa/ast github.com/open-policy-agent/opa/ast/json @@ -1294,9 +1294,12 @@ github.com/open-policy-agent/opa/internal/file/url github.com/open-policy-agent/opa/internal/future github.com/open-policy-agent/opa/internal/gojsonschema github.com/open-policy-agent/opa/internal/json/patch +github.com/open-policy-agent/opa/internal/jsonv2 github.com/open-policy-agent/opa/internal/lcss github.com/open-policy-agent/opa/internal/leb128 github.com/open-policy-agent/opa/internal/merge +github.com/open-policy-agent/opa/internal/methodlesstemplate +github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort github.com/open-policy-agent/opa/internal/planner github.com/open-policy-agent/opa/internal/providers/aws github.com/open-policy-agent/opa/internal/providers/aws/crypto @@ -1325,9 +1328,11 @@ github.com/open-policy-agent/opa/v1/ast/internal/tokens github.com/open-policy-agent/opa/v1/ast/json github.com/open-policy-agent/opa/v1/ast/location github.com/open-policy-agent/opa/v1/bundle +github.com/open-policy-agent/opa/v1/bundle/v1pb github.com/open-policy-agent/opa/v1/capabilities github.com/open-policy-agent/opa/v1/format github.com/open-policy-agent/opa/v1/ir +github.com/open-policy-agent/opa/v1/ir/v1pb github.com/open-policy-agent/opa/v1/keys github.com/open-policy-agent/opa/v1/loader github.com/open-policy-agent/opa/v1/loader/extension @@ -2122,7 +2127,7 @@ github.com/urfave/cli/v2 ## explicit; go 1.24 github.com/valyala/fastjson github.com/valyala/fastjson/fastfloat -# github.com/vektah/gqlparser/v2 v2.5.34 +# github.com/vektah/gqlparser/v2 v2.5.36 ## explicit; go 1.22 github.com/vektah/gqlparser/v2/ast github.com/vektah/gqlparser/v2/gqlerror