mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
Modernize fixes and some string building improvements (#8993)
Mostly automated fixes from running: ``` go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest --fix ./... ``` But carefully reviewed, and several fixes reverted as they looked like they potentially could be less performant, and in a few cases due to bugs in the analyzer that changed semantics of the code. Will report these upstream. Mostly good fixes though! Signed-off-by: Anders Eknert <anders.eknert@apple.com>
This commit is contained in:
@@ -21,6 +21,10 @@ linters:
|
|||||||
- usetesting
|
- usetesting
|
||||||
# - gosec # too many false positives
|
# - gosec # too many false positives
|
||||||
settings:
|
settings:
|
||||||
|
errcheck:
|
||||||
|
exclude-functions:
|
||||||
|
- github.com/open-policy-agent/opa/v1/util.WriteAppender
|
||||||
|
- github.com/open-policy-agent/opa/v1/util.WriteInt
|
||||||
gocritic:
|
gocritic:
|
||||||
enabled-checks:
|
enabled-checks:
|
||||||
# NOTE that these are rules enabled in addition to the default set
|
# NOTE that these are rules enabled in addition to the default set
|
||||||
|
|||||||
+2
-4
@@ -852,9 +852,7 @@ main contains "hello" if {
|
|||||||
// runExec to hang indefinitely. WithContext allows us to cancel the context
|
// runExec to hang indefinitely. WithContext allows us to cancel the context
|
||||||
// when we have the required errors logged.
|
// when we have the required errors logged.
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
err := runExecWithContext(ctx, params)
|
err := runExecWithContext(ctx, params)
|
||||||
// we cancelled the context, so we expect that error
|
// we cancelled the context, so we expect that error
|
||||||
if err != nil && err.Error() != "context canceled" {
|
if err != nil && err.Error() != "context canceled" {
|
||||||
@@ -868,7 +866,7 @@ main contains "hello" if {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
test.EventuallyOrFatal(t, 5*time.Second, func() bool {
|
test.EventuallyOrFatal(t, 5*time.Second, func() bool {
|
||||||
for _, expErr := range tc.expErrs {
|
for _, expErr := range tc.expErrs {
|
||||||
|
|||||||
+2
-3
@@ -9,6 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
goRuntime "runtime"
|
goRuntime "runtime"
|
||||||
@@ -125,9 +126,7 @@ func opaTest(args []string, testParams testCommandParams) int {
|
|||||||
if err == nil && testParams.coverage {
|
if err == nil && testParams.coverage {
|
||||||
modules = make(map[string]*ast.Module)
|
modules = make(map[string]*ast.Module)
|
||||||
for name, b := range bundles {
|
for name, b := range bundles {
|
||||||
for k, v := range b.ParsedModules(name) {
|
maps.Copy(modules, b.ParsedModules(name))
|
||||||
modules[k] = v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ func reflectSchema() ([]byte, error) {
|
|||||||
// DisallowUnknownFields), and embedders rely on this to attach custom
|
// DisallowUnknownFields), and embedders rely on this to attach custom
|
||||||
// configuration alongside the documented fields. Keep the schema in
|
// configuration alongside the documented fields. Keep the schema in
|
||||||
// step with that contract; sub-records like WasmResolver stay strict.
|
// step with that contract; sub-records like WasmResolver stay strict.
|
||||||
b.AllowAdditionalProperties(reflect.TypeOf(bundle.Manifest{}))
|
b.AllowAdditionalProperties(reflect.TypeFor[bundle.Manifest]())
|
||||||
rootRef, err := b.AddStruct(reflect.TypeOf(bundle.Manifest{}))
|
rootRef, err := b.AddStruct(reflect.TypeFor[bundle.Manifest]())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func reflectSchema() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rootRef, err := b.AddStruct(reflect.TypeOf(ir.Policy{}))
|
rootRef, err := b.AddStruct(reflect.TypeFor[ir.Policy]())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -74,13 +74,13 @@ func planResolver(b *genjsonschema.Builder, t reflect.Type) (any, bool, error) {
|
|||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
switch {
|
switch {
|
||||||
case t == reflect.TypeOf(ir.Operand{}):
|
case t == reflect.TypeFor[ir.Operand]():
|
||||||
ref, err := addOperand(b)
|
ref, err := addOperand(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
return genjsonschema.Map("$ref", ref), true, nil
|
return genjsonschema.Map("$ref", ref), true, nil
|
||||||
case t == reflect.TypeOf(ir.Block{}):
|
case t == reflect.TypeFor[ir.Block]():
|
||||||
ref, err := addBlock(b)
|
ref, err := addBlock(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@@ -96,13 +96,13 @@ func planResolver(b *genjsonschema.Builder, t reflect.Type) (any, bool, error) {
|
|||||||
}
|
}
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
switch {
|
switch {
|
||||||
case t == reflect.TypeOf((*ir.Stmt)(nil)).Elem():
|
case t == reflect.TypeFor[ir.Stmt]():
|
||||||
ref, err := addStmtUnion(b)
|
ref, err := addStmtUnion(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
return genjsonschema.Map("$ref", ref), true, nil
|
return genjsonschema.Map("$ref", ref), true, nil
|
||||||
case t == reflect.TypeOf((*ir.Val)(nil)).Elem():
|
case t == reflect.TypeFor[ir.Val]():
|
||||||
ref, err := addValUnion(b)
|
ref, err := addValUnion(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -327,10 +328,8 @@ func MakeNullable(schema any) any {
|
|||||||
out[i] = Entry{"type", []string{v, "null"}}
|
out[i] = Entry{"type", []string{v, "null"}}
|
||||||
return out
|
return out
|
||||||
case []string:
|
case []string:
|
||||||
for _, s := range v {
|
if slices.Contains(v, "null") {
|
||||||
if s == "null" {
|
return m
|
||||||
return m
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
out := cloneOrderedMap(m)
|
out := cloneOrderedMap(m)
|
||||||
widened := make([]string, len(v)+1)
|
widened := make([]string, len(v)+1)
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ type primitives struct {
|
|||||||
|
|
||||||
func TestReflectStructPrimitives(t *testing.T) {
|
func TestReflectStructPrimitives(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(primitives{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[primitives]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -196,7 +196,7 @@ type omitFields struct {
|
|||||||
|
|
||||||
func TestOmitEmptyAndNullability(t *testing.T) {
|
func TestOmitEmptyAndNullability(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(omitFields{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[omitFields]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -216,7 +216,7 @@ type withMaps struct {
|
|||||||
|
|
||||||
func TestMapHandling(t *testing.T) {
|
func TestMapHandling(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(withMaps{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[withMaps]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -238,7 +238,7 @@ type outer struct {
|
|||||||
|
|
||||||
func TestNestedStructsAndPointer(t *testing.T) {
|
func TestNestedStructsAndPointer(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(outer{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[outer]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -260,7 +260,7 @@ type embedder struct {
|
|||||||
|
|
||||||
func TestEmbeddedStructFieldsArePromoted(t *testing.T) {
|
func TestEmbeddedStructFieldsArePromoted(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(embedder{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[embedder]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -281,13 +281,13 @@ type withInterface struct {
|
|||||||
|
|
||||||
func TestResolverInterceptsTypes(t *testing.T) {
|
func TestResolverInterceptsTypes(t *testing.T) {
|
||||||
resolver := func(_ *Builder, t reflect.Type) (any, bool, error) {
|
resolver := func(_ *Builder, t reflect.Type) (any, bool, error) {
|
||||||
if t == reflect.TypeOf((*marker)(nil)).Elem() {
|
if t == reflect.TypeFor[marker]() {
|
||||||
return OrderedMap{{"description", "opaque marker"}}, true, nil
|
return OrderedMap{{"description", "opaque marker"}}, true, nil
|
||||||
}
|
}
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
b := NewBuilder(resolver)
|
b := NewBuilder(resolver)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(withInterface{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[withInterface]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -305,13 +305,13 @@ func TestResolverResultIsNullableWhenFieldCanBeNull(t *testing.T) {
|
|||||||
// resolver's bare schema gets wrapped in a nullable form so the
|
// resolver's bare schema gets wrapped in a nullable form so the
|
||||||
// generated schema admits null in addition to the resolved shape.
|
// generated schema admits null in addition to the resolved shape.
|
||||||
resolver := func(_ *Builder, t reflect.Type) (any, bool, error) {
|
resolver := func(_ *Builder, t reflect.Type) (any, bool, error) {
|
||||||
if t == reflect.TypeOf((*marker)(nil)).Elem() {
|
if t == reflect.TypeFor[marker]() {
|
||||||
return OrderedMap{{"description", "opaque marker"}}, true, nil
|
return OrderedMap{{"description", "opaque marker"}}, true, nil
|
||||||
}
|
}
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
b := NewBuilder(resolver)
|
b := NewBuilder(resolver)
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(withRequiredInterface{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[withRequiredInterface]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -323,7 +323,7 @@ func TestResolverResultIsNullableWhenFieldCanBeNull(t *testing.T) {
|
|||||||
|
|
||||||
func TestInterfaceWithoutResolverErrors(t *testing.T) {
|
func TestInterfaceWithoutResolverErrors(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
_, err := b.AddStruct(reflect.TypeOf(withInterface{}))
|
_, err := b.AddStruct(reflect.TypeFor[withInterface]())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected error for unresolved non-empty interface")
|
t.Fatal("expected error for unresolved non-empty interface")
|
||||||
}
|
}
|
||||||
@@ -334,13 +334,13 @@ func TestResolverHandledWithNilSchemaErrors(t *testing.T) {
|
|||||||
// otherwise the field would marshal as JSON null, silently corrupting
|
// otherwise the field would marshal as JSON null, silently corrupting
|
||||||
// output.
|
// output.
|
||||||
resolver := func(_ *Builder, t reflect.Type) (any, bool, error) {
|
resolver := func(_ *Builder, t reflect.Type) (any, bool, error) {
|
||||||
if t == reflect.TypeOf((*marker)(nil)).Elem() {
|
if t == reflect.TypeFor[marker]() {
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
b := NewBuilder(resolver)
|
b := NewBuilder(resolver)
|
||||||
_, err := b.AddStruct(reflect.TypeOf(withInterface{}))
|
_, err := b.AddStruct(reflect.TypeFor[withInterface]())
|
||||||
if err == nil || !strings.Contains(err.Error(), "nil schema") {
|
if err == nil || !strings.Contains(err.Error(), "nil schema") {
|
||||||
t.Fatalf("expected nil-schema error, got: %v", err)
|
t.Fatalf("expected nil-schema error, got: %v", err)
|
||||||
}
|
}
|
||||||
@@ -386,7 +386,7 @@ type unsupportedKind struct {
|
|||||||
|
|
||||||
func TestUnsupportedKindReportsFieldPath(t *testing.T) {
|
func TestUnsupportedKindReportsFieldPath(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
_, err := b.AddStruct(reflect.TypeOf(unsupportedKind{}))
|
_, err := b.AddStruct(reflect.TypeFor[unsupportedKind]())
|
||||||
if err == nil || !strings.Contains(err.Error(), "unsupportedKind.Ch") {
|
if err == nil || !strings.Contains(err.Error(), "unsupportedKind.Ch") {
|
||||||
t.Fatalf("expected error mentioning field path, got: %v", err)
|
t.Fatalf("expected error mentioning field path, got: %v", err)
|
||||||
}
|
}
|
||||||
@@ -398,7 +398,7 @@ type intKeyMap struct {
|
|||||||
|
|
||||||
func TestNonStringMapKeyErrors(t *testing.T) {
|
func TestNonStringMapKeyErrors(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
_, err := b.AddStruct(reflect.TypeOf(intKeyMap{}))
|
_, err := b.AddStruct(reflect.TypeFor[intKeyMap]())
|
||||||
if err == nil || !strings.Contains(err.Error(), "map key") {
|
if err == nil || !strings.Contains(err.Error(), "map key") {
|
||||||
t.Fatalf("expected map-key error, got: %v", err)
|
t.Fatalf("expected map-key error, got: %v", err)
|
||||||
}
|
}
|
||||||
@@ -406,8 +406,8 @@ func TestNonStringMapKeyErrors(t *testing.T) {
|
|||||||
|
|
||||||
func TestAllowAdditionalPropertiesSkipsClosedClause(t *testing.T) {
|
func TestAllowAdditionalPropertiesSkipsClosedClause(t *testing.T) {
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
b.AllowAdditionalProperties(reflect.TypeOf(primitives{}))
|
b.AllowAdditionalProperties(reflect.TypeFor[primitives]())
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(primitives{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[primitives]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
@@ -416,8 +416,8 @@ func TestAllowAdditionalPropertiesSkipsClosedClause(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// Sanity check: opting in by pointer type also works.
|
// Sanity check: opting in by pointer type also works.
|
||||||
b2 := NewBuilder(nil)
|
b2 := NewBuilder(nil)
|
||||||
b2.AllowAdditionalProperties(reflect.TypeOf(&primitives{}))
|
b2.AllowAdditionalProperties(reflect.TypeFor[*primitives]())
|
||||||
if _, err := b2.AddStruct(reflect.TypeOf(primitives{})); err != nil {
|
if _, err := b2.AddStruct(reflect.TypeFor[primitives]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got2 := mustMarshal(t, b2.DefsOrdered())
|
got2 := mustMarshal(t, b2.DefsOrdered())
|
||||||
@@ -431,8 +431,8 @@ func TestAllowAdditionalPropertiesIsPerType(t *testing.T) {
|
|||||||
// `inner` def — additionalProperties:false is the right default for
|
// `inner` def — additionalProperties:false is the right default for
|
||||||
// sub-records.
|
// sub-records.
|
||||||
b := NewBuilder(nil)
|
b := NewBuilder(nil)
|
||||||
b.AllowAdditionalProperties(reflect.TypeOf(outer{}))
|
b.AllowAdditionalProperties(reflect.TypeFor[outer]())
|
||||||
if _, err := b.AddStruct(reflect.TypeOf(outer{})); err != nil {
|
if _, err := b.AddStruct(reflect.TypeFor[outer]()); err != nil {
|
||||||
t.Fatalf("AddStruct: %v", err)
|
t.Fatalf("AddStruct: %v", err)
|
||||||
}
|
}
|
||||||
got := mustMarshal(t, b.DefsOrdered())
|
got := mustMarshal(t, b.DefsOrdered())
|
||||||
|
|||||||
@@ -32,11 +32,8 @@ type SchemaLoader struct {
|
|||||||
|
|
||||||
// NewSchemaLoader creates a new NewSchemaLoader
|
// NewSchemaLoader creates a new NewSchemaLoader
|
||||||
func NewSchemaLoader() *SchemaLoader {
|
func NewSchemaLoader() *SchemaLoader {
|
||||||
|
|
||||||
ps := &SchemaLoader{
|
ps := &SchemaLoader{
|
||||||
pool: &schemaPool{
|
pool: &schemaPool{schemaPoolDocuments: make(map[string]*schemaPoolDocument)},
|
||||||
schemaPoolDocuments: make(map[string]*schemaPoolDocument),
|
|
||||||
},
|
|
||||||
AutoDetect: true,
|
AutoDetect: true,
|
||||||
Validate: false,
|
Validate: false,
|
||||||
Draft: Hybrid,
|
Draft: Hybrid,
|
||||||
@@ -46,15 +43,10 @@ func NewSchemaLoader() *SchemaLoader {
|
|||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sl *SchemaLoader) validateMetaschema(documentNode any) error {
|
func (sl *SchemaLoader) validateMetaschema(documentNode any) (err error) {
|
||||||
|
var schema string
|
||||||
var (
|
|
||||||
schema string
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if sl.AutoDetect {
|
if sl.AutoDetect {
|
||||||
schema, _, err = parseSchemaURL(documentNode)
|
if schema, _, err = parseSchemaURL(documentNode); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +63,6 @@ func (sl *SchemaLoader) validateMetaschema(documentNode any) error {
|
|||||||
sl.Validate = false
|
sl.Validate = false
|
||||||
|
|
||||||
metaSchema, err := sl.Compile(NewReferenceLoader(schema))
|
metaSchema, err := sl.Compile(NewReferenceLoader(schema))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -84,7 +75,7 @@ func (sl *SchemaLoader) validateMetaschema(documentNode any) error {
|
|||||||
var res bytes.Buffer
|
var res bytes.Buffer
|
||||||
for _, err := range result.Errors() {
|
for _, err := range result.Errors() {
|
||||||
res.WriteString(err.String())
|
res.WriteString(err.String())
|
||||||
res.WriteString("\n")
|
res.WriteByte('\n')
|
||||||
}
|
}
|
||||||
return errors.New(res.String())
|
return errors.New(res.String())
|
||||||
}
|
}
|
||||||
@@ -99,7 +90,6 @@ func (sl *SchemaLoader) AddSchemas(loaders ...JSONLoader) error {
|
|||||||
|
|
||||||
for _, loader := range loaders {
|
for _, loader := range loaders {
|
||||||
doc, err := loader.LoadJSON()
|
doc, err := loader.LoadJSON()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -122,15 +112,12 @@ func (sl *SchemaLoader) AddSchemas(loaders ...JSONLoader) error {
|
|||||||
|
|
||||||
// AddSchema adds a schema under the provided URL to the schema cache
|
// AddSchema adds a schema under the provided URL to the schema cache
|
||||||
func (sl *SchemaLoader) AddSchema(url string, loader JSONLoader) error {
|
func (sl *SchemaLoader) AddSchema(url string, loader JSONLoader) error {
|
||||||
|
|
||||||
ref, err := gojsonreference.NewJsonReference(url)
|
ref, err := gojsonreference.NewJsonReference(url)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
doc, err := loader.LoadJSON()
|
doc, err := loader.LoadJSON()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -146,9 +133,7 @@ func (sl *SchemaLoader) AddSchema(url string, loader JSONLoader) error {
|
|||||||
|
|
||||||
// Compile loads and compiles a schema
|
// Compile loads and compiles a schema
|
||||||
func (sl *SchemaLoader) Compile(rootSchema JSONLoader) (*Schema, error) {
|
func (sl *SchemaLoader) Compile(rootSchema JSONLoader) (*Schema, error) {
|
||||||
|
|
||||||
ref, err := rootSchema.JSONReference()
|
ref, err := rootSchema.JSONReference()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -170,14 +155,12 @@ func (sl *SchemaLoader) Compile(rootSchema JSONLoader) (*Schema, error) {
|
|||||||
doc = spd.Document
|
doc = spd.Document
|
||||||
} else {
|
} else {
|
||||||
// Load JSON directly
|
// Load JSON directly
|
||||||
doc, err = rootSchema.LoadJSON()
|
if doc, err = rootSchema.LoadJSON(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// References need only be parsed if loading JSON directly
|
// References need only be parsed if loading JSON directly
|
||||||
// as pool.GetDocument already does this for us if loading by reference
|
// as pool.GetDocument already does this for us if loading by reference
|
||||||
err = sl.pool.parseReferences(doc, ref, true)
|
if err = sl.pool.parseReferences(doc, ref, true); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,8 +182,7 @@ func (sl *SchemaLoader) Compile(rootSchema JSONLoader) (*Schema, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.parse(doc, draft)
|
if err = d.parse(doc, draft); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func (*prettyFormatter) Format(e *logrus.Entry) ([]byte, error) {
|
|||||||
b.WriteString(" = ")
|
b.WriteString(" = ")
|
||||||
}
|
}
|
||||||
b.WriteString(stringVal)
|
b.WriteString(stringVal)
|
||||||
b.WriteString("\n")
|
b.WriteByte('\n')
|
||||||
}
|
}
|
||||||
b.WriteByte('\n')
|
b.WriteByte('\n')
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
|
|||||||
@@ -100,14 +100,6 @@ func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// goodFunc reports whether the function or method has the right result signature.
|
||||||
func goodFunc(name string, typ reflect.Type) error {
|
func goodFunc(name string, typ reflect.Type) error {
|
||||||
// We allow functions with 1 result or 2 results where the second is an error.
|
// We allow functions with 1 result or 2 results where the second is an error.
|
||||||
|
|||||||
@@ -175,9 +175,9 @@ func (t *Template) Delims(left, right string) *Template {
|
|||||||
func (t *Template) Funcs(funcMap FuncMap) *Template {
|
func (t *Template) Funcs(funcMap FuncMap) *Template {
|
||||||
t.init()
|
t.init()
|
||||||
t.muFuncs.Lock()
|
t.muFuncs.Lock()
|
||||||
defer t.muFuncs.Unlock()
|
|
||||||
addValueFuncs(t.execFuncs, funcMap)
|
addValueFuncs(t.execFuncs, funcMap)
|
||||||
addFuncs(t.parseFuncs, funcMap)
|
maps.Copy(t.parseFuncs, funcMap)
|
||||||
|
t.muFuncs.Unlock()
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,48 +28,37 @@ func getHost(r *http.Request) string {
|
|||||||
// If Host is an IPv6 literal with a port number, Hostname returns the
|
// If Host is an IPv6 literal with a port number, Hostname returns the
|
||||||
// IPv6 literal without the square brackets. IPv6 literals may include
|
// IPv6 literal without the square brackets. IPv6 literals may include
|
||||||
// a zone identifier.
|
// a zone identifier.
|
||||||
//
|
|
||||||
// Copied from the Go 1.8 standard library (net/url)
|
|
||||||
func stripPort(hostport string) string {
|
func stripPort(hostport string) string {
|
||||||
colon := strings.IndexByte(hostport, ':')
|
before, _, ok := strings.Cut(hostport, ":")
|
||||||
if colon == -1 {
|
if !ok {
|
||||||
return hostport
|
return hostport
|
||||||
}
|
}
|
||||||
if i := strings.IndexByte(hostport, ']'); i != -1 {
|
if before, _, ok := strings.Cut(hostport, "]"); ok {
|
||||||
return strings.TrimPrefix(hostport[:i], "[")
|
return strings.TrimPrefix(before, "[")
|
||||||
}
|
}
|
||||||
return hostport[:colon]
|
return before
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port returns the port part of u.Host, without the leading colon.
|
// Port returns the port part of u.Host, without the leading colon.
|
||||||
// If u.Host doesn't contain a port, Port returns an empty string.
|
// If u.Host doesn't contain a port, Port returns an empty string.
|
||||||
//
|
|
||||||
// Copied from the Go 1.8 standard library (net/url)
|
|
||||||
func portOnly(hostport string) string {
|
func portOnly(hostport string) string {
|
||||||
colon := strings.IndexByte(hostport, ':')
|
_, after, ok := strings.Cut(hostport, ":")
|
||||||
if colon == -1 {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if i := strings.Index(hostport, "]:"); i != -1 {
|
if _, after, ok := strings.Cut(hostport, "]:"); ok {
|
||||||
return hostport[i+len("]:"):]
|
return after
|
||||||
}
|
}
|
||||||
if strings.Contains(hostport, "]") {
|
if strings.Contains(hostport, "]") {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return hostport[colon+len(":"):]
|
return after
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the specified URI is using the standard port
|
// Returns true if the specified URI is using the standard port
|
||||||
// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
|
// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
|
||||||
func isDefaultPort(scheme, port string) bool {
|
func isDefaultPort(scheme, port string) bool {
|
||||||
if port == "" {
|
return port == "" ||
|
||||||
return true
|
(strings.EqualFold(scheme, "http") && port == "80") ||
|
||||||
}
|
(strings.EqualFold(scheme, "https") && port == "443")
|
||||||
|
|
||||||
lowerCaseScheme := strings.ToLower(scheme)
|
|
||||||
if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package version
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/open-policy-agent/opa/v1/storage"
|
"github.com/open-policy-agent/opa/v1/storage"
|
||||||
@@ -19,7 +18,6 @@ var versionPath = storage.MustParsePath("/system/version")
|
|||||||
// Write the build version information into storage. This makes the
|
// Write the build version information into storage. This makes the
|
||||||
// version information available to the REPL and the HTTP server.
|
// version information available to the REPL and the HTTP server.
|
||||||
func Write(ctx context.Context, store storage.Store, txn storage.Transaction) error {
|
func Write(ctx context.Context, store storage.Store, txn storage.Transaction) error {
|
||||||
|
|
||||||
if err := storage.MakeDir(ctx, store, txn, versionPath); err != nil {
|
if err := storage.MakeDir(ctx, store, txn, versionPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -33,4 +31,4 @@ func Write(ctx context.Context, store storage.Store, txn storage.Transaction) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UserAgent defines the current OPA instances User-Agent default header value.
|
// UserAgent defines the current OPA instances User-Agent default header value.
|
||||||
var UserAgent = fmt.Sprintf("Open-Policy-Agent/%s (%s, %s)", version.Version, runtime.GOOS, runtime.GOARCH)
|
var UserAgent = "Open-Policy-Agent/" + version.Version + " (" + runtime.GOOS + ", " + runtime.GOARCH + ")"
|
||||||
|
|||||||
@@ -135,20 +135,14 @@ func (d *builtinDispatcher) opaAbort(_ context.Context, addr int32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *builtinDispatcher) opaPrintln(_ context.Context, addr int32) {
|
func (d *builtinDispatcher) opaPrintln(_ context.Context, addr int32) {
|
||||||
uaddr := uint32(addr)
|
uaddr, size := uint32(addr), d.mem.Size()
|
||||||
size := d.mem.Size()
|
if uaddr < size {
|
||||||
if uaddr >= size {
|
if data, ok := d.mem.Read(uaddr, size-uaddr); ok {
|
||||||
return
|
if before, _, ok := bytes.Cut(data, []byte{0}); ok {
|
||||||
|
os.Stderr.Write(append(before, '\n'))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
data, ok := d.mem.Read(uaddr, size-uaddr)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n := bytes.IndexByte(data, 0)
|
|
||||||
if n < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Fprintln(os.Stderr, string(data[:n]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *builtinDispatcher) opaBuiltin0(ctx context.Context, id, _ int32) int32 {
|
func (d *builtinDispatcher) opaBuiltin0(ctx context.Context, id, _ int32) int32 {
|
||||||
@@ -229,11 +223,11 @@ func (d *builtinDispatcher) fromWasmValue(ctx context.Context, addr int32) (*ast
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("invalid serialized value address")
|
return nil, errors.New("invalid serialized value address")
|
||||||
}
|
}
|
||||||
n := bytes.IndexByte(data, 0)
|
before, _, ok := bytes.Cut(data, []byte{0})
|
||||||
if n < 0 {
|
if !ok {
|
||||||
return nil, errors.New("unterminated serialized value")
|
return nil, errors.New("unterminated serialized value")
|
||||||
}
|
}
|
||||||
return ast.ParseTerm(string(data[:n]))
|
return ast.ParseTerm(string(before))
|
||||||
}
|
}
|
||||||
|
|
||||||
// toWasmValue serialises term, writes the bytes into Wasm memory via
|
// toWasmValue serialises term, writes the bytes into Wasm memory via
|
||||||
|
|||||||
@@ -305,10 +305,7 @@ func (i *VM) Eval(ctx context.Context,
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("read result from memory at %d", resultAddr)
|
return nil, fmt.Errorf("read result from memory at %d", resultAddr)
|
||||||
}
|
}
|
||||||
n := bytes.IndexByte(data, 0)
|
n := max(bytes.IndexByte(data, 0), 0)
|
||||||
if n < 0 {
|
|
||||||
n = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip free'ing input and result JSON as the heap will be reset next round anyway.
|
// Skip free'ing input and result JSON as the heap will be reset next round anyway.
|
||||||
return data[:n], nil
|
return data[:n], nil
|
||||||
@@ -386,10 +383,7 @@ func (i *VM) evalCompat(ctx context.Context,
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("read result from memory at %d", serialized)
|
return nil, fmt.Errorf("read result from memory at %d", serialized)
|
||||||
}
|
}
|
||||||
n := bytes.IndexByte(data, 0)
|
n := max(bytes.IndexByte(data, 0), 0)
|
||||||
if n < 0 {
|
|
||||||
n = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics.Timer("wasm_vm_eval_prepare_result").Stop()
|
metrics.Timer("wasm_vm_eval_prepare_result").Stop()
|
||||||
return data[:n], nil
|
return data[:n], nil
|
||||||
@@ -593,10 +587,7 @@ func (i *VM) fromRegoJSON(ctx context.Context, addr int32, free bool) (any, erro
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("read memory at %d", serialized)
|
return nil, fmt.Errorf("read memory at %d", serialized)
|
||||||
}
|
}
|
||||||
n := bytes.IndexByte(data, 0)
|
n := max(bytes.IndexByte(data, 0), 0)
|
||||||
if n < 0 {
|
|
||||||
n = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the result into go types.
|
// Parse the result into go types.
|
||||||
decoder := json.NewDecoder(bytes.NewReader(data[:n]))
|
decoder := json.NewDecoder(bytes.NewReader(data[:n]))
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !opa_wasm && !generate
|
//go:build !opa_wasm && !generate
|
||||||
// +build !opa_wasm,!generate
|
|
||||||
|
|
||||||
package capabilities
|
package capabilities
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -4278,13 +4278,13 @@ func (n *ModuleTreeNode) DepthFirst(f func(*ModuleTreeNode) bool) {
|
|||||||
// TreeNode represents a node in the rule tree. The rule tree is keyed by
|
// TreeNode represents a node in the rule tree. The rule tree is keyed by
|
||||||
// rule path.
|
// rule path.
|
||||||
type TreeNode struct {
|
type TreeNode struct {
|
||||||
|
Values []*Rule
|
||||||
|
Sorted []Value
|
||||||
Key Value
|
Key Value
|
||||||
External *ExternalIndex
|
External *ExternalIndex
|
||||||
Values []*Rule
|
|
||||||
Children map[Value]*TreeNode
|
|
||||||
Sorted []Value
|
|
||||||
Hide bool
|
|
||||||
Index RuleIndex
|
Index RuleIndex
|
||||||
|
Children map[Value]*TreeNode
|
||||||
|
Hide bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *TreeNode) String() string {
|
func (n *TreeNode) String() string {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -275,13 +276,7 @@ func TestCompilerStageSkippingWithAfterStages(t *testing.T) {
|
|||||||
c.Compile(map[string]*Module{})
|
c.Compile(map[string]*Module{})
|
||||||
|
|
||||||
stages := c.StagesToRun()
|
stages := c.StagesToRun()
|
||||||
found := false
|
found := slices.Contains(stages, "CustomAfterCheckTypes")
|
||||||
for _, s := range stages {
|
|
||||||
if s == "CustomAfterCheckTypes" {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
t.Error("after stage should be in StagesToRun()")
|
t.Error("after stage should be in StagesToRun()")
|
||||||
|
|||||||
@@ -9145,8 +9145,8 @@ p := $"{walk(["a", "b"])}"`,
|
|||||||
t.Fatal("expected error, got none")
|
t.Fatal("expected error, got none")
|
||||||
}
|
}
|
||||||
if c.Errors[0].Message != tc.exp {
|
if c.Errors[0].Message != tc.exp {
|
||||||
if strings.HasPrefix(tc.exp, "contains:") {
|
if after, ok := strings.CutPrefix(tc.exp, "contains:"); ok {
|
||||||
if exp := strings.TrimPrefix(tc.exp, "contains:"); !strings.Contains(c.Errors[0].Message, exp) {
|
if exp := after; !strings.Contains(c.Errors[0].Message, exp) {
|
||||||
t.Fatalf("expected error containing:\n\n%s\n\ngot:\n\n%s", tc.exp, c.Errors[0].Message)
|
t.Fatalf("expected error containing:\n\n%s\n\ngot:\n\n%s", tc.exp, c.Errors[0].Message)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ast
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"slices"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -81,10 +82,8 @@ type fakeEvalResolver struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r fakeEvalResolver) Resolve(ref Ref) (Value, error) {
|
func (r fakeEvalResolver) Resolve(ref Ref) (Value, error) {
|
||||||
for _, u := range r.unknowns {
|
if slices.ContainsFunc(r.unknowns, ref.HasPrefix) {
|
||||||
if ref.HasPrefix(u) {
|
return nil, UnknownValueErr{}
|
||||||
return nil, UnknownValueErr{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ref.HasPrefix(InputRootRef) {
|
if ref.HasPrefix(InputRootRef) {
|
||||||
if r.input == nil {
|
if r.input == nil {
|
||||||
|
|||||||
+14
-5
@@ -8,6 +8,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/open-policy-agent/opa/v1/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (node *trieNode) mermaid() string {
|
func (node *trieNode) mermaid() string {
|
||||||
@@ -159,18 +161,23 @@ func (node *trieNode) format(sb *strings.Builder, depth int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(node.rules) > 0 {
|
if len(node.rules) > 0 {
|
||||||
fmt.Fprintf(sb, " [%d rule(s)]", len(node.rules))
|
sb.WriteString(" [")
|
||||||
|
util.WriteInt(sb, len(node.rules))
|
||||||
|
sb.WriteString(" rule(s)]")
|
||||||
}
|
}
|
||||||
if len(node.mappers) > 0 {
|
if len(node.mappers) > 0 {
|
||||||
fmt.Fprintf(sb, " [%d mapper(s)]", len(node.mappers))
|
sb.WriteString(" [")
|
||||||
|
util.WriteInt(sb, len(node.mappers))
|
||||||
|
sb.WriteString(" mapper(s)]")
|
||||||
}
|
}
|
||||||
if node.value != nil {
|
if node.value != nil {
|
||||||
fmt.Fprintf(sb, " value=%v", node.value)
|
sb.WriteString(" value=")
|
||||||
|
sb.WriteString(node.value.String())
|
||||||
}
|
}
|
||||||
if node.multiple {
|
if node.multiple {
|
||||||
sb.WriteString(" [multiple]")
|
sb.WriteString(" [multiple]")
|
||||||
}
|
}
|
||||||
sb.WriteString("\n")
|
sb.WriteByte('\n')
|
||||||
|
|
||||||
if node.undefined != nil {
|
if node.undefined != nil {
|
||||||
sb.WriteString(indent)
|
sb.WriteString(indent)
|
||||||
@@ -197,7 +204,9 @@ func (node *trieNode) format(sb *strings.Builder, depth int) {
|
|||||||
})
|
})
|
||||||
for i := range scalars {
|
for i := range scalars {
|
||||||
sb.WriteString(indent)
|
sb.WriteString(indent)
|
||||||
fmt.Fprintf(sb, " %v:\n", scalars[i])
|
sb.WriteString(" ")
|
||||||
|
sb.WriteString(scalars[i].String())
|
||||||
|
sb.WriteString(":\n")
|
||||||
for j := range nodes {
|
for j := range nodes {
|
||||||
if ValueEqual(scalars[i], scalars[j]) {
|
if ValueEqual(scalars[i], scalars[j]) {
|
||||||
nodes[j].format(sb, depth+2)
|
nodes[j].format(sb, depth+2)
|
||||||
|
|||||||
+11
-9
@@ -1485,17 +1485,19 @@ func (d *SomeDecl) Hash() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *Every) String() string {
|
func (q *Every) String() string {
|
||||||
|
b := bytes.NewBufferString("every ")
|
||||||
if q.Key != nil {
|
if q.Key != nil {
|
||||||
return fmt.Sprintf("every %s, %s in %s { %s }",
|
util.WriteAppender(b, q.Key)
|
||||||
q.Key,
|
b.WriteString(", ")
|
||||||
q.Value,
|
|
||||||
q.Domain,
|
|
||||||
q.Body)
|
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("every %s in %s { %s }",
|
util.WriteAppender(b, q.Value)
|
||||||
q.Value,
|
b.WriteString(" in ")
|
||||||
q.Domain,
|
util.WriteAppender(b, q.Domain)
|
||||||
q.Body)
|
b.WriteString(" { ")
|
||||||
|
util.WriteAppender(b, q.Body)
|
||||||
|
b.WriteString(" }")
|
||||||
|
|
||||||
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Every) Loc() *Location {
|
func (q *Every) Loc() *Location {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/open-policy-agent/opa/v1/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dump returns a string representation of the tree structure rooted at this node.
|
// Dump returns a string representation of the tree structure rooted at this node.
|
||||||
@@ -24,9 +26,10 @@ func (n *TreeNode) dumpRecursive(sb *strings.Builder, prefix, childPrefix string
|
|||||||
fmt.Fprintf(sb, " ext:%v", n.External.Ref)
|
fmt.Fprintf(sb, " ext:%v", n.External.Ref)
|
||||||
}
|
}
|
||||||
if len(n.Values) > 0 {
|
if len(n.Values) > 0 {
|
||||||
fmt.Fprintf(sb, " rules:%d", len(n.Values))
|
sb.WriteString(" rules:")
|
||||||
|
util.WriteInt(sb, len(n.Values))
|
||||||
}
|
}
|
||||||
sb.WriteString("\n")
|
sb.WriteByte('\n')
|
||||||
|
|
||||||
if len(n.Children) == 0 {
|
if len(n.Children) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
+3
-5
@@ -1815,10 +1815,8 @@ func preProcessBundle(loader DirectoryLoader, skipVerify bool, sizeLimitBytes in
|
|||||||
base := filepath.Base(f.Path())
|
base := filepath.Base(f.Path())
|
||||||
|
|
||||||
if base == patchFile {
|
if base == patchFile {
|
||||||
|
b := new(bytes.Buffer)
|
||||||
var b bytes.Buffer
|
f.reader = io.TeeReader(f.reader, b)
|
||||||
tee := io.TeeReader(f.reader, &b)
|
|
||||||
f.reader = tee
|
|
||||||
|
|
||||||
buf, err := readFile(f, sizeLimitBytes)
|
buf, err := readFile(f, sizeLimitBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1829,7 +1827,7 @@ func preProcessBundle(loader DirectoryLoader, skipVerify bool, sizeLimitBytes in
|
|||||||
return bundle, nil, fmt.Errorf("bundle load failed on patch decode: %w", err)
|
return bundle, nil, fmt.Errorf("bundle load failed on patch decode: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.reader = &b
|
f.reader = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -230,7 +230,7 @@ func unmarshalConfig(raw []byte) (*Config, error) {
|
|||||||
func knownConfigFields(objValue reflect.Value) map[string]reflect.Value {
|
func knownConfigFields(objValue reflect.Value) map[string]reflect.Value {
|
||||||
knownFields := map[string]reflect.Value{}
|
knownFields := map[string]reflect.Value{}
|
||||||
for i := 0; i != objValue.NumField(); i++ {
|
for i := 0; i != objValue.NumField(); i++ {
|
||||||
jsonName := strings.Split(objValue.Type().Field(i).Tag.Get("json"), ",")[0]
|
jsonName, _, _ := strings.Cut(objValue.Type().Field(i).Tag.Get("json"), ",")
|
||||||
if jsonName == "" || jsonName == "-" {
|
if jsonName == "" || jsonName == "-" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ func structKeys(specs *[]ConfigSpec, pattern []string, t reflect.Type) []string
|
|||||||
for i := range t.NumField() {
|
for i := range t.NumField() {
|
||||||
field := t.Field(i)
|
field := t.Field(i)
|
||||||
|
|
||||||
name := strings.Split(field.Tag.Get("json"), ",")[0]
|
name, _, _ := strings.Cut(field.Tag.Get("json"), ",")
|
||||||
if name == "-" {
|
if name == "-" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ func TestParseConfigNonStringDecisionErrors(t *testing.T) {
|
|||||||
// updating validate.rego (or vice versa), this test fails.
|
// updating validate.rego (or vice versa), this test fails.
|
||||||
func TestCoreValidationRootSpecMatchesConfigStruct(t *testing.T) {
|
func TestCoreValidationRootSpecMatchesConfigStruct(t *testing.T) {
|
||||||
structKeys := map[string]struct{}{}
|
structKeys := map[string]struct{}{}
|
||||||
objType := reflect.TypeOf(Config{})
|
objType := reflect.TypeFor[Config]()
|
||||||
for i := range objType.NumField() {
|
for i := range objType.NumField() {
|
||||||
name := strings.Split(objType.Field(i).Tag.Get("json"), ",")[0]
|
name, _, _ := strings.Cut(objType.Field(i).Tag.Get("json"), ",")
|
||||||
if name == "" || name == "-" {
|
if name == "" || name == "-" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,19 +311,19 @@ type Counter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type counter struct {
|
type counter struct {
|
||||||
c uint64
|
c atomic.Uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *counter) Incr() {
|
func (c *counter) Incr() {
|
||||||
atomic.AddUint64(&c.c, 1)
|
c.c.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *counter) Add(n uint64) {
|
func (c *counter) Add(n uint64) {
|
||||||
atomic.AddUint64(&c.c, n)
|
c.c.Add(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *counter) Value() any {
|
func (c *counter) Value() any {
|
||||||
return atomic.LoadUint64(&c.c)
|
return c.c.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Statistics(num ...int64) any {
|
func Statistics(num ...int64) any {
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ func (c Client) Do(ctx context.Context, method, path string) (*http.Response, er
|
|||||||
if len(dump) < defaultResponseSizeLimitBytes {
|
if len(dump) < defaultResponseSizeLimitBytes {
|
||||||
c.loggerFields["response"] = string(dump)
|
c.loggerFields["response"] = string(dump)
|
||||||
} else {
|
} else {
|
||||||
c.loggerFields["response"] = fmt.Sprintf("%v...", string(dump[:defaultResponseSizeLimitBytes]))
|
c.loggerFields["response"] = string(dump[:defaultResponseSizeLimitBytes]) + "..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.logger.WithFields(c.loggerFields).Debug("Received response.")
|
c.logger.WithFields(c.loggerFields).Debug("Received response.")
|
||||||
|
|||||||
+12
-7
@@ -447,8 +447,12 @@ func EvalEvaluatedRuleTracker(t *topdown.EvaluatedRuleTracker) EvalOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pq preparedQuery) Modules() map[string]*ast.Module {
|
func (pq preparedQuery) Modules() map[string]*ast.Module {
|
||||||
mods := make(map[string]*ast.Module)
|
size := len(pq.r.parsedModules)
|
||||||
|
for _, b := range pq.r.bundles {
|
||||||
|
size += len(b.Modules)
|
||||||
|
}
|
||||||
|
|
||||||
|
mods := make(map[string]*ast.Module, size)
|
||||||
maps.Copy(mods, pq.r.parsedModules)
|
maps.Copy(mods, pq.r.parsedModules)
|
||||||
|
|
||||||
for _, b := range pq.r.bundles {
|
for _, b := range pq.r.bundles {
|
||||||
@@ -597,13 +601,16 @@ func (errs Errors) Error() string {
|
|||||||
return "no error"
|
return "no error"
|
||||||
}
|
}
|
||||||
if len(errs) == 1 {
|
if len(errs) == 1 {
|
||||||
return fmt.Sprintf("1 error occurred: %v", errs[0].Error())
|
return "1 error occurred: " + errs[0].Error()
|
||||||
}
|
}
|
||||||
buf := []string{fmt.Sprintf("%v errors occurred", len(errs))}
|
bb := new(bytes.Buffer)
|
||||||
|
util.WriteInt(bb, len(errs))
|
||||||
|
bb.WriteString(" errors occurred")
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
buf = append(buf, err.Error())
|
bb.WriteByte('\n')
|
||||||
|
bb.WriteString(err.Error())
|
||||||
}
|
}
|
||||||
return strings.Join(buf, "\n")
|
return bb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var errPartialEvaluationNotEffective = errors.New("partial evaluation not effective")
|
var errPartialEvaluationNotEffective = errors.New("partial evaluation not effective")
|
||||||
@@ -1639,7 +1646,6 @@ func CompilePartial(yes bool) CompileOption {
|
|||||||
// Compile returns a compiled policy query.
|
// Compile returns a compiled policy query.
|
||||||
func (r *Rego) Compile(ctx context.Context, opts ...CompileOption) (*CompileResult, error) {
|
func (r *Rego) Compile(ctx context.Context, opts ...CompileOption) (*CompileResult, error) {
|
||||||
var cfg CompileContext
|
var cfg CompileContext
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&cfg)
|
opt(&cfg)
|
||||||
}
|
}
|
||||||
@@ -1648,7 +1654,6 @@ func (r *Rego) Compile(ctx context.Context, opts ...CompileOption) (*CompileResu
|
|||||||
modules := make([]*ast.Module, 0, len(r.compiler.Modules))
|
modules := make([]*ast.Module, 0, len(r.compiler.Modules))
|
||||||
|
|
||||||
if cfg.partial {
|
if cfg.partial {
|
||||||
|
|
||||||
pq, err := r.Partial(ctx)
|
pq, err := r.Partial(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !linux && !windows
|
//go:build !linux && !windows
|
||||||
// +build !linux,!windows
|
|
||||||
|
|
||||||
// Copyright 2022 The OPA Authors. All rights reserved.
|
// Copyright 2022 The OPA Authors. All rights reserved.
|
||||||
// Use of this source code is governed by an Apache2
|
// Use of this source code is governed by an Apache2
|
||||||
|
|||||||
+9
-5
@@ -266,12 +266,16 @@ func (s *Server) Shutdown(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(errorList) > 0 {
|
if len(errorList) > 0 {
|
||||||
errMsg := "error while shutting down: "
|
errMsg := new(strings.Builder)
|
||||||
|
errMsg.WriteString("error while shutting down: ")
|
||||||
for i, err := range errorList {
|
for i, err := range errorList {
|
||||||
//nolint:perfsprint
|
errMsg.WriteByte('(')
|
||||||
errMsg += fmt.Sprintf("(%d) %s. ", i, err.Error())
|
util.WriteInt(errMsg, i)
|
||||||
|
errMsg.WriteString(") ")
|
||||||
|
errMsg.WriteString(err.Error())
|
||||||
|
errMsg.WriteString(". ")
|
||||||
}
|
}
|
||||||
return errors.New(errMsg)
|
return errors.New(errMsg.String())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -869,7 +873,7 @@ func (s *Server) initRouters(ctx context.Context) {
|
|||||||
for _, router := range []*http.ServeMux{mainRouter, diagRouter} {
|
for _, router := range []*http.ServeMux{mainRouter, diagRouter} {
|
||||||
if s.metrics != nil {
|
if s.metrics != nil {
|
||||||
s.metrics.RegisterEndpoints(func(path, method string, handler http.Handler) {
|
s.metrics.RegisterEndpoints(func(path, method string, handler http.Handler) {
|
||||||
router.Handle(fmt.Sprintf("%s %s", method, path), handler)
|
router.Handle(method+" "+path, handler)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ var jsonFields = map[reflect.Type]map[string]bool{}
|
|||||||
// UnmarshalExtras and MarshalExtras can distinguish known fields from extras.
|
// UnmarshalExtras and MarshalExtras can distinguish known fields from extras.
|
||||||
// Call from an init() function in the package that defines T.
|
// Call from an init() function in the package that defines T.
|
||||||
func RegisterJSONFields[T any]() {
|
func RegisterJSONFields[T any]() {
|
||||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
t := reflect.TypeFor[T]()
|
||||||
if t.Kind() != reflect.Struct {
|
if t.Kind() != reflect.Struct {
|
||||||
panic(fmt.Sprintf("types: RegisterJSONFields[%s]: not a struct", t))
|
panic(fmt.Sprintf("types: RegisterJSONFields[%s]: not a struct", t))
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ func RegisterJSONFields[T any]() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func knownJSONFields[T any]() map[string]bool {
|
func knownJSONFields[T any]() map[string]bool {
|
||||||
t := reflect.TypeOf((*T)(nil)).Elem()
|
t := reflect.TypeFor[T]()
|
||||||
f, ok := jsonFields[t]
|
f, ok := jsonFields[t]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("types: %s not registered with RegisterJSONFields", t))
|
panic(fmt.Sprintf("types: %s not registered with RegisterJSONFields", t))
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ type Options struct {
|
|||||||
// Store provides a disk-based implementation of the storage.Store interface.
|
// Store provides a disk-based implementation of the storage.Store interface.
|
||||||
type Store struct {
|
type Store struct {
|
||||||
db *badger.DB // underlying key-value store
|
db *badger.DB // underlying key-value store
|
||||||
xid uint64 // next transaction id
|
xid atomic.Uint64 // next transaction id
|
||||||
rmu sync.RWMutex // reader-writer lock
|
rmu sync.RWMutex // reader-writer lock
|
||||||
wmu sync.Mutex // writer lock
|
wmu sync.Mutex // writer lock
|
||||||
pm *pathMapper // maps logical storage paths to underlying store keys
|
pm *pathMapper // maps logical storage paths to underlying store keys
|
||||||
@@ -239,7 +239,7 @@ func (db *Store) NewTransaction(_ context.Context, params ...storage.Transaction
|
|||||||
context = params[0].Context
|
context = params[0].Context
|
||||||
}
|
}
|
||||||
|
|
||||||
xid := atomic.AddUint64(&db.xid, uint64(1))
|
xid := db.xid.Add(1)
|
||||||
if write {
|
if write {
|
||||||
db.wmu.Lock() // only one concurrent write txn
|
db.wmu.Lock() // only one concurrent write txn
|
||||||
} else {
|
} else {
|
||||||
@@ -274,7 +274,7 @@ func (db *Store) Truncate(ctx context.Context, txn storage.Transaction, params s
|
|||||||
|
|
||||||
// write new bundle policy and data into the existing DB
|
// write new bundle policy and data into the existing DB
|
||||||
underlying := db.db.NewTransaction(true)
|
underlying := db.db.NewTransaction(true)
|
||||||
xid := atomic.AddUint64(&db.xid, uint64(1))
|
xid := db.xid.Add(uint64(1))
|
||||||
underlyingTxn := newTransaction(xid, true, underlying, params.Context, db.pm, db.partitions, db)
|
underlyingTxn := newTransaction(xid, true, underlying, params.Context, db.pm, db.partitions, db)
|
||||||
|
|
||||||
// For backwards compatibility, check if `RootOverwrite` was configured.
|
// For backwards compatibility, check if `RootOverwrite` was configured.
|
||||||
@@ -314,7 +314,7 @@ func (db *Store) Truncate(ctx context.Context, txn storage.Transaction, params s
|
|||||||
}
|
}
|
||||||
|
|
||||||
underlying = db.db.NewTransaction(true)
|
underlying = db.db.NewTransaction(true)
|
||||||
xid = atomic.AddUint64(&db.xid, uint64(1))
|
xid = db.xid.Add(uint64(1))
|
||||||
underlyingTxn = newTransaction(xid, true, underlying, params.Context, db.pm, db.partitions, db)
|
underlyingTxn = newTransaction(xid, true, underlying, params.Context, db.pm, db.partitions, db)
|
||||||
|
|
||||||
if err = underlyingTxn.UpsertPolicy(ctx, strings.TrimLeft(update.Path.String(), "/"), update.Value); err != nil {
|
if err = underlyingTxn.UpsertPolicy(ctx, strings.TrimLeft(update.Path.String(), "/"), update.Value); err != nil {
|
||||||
@@ -397,7 +397,7 @@ func (db *Store) doTruncateData(ctx context.Context, underlying *transaction, ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
txn := badgerdb.NewTransaction(true)
|
txn := badgerdb.NewTransaction(true)
|
||||||
xid := atomic.AddUint64(&db.xid, uint64(1))
|
xid := db.xid.Add(1)
|
||||||
sTxn := newTransaction(xid, true, txn, params.Context, db.pm, db.partitions, db)
|
sTxn := newTransaction(xid, true, txn, params.Context, db.pm, db.partitions, db)
|
||||||
|
|
||||||
if err = sTxn.Write(ctx, storage.AddOp, path, value); err != nil {
|
if err = sTxn.Write(ctx, storage.AddOp, path, value); err != nil {
|
||||||
@@ -480,8 +480,7 @@ func (db *Store) Commit(ctx context.Context, txn storage.Transaction) error {
|
|||||||
}
|
}
|
||||||
write := false // read only txn
|
write := false // read only txn
|
||||||
readOnly := db.db.NewTransaction(write)
|
readOnly := db.db.NewTransaction(write)
|
||||||
xid := atomic.AddUint64(&db.xid, uint64(1))
|
readTxn := newTransaction(db.xid.Add(1), write, readOnly, nil, db.pm, db.partitions, db)
|
||||||
readTxn := newTransaction(xid, write, readOnly, nil, db.pm, db.partitions, db)
|
|
||||||
for h := range db.triggers {
|
for h := range db.triggers {
|
||||||
h.cb(ctx, readTxn, event)
|
h.cb(ctx, readTxn, event)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
|
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// InternalErr indicates an unknown, internal error has occurred.
|
// InternalErr indicates an unknown, internal error has occurred.
|
||||||
InternalErr = "storage_internal_error"
|
InternalErr = "storage_internal_error"
|
||||||
@@ -49,7 +45,7 @@ type Error struct {
|
|||||||
|
|
||||||
func (err *Error) Error() string {
|
func (err *Error) Error() string {
|
||||||
if err.Message != "" {
|
if err.Message != "" {
|
||||||
return fmt.Sprintf("%v: %v", err.Code, err.Message)
|
return err.Code + ": " + err.Message
|
||||||
}
|
}
|
||||||
return err.Code
|
return err.Code
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func NewFromASTObject(data ast.Object) storage.Store {
|
|||||||
type store struct {
|
type store struct {
|
||||||
rmu sync.RWMutex // reader-writer lock
|
rmu sync.RWMutex // reader-writer lock
|
||||||
wmu sync.Mutex // writer lock
|
wmu sync.Mutex // writer lock
|
||||||
xid uint64 // last generated transaction id
|
xid atomic.Uint64 // last generated transaction id
|
||||||
data any // raw or AST data
|
data any // raw or AST data
|
||||||
policies map[string][]byte // raw policies
|
policies map[string][]byte // raw policies
|
||||||
triggers map[*handle]storage.TriggerConfig // registered triggers
|
triggers map[*handle]storage.TriggerConfig // registered triggers
|
||||||
@@ -137,7 +137,7 @@ type handle struct {
|
|||||||
|
|
||||||
func (db *store) NewTransaction(_ context.Context, params ...storage.TransactionParams) (storage.Transaction, error) {
|
func (db *store) NewTransaction(_ context.Context, params ...storage.TransactionParams) (storage.Transaction, error) {
|
||||||
txn := &transaction{
|
txn := &transaction{
|
||||||
xid: atomic.AddUint64(&db.xid, uint64(1)),
|
xid: db.xid.Add(1),
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !bench_disk
|
//go:build !bench_disk
|
||||||
// +build !bench_disk
|
|
||||||
|
|
||||||
// nolint: unused // build tags confuse these linters
|
// nolint: unused // build tags confuse these linters
|
||||||
package authz
|
package authz
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !bench_disk
|
//go:build !bench_disk
|
||||||
// +build !bench_disk
|
|
||||||
|
|
||||||
// nolint: unused // build tags confuse these linters
|
// nolint: unused // build tags confuse these linters
|
||||||
package authz
|
package authz
|
||||||
|
|||||||
+4
-14
@@ -7,7 +7,6 @@ package topdown
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
@@ -73,7 +72,6 @@ type (
|
|||||||
// function. If a random number generator cannot be created, an error is
|
// function. If a random number generator cannot be created, an error is
|
||||||
// returned.
|
// returned.
|
||||||
func (bctx *BuiltinContext) Rand() (*rand.Rand, error) {
|
func (bctx *BuiltinContext) Rand() (*rand.Rand, error) {
|
||||||
|
|
||||||
if bctx.rand != nil {
|
if bctx.rand != nil {
|
||||||
return bctx.rand, nil
|
return bctx.rand, nil
|
||||||
}
|
}
|
||||||
@@ -180,26 +178,18 @@ func functionalWrapper4(name string, fn FunctionalBuiltin4) BuiltinFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleBuiltinErr(name string, loc *ast.Location, err error) error {
|
func handleBuiltinErr(name string, loc *ast.Location, err error) error {
|
||||||
|
var code string
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case BuiltinEmpty:
|
case BuiltinEmpty:
|
||||||
return nil
|
return nil
|
||||||
case *Error, Halt:
|
case *Error, Halt:
|
||||||
return err
|
return err
|
||||||
case builtins.ErrOperand:
|
case builtins.ErrOperand:
|
||||||
e := &Error{
|
code = TypeErr
|
||||||
Code: TypeErr,
|
|
||||||
Message: fmt.Sprintf("%v: %v", name, err.Error()),
|
|
||||||
Location: loc,
|
|
||||||
}
|
|
||||||
return e.Wrap(err)
|
|
||||||
default:
|
default:
|
||||||
e := &Error{
|
code = BuiltinErr
|
||||||
Code: BuiltinErr,
|
|
||||||
Message: fmt.Sprintf("%v: %v", name, err.Error()),
|
|
||||||
Location: loc,
|
|
||||||
}
|
|
||||||
return e.Wrap(err)
|
|
||||||
}
|
}
|
||||||
|
return (&Error{Code: code, Message: name + ": " + err.Error(), Location: loc}).Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readInt64(r io.Reader) (int64, error) {
|
func readInt64(r io.Reader) (int64, error) {
|
||||||
|
|||||||
Vendored
+2
-4
@@ -626,14 +626,12 @@ func TestConcurrentInsert(t *testing.T) {
|
|||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
for range 5 {
|
for range 5 {
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
go func() {
|
wg.Go(func() {
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
cacheValue2 := newInterQueryCacheValue(ast.String("bar2"), 5)
|
cacheValue2 := newInterQueryCacheValue(ast.String("bar2"), 5)
|
||||||
cache.Insert(ast.String("foo2"), cacheValue2)
|
cache.Insert(ast.String("foo2"), cacheValue2)
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func generateNestedDataset(size int) map[string]any {
|
|||||||
for i := range size {
|
for i := range size {
|
||||||
// Random nested object with 3-5 levels of nesting
|
// Random nested object with 3-5 levels of nesting
|
||||||
permissions := make([]any, rng.Intn(10)+1)
|
permissions := make([]any, rng.Intn(10)+1)
|
||||||
for j := 0; j < len(permissions); j++ {
|
for j := range permissions {
|
||||||
permissions[j] = map[string]any{
|
permissions[j] = map[string]any{
|
||||||
"name": fmt.Sprintf("perm_%d", j),
|
"name": fmt.Sprintf("perm_%d", j),
|
||||||
"level": rng.Intn(10),
|
"level": rng.Intn(10),
|
||||||
|
|||||||
@@ -66,8 +66,7 @@ func BenchmarkBuiltinGlobMatchAsync(b *testing.B) {
|
|||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
for i := range clientCount {
|
for i := range clientCount {
|
||||||
clientID := i
|
clientID := i
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
for j := range patternCount {
|
for j := range patternCount {
|
||||||
var operands []*ast.Term
|
var operands []*ast.Term
|
||||||
if reusePattern {
|
if reusePattern {
|
||||||
@@ -88,8 +87,7 @@ func BenchmarkBuiltinGlobMatchAsync(b *testing.B) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Done()
|
})
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -394,7 +394,7 @@ func verifyURLHost(bctx BuiltinContext, unverifiedURL string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
host := strings.Split(parsedURL.Host, ":")[0]
|
host, _, _ := strings.Cut(parsedURL.Host, ":")
|
||||||
|
|
||||||
return verifyHost(bctx, host)
|
return verifyHost(bctx, host)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -806,7 +806,7 @@ func TestHTTPRedirectAllowNet(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
serverHost := strings.Split(serverURL.Host, ":")[0]
|
serverHost, _, _ := strings.Cut(serverURL.Host, ":")
|
||||||
|
|
||||||
// expected result
|
// expected result
|
||||||
expectedResult := make(map[string]any)
|
expectedResult := make(map[string]any)
|
||||||
@@ -3712,7 +3712,7 @@ func TestHTTPGetRequestAllowNet(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
serverHost := strings.Split(serverURL.Host, ":")[0]
|
serverHost, _, _ := strings.Cut(serverURL.Host, ":")
|
||||||
|
|
||||||
// expected result
|
// expected result
|
||||||
expectedResult := make(map[string]any)
|
expectedResult := make(map[string]any)
|
||||||
@@ -3820,7 +3820,7 @@ func TestHTTPWithCustomTransport(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
serverHost := strings.Split(serverURL.Host, ":")[0]
|
serverHost, _, _ := strings.Cut(serverURL.Host, ":")
|
||||||
|
|
||||||
// expected result
|
// expected result
|
||||||
expectedResult := make(map[string]any)
|
expectedResult := make(map[string]any)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !race
|
//go:build !race
|
||||||
// +build !race
|
|
||||||
|
|
||||||
package topdown
|
package topdown
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func parseNumBytesError(msg string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func errBytesUnitNotRecognized(unit string) error {
|
func errBytesUnitNotRecognized(unit string) error {
|
||||||
return parseNumBytesError(fmt.Sprintf("byte unit %s not recognized", unit))
|
return parseNumBytesError("byte unit " + unit + " not recognized")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -116,9 +116,7 @@ func builtinNumBytes(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term
|
|||||||
|
|
||||||
// Makes the string lower case and removes quotation marks
|
// Makes the string lower case and removes quotation marks
|
||||||
func formatString(s ast.String) string {
|
func formatString(s ast.String) string {
|
||||||
str := string(s)
|
return strings.ReplaceAll(strings.ToLower(string(s)), "\"", "")
|
||||||
lower := strings.ToLower(str)
|
|
||||||
return strings.ReplaceAll(lower, "\"", "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits the string into a number string à la "10" or "10.2" and a unit
|
// Splits the string into a number string à la "10" or "10.2" and a unit
|
||||||
|
|||||||
@@ -66,8 +66,7 @@ func BenchmarkBuiltinRegexMatchAsync(b *testing.B) {
|
|||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
for i := range clientCount {
|
for i := range clientCount {
|
||||||
clientID := i
|
clientID := i
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
for j := range patternCount {
|
for j := range patternCount {
|
||||||
var operands []*ast.Term
|
var operands []*ast.Term
|
||||||
if reusePattern {
|
if reusePattern {
|
||||||
@@ -83,8 +82,7 @@ func BenchmarkBuiltinRegexMatchAsync(b *testing.B) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Done()
|
})
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -583,20 +583,13 @@ func builtinSplitN(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term)
|
|||||||
limit = -1
|
limit = -1
|
||||||
}
|
}
|
||||||
parts := strings.SplitN(text, delim, limit)
|
parts := strings.SplitN(text, delim, limit)
|
||||||
end := n
|
result = make([]*ast.Term, min(n, len(parts)))
|
||||||
if end > len(parts) {
|
|
||||||
end = len(parts)
|
|
||||||
}
|
|
||||||
result = make([]*ast.Term, end)
|
|
||||||
for i := range result {
|
for i := range result {
|
||||||
result[i] = ast.InternedTerm(parts[i])
|
result[i] = ast.InternedTerm(parts[i])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parts := strings.Split(text, delim)
|
parts := strings.Split(text, delim)
|
||||||
start := len(parts) + n
|
start := max(len(parts)+n, 0)
|
||||||
if start < 0 {
|
|
||||||
start = 0
|
|
||||||
}
|
|
||||||
result = make([]*ast.Term, len(parts)-start)
|
result = make([]*ast.Term, len(parts)-start)
|
||||||
for i, p := range parts[start:] {
|
for i, p := range parts[start:] {
|
||||||
result[i] = ast.InternedTerm(p)
|
result[i] = ast.InternedTerm(p)
|
||||||
|
|||||||
@@ -175,43 +175,39 @@ func BenchmarkConcurrency8Writers(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkConcurrency(b *testing.B, params []storage.TransactionParams) {
|
func benchmarkConcurrency(b *testing.B, params []storage.TransactionParams) {
|
||||||
|
|
||||||
mod, data := test.GenerateConcurrencyBenchmarkData()
|
mod, data := test.GenerateConcurrencyBenchmarkData()
|
||||||
ctx := b.Context()
|
ctx := b.Context()
|
||||||
store := inmem.NewFromObject(data)
|
store := inmem.NewFromObject(data)
|
||||||
mods := map[string]*ast.Module{"module": ast.MustParseModule(mod)}
|
body := ast.MustParseBody("data.test.p = x")
|
||||||
compiler := ast.NewCompiler()
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
if compiler.Compile(mods); compiler.Failed() {
|
compiler, err := ast.CompileModules(map[string]string{"module": mod})
|
||||||
b.Fatalf("Unexpected compiler error: %v", compiler.Errors)
|
if err != nil {
|
||||||
|
b.Fatalf("Unexpected compiler error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for b.Loop() {
|
for b.Loop() {
|
||||||
wg := new(sync.WaitGroup)
|
for _, param := range params {
|
||||||
queriesPerCore := 1000 / len(params)
|
wg.Go(func() {
|
||||||
for j := range params {
|
for range 1000 / len(params) {
|
||||||
param := params[j] // capture j'th params before goroutine
|
txn, err := store.NewTransaction(ctx, param)
|
||||||
wg.Add(1)
|
if err != nil {
|
||||||
go func() {
|
b.Fatalf("Unexpected transaction error: %v", err)
|
||||||
defer wg.Done()
|
}
|
||||||
for range queriesPerCore {
|
rs, err := NewQuery(body).
|
||||||
txn := storage.NewTransactionOrDie(ctx, store, param)
|
|
||||||
query := NewQuery(ast.MustParseBody("data.test.p = x")).
|
|
||||||
WithCompiler(compiler).
|
WithCompiler(compiler).
|
||||||
WithStore(store).
|
WithStore(store).
|
||||||
WithTransaction(txn)
|
WithTransaction(txn).
|
||||||
rs, err := query.Run(ctx)
|
Run(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Errorf("Unexpected topdown query error: %v", err)
|
b.Fatalf("Unexpected topdown query error: %v", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if len(rs) != 1 || !rs[0][ast.Var("x")].Equal(ast.BooleanTerm(true)) {
|
if len(rs) != 1 || !rs[0][ast.Var("x")].Equal(ast.BooleanTerm(true)) {
|
||||||
b.Errorf("Unexpected undefined/extra/bad result: %v", rs)
|
b.Fatalf("Unexpected undefined/extra/bad result: %v", rs)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
store.Abort(ctx, txn)
|
store.Abort(ctx, txn)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@@ -548,14 +544,16 @@ func BenchmarkWalk(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
err = storage.Txn(b.Context(), store, storage.TransactionParams{}, func(txn storage.Transaction) error {
|
ctx := b.Context()
|
||||||
|
|
||||||
|
err = storage.Txn(ctx, store, storage.TransactionParams{}, func(txn storage.Transaction) error {
|
||||||
q := NewQuery(compiledQuery).
|
q := NewQuery(compiledQuery).
|
||||||
WithStore(store).
|
WithStore(store).
|
||||||
WithCompiler(compiler).
|
WithCompiler(compiler).
|
||||||
WithTransaction(txn)
|
WithTransaction(txn)
|
||||||
|
|
||||||
for b.Loop() {
|
for b.Loop() {
|
||||||
rs, err := q.Run(b.Context())
|
rs, err := q.Run(ctx)
|
||||||
if err != nil || len(rs) != 1 || !rs[0][ast.Var("x")].Equal(ast.IntNumberTerm(n-1)) {
|
if err != nil || len(rs) != 1 || !rs[0][ast.Var("x")].Equal(ast.IntNumberTerm(n-1)) {
|
||||||
b.Fatal("Unexpected result:", rs, "err:", err)
|
b.Fatal("Unexpected result:", rs, "err:", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-7
@@ -845,7 +845,7 @@ func PrettyEvent(w io.Writer, e *Event, opts PrettyEventOpts) error {
|
|||||||
|
|
||||||
func printPrettyVars(w *bytes.Buffer, exprVars map[string]varInfo) {
|
func printPrettyVars(w *bytes.Buffer, exprVars map[string]varInfo) {
|
||||||
containsTabs := false
|
containsTabs := false
|
||||||
varRows := make(map[int]any)
|
varRows := make(map[int]any, len(exprVars))
|
||||||
for _, info := range exprVars {
|
for _, info := range exprVars {
|
||||||
if len(info.exprLoc.Tabs) > 0 {
|
if len(info.exprLoc.Tabs) > 0 {
|
||||||
containsTabs = true
|
containsTabs = true
|
||||||
@@ -891,10 +891,10 @@ func printPrettyVars(w *bytes.Buffer, exprVars map[string]varInfo) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteString("\n")
|
w.WriteByte('\n')
|
||||||
printArrows(w, byCol, -1)
|
printArrows(w, byCol, -1)
|
||||||
for i := len(byCol) - 1; i >= 0; i-- {
|
for i := len(byCol) - 1; i >= 0; i-- {
|
||||||
w.WriteString("\n")
|
w.WriteByte('\n')
|
||||||
printArrows(w, byCol, i)
|
printArrows(w, byCol, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -909,7 +909,6 @@ func printArrows(w *bytes.Buffer, l []varInfo, printValueAt int) {
|
|||||||
}
|
}
|
||||||
isFirst := true
|
isFirst := true
|
||||||
for i, info := range slice {
|
for i, info := range slice {
|
||||||
|
|
||||||
isLast := i >= len(slice)-1
|
isLast := i >= len(slice)-1
|
||||||
col := info.col
|
col := info.col
|
||||||
|
|
||||||
@@ -926,11 +925,11 @@ func printArrows(w *bytes.Buffer, l []varInfo, printValueAt int) {
|
|||||||
for j := range spaces {
|
for j := range spaces {
|
||||||
tab := false
|
tab := false
|
||||||
if slices.Contains(info.exprLoc.Tabs, j+prevCol+1) {
|
if slices.Contains(info.exprLoc.Tabs, j+prevCol+1) {
|
||||||
w.WriteString("\t")
|
w.WriteByte('\t')
|
||||||
tab = true
|
tab = true
|
||||||
}
|
}
|
||||||
if !tab {
|
if !tab {
|
||||||
w.WriteString(" ")
|
w.WriteByte(' ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,7 +942,7 @@ func printArrows(w *bytes.Buffer, l []varInfo, printValueAt int) {
|
|||||||
w.WriteString(valueStr)
|
w.WriteString(valueStr)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("|")
|
w.WriteByte('|')
|
||||||
}
|
}
|
||||||
prevCol = col
|
prevCol = col
|
||||||
isFirst = false
|
isFirst = false
|
||||||
|
|||||||
+1
-1
@@ -345,7 +345,7 @@ func (p *DynamicProperty) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *DynamicProperty) String() string {
|
func (p *DynamicProperty) String() string {
|
||||||
return fmt.Sprintf("%s: %s", Sprint(p.Key), Sprint(p.Value))
|
return Sprint(p.Key) + ": " + Sprint(p.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object represents the object type.
|
// Object represents the object type.
|
||||||
|
|||||||
+38
-1
@@ -1,6 +1,9 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding"
|
||||||
|
"io"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -8,6 +11,18 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Signed interface {
|
||||||
|
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||||
|
}
|
||||||
|
Unsigned interface {
|
||||||
|
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||||
|
}
|
||||||
|
Integer interface {
|
||||||
|
Signed | Unsigned
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// SyncPool is a generic sync.Pool for type T, providing some convenience
|
// SyncPool is a generic sync.Pool for type T, providing some convenience
|
||||||
// over sync.Pool directly: [SyncPool.Put] ensures that nil values are not
|
// over sync.Pool directly: [SyncPool.Put] ensures that nil values are not
|
||||||
// put into the pool, and [SyncPool.Get] returns a pointer to T without having
|
// put into the pool, and [SyncPool.Get] returns a pointer to T without having
|
||||||
@@ -147,10 +162,32 @@ func NumDigitsUint(n uint64) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AppendInt is a less messy version of strconv.AppendInt for base 10 ints.
|
// AppendInt is a less messy version of strconv.AppendInt for base 10 ints.
|
||||||
func AppendInt(buf []byte, n int) []byte {
|
func AppendInt[T Integer](buf []byte, n T) []byte {
|
||||||
return strconv.AppendInt(buf, int64(n), 10)
|
return strconv.AppendInt(buf, int64(n), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteInt writes the string form of n to out.
|
||||||
|
func WriteInt[T Integer](out io.Writer, n T) (int, error) {
|
||||||
|
var buf []byte
|
||||||
|
if b, ok := out.(*bytes.Buffer); ok {
|
||||||
|
buf = b.AvailableBuffer()
|
||||||
|
}
|
||||||
|
return out.Write(AppendInt(buf, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAppender writes the appended text of appender to out.
|
||||||
|
func WriteAppender[T encoding.TextAppender](out io.Writer, appender T) (int, error) {
|
||||||
|
var buf []byte
|
||||||
|
if b, ok := out.(*bytes.Buffer); ok {
|
||||||
|
buf = b.AvailableBuffer()
|
||||||
|
}
|
||||||
|
b, err := appender.AppendText(buf)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return out.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
// Atoi is a convenience function for [Atoi64] where an int is preferable to an int64.
|
// 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
|
// See the documentation of [Atoi64] for details on the performance benefits of this
|
||||||
// function over strconv.Atoi.
|
// function over strconv.Atoi.
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func populateDefaultTypes(t *testing.T, fieldType reflect.Type, fieldValue refle
|
|||||||
|
|
||||||
switch fieldType.Kind() {
|
switch fieldType.Kind() {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if fieldType == reflect.TypeOf(json.RawMessage{}) {
|
if fieldType == reflect.TypeFor[json.RawMessage]() {
|
||||||
fieldValue.Set(reflect.ValueOf(fmt.Appendf(nil, `{"test": "bar-%d"}`, index)))
|
fieldValue.Set(reflect.ValueOf(fmt.Appendf(nil, `{"test": "bar-%d"}`, index)))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ func populateDefaultTypes(t *testing.T, fieldType reflect.Type, fieldValue refle
|
|||||||
return true
|
return true
|
||||||
|
|
||||||
case fieldType.Key().Kind() == reflect.String &&
|
case fieldType.Key().Kind() == reflect.String &&
|
||||||
fieldType.Elem() == reflect.TypeOf(json.RawMessage{}):
|
fieldType.Elem() == reflect.TypeFor[json.RawMessage]():
|
||||||
|
|
||||||
fieldValue.Set(reflect.ValueOf(map[string]json.RawMessage{
|
fieldValue.Set(reflect.ValueOf(map[string]json.RawMessage{
|
||||||
"key1": fmt.Appendf(nil, `{"test": "bar-%d"}`, index),
|
"key1": fmt.Appendf(nil, `{"test": "bar-%d"}`, index),
|
||||||
|
|||||||
Reference in New Issue
Block a user