mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-08-03 19:35:23 -04:00
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] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
9df3881128
commit
e12966a4fd
6
go.mod
6
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
|
||||
|
||||
20
go.sum
20
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=
|
||||
|
||||
1
vendor/github.com/go-logr/logr/context_noslog.go
generated
vendored
1
vendor/github.com/go-logr/logr/context_noslog.go
generated
vendored
@@ -1,5 +1,4 @@
|
||||
//go:build !go1.21
|
||||
// +build !go1.21
|
||||
|
||||
/*
|
||||
Copyright 2019 The logr Authors.
|
||||
|
||||
1
vendor/github.com/go-logr/logr/context_slog.go
generated
vendored
1
vendor/github.com/go-logr/logr/context_slog.go
generated
vendored
@@ -1,5 +1,4 @@
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
|
||||
/*
|
||||
Copyright 2019 The logr Authors.
|
||||
|
||||
47
vendor/github.com/go-logr/logr/funcr/funcr.go
generated
vendored
47
vendor/github.com/go-logr/logr/funcr/funcr.go
generated
vendored
@@ -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 `"<max-log-depth-exceeded>"`
|
||||
}
|
||||
@@ -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(`"<unhandled-%s>"`, 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
|
||||
|
||||
22
vendor/github.com/go-logr/logr/funcr/slogsink.go
generated
vendored
22
vendor/github.com/go-logr/logr/funcr/slogsink.go
generated
vendored
@@ -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, "<max-log-depth-exceeded>")
|
||||
}
|
||||
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
|
||||
|
||||
1
vendor/github.com/go-logr/logr/sloghandler.go
generated
vendored
1
vendor/github.com/go-logr/logr/sloghandler.go
generated
vendored
@@ -1,5 +1,4 @@
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
|
||||
/*
|
||||
Copyright 2023 The logr Authors.
|
||||
|
||||
1
vendor/github.com/go-logr/logr/slogr.go
generated
vendored
1
vendor/github.com/go-logr/logr/slogr.go
generated
vendored
@@ -1,5 +1,4 @@
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
|
||||
/*
|
||||
Copyright 2023 The logr Authors.
|
||||
|
||||
1
vendor/github.com/go-logr/logr/slogsink.go
generated
vendored
1
vendor/github.com/go-logr/logr/slogsink.go
generated
vendored
@@ -1,5 +1,4 @@
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
|
||||
/*
|
||||
Copyright 2023 The logr Authors.
|
||||
|
||||
5026
vendor/github.com/open-policy-agent/opa/capabilities/v1.19.0.json
generated
vendored
Normal file
5026
vendor/github.com/open-policy-agent/opa/capabilities/v1.19.0.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/github.com/open-policy-agent/opa/internal/compiler/wasm/opa/opa.wasm
generated
vendored
BIN
vendor/github.com/open-policy-agent/opa/internal/compiler/wasm/opa/opa.wasm
generated
vendored
Binary file not shown.
9
vendor/github.com/open-policy-agent/opa/internal/gojsonschema/errors.go
generated
vendored
9
vendor/github.com/open-policy-agent/opa/internal/gojsonschema/errors.go
generated
vendored
@@ -4,7 +4,14 @@ package gojsonschema
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
"text/template"
|
||||
|
||||
// A method-less copy of text/template (see internal/methodlesstemplate). Locale
|
||||
// format strings expand only simple {{.field}} placeholders over ErrorDetails
|
||||
// (map[string]any), which has 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"
|
||||
)
|
||||
|
||||
var errorTemplates = errorTemplate{template.New("errors-new"), sync.RWMutex{}}
|
||||
|
||||
5
vendor/github.com/open-policy-agent/opa/internal/gojsonschema/schema.go
generated
vendored
5
vendor/github.com/open-policy-agent/opa/internal/gojsonschema/schema.go
generated
vendored
@@ -31,7 +31,10 @@ import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"text/template"
|
||||
|
||||
// Method-less copy of text/template; see the import note in errors.go
|
||||
// (golang/go#72895, #7903). ErrorTemplateFuncs below is its FuncMap.
|
||||
template "github.com/open-policy-agent/opa/internal/methodlesstemplate"
|
||||
|
||||
"github.com/xeipuuv/gojsonreference"
|
||||
)
|
||||
|
||||
79
vendor/github.com/open-policy-agent/opa/internal/jsonv2/jsonv2.go
generated
vendored
Normal file
79
vendor/github.com/open-policy-agent/opa/internal/jsonv2/jsonv2.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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 jsonv2
|
||||
|
||||
// This migration must not change OPA's JSON output, but json.Marshal defaults
|
||||
// to v2 semantics (no HTML escaping, non-deterministic map key order). So
|
||||
// every entry point into v2 here must establish v1 options (see
|
||||
// [jsonv1.DefaultOptionsV1]); nested encodes inherit them from the caller's
|
||||
// encoder. MarshalMarshalerTo is the only such entry point today, but that's
|
||||
// incidental — any new json.Marshal, json.MarshalWrite, or jsontext.NewEncoder
|
||||
// added here must do the same.
|
||||
|
||||
import (
|
||||
jsonv1 "encoding/json"
|
||||
"encoding/json/jsontext"
|
||||
"encoding/json/v2"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// WriteMarshalerToArray writes the JSON array of items to the encoder.
|
||||
func WriteMarshalerToArray[T json.MarshalerTo](e *jsontext.Encoder, items []T) error {
|
||||
e.WriteToken(jsontext.BeginArray)
|
||||
for _, item := range items {
|
||||
if err := item.MarshalJSONTo(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.WriteToken(jsontext.EndArray)
|
||||
}
|
||||
|
||||
// WriteField writes the object member name and then v's JSON encoding, so that
|
||||
// the member is written and checked in one statement. A nil v is written as
|
||||
// JSON null rather than dispatched to MarshalJSONTo: v1's reflection-based
|
||||
// encoder already does this for a nil pointer, so writing null here keeps
|
||||
// output identical to v1, rather than panicking on the types whose
|
||||
// MarshalJSONTo assumes a non-nil receiver.
|
||||
func WriteField[T json.MarshalerTo](e *jsontext.Encoder, name string, v T) error {
|
||||
e.WriteToken(jsontext.String(name))
|
||||
if rv := reflect.ValueOf(v); rv.Kind() == reflect.Pointer && rv.IsNil() {
|
||||
return e.WriteToken(jsontext.Null)
|
||||
}
|
||||
return v.MarshalJSONTo(e)
|
||||
}
|
||||
|
||||
// WriteFieldArray writes the object member name and then the JSON array of items.
|
||||
func WriteFieldArray[T json.MarshalerTo](e *jsontext.Encoder, name string, items []T) error {
|
||||
e.WriteToken(jsontext.String(name))
|
||||
return WriteMarshalerToArray(e, items)
|
||||
}
|
||||
|
||||
// WriteFieldValue is [WriteField] for values that don't implement [json.MarshalerTo].
|
||||
func WriteFieldValue(e *jsontext.Encoder, name string, v any) error {
|
||||
e.WriteToken(jsontext.String(name))
|
||||
return json.MarshalEncode(e, v)
|
||||
}
|
||||
|
||||
// WriteMarshalerToArrayOrNull is [WriteMarshalerToArray] but writes null for a nil
|
||||
// slice, as encoding/json v1 does. Types whose pre-1.27 MarshalJSON returns "[]"
|
||||
// for an empty value must keep using [WriteMarshalerToArray].
|
||||
func WriteMarshalerToArrayOrNull[T json.MarshalerTo](e *jsontext.Encoder, items []T) error {
|
||||
if items == nil {
|
||||
return e.WriteToken(jsontext.Null)
|
||||
}
|
||||
return WriteMarshalerToArray(e, items)
|
||||
}
|
||||
|
||||
// MarshalMarshalerTo provides a MarshalJSON implementation for any type that
|
||||
// implements json.MarshalerTo. json.Marshal dispatches to MarshalJSONTo, so this
|
||||
// doesn't recurse; the constraint is what guarantees that at compile time.
|
||||
//
|
||||
// This is the entry point into v2 that establishes v1 options, per the
|
||||
// package-level comment above.
|
||||
func MarshalMarshalerTo[T json.MarshalerTo](v T) ([]byte, error) {
|
||||
return json.Marshal(v, jsonv1.DefaultOptionsV1())
|
||||
}
|
||||
27
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/LICENSE
generated
vendored
Normal file
27
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
28
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/README.md
generated
vendored
Normal file
28
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/README.md
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# methodlesstemplate
|
||||
|
||||
A vendored copy of the Go standard library's `text/template`, with **one** behavioral change: the
|
||||
method-calls-on-data branch in `exec.go`'s `evalField` (`reflect.Value.MethodByName`) is removed.
|
||||
|
||||
A reachable, non-constant `reflect.Value.MethodByName` makes the Go linker disable method-level
|
||||
dead-code elimination for the **entire binary** (golang/go#72895). OPA reaches `text/template` from
|
||||
its compiler (schema errors) and the `strings.render_template` builtin, so that one edge retains the
|
||||
full reflected method surface of every embedder — a large binary-size regression (#7903). Rego
|
||||
values and gojsonschema `ErrorDetails` decode to `map[string]any` / `[]any` / scalars, which have no
|
||||
methods, so eliding the data-method lookup is a behavioral no-op while restoring DCE.
|
||||
|
||||
Only `exec.go` differs from the upstream stdlib. `doc.go`, `funcs.go`, `option.go`, `template.go`,
|
||||
and `internal/fmtsort/sort.go` are byte-identical to their Go release; `text/template/parse` is
|
||||
reused via its normal import. `helper.go` (ParseFiles/ParseGlob/ParseFS) is intentionally not
|
||||
vendored. Go's BSD `LICENSE` and per-file copyright headers are preserved.
|
||||
|
||||
## Regenerating
|
||||
|
||||
Do not hand-edit these files. To re-sync to a new Go release, run under the target toolchain:
|
||||
|
||||
```
|
||||
GOTOOLCHAIN=go1.26.0 build/regen-methodless-template.sh
|
||||
```
|
||||
|
||||
The script copies the stdlib files verbatim and re-applies the single method-elision edit. If the
|
||||
edit no longer applies (the stdlib changed that region), the script fails and the elision must be
|
||||
re-derived and the patch in the script updated.
|
||||
502
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/doc.go
generated
vendored
Normal file
502
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/doc.go
generated
vendored
Normal file
@@ -0,0 +1,502 @@
|
||||
// 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 implements data-driven templates for generating textual output.
|
||||
|
||||
To generate HTML output, see [html/template], which has the same interface
|
||||
as this package but automatically secures HTML output against certain attacks.
|
||||
|
||||
Templates are executed by applying them to a data structure. Annotations in the
|
||||
template refer to elements of the data structure (typically a field of a struct
|
||||
or a key in a map) to control execution and derive values to be displayed.
|
||||
Execution of the template walks the structure and sets the cursor, represented
|
||||
by a period '.' and called "dot", to the value at the current location in the
|
||||
structure as execution proceeds.
|
||||
|
||||
The security model used by this package assumes that template authors are
|
||||
trusted. The package does not auto-escape output, so injecting code into
|
||||
a template can lead to arbitrary code execution if the template is executed
|
||||
by an untrusted source.
|
||||
|
||||
The input text for a template is UTF-8-encoded text in any format.
|
||||
"Actions"--data evaluations or control structures--are delimited by
|
||||
"{{" and "}}"; all text outside actions is copied to the output unchanged.
|
||||
|
||||
Once parsed, a template may be executed safely in parallel, although if parallel
|
||||
executions share a Writer the output may be interleaved.
|
||||
|
||||
Here is a trivial example that prints "17 items are made of wool".
|
||||
|
||||
type Inventory struct {
|
||||
Material string
|
||||
Count uint
|
||||
}
|
||||
sweaters := Inventory{"wool", 17}
|
||||
tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
|
||||
if err != nil { panic(err) }
|
||||
err = tmpl.Execute(os.Stdout, sweaters)
|
||||
if err != nil { panic(err) }
|
||||
|
||||
More intricate examples appear below.
|
||||
|
||||
Text and spaces
|
||||
|
||||
By default, all text between actions is copied verbatim when the template is
|
||||
executed. For example, the string " items are made of " in the example above
|
||||
appears on standard output when the program is run.
|
||||
|
||||
However, to aid in formatting template source code, if an action's left
|
||||
delimiter (by default "{{") is followed immediately by a minus sign and white
|
||||
space, all trailing white space is trimmed from the immediately preceding text.
|
||||
Similarly, if the right delimiter ("}}") is preceded by white space and a minus
|
||||
sign, all leading white space is trimmed from the immediately following text.
|
||||
In these trim markers, the white space must be present:
|
||||
"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while
|
||||
"{{-3}}" parses as an action containing the number -3.
|
||||
|
||||
For instance, when executing the template whose source is
|
||||
|
||||
"{{23 -}} < {{- 45}}"
|
||||
|
||||
the generated output would be
|
||||
|
||||
"23<45"
|
||||
|
||||
For this trimming, the definition of white space characters is the same as in Go:
|
||||
space, horizontal tab, carriage return, and newline.
|
||||
|
||||
Actions
|
||||
|
||||
Here is the list of actions. "Arguments" and "pipelines" are evaluations of
|
||||
data, defined in detail in the corresponding sections that follow.
|
||||
|
||||
*/
|
||||
// {{/* a comment */}}
|
||||
// {{- /* a comment with white space trimmed from preceding and following text */ -}}
|
||||
// A comment; discarded. May contain newlines.
|
||||
// Comments do not nest and must start and end at the
|
||||
// delimiters, as shown here.
|
||||
/*
|
||||
|
||||
{{pipeline}}
|
||||
The default textual representation (the same as would be
|
||||
printed by fmt.Print) of the value of the pipeline is copied
|
||||
to the output.
|
||||
|
||||
{{if pipeline}} T1 {{end}}
|
||||
If the value of the pipeline is empty, no output is generated;
|
||||
otherwise, T1 is executed. The empty values are false, 0, any
|
||||
nil pointer or interface value, and any array, slice, map, or
|
||||
string of length zero.
|
||||
Dot is unaffected.
|
||||
|
||||
{{if pipeline}} T1 {{else}} T0 {{end}}
|
||||
If the value of the pipeline is empty, T0 is executed;
|
||||
otherwise, T1 is executed. Dot is unaffected.
|
||||
|
||||
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
|
||||
To simplify the appearance of if-else chains, the else action
|
||||
of an if may include another if directly; the effect is exactly
|
||||
the same as writing
|
||||
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
|
||||
|
||||
{{range pipeline}} T1 {{end}}
|
||||
The value of the pipeline must be an array, slice, map, iter.Seq,
|
||||
iter.Seq2, integer or channel.
|
||||
If the value of the pipeline has length zero, nothing is output;
|
||||
otherwise, dot is set to the successive elements of the array,
|
||||
slice, or map and T1 is executed. If the value is a map and the
|
||||
keys are of basic type with a defined order, the elements will be
|
||||
visited in sorted key order.
|
||||
|
||||
{{range pipeline}} T1 {{else}} T0 {{end}}
|
||||
The value of the pipeline must be an array, slice, map, iter.Seq,
|
||||
iter.Seq2, integer or channel.
|
||||
If the value of the pipeline has length zero, dot is unaffected and
|
||||
T0 is executed; otherwise, dot is set to the successive elements
|
||||
of the array, slice, or map and T1 is executed.
|
||||
|
||||
{{break}}
|
||||
The innermost {{range pipeline}} loop is ended early, stopping the
|
||||
current iteration and bypassing all remaining iterations.
|
||||
|
||||
{{continue}}
|
||||
The current iteration of the innermost {{range pipeline}} loop is
|
||||
stopped, and the loop starts the next iteration.
|
||||
|
||||
{{template "name"}}
|
||||
The template with the specified name is executed with nil data.
|
||||
|
||||
{{template "name" pipeline}}
|
||||
The template with the specified name is executed with dot set
|
||||
to the value of the pipeline.
|
||||
|
||||
{{block "name" pipeline}} T1 {{end}}
|
||||
A block is shorthand for defining a template
|
||||
{{define "name"}} T1 {{end}}
|
||||
and then executing it in place
|
||||
{{template "name" pipeline}}
|
||||
The typical use is to define a set of root templates that are
|
||||
then customized by redefining the block templates within.
|
||||
|
||||
{{with pipeline}} T1 {{end}}
|
||||
If the value of the pipeline is empty, no output is generated;
|
||||
otherwise, dot is set to the value of the pipeline and T1 is
|
||||
executed.
|
||||
|
||||
{{with pipeline}} T1 {{else}} T0 {{end}}
|
||||
If the value of the pipeline is empty, dot is unaffected and T0
|
||||
is executed; otherwise, dot is set to the value of the pipeline
|
||||
and T1 is executed.
|
||||
|
||||
{{with pipeline}} T1 {{else with pipeline}} T0 {{end}}
|
||||
To simplify the appearance of with-else chains, the else action
|
||||
of a with may include another with directly; the effect is exactly
|
||||
the same as writing
|
||||
{{with pipeline}} T1 {{else}}{{with pipeline}} T0 {{end}}{{end}}
|
||||
|
||||
|
||||
Arguments
|
||||
|
||||
An argument is a simple value, denoted by one of the following.
|
||||
|
||||
- A boolean, string, character, integer, floating-point, imaginary
|
||||
or complex constant in Go syntax. These behave like Go's untyped
|
||||
constants. Note that, as in Go, whether a large integer constant
|
||||
overflows when assigned or passed to a function can depend on whether
|
||||
the host machine's ints are 32 or 64 bits.
|
||||
- The keyword nil, representing an untyped Go nil.
|
||||
- The character '.' (period):
|
||||
|
||||
.
|
||||
|
||||
The result is the value of dot.
|
||||
- A variable name, which is a (possibly empty) alphanumeric string
|
||||
preceded by a dollar sign, such as
|
||||
|
||||
$piOver2
|
||||
|
||||
or
|
||||
|
||||
$
|
||||
|
||||
The result is the value of the variable.
|
||||
Variables are described below.
|
||||
- The name of a field of the data, which must be a struct, preceded
|
||||
by a period, such as
|
||||
|
||||
.Field
|
||||
|
||||
The result is the value of the field. Field invocations may be
|
||||
chained:
|
||||
|
||||
.Field1.Field2
|
||||
|
||||
Fields can also be evaluated on variables, including chaining:
|
||||
|
||||
$x.Field1.Field2
|
||||
- The name of a key of the data, which must be a map, preceded
|
||||
by a period, such as
|
||||
|
||||
.Key
|
||||
|
||||
The result is the map element value indexed by the key.
|
||||
Key invocations may be chained and combined with fields to any
|
||||
depth:
|
||||
|
||||
.Field1.Key1.Field2.Key2
|
||||
|
||||
Although the key must be an alphanumeric identifier, unlike with
|
||||
field names they do not need to start with an upper case letter.
|
||||
Keys can also be evaluated on variables, including chaining:
|
||||
|
||||
$x.key1.key2
|
||||
- The name of a niladic method of the data, preceded by a period,
|
||||
such as
|
||||
|
||||
.Method
|
||||
|
||||
The result is the value of invoking the method with dot as the
|
||||
receiver, dot.Method(). Such a method must have one return value (of
|
||||
any type) or two return values, the second of which is an error.
|
||||
If it has two and the returned error is non-nil, execution terminates
|
||||
and an error is returned to the caller as the value of Execute.
|
||||
Method invocations may be chained and combined with fields and keys
|
||||
to any depth:
|
||||
|
||||
.Field1.Key1.Method1.Field2.Key2.Method2
|
||||
|
||||
Methods can also be evaluated on variables, including chaining:
|
||||
|
||||
$x.Method1.Field
|
||||
- The name of a niladic function, such as
|
||||
|
||||
fun
|
||||
|
||||
The result is the value of invoking the function, fun(). The return
|
||||
types and values behave as in methods. Functions and function
|
||||
names are described below.
|
||||
- A parenthesized instance of one the above, for grouping. The result
|
||||
may be accessed by a field or map key invocation.
|
||||
|
||||
print (.F1 arg1) (.F2 arg2)
|
||||
(.StructValuedMethod "arg").Field
|
||||
|
||||
Arguments may evaluate to any type; if they are pointers the implementation
|
||||
automatically indirects to the base type when required.
|
||||
If an evaluation yields a function value, such as a function-valued
|
||||
field of a struct, the function is not invoked automatically, but it
|
||||
can be used as a truth value for an if action and the like. To invoke
|
||||
it, use the call function, defined below.
|
||||
|
||||
Pipelines
|
||||
|
||||
A pipeline is a possibly chained sequence of "commands". A command is a simple
|
||||
value (argument) or a function or method call, possibly with multiple arguments:
|
||||
|
||||
Argument
|
||||
The result is the value of evaluating the argument.
|
||||
.Method [Argument...]
|
||||
The method can be alone or the last element of a chain but,
|
||||
unlike methods in the middle of a chain, it can take arguments.
|
||||
The result is the value of calling the method with the
|
||||
arguments:
|
||||
dot.Method(Argument1, etc.)
|
||||
functionName [Argument...]
|
||||
The result is the value of calling the function associated
|
||||
with the name:
|
||||
function(Argument1, etc.)
|
||||
Functions and function names are described below.
|
||||
|
||||
A pipeline may be "chained" by separating a sequence of commands with pipeline
|
||||
characters '|'. In a chained pipeline, the result of each command is
|
||||
passed as the last argument of the following command. The output of the final
|
||||
command in the pipeline is the value of the pipeline.
|
||||
|
||||
The output of a command will be either one value or two values, the second of
|
||||
which has type error. If that second value is present and evaluates to
|
||||
non-nil, execution terminates and the error is returned to the caller of
|
||||
Execute.
|
||||
|
||||
Variables
|
||||
|
||||
A pipeline inside an action may initialize a variable to capture the result.
|
||||
The initialization has syntax
|
||||
|
||||
$variable := pipeline
|
||||
|
||||
where $variable is the name of the variable. An action that declares a
|
||||
variable produces no output.
|
||||
|
||||
Variables previously declared can also be assigned, using the syntax
|
||||
|
||||
$variable = pipeline
|
||||
|
||||
If a "range" action initializes a variable, the variable is set to the
|
||||
successive elements of the iteration. Also, a "range" may declare two
|
||||
variables, separated by a comma:
|
||||
|
||||
range $index, $element := pipeline
|
||||
|
||||
in which case $index and $element are set to the successive values of the
|
||||
array/slice index or map key and element, respectively. Note that if there is
|
||||
only one variable, it is assigned the element; this is opposite to the
|
||||
convention in Go range clauses.
|
||||
|
||||
A variable's scope extends to the "end" action of the control structure ("if",
|
||||
"with", or "range") in which it is declared, or to the end of the template if
|
||||
there is no such control structure. A template invocation does not inherit
|
||||
variables from the point of its invocation.
|
||||
|
||||
When execution begins, $ is set to the data argument passed to Execute, that is,
|
||||
to the starting value of dot.
|
||||
|
||||
Examples
|
||||
|
||||
Here are some example one-line templates demonstrating pipelines and variables.
|
||||
All produce the quoted word "output":
|
||||
|
||||
{{"\"output\""}}
|
||||
A string constant.
|
||||
{{`"output"`}}
|
||||
A raw string constant.
|
||||
{{printf "%q" "output"}}
|
||||
A function call.
|
||||
{{"output" | printf "%q"}}
|
||||
A function call whose final argument comes from the previous
|
||||
command.
|
||||
{{printf "%q" (print "out" "put")}}
|
||||
A parenthesized argument.
|
||||
{{"put" | printf "%s%s" "out" | printf "%q"}}
|
||||
A more elaborate call.
|
||||
{{"output" | printf "%s" | printf "%q"}}
|
||||
A longer chain.
|
||||
{{with "output"}}{{printf "%q" .}}{{end}}
|
||||
A with action using dot.
|
||||
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
|
||||
A with action that creates and uses a variable.
|
||||
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
|
||||
A with action that uses the variable in another action.
|
||||
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
|
||||
The same, but pipelined.
|
||||
|
||||
Functions
|
||||
|
||||
During execution functions are found in two function maps: first in the
|
||||
template, then in the global function map. By default, no functions are defined
|
||||
in the template but the Funcs method can be used to add them.
|
||||
|
||||
Predefined global functions are named as follows.
|
||||
|
||||
and
|
||||
Returns the boolean AND of its arguments by returning the
|
||||
first empty argument or the last argument. That is,
|
||||
"and x y" behaves as "if x then y else x."
|
||||
Evaluation proceeds through the arguments left to right
|
||||
and returns when the result is determined.
|
||||
call
|
||||
Returns the result of calling the first argument, which
|
||||
must be a function, with the remaining arguments as parameters.
|
||||
Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
|
||||
Y is a func-valued field, map entry, or the like.
|
||||
The first argument must be the result of an evaluation
|
||||
that yields a value of function type (as distinct from
|
||||
a predefined function such as print). The function must
|
||||
return either one or two result values, the second of which
|
||||
is of type error. If the arguments don't match the function
|
||||
or the returned error value is non-nil, execution stops.
|
||||
html
|
||||
Returns the escaped HTML equivalent of the textual
|
||||
representation of its arguments. This function is unavailable
|
||||
in html/template, with a few exceptions.
|
||||
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.
|
||||
slice
|
||||
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.
|
||||
js
|
||||
Returns the escaped JavaScript equivalent of the textual
|
||||
representation of its arguments.
|
||||
len
|
||||
Returns the integer length of its argument.
|
||||
not
|
||||
Returns the boolean negation of its single argument.
|
||||
or
|
||||
Returns the boolean OR of its arguments by returning the
|
||||
first non-empty argument or the last argument, that is,
|
||||
"or x y" behaves as "if x then x else y".
|
||||
Evaluation proceeds through the arguments left to right
|
||||
and returns when the result is determined.
|
||||
print
|
||||
An alias for fmt.Sprint
|
||||
printf
|
||||
An alias for fmt.Sprintf
|
||||
println
|
||||
An alias for fmt.Sprintln
|
||||
urlquery
|
||||
Returns the escaped value of the textual representation of
|
||||
its arguments in a form suitable for embedding in a URL query.
|
||||
This function is unavailable in html/template, with a few
|
||||
exceptions.
|
||||
|
||||
The boolean functions take any zero value to be false and a non-zero
|
||||
value to be true.
|
||||
|
||||
There is also a set of binary comparison operators defined as
|
||||
functions:
|
||||
|
||||
eq
|
||||
Returns the boolean truth of arg1 == arg2
|
||||
ne
|
||||
Returns the boolean truth of arg1 != arg2
|
||||
lt
|
||||
Returns the boolean truth of arg1 < arg2
|
||||
le
|
||||
Returns the boolean truth of arg1 <= arg2
|
||||
gt
|
||||
Returns the boolean truth of arg1 > 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
|
||||
1132
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/exec.go
generated
vendored
Normal file
1132
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/exec.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
783
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/funcs.go
generated
vendored
Normal file
783
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/funcs.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
154
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort/sort.go
generated
vendored
Normal file
154
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/internal/fmtsort/sort.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
72
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/option.go
generated
vendored
Normal file
72
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/option.go
generated
vendored
Normal file
@@ -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
|
||||
// "<no value>".
|
||||
// "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)
|
||||
}
|
||||
236
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/template.go
generated
vendored
Normal file
236
vendor/github.com/open-policy-agent/opa/internal/methodlesstemplate/template.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
163
vendor/github.com/open-policy-agent/opa/internal/planner/planner.go
generated
vendored
163
vendor/github.com/open-policy-agent/opa/internal/planner/planner.go
generated
vendored
@@ -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
|
||||
// | | <plan(body)> # assigns Local<cond> = true at each success point
|
||||
// | | is_defined &{Source:Local<cond>} # 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<cond>}
|
||||
// | block lhs
|
||||
// | | <plan(LHS body)>
|
||||
// | | assign_var &{Target:Local<cond>} # Local<cond> = true on success
|
||||
// | is_defined &{Source:Local<cond>} # aborts outer if LHS produced no success
|
||||
// | reset &{Target:Local<cond>} # clear before RHS
|
||||
// | block rhs
|
||||
// | | <plan(RHS body)>
|
||||
// | | assign_var &{Target:Local<cond>} # Local<cond> = true on success
|
||||
// | is_defined &{Source:Local<cond>} # 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<cond>}
|
||||
// | block lhs
|
||||
// | | <plan(LHS body)>
|
||||
// | | assign_var &{Target:Local<cond>} # Local<cond> = true on success
|
||||
// | block outer
|
||||
// | | block skip
|
||||
// | | | is_defined &{Source:Local<cond>} # if defined ..
|
||||
// | | | break &{Index:1} # .. break past RHS
|
||||
// | | block rhs
|
||||
// | | | <plan(RHS body)>
|
||||
// | | | assign_var &{Target:Local<cond>} # Local<cond> = true on success
|
||||
// | is_defined &{Source:Local<cond>} # 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
|
||||
|
||||
46
vendor/github.com/open-policy-agent/opa/internal/planner/rules.go
generated
vendored
46
vendor/github.com/open-policy-agent/opa/internal/planner/rules.go
generated
vendored
@@ -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
|
||||
|
||||
6
vendor/github.com/open-policy-agent/opa/internal/semver/semver.go
generated
vendored
6
vendor/github.com/open-policy-agent/opa/internal/semver/semver.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
108
vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go
generated
vendored
108
vendor/github.com/open-policy-agent/opa/v1/ast/annotations.go
generated
vendored
@@ -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
|
||||
|
||||
124
vendor/github.com/open-policy-agent/opa/v1/ast/annotations_json.go
generated
vendored
Normal file
124
vendor/github.com/open-policy-agent/opa/v1/ast/annotations_json.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
195
vendor/github.com/open-policy-agent/opa/v1/ast/annotations_jsonv2.go
generated
vendored
Normal file
195
vendor/github.com/open-policy-agent/opa/v1/ast/annotations_jsonv2.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
50
vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go
generated
vendored
50
vendor/github.com/open-policy-agent/opa/v1/ast/builtins.go
generated
vendored
@@ -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,
|
||||
}
|
||||
|
||||
4
vendor/github.com/open-policy-agent/opa/v1/ast/check.go
generated
vendored
4
vendor/github.com/open-policy-agent/opa/v1/ast/check.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
16
vendor/github.com/open-policy-agent/opa/v1/ast/compare.go
generated
vendored
16
vendor/github.com/open-policy-agent/opa/v1/ast/compare.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
284
vendor/github.com/open-policy-agent/opa/v1/ast/compile.go
generated
vendored
284
vendor/github.com/open-policy-agent/opa/v1/ast/compile.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
29
vendor/github.com/open-policy-agent/opa/v1/ast/errors.go
generated
vendored
29
vendor/github.com/open-policy-agent/opa/v1/ast/errors.go
generated
vendored
@@ -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...))
|
||||
|
||||
69
vendor/github.com/open-policy-agent/opa/v1/ast/external_source.go
generated
vendored
69
vendor/github.com/open-policy-agent/opa/v1/ast/external_source.go
generated
vendored
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
315
vendor/github.com/open-policy-agent/opa/v1/ast/index.go
generated
vendored
315
vendor/github.com/open-policy-agent/opa/v1/ast/index.go
generated
vendored
@@ -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 <collection>` (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)
|
||||
}
|
||||
|
||||
40
vendor/github.com/open-policy-agent/opa/v1/ast/location/location.go
generated
vendored
40
vendor/github.com/open-policy-agent/opa/v1/ast/location/location.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
47
vendor/github.com/open-policy-agent/opa/v1/ast/location/location_json.go
generated
vendored
Normal file
47
vendor/github.com/open-policy-agent/opa/v1/ast/location/location_json.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
50
vendor/github.com/open-policy-agent/opa/v1/ast/location/location_jsonv2.go
generated
vendored
Normal file
50
vendor/github.com/open-policy-agent/opa/v1/ast/location/location_jsonv2.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
2
vendor/github.com/open-policy-agent/opa/v1/ast/map.go
generated
vendored
2
vendor/github.com/open-policy-agent/opa/v1/ast/map.go
generated
vendored
@@ -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]
|
||||
|
||||
24
vendor/github.com/open-policy-agent/opa/v1/ast/mermaid.go
generated
vendored
24
vendor/github.com/open-policy-agent/opa/v1/ast/mermaid.go
generated
vendored
@@ -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
|
||||
|
||||
297
vendor/github.com/open-policy-agent/opa/v1/ast/parser.go
generated
vendored
297
vendor/github.com/open-policy-agent/opa/v1/ast/parser.go
generated
vendored
@@ -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 {
|
||||
|
||||
414
vendor/github.com/open-policy-agent/opa/v1/ast/policy.go
generated
vendored
414
vendor/github.com/open-policy-agent/opa/v1/ast/policy.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
18
vendor/github.com/open-policy-agent/opa/v1/ast/policy_appenders.go
generated
vendored
18
vendor/github.com/open-policy-agent/opa/v1/ast/policy_appenders.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
289
vendor/github.com/open-policy-agent/opa/v1/ast/policy_json.go
generated
vendored
Normal file
289
vendor/github.com/open-policy-agent/opa/v1/ast/policy_json.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
524
vendor/github.com/open-policy-agent/opa/v1/ast/policy_jsonv2.go
generated
vendored
Normal file
524
vendor/github.com/open-policy-agent/opa/v1/ast/policy_jsonv2.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
17
vendor/github.com/open-policy-agent/opa/v1/ast/string_length.go
generated
vendored
17
vendor/github.com/open-policy-agent/opa/v1/ast/string_length.go
generated
vendored
@@ -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 + " }"
|
||||
|
||||
237
vendor/github.com/open-policy-agent/opa/v1/ast/term.go
generated
vendored
237
vendor/github.com/open-policy-agent/opa/v1/ast/term.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
8
vendor/github.com/open-policy-agent/opa/v1/ast/term_appenders.go
generated
vendored
8
vendor/github.com/open-policy-agent/opa/v1/ast/term_appenders.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
95
vendor/github.com/open-policy-agent/opa/v1/ast/term_json.go
generated
vendored
Normal file
95
vendor/github.com/open-policy-agent/opa/v1/ast/term_json.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
251
vendor/github.com/open-policy-agent/opa/v1/ast/term_jsonv2.go
generated
vendored
Normal file
251
vendor/github.com/open-policy-agent/opa/v1/ast/term_jsonv2.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
5
vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json
generated
vendored
5
vendor/github.com/open-policy-agent/opa/v1/ast/version_index.json
generated
vendored
@@ -845,6 +845,11 @@
|
||||
"Minor": 36,
|
||||
"Patch": 0
|
||||
},
|
||||
"strings.split_n": {
|
||||
"Major": 1,
|
||||
"Minor": 19,
|
||||
"Patch": 0
|
||||
},
|
||||
"substring": {
|
||||
"Major": 0,
|
||||
"Minor": 17,
|
||||
|
||||
157
vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go
generated
vendored
157
vendor/github.com/open-policy-agent/opa/v1/bundle/bundle.go
generated
vendored
@@ -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
|
||||
|
||||
5
vendor/github.com/open-policy-agent/opa/v1/bundle/file.go
generated
vendored
5
vendor/github.com/open-policy-agent/opa/v1/bundle/file.go
generated
vendored
@@ -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)) {
|
||||
|
||||
6
vendor/github.com/open-policy-agent/opa/v1/bundle/manifest.proto
generated
vendored
6
vendor/github.com/open-policy-agent/opa/v1/bundle/manifest.proto
generated
vendored
@@ -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.
|
||||
|
||||
434
vendor/github.com/open-policy-agent/opa/v1/bundle/proto.go
generated
vendored
Normal file
434
vendor/github.com/open-policy-agent/opa/v1/bundle/proto.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
751
vendor/github.com/open-policy-agent/opa/v1/bundle/v1pb/manifest.pb.go
generated
vendored
Normal file
751
vendor/github.com/open-policy-agent/opa/v1/bundle/v1pb/manifest.pb.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
7
vendor/github.com/open-policy-agent/opa/v1/format/format.go
generated
vendored
7
vendor/github.com/open-policy-agent/opa/v1/format/format.go
generated
vendored
@@ -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 <term>` 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)
|
||||
|
||||
340
vendor/github.com/open-policy-agent/opa/v1/ir/proto.go
generated
vendored
Normal file
340
vendor/github.com/open-policy-agent/opa/v1/ir/proto.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
3449
vendor/github.com/open-policy-agent/opa/v1/ir/v1pb/plan.pb.go
generated
vendored
Normal file
3449
vendor/github.com/open-policy-agent/opa/v1/ir/v1pb/plan.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
vendor/github.com/open-policy-agent/opa/v1/keys/keys.go
generated
vendored
3
vendor/github.com/open-policy-agent/opa/v1/keys/keys.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
87
vendor/github.com/open-policy-agent/opa/v1/logging/slog.go
generated
vendored
87
vendor/github.com/open-policy-agent/opa/v1/logging/slog.go
generated
vendored
@@ -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)
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go
generated
vendored
14
vendor/github.com/open-policy-agent/opa/v1/storage/internal/ptr/ptr.go
generated
vendored
@@ -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
|
||||
|
||||
83
vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go
generated
vendored
83
vendor/github.com/open-policy-agent/opa/v1/topdown/aggregates.go
generated
vendored
@@ -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))
|
||||
}
|
||||
|
||||
28
vendor/github.com/open-policy-agent/opa/v1/topdown/arithmetic.go
generated
vendored
28
vendor/github.com/open-policy-agent/opa/v1/topdown/arithmetic.go
generated
vendored
@@ -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)))
|
||||
|
||||
15
vendor/github.com/open-policy-agent/opa/v1/topdown/builtins/builtins.go
generated
vendored
15
vendor/github.com/open-policy-agent/opa/v1/topdown/builtins/builtins.go
generated
vendored
@@ -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.
|
||||
|
||||
57
vendor/github.com/open-policy-agent/opa/v1/topdown/cache.go
generated
vendored
57
vendor/github.com/open-policy-agent/opa/v1/topdown/cache.go
generated
vendored
@@ -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
|
||||
|
||||
68
vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go
generated
vendored
68
vendor/github.com/open-policy-agent/opa/v1/topdown/copypropagation/copypropagation.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
24
vendor/github.com/open-policy-agent/opa/v1/topdown/errors_jsonv2.go
generated
vendored
Normal file
24
vendor/github.com/open-policy-agent/opa/v1/topdown/errors_jsonv2.go
generated
vendored
Normal file
@@ -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))
|
||||
}
|
||||
508
vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go
generated
vendored
508
vendor/github.com/open-policy-agent/opa/v1/topdown/eval.go
generated
vendored
@@ -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
|
||||
|
||||
2
vendor/github.com/open-policy-agent/opa/v1/topdown/query.go
generated
vendored
2
vendor/github.com/open-policy-agent/opa/v1/topdown/query.go
generated
vendored
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
30
vendor/github.com/open-policy-agent/opa/v1/topdown/save.go
generated
vendored
30
vendor/github.com/open-policy-agent/opa/v1/topdown/save.go
generated
vendored
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
105
vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go
generated
vendored
105
vendor/github.com/open-policy-agent/opa/v1/topdown/strings.go
generated
vendored
@@ -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)
|
||||
|
||||
9
vendor/github.com/open-policy-agent/opa/v1/topdown/template.go
generated
vendored
9
vendor/github.com/open-policy-agent/opa/v1/topdown/template.go
generated
vendored
@@ -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"
|
||||
|
||||
58
vendor/github.com/open-policy-agent/opa/v1/topdown/trace.go
generated
vendored
58
vendor/github.com/open-policy-agent/opa/v1/topdown/trace.go
generated
vendored
@@ -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 {
|
||||
|
||||
16
vendor/github.com/open-policy-agent/opa/v1/util/compare.go
generated
vendored
16
vendor/github.com/open-policy-agent/opa/v1/util/compare.go
generated
vendored
@@ -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 {
|
||||
|
||||
30
vendor/github.com/open-policy-agent/opa/v1/util/hashmap.go
generated
vendored
30
vendor/github.com/open-policy-agent/opa/v1/util/hashmap.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
89
vendor/github.com/open-policy-agent/opa/v1/util/performance.go
generated
vendored
89
vendor/github.com/open-policy-agent/opa/v1/util/performance.go
generated
vendored
@@ -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 {
|
||||
|
||||
91
vendor/github.com/open-policy-agent/opa/v1/util/queue.go
generated
vendored
91
vendor/github.com/open-policy-agent/opa/v1/util/queue.go
generated
vendored
@@ -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()
|
||||
}
|
||||
|
||||
2
vendor/github.com/open-policy-agent/opa/v1/version/version.go
generated
vendored
2
vendor/github.com/open-policy-agent/opa/v1/version/version.go
generated
vendored
@@ -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()
|
||||
|
||||
8
vendor/github.com/vektah/gqlparser/v2/ast/definition.go
generated
vendored
8
vendor/github.com/vektah/gqlparser/v2/ast/definition.go
generated
vendored
@@ -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
|
||||
|
||||
6
vendor/github.com/vektah/gqlparser/v2/ast/dumper.go
generated
vendored
6
vendor/github.com/vektah/gqlparser/v2/ast/dumper.go
generated
vendored
@@ -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()
|
||||
|
||||
6
vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go
generated
vendored
6
vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go
generated
vendored
@@ -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 {
|
||||
|
||||
6
vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml
generated
vendored
6
vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml
generated
vendored
@@ -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:
|
||||
|
||||
14
vendor/github.com/vektah/gqlparser/v2/parser/schema.go
generated
vendored
14
vendor/github.com/vektah/gqlparser/v2/parser/schema.go
generated
vendored
@@ -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()
|
||||
|
||||
24
vendor/github.com/vektah/gqlparser/v2/validator/schema.go
generated
vendored
24
vendor/github.com/vektah/gqlparser/v2/validator/schema.go
generated
vendored
@@ -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)
|
||||
|
||||
31
vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml
generated
vendored
31
vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml
generated
vendored
@@ -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: |
|
||||
|
||||
19
vendor/github.com/vektah/gqlparser/v2/validator/vars.go
generated
vendored
19
vendor/github.com/vektah/gqlparser/v2/validator/vars.go
generated
vendored
@@ -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")
|
||||
}
|
||||
|
||||
11
vendor/modules.txt
vendored
11
vendor/modules.txt
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user