build(deps): bump github.com/open-policy-agent/opa from 1.3.0 to 1.4.2
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 1.3.0 to 1.4.2. - [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.3.0...v1.4.2) --- updated-dependencies: - dependency-name: github.com/open-policy-agent/opa dependency-version: 1.4.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
+4849
File diff suppressed because it is too large
Load Diff
+4849
File diff suppressed because it is too large
Load Diff
+4849
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -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:"-"`
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ const (
|
||||
type Directive struct {
|
||||
Name string
|
||||
Arguments ArgumentList
|
||||
Position *Position `dump:"-"`
|
||||
Position *Position `dump:"-" json:"-"`
|
||||
|
||||
// Requires validation
|
||||
ParentDefinition *Definition
|
||||
|
||||
+4
-4
@@ -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:"-"`
|
||||
}
|
||||
|
||||
+3
-3
@@ -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:"-"`
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+709
-211
File diff suppressed because it is too large
Load Diff
+39
-10
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user