Skip to content

Commit 8738755

Browse files
authored
chore: Compile rego once to save CPU cycles in testing (coder#4169)
Compiling rego isn't very fast, so this should speed up tests in CI!
1 parent 1e1967e commit 8738755

File tree

4 files changed

+33
-41
lines changed

4 files changed

+33
-41
lines changed

coderd/coderd.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,7 @@ func New(options *Options) *API {
109109
options.MetricsCacheRefreshInterval = time.Hour
110110
}
111111
if options.Authorizer == nil {
112-
var err error
113-
options.Authorizer, err = rbac.NewAuthorizer()
114-
if err != nil {
115-
// This should never happen, as the unit tests would fail if the
116-
// default built in authorizer failed.
117-
panic(xerrors.Errorf("rego authorize panic: %w", err))
118-
}
112+
options.Authorizer = rbac.NewAuthorizer()
119113
}
120114
if options.PrometheusRegistry == nil {
121115
options.PrometheusRegistry = prometheus.NewRegistry()

coderd/rbac/authz.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
_ "embed"
66
"fmt"
7+
"sync"
78

89
"github.com/open-policy-agent/opa/rego"
910
"go.opentelemetry.io/otel/attribute"
@@ -66,32 +67,37 @@ type RegoAuthorizer struct {
6667

6768
var _ Authorizer = (*RegoAuthorizer)(nil)
6869

69-
// Load the policy from policy.rego in this directory.
70-
//
71-
//go:embed policy.rego
72-
var policy string
70+
var (
71+
// Load the policy from policy.rego in this directory.
72+
//
73+
//go:embed policy.rego
74+
policy string
75+
queryOnce sync.Once
76+
query rego.PreparedEvalQuery
77+
)
7378

7479
const (
7580
rolesOkCheck = "role_ok"
7681
scopeOkCheck = "scope_ok"
7782
)
7883

79-
func NewAuthorizer() (*RegoAuthorizer, error) {
80-
ctx := context.Background()
81-
query, err := rego.New(
82-
// Bind the results to 2 variables for easy checking later.
83-
rego.Query(
84-
fmt.Sprintf("%s := data.authz.role_allow "+
85-
"%s := data.authz.scope_allow",
86-
rolesOkCheck, scopeOkCheck),
87-
),
88-
rego.Module("policy.rego", policy),
89-
).PrepareForEval(ctx)
90-
91-
if err != nil {
92-
return nil, xerrors.Errorf("prepare query: %w", err)
93-
}
94-
return &RegoAuthorizer{query: query}, nil
84+
func NewAuthorizer() *RegoAuthorizer {
85+
queryOnce.Do(func() {
86+
var err error
87+
query, err = rego.New(
88+
// Bind the results to 2 variables for easy checking later.
89+
rego.Query(
90+
fmt.Sprintf("%s := data.authz.role_allow "+
91+
"%s := data.authz.scope_allow",
92+
rolesOkCheck, scopeOkCheck),
93+
),
94+
rego.Module("policy.rego", policy),
95+
).PrepareForEval(context.Background())
96+
if err != nil {
97+
panic(xerrors.Errorf("compile rego: %w", err))
98+
}
99+
})
100+
return &RegoAuthorizer{query: query}
95101
}
96102

97103
type authSubject struct {

coderd/rbac/authz_internal_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ func (w fakeObject) RBACObject() Object {
4040

4141
func TestFilterError(t *testing.T) {
4242
t.Parallel()
43-
auth, err := NewAuthorizer()
44-
require.NoError(t, err)
45-
46-
_, err = Filter(context.Background(), auth, uuid.NewString(), []string{}, ScopeAll, ActionRead, []Object{ResourceUser, ResourceWorkspace})
43+
auth := NewAuthorizer()
44+
_, err := Filter(context.Background(), auth, uuid.NewString(), []string{}, ScopeAll, ActionRead, []Object{ResourceUser, ResourceWorkspace})
4745
require.ErrorContains(t, err, "object types must be uniform")
4846
}
4947

@@ -160,8 +158,7 @@ func TestFilter(t *testing.T) {
160158

161159
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
162160
defer cancel()
163-
auth, err := NewAuthorizer()
164-
require.NoError(t, err, "new auth")
161+
auth := NewAuthorizer()
165162

166163
scope := ScopeAll
167164
if tc.Scope != "" {
@@ -742,8 +739,7 @@ type authTestCase struct {
742739

743740
func testAuthorize(t *testing.T, name string, subject subject, sets ...[]authTestCase) {
744741
t.Helper()
745-
authorizer, err := NewAuthorizer()
746-
require.NoError(t, err)
742+
authorizer := NewAuthorizer()
747743
for _, cases := range sets {
748744
for i, c := range cases {
749745
c := c

coderd/rbac/builtin_test.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,7 @@ func BenchmarkRBACFilter(b *testing.B) {
8282
},
8383
}
8484

85-
authorizer, err := rbac.NewAuthorizer()
86-
if err != nil {
87-
require.NoError(b, err)
88-
}
85+
authorizer := rbac.NewAuthorizer()
8986
for _, c := range benchCases {
9087
b.Run(c.Name, func(b *testing.B) {
9188
objects := benchmarkSetup(orgs, users, b.N)
@@ -119,8 +116,7 @@ type authSubject struct {
119116
func TestRolePermissions(t *testing.T) {
120117
t.Parallel()
121118

122-
auth, err := rbac.NewAuthorizer()
123-
require.NoError(t, err, "new rego authorizer")
119+
auth := rbac.NewAuthorizer()
124120

125121
// currentUser is anything that references "me", "mine", or "my".
126122
currentUser := uuid.New()

0 commit comments

Comments
 (0)