Merge pull request #784 from opencloud-eu/dependabot/go_modules/github.com/open-policy-agent/opa-1.4.2

build(deps): bump github.com/open-policy-agent/opa from 1.3.0 to 1.4.2
This commit is contained in:
Ralf Haferkamp
2025-05-08 08:54:32 +02:00
committed by GitHub
23 changed files with 15675 additions and 360 deletions
+2 -1
View File
@@ -62,7 +62,7 @@ require (
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.37.0
github.com/open-policy-agent/opa v1.3.0
github.com/open-policy-agent/opa v1.4.2
github.com/opencloud-eu/reva/v2 v2.32.0
github.com/orcaman/concurrent-map v1.0.0
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240829135935-80dc00d6f5ea
@@ -167,6 +167,7 @@ require (
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/ristretto v0.2.0 // indirect
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
+8 -8
View File
@@ -257,15 +257,15 @@ github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS3
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.6.0 h1:acOwfOOZ4p1dPRnYzvkVm7rUk2Y21TgPVepCy5dJdFQ=
github.com/dgraph-io/badger/v4 v4.6.0/go.mod h1:KSJ5VTuZNC3Sd+YhvVjk2nYua9UZnnTr/SkXvdtiPgI=
github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y=
github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA=
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.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I=
github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4=
github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM=
github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -858,8 +858,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.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/open-policy-agent/opa v1.3.0 h1:zVvQvQg+9+FuSRBt4LgKNzJwsWl/c85kD5jPozJTydY=
github.com/open-policy-agent/opa v1.3.0/go.mod h1:t9iPNhaplD2qpiBqeudzJtEX3fKHK8zdA29oFvofAHo=
github.com/open-policy-agent/opa v1.4.2 h1:ag4upP7zMsa4WE2p1pwAFeG4Pn3mNwfAx9DLhhJfbjU=
github.com/open-policy-agent/opa v1.4.2/go.mod h1:DNzZPKqKh4U0n0ANxcCVlw8lCSv2c+h5G/3QvSYdWZ8=
github.com/opencloud-eu/reva/v2 v2.32.0 h1:JRWPleHiEl0film95Gkh1iBEhc6eikEsx5FKLfVx6l8=
github.com/opencloud-eu/reva/v2 v2.32.0/go.mod h1:FDhGVC+ZsRRWdC3am4EbuILBtviTbCDVrTUjFECOqvg=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -29,7 +29,7 @@ type Definition struct {
Types []string // union
EnumValues EnumValueList // enum
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
BuiltIn bool `dump:"-"`
}
@@ -65,7 +65,7 @@ type FieldDefinition struct {
DefaultValue *Value // only for input objects
Type *Type
Directives DirectiveList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type ArgumentDefinition struct {
@@ -74,14 +74,14 @@ type ArgumentDefinition struct {
DefaultValue *Value
Type *Type
Directives DirectiveList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type EnumValueDefinition struct {
Description string
Name string
Directives DirectiveList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type DirectiveDefinition struct {
@@ -90,5 +90,5 @@ type DirectiveDefinition struct {
Arguments ArgumentDefinitionList
Locations []DirectiveLocation
IsRepeatable bool
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
@@ -30,7 +30,7 @@ const (
type Directive struct {
Name string
Arguments ArgumentList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
// Requires validation
ParentDefinition *Definition
@@ -3,7 +3,7 @@ package ast
type QueryDocument struct {
Operations OperationList
Fragments FragmentDefinitionList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type SchemaDocument struct {
@@ -12,7 +12,7 @@ type SchemaDocument struct {
Directives DirectiveDefinitionList
Definitions DefinitionList
Extensions DefinitionList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
func (d *SchemaDocument) Merge(other *SchemaDocument) {
@@ -69,11 +69,11 @@ type SchemaDefinition struct {
Description string
Directives DirectiveList
OperationTypes OperationTypeDefinitionList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type OperationTypeDefinition struct {
Operation Operation
Type string
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
@@ -8,7 +8,7 @@ type FragmentSpread struct {
ObjectDefinition *Definition
Definition *FragmentDefinition
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type InlineFragment struct {
@@ -19,7 +19,7 @@ type InlineFragment struct {
// Require validation
ObjectDefinition *Definition
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type FragmentDefinition struct {
@@ -34,5 +34,5 @@ type FragmentDefinition struct {
// Require validation
Definition *Definition
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
@@ -14,7 +14,7 @@ type OperationDefinition struct {
VariableDefinitions VariableDefinitionList
Directives DirectiveList
SelectionSet SelectionSet
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
type VariableDefinition struct {
@@ -22,7 +22,7 @@ type VariableDefinition struct {
Type *Type
DefaultValue *Value
Directives DirectiveList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
// Requires validation
Definition *Definition
@@ -21,7 +21,7 @@ type Field struct {
Arguments ArgumentList
Directives DirectiveList
SelectionSet SelectionSet
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
// Require validation
Definition *FieldDefinition
@@ -31,7 +31,7 @@ type Field struct {
type Argument struct {
Name string
Value *Value
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
func (s *Field) ArgumentMap(vars map[string]interface{}) map[string]interface{} {
+1 -1
View File
@@ -20,7 +20,7 @@ type Type struct {
NamedType string
Elem *Type
NonNull bool
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
func (t *Type) Name() string {
+2 -2
View File
@@ -25,7 +25,7 @@ type Value struct {
Raw string
Children ChildValueList
Kind ValueKind
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
// Require validation
Definition *Definition
@@ -36,7 +36,7 @@ type Value struct {
type ChildValue struct {
Name string
Value *Value
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
}
func (v *Value) Value(vars map[string]interface{}) (interface{}, error) {
+4 -2
View File
@@ -122,7 +122,8 @@ func CapabilitiesForThisVersion(opts ...CapabilitiesOption) *Capabilities {
return strings.Compare(a.Name, b.Name)
})
if co.regoVersion == RegoV0 || co.regoVersion == RegoV0CompatV1 {
switch co.regoVersion {
case RegoV0, RegoV0CompatV1:
for kw := range allFutureKeywords {
f.FutureKeywords = append(f.FutureKeywords, kw)
}
@@ -131,8 +132,9 @@ func CapabilitiesForThisVersion(opts ...CapabilitiesOption) *Capabilities {
FeatureRefHeadStringPrefixes,
FeatureRefHeads,
FeatureRegoV1Import,
FeatureRegoV1, // Included in v0 capabilities to allow v1 bundles in --v0-compatible mode
}
} else {
default:
for kw := range futureKeywords {
f.FutureKeywords = append(f.FutureKeywords, kw)
}
+14 -5
View File
@@ -1511,11 +1511,20 @@ func bundleRegoVersions(bundle *Bundle, regoVersion ast.RegoVersion, usePath boo
if err != nil {
return nil, err
}
// only record the rego version if it's different from one applied globally to the result bundle
if regoVersion != ast.RegoUndefined && v != regoVersion {
// We store the rego version by the absolute path to the bundle root, as this will be the - possibly new - path
// to the module inside the merged bundle.
fileRegoVersions[bundleAbsolutePath(m, usePath)] = v.Int()
// only record the rego version if it's different from the one applied globally to the result bundle
if v != ast.RegoUndefined {
if regoVersion == ast.RegoUndefined {
// We store the rego version by the absolute path to the bundle root, as this will be the - possibly new - path
// to the module inside the merged bundle.
fileRegoVersions[bundleAbsolutePath(m, usePath)] = v.Int()
} else {
vInt := v.Int()
gVInt := regoVersion.Int()
if vInt != gVInt {
fileRegoVersions[bundleAbsolutePath(m, usePath)] = vInt
}
}
}
}
File diff suppressed because it is too large Load Diff
+39 -10
View File
@@ -2019,15 +2019,36 @@ func (e evalFunc) eval(iter unifyIterator) error {
return e.e.saveCall(argCount, e.terms, iter)
}
if e.e.partial() && (e.e.inliningControl.shallow || e.e.inliningControl.Disabled(e.ref, false)) {
// check if the function definitions, or any of the arguments
// contain something unknown
unknown := e.e.unknown(e.ref, e.e.bindings)
for i := 1; !unknown && i <= argCount; i++ {
unknown = e.e.unknown(e.terms[i], e.e.bindings)
if e.e.partial() {
var mustGenerateSupport bool
if defRule := e.ir.Default; defRule != nil {
// The presence of a default func might force us to generate support
if len(defRule.Head.Args) == len(e.terms)-1 {
// The function is called without collecting the result in an output term,
// therefore any successful evaluation of the function is of interest, including the default value ...
if ret := defRule.Head.Value; ret == nil || !ret.Equal(ast.InternedBooleanTerm(false)) {
// ... unless the default value is false,
mustGenerateSupport = true
}
} else {
// The function is called with an output term, therefore any successful evaluation of the function is of interest.
// NOTE: Because of how the compiler rewrites function calls, we can't know if the result value is compared
// to a constant value, so we can't be as clever as we are for rules.
mustGenerateSupport = true
}
}
if unknown {
return e.partialEvalSupport(argCount, iter)
if mustGenerateSupport || e.e.inliningControl.shallow || e.e.inliningControl.Disabled(e.ref, false) {
// check if the function definitions, or any of the arguments
// contain something unknown
unknown := e.e.unknown(e.ref, e.e.bindings)
for i := 1; !unknown && i <= argCount; i++ {
unknown = e.e.unknown(e.terms[i], e.e.bindings)
}
if unknown {
return e.partialEvalSupport(argCount, iter)
}
}
}
@@ -2226,6 +2247,13 @@ func (e evalFunc) partialEvalSupport(declArgsLen int, iter unifyIterator) error
return err
}
}
if e.ir.Default != nil {
err := e.partialEvalSupportRule(e.ir.Default, path)
if err != nil {
return err
}
}
}
if !e.e.saveSupport.Exists(path) { // we haven't saved anything, nothing to call
@@ -2274,8 +2302,9 @@ func (e evalFunc) partialEvalSupportRule(rule *ast.Rule, path ast.Ref) error {
}
e.e.saveSupport.Insert(path, &ast.Rule{
Head: head,
Body: plugged,
Head: head,
Body: plugged,
Default: rule.Default,
})
}
child.traceRedo(rule)
+286 -98
View File
@@ -18,6 +18,7 @@ import (
"github.com/open-policy-agent/opa/v1/ast"
"github.com/open-policy-agent/opa/v1/topdown/builtins"
"github.com/open-policy-agent/opa/v1/topdown/cache"
)
// Parses a GraphQL schema, and returns the GraphQL AST for the schema.
@@ -223,9 +224,11 @@ func pruneIrrelevantGraphQLASTNodes(value ast.Value) ast.Value {
}
// Reports errors from parsing/validation.
func builtinGraphQLParse(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
func builtinGraphQLParse(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
var queryDoc *gqlast.QueryDocument
var schemaDoc *gqlast.SchemaDocument
var schemaASTValue ast.Value
var querySchema ast.Value
var err error
// Parse/translate query if it's a string/object.
@@ -242,42 +245,56 @@ func builtinGraphQLParse(_ BuiltinContext, operands []*ast.Term, iter func(*ast.
return err
}
// Parse/translate schema if it's a string/object.
switch x := operands[1].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return builtins.NewOperandTypeErr(1, x, "string", "object")
}
if err != nil {
return err
}
schemaCacheKey, schema := cacheGetSchema(bctx, operands[1])
schemaASTCacheKey, querySchema := cacheGetSchemaAST(bctx, operands[1])
if schema == nil || querySchema == nil {
// Parse/translate schema if it's a string/object.
switch x := operands[1].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return builtins.NewOperandTypeErr(1, x, "string", "object")
}
if err != nil {
return err
}
// Convert SchemaDoc to Object before validating and converting it to a Schema
// This precludes inclusion of extra definitions from the default GraphQL schema
if querySchema == nil {
schemaASTValue, err = ast.InterfaceToValue(schemaDoc)
if err != nil {
return err
}
querySchema = pruneIrrelevantGraphQLASTNodes(schemaASTValue.(ast.Object))
cacheInsertSchemaAST(bctx, schemaASTCacheKey, querySchema)
}
// Validate the query against the schema, erroring if there's an issue.
if schema == nil {
schema, err = convertSchema(schemaDoc)
if err != nil {
return err
}
cacheInsertSchema(bctx, schemaCacheKey, schema)
}
}
// Transform the ASTs into Objects.
queryASTValue, err := ast.InterfaceToValue(queryDoc)
if err != nil {
return err
}
schemaASTValue, err := ast.InterfaceToValue(schemaDoc)
if err != nil {
return err
}
// Validate the query against the schema, erroring if there's an issue.
schema, err := convertSchema(schemaDoc)
if err != nil {
return err
}
if err := validateQuery(schema, queryDoc); err != nil {
return err
}
// Recursively remove irrelevant AST structures.
queryResult := pruneIrrelevantGraphQLASTNodes(queryASTValue.(ast.Object))
querySchema := pruneIrrelevantGraphQLASTNodes(schemaASTValue.(ast.Object))
// Construct return value.
verified := ast.ArrayTerm(
@@ -289,9 +306,11 @@ func builtinGraphQLParse(_ BuiltinContext, operands []*ast.Term, iter func(*ast.
}
// Returns default value when errors occur.
func builtinGraphQLParseAndVerify(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
func builtinGraphQLParseAndVerify(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
var queryDoc *gqlast.QueryDocument
var schemaDoc *gqlast.SchemaDocument
var schemaASTValue ast.Value
var querySchema ast.Value
var err error
unverified := ast.ArrayTerm(
@@ -314,42 +333,57 @@ func builtinGraphQLParseAndVerify(_ BuiltinContext, operands []*ast.Term, iter f
return iter(unverified)
}
// Parse/translate schema if it's a string/object.
switch x := operands[1].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return iter(unverified)
}
if err != nil {
return iter(unverified)
}
// Transform the ASTs into Objects.
queryASTValue, err := ast.InterfaceToValue(queryDoc)
if err != nil {
return iter(unverified)
}
schemaASTValue, err := ast.InterfaceToValue(schemaDoc)
if err != nil {
return iter(unverified)
schemaCacheKey, schema := cacheGetSchema(bctx, operands[1])
schemaASTCacheKey, querySchema := cacheGetSchemaAST(bctx, operands[1])
if schema == nil || querySchema == nil {
// Parse/translate schema if it's a string/object.
switch x := operands[1].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return iter(unverified)
}
if err != nil {
return iter(unverified)
}
// Convert SchemaDoc to Object before validating and converting it to a Schema
// This precludes inclusion of extra definitions from the default GraphQL schema
if querySchema == nil {
schemaASTValue, err = ast.InterfaceToValue(schemaDoc)
if err != nil {
return iter(unverified)
}
querySchema = pruneIrrelevantGraphQLASTNodes(schemaASTValue.(ast.Object))
cacheInsertSchemaAST(bctx, schemaASTCacheKey, querySchema)
}
if schema == nil {
schema, err = convertSchema(schemaDoc)
if err != nil {
return iter(unverified)
}
cacheInsertSchema(bctx, schemaCacheKey, schema)
}
}
// Validate the query against the schema, erroring if there's an issue.
schema, err := convertSchema(schemaDoc)
if err != nil {
return iter(unverified)
}
if err := validateQuery(schema, queryDoc); err != nil {
return iter(unverified)
}
// Recursively remove irrelevant AST structures.
queryResult := pruneIrrelevantGraphQLASTNodes(queryASTValue.(ast.Object))
querySchema := pruneIrrelevantGraphQLASTNodes(schemaASTValue.(ast.Object))
// Construct return value.
verified := ast.ArrayTerm(
@@ -385,33 +419,43 @@ func builtinGraphQLParseQuery(_ BuiltinContext, operands []*ast.Term, iter func(
return iter(ast.NewTerm(result))
}
func builtinGraphQLParseSchema(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
raw, err := builtins.StringOperand(operands[0].Value, 1)
if err != nil {
return err
func builtinGraphQLParseSchema(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
schemaDocCacheKey, schemaDoc := cacheGetSchemaDoc(bctx, operands[0])
if schemaDoc == nil {
raw, err := builtins.StringOperand(operands[0].Value, 1)
if err != nil {
return err
}
// Get the highly-nested AST struct, along with any errors generated.
schemaDoc, err = parseSchema(string(raw))
if err != nil {
return err
}
// Note SchemaDoc is not validated
cacheInsertSchemaDoc(bctx, schemaDocCacheKey, schemaDoc)
}
// Get the highly-nested AST struct, along with any errors generated.
schema, err := parseSchema(string(raw))
if err != nil {
return err
schemaASTCacheKey, schemaAST := cacheGetSchemaAST(bctx, operands[0])
if schemaAST == nil {
// Transform the AST into an Object.
value, err := ast.InterfaceToValue(schemaDoc)
if err != nil {
return err
}
// Recursively remove irrelevant AST structures.
schemaAST = pruneIrrelevantGraphQLASTNodes(value.(ast.Object))
cacheInsertSchemaAST(bctx, schemaASTCacheKey, schemaAST)
}
// Transform the AST into an Object.
value, err := ast.InterfaceToValue(schema)
if err != nil {
return err
}
// Recursively remove irrelevant AST structures.
result := pruneIrrelevantGraphQLASTNodes(value.(ast.Object))
return iter(ast.NewTerm(result))
return iter(ast.NewTerm(schemaAST))
}
func builtinGraphQLIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
func builtinGraphQLIsValid(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
var queryDoc *gqlast.QueryDocument
var schemaDoc *gqlast.SchemaDocument
var schema *gqlast.Schema
var err error
switch x := operands[0].Value.(type) {
@@ -427,24 +471,29 @@ func builtinGraphQLIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*as
return iter(ast.InternedBooleanTerm(false))
}
switch x := operands[1].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return iter(ast.InternedBooleanTerm(false))
}
if err != nil {
return iter(ast.InternedBooleanTerm(false))
schemaCacheKey, schema := cacheGetSchema(bctx, operands[1])
if schema == nil {
switch x := operands[1].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return iter(ast.InternedBooleanTerm(false))
}
if err != nil {
return iter(ast.InternedBooleanTerm(false))
}
// Validate the query against the schema, erroring if there's an issue.
schema, err = convertSchema(schemaDoc)
if err != nil {
return iter(ast.InternedBooleanTerm(false))
}
cacheInsertSchema(bctx, schemaCacheKey, schema)
}
// Validate the query against the schema, erroring if there's an issue.
schema, err := convertSchema(schemaDoc)
if err != nil {
return iter(ast.InternedBooleanTerm(false))
}
if err := validateQuery(schema, queryDoc); err != nil {
return iter(ast.InternedBooleanTerm(false))
}
@@ -453,29 +502,168 @@ func builtinGraphQLIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*as
return iter(ast.InternedBooleanTerm(true))
}
func builtinGraphQLSchemaIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
var schemaDoc *gqlast.SchemaDocument
func builtinGraphQLSchemaIsValid(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
var err error
switch x := operands[0].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return iter(ast.InternedBooleanTerm(false))
}
if err != nil {
return iter(ast.InternedBooleanTerm(false))
// Schemas are only cached if they are valid
schemaCacheKey, schema := cacheGetSchema(bctx, operands[0])
if schema == nil {
var schemaDoc *gqlast.SchemaDocument
var validatedSchema *gqlast.Schema
switch x := operands[0].Value.(type) {
case ast.String:
schemaDoc, err = parseSchema(string(x))
case ast.Object:
schemaDoc, err = objectToSchemaDocument(x)
default:
// Error if wrong type.
return iter(ast.InternedBooleanTerm(false))
}
if err != nil {
return iter(ast.InternedBooleanTerm(false))
}
// Validate the schema, this determines the result
// and whether there is a schema to cache
validatedSchema, err = convertSchema(schemaDoc)
if err == nil {
cacheInsertSchema(bctx, schemaCacheKey, validatedSchema)
}
}
// Validate the schema, this determines the result
_, err = convertSchema(schemaDoc)
return iter(ast.InternedBooleanTerm(err == nil))
}
// Insert Schema into cache
func cacheInsertSchema(bctx BuiltinContext, key string, schema *gqlast.Schema) {
if bctx.InterQueryBuiltinValueCache == nil || key == "" {
return
}
cacheKey := ast.String(key)
c := bctx.InterQueryBuiltinValueCache.GetCache(gqlCacheName)
if c == nil {
return
}
c.Insert(cacheKey, schema)
}
// Insert SchemaAST into cache
func cacheInsertSchemaAST(bctx BuiltinContext, key string, schemaAST ast.Value) {
if bctx.InterQueryBuiltinValueCache == nil || key == "" {
return
}
cacheKeyAST := ast.String(key)
c := bctx.InterQueryBuiltinValueCache.GetCache(gqlCacheName)
if c == nil {
return
}
c.Insert(cacheKeyAST, schemaAST)
}
// Insert SchemaDocument into cache
func cacheInsertSchemaDoc(bctx BuiltinContext, key string, schemaDoc *gqlast.SchemaDocument) {
if bctx.InterQueryBuiltinValueCache == nil || key == "" {
return
}
cacheKey := ast.String(key)
c := bctx.InterQueryBuiltinValueCache.GetCache(gqlCacheName)
if c == nil {
return
}
c.Insert(cacheKey, schemaDoc)
}
// Returns the cache key and a Schema if this key already exists in the cache
func cacheGetSchema(bctx BuiltinContext, t *ast.Term) (string, *gqlast.Schema) {
if bctx.InterQueryBuiltinValueCache != nil {
if c := bctx.InterQueryBuiltinValueCache.GetCache(gqlCacheName); c != nil {
if key, keyOk := cacheKeyWithPrefix(bctx, t, "gql_schema-"); keyOk {
if val, ok := c.Get(ast.String(key)); ok {
if schema, isSchema := val.(*gqlast.Schema); isSchema {
return key, schema
}
}
return key, nil
}
}
}
return "", nil
}
// Returns the cache key and a SchemaDocument if this key already exists in the cache
// Note: the SchemaDocument is not a validated Schema
func cacheGetSchemaDoc(bctx BuiltinContext, t *ast.Term) (string, *gqlast.SchemaDocument) {
if bctx.InterQueryBuiltinValueCache != nil {
if c := bctx.InterQueryBuiltinValueCache.GetCache(gqlCacheName); c != nil {
if key, keyOk := cacheKeyWithPrefix(bctx, t, "gql_schema_doc-"); keyOk {
if val, ok := c.Get(ast.String(key)); ok {
if schemaDoc, isSchemaDoc := val.(*gqlast.SchemaDocument); isSchemaDoc {
return key, schemaDoc
}
}
return key, nil
}
}
}
return "", nil
}
// Returns the cache key and a SchemaDocument if this key already exists in the cache
// Note: the AST should be pruned
func cacheGetSchemaAST(bctx BuiltinContext, t *ast.Term) (string, ast.Value) {
if bctx.InterQueryBuiltinValueCache != nil {
if c := bctx.InterQueryBuiltinValueCache.GetCache(gqlCacheName); c != nil {
if key, keyOk := cacheKeyWithPrefix(bctx, t, "gql_schema_ast-"); keyOk {
if val, ok := c.Get(ast.String(key)); ok {
if schemaAST, isSchemaAST := val.(ast.Value); isSchemaAST {
return key, schemaAST
}
}
return key, nil
}
}
}
return "", nil
}
// Compute a constant size key for use with the cache
func cacheKeyWithPrefix(bctx BuiltinContext, t *ast.Term, prefix string) (string, bool) {
var cacheKey ast.String
var ok = false
if bctx.InterQueryBuiltinValueCache != nil {
switch t.Value.(type) {
case ast.String:
err := builtinCryptoSha256(bctx, []*ast.Term{t}, func(term *ast.Term) error {
cacheKey = term.Value.(ast.String)
return nil
})
ok = (len(cacheKey) > 0) && (err == nil)
case ast.Object:
objTerm := ast.StringTerm(t.String())
err := builtinCryptoSha256(bctx, []*ast.Term{objTerm}, func(term *ast.Term) error {
cacheKey = term.Value.(ast.String)
return nil
})
ok = (len(cacheKey) > 0) && (err == nil)
default:
ok = false
}
}
return prefix + string(cacheKey), ok
}
const gqlCacheName = "graphql"
func init() {
var defaultCacheEntries int = 10
var graphqlCacheConfig = cache.NamedValueCacheConfig{
MaxNumEntries: &defaultCacheEntries,
}
cache.RegisterDefaultInterQueryBuiltinValueCacheConfig(gqlCacheName, &graphqlCacheConfig)
RegisterBuiltinFunc(ast.GraphQLParse.Name, builtinGraphQLParse)
RegisterBuiltinFunc(ast.GraphQLParseAndVerify.Name, builtinGraphQLParseAndVerify)
RegisterBuiltinFunc(ast.GraphQLParseQuery.Name, builtinGraphQLParseQuery)
+1 -1
View File
@@ -344,7 +344,7 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support []
if q.seed == nil {
q.seed = rand.Reader
}
if !q.time.IsZero() {
if q.time.IsZero() {
q.time = time.Now()
}
if q.metrics == nil {
+8 -1
View File
@@ -443,7 +443,14 @@ func builtinUpper(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) e
return err
}
return iter(ast.StringTerm(strings.ToUpper(string(s))))
arg := string(s)
upp := strings.ToUpper(arg)
if arg == upp {
return iter(operands[0])
}
return iter(ast.StringTerm(upp))
}
func builtinSplit(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
+32
View File
@@ -0,0 +1,32 @@
package util
import (
"github.com/open-policy-agent/opa/v1/metrics"
)
// This prevents getting blocked forever writing to a full buffer, in case another routine fills the last space.
// Retrying maxEventRetry times to drop the oldest event. Dropping the incoming event if there still isn't room.
const maxEventRetry = 1000
// PushFIFO pushes data into a buffered channel without blocking when full, making room by dropping the oldest data.
// An optional metric can be recorded when data is dropped.
func PushFIFO[T any](buffer chan T, data T, metrics metrics.Metrics, metricName string) {
for range maxEventRetry {
// non-blocking send to the buffer, to prevent blocking if buffer is full so room can be made.
select {
case buffer <- data:
return
default:
}
// non-blocking drop from the buffer to make room for incoming event
select {
case <-buffer:
if metrics != nil && metricName != "" {
metrics.Counter(metricName).Incr()
}
default:
}
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ import (
)
// Version is the canonical version of OPA.
var Version = "1.3.0"
var Version = "1.4.2"
// GoVersion is the version of Go this was built with
var GoVersion = runtime.Version()
+4 -2
View File
@@ -371,6 +371,8 @@ github.com/desertbit/timer
github.com/dgraph-io/ristretto
github.com/dgraph-io/ristretto/z
github.com/dgraph-io/ristretto/z/simd
# github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da
## explicit
# github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
## explicit
github.com/dgryski/go-rendezvous
@@ -1098,8 +1100,8 @@ 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.3.0
## explicit; go 1.23.6
# github.com/open-policy-agent/opa v1.4.2
## explicit; go 1.23.8
github.com/open-policy-agent/opa/ast
github.com/open-policy-agent/opa/ast/json
github.com/open-policy-agent/opa/bundle