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

3
go.mod
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

16
go.sum
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

View File

@@ -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:"-"`
}

View File

@@ -30,7 +30,7 @@ const (
type Directive struct {
Name string
Arguments ArgumentList
Position *Position `dump:"-"`
Position *Position `dump:"-" json:"-"`
// Requires validation
ParentDefinition *Definition

View File

@@ -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:"-"`
}

View File

@@ -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:"-"`
}

View File

@@ -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

View File

@@ -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{} {

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 {

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) {

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)
}

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

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)

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)

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 {

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 {

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:
}
}
}

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()

6
vendor/modules.txt vendored
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