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:
Anders Eknert
2026-08-10 12:49:15 +02:00
committed by GitHub
parent aae2c0231a
commit 2378494a23
53 changed files with 250 additions and 290 deletions
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+2 -2
View File
@@ -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
} }
+5 -5
View File
@@ -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
+3 -4
View File
@@ -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)
+20 -20
View File
@@ -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())
+9 -27
View File
@@ -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
} }
+1 -1
View File
@@ -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
-8
View File
@@ -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.
+2 -2
View File
@@ -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
} }
+13 -24
View File
@@ -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
} }
+1 -3
View File
@@ -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 + ")"
+10 -16
View File
@@ -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
+3 -12
View File
@@ -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
View File
@@ -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 {
+2 -7
View File
@@ -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()")
+2 -2
View File
@@ -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 {
+3 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+5 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
} }
+2 -2
View File
@@ -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
} }
+4 -4
View File
@@ -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 {
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}) })
} }
+2 -2
View File
@@ -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))
+6 -7
View File
@@ -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)
} }
+1 -5
View File
@@ -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
} }
+2 -2
View File
@@ -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,
} }
-1
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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) {
+2 -4
View File
@@ -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()
+1 -1
View File
@@ -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),
+2 -4
View File
@@ -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
View File
@@ -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)
} }
+3 -3
View File
@@ -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)
-1
View File
@@ -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
+2 -4
View File
@@ -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
+2 -4
View File
@@ -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()
} }
+2 -9
View File
@@ -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)
+22 -24
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+2 -2
View File
@@ -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),