Skip to content

Commit 7a14b64

Browse files
committed
Condense into 1 file
System.go is still on it's own until a solution is in place
1 parent c5346ad commit 7a14b64

30 files changed

+2896
-3120
lines changed

coderd/database/dbauthz/apikey.go

Lines changed: 0 additions & 39 deletions
This file was deleted.

coderd/database/dbauthz/apikey_test.go

Lines changed: 0 additions & 51 deletions
This file was deleted.

coderd/database/dbauthz/audit.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

coderd/database/dbauthz/audit_test.go

Lines changed: 0 additions & 23 deletions
This file was deleted.

coderd/database/dbauthz/authzquerier.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package dbauthz
33
import (
44
"context"
55
"database/sql"
6+
"fmt"
67
"time"
78

9+
"golang.org/x/xerrors"
10+
811
"cdr.dev/slog"
912

1013
"github.com/coder/coder/coderd/database"
@@ -13,6 +16,44 @@ import (
1316

1417
var _ database.Store = (*AuthzQuerier)(nil)
1518

19+
var (
20+
// NoActorError wraps ErrNoRows for the api to return a 404. This is the correct
21+
// response when the user is not authorized.
22+
NoActorError = xerrors.Errorf("no authorization actor in context: %w", sql.ErrNoRows)
23+
)
24+
25+
// NotAuthorizedError is a sentinel error that unwraps to sql.ErrNoRows.
26+
// This allows the internal error to be read by the caller if needed. Otherwise
27+
// it will be handled as a 404.
28+
type NotAuthorizedError struct {
29+
Err error
30+
}
31+
32+
func (e NotAuthorizedError) Error() string {
33+
return fmt.Sprintf("unauthorized: %s", e.Err.Error())
34+
}
35+
36+
// Unwrap will always unwrap to a sql.ErrNoRows so the API returns a 404.
37+
// So 'errors.Is(err, sql.ErrNoRows)' will always be true.
38+
func (NotAuthorizedError) Unwrap() error {
39+
return sql.ErrNoRows
40+
}
41+
42+
func LogNotAuthorizedError(ctx context.Context, logger slog.Logger, err error) error {
43+
// Only log the errors if it is an UnauthorizedError error.
44+
internalError := new(rbac.UnauthorizedError)
45+
if err != nil && xerrors.As(err, internalError) {
46+
logger.Debug(ctx, "unauthorized",
47+
slog.F("internal", internalError.Internal()),
48+
slog.F("input", internalError.Input()),
49+
slog.Error(err),
50+
)
51+
}
52+
return NotAuthorizedError{
53+
Err: err,
54+
}
55+
}
56+
1657
// AuthzQuerier is a wrapper around the database store that performs authorization
1758
// checks before returning data. All AuthzQuerier methods expect an authorization
1859
// subject present in the context. If no subject is present, most methods will

coderd/database/dbauthz/authz_test.go renamed to coderd/database/dbauthz/authzquerier_test.go

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,54 @@ import (
66
"reflect"
77
"testing"
88

9-
"github.com/google/uuid"
10-
"github.com/stretchr/testify/require"
11-
"golang.org/x/xerrors"
9+
"cdr.dev/slog/sloggers/slogtest"
1210

1311
"cdr.dev/slog"
14-
"cdr.dev/slog/sloggers/slogtest"
1512
"github.com/coder/coder/coderd/coderdtest"
1613
"github.com/coder/coder/coderd/database"
1714
"github.com/coder/coder/coderd/database/dbauthz"
1815
"github.com/coder/coder/coderd/database/dbfake"
1916
"github.com/coder/coder/coderd/database/dbgen"
2017
"github.com/coder/coder/coderd/rbac"
18+
"github.com/google/uuid"
19+
"github.com/stretchr/testify/require"
20+
"golang.org/x/xerrors"
2121
)
2222

23+
func TestPing(t *testing.T) {
24+
t.Parallel()
25+
26+
q := dbauthz.New(dbfake.New(), &coderdtest.RecordingAuthorizer{}, slog.Make())
27+
_, err := q.Ping(context.Background())
28+
require.NoError(t, err, "must not error")
29+
}
30+
31+
// TestInTX is not perfect, just checks that it properly checks auth.
32+
func TestInTX(t *testing.T) {
33+
t.Parallel()
34+
35+
db := dbfake.New()
36+
q := dbauthz.New(db, &coderdtest.RecordingAuthorizer{
37+
Wrapped: &coderdtest.FakeAuthorizer{AlwaysReturn: xerrors.New("custom error")},
38+
}, slog.Make())
39+
actor := rbac.Subject{
40+
ID: uuid.NewString(),
41+
Roles: rbac.RoleNames{rbac.RoleOwner()},
42+
Groups: []string{},
43+
Scope: rbac.ScopeAll,
44+
}
45+
46+
w := dbgen.Workspace(t, db, database.Workspace{})
47+
ctx := dbauthz.WithAuthorizeContext(context.Background(), actor)
48+
err := q.InTx(func(tx database.Store) error {
49+
// The inner tx should use the parent's authz
50+
_, err := tx.GetWorkspaceByID(ctx, w.ID)
51+
return err
52+
}, nil)
53+
require.Error(t, err, "must error")
54+
require.ErrorAs(t, err, &dbauthz.NotAuthorizedError{}, "must be an authorized error")
55+
}
56+
2357
func TestNotAuthorizedError(t *testing.T) {
2458
t.Parallel()
2559

@@ -81,40 +115,6 @@ func TestDBAuthzRecursive(t *testing.T) {
81115
}
82116
}
83117

84-
func TestPing(t *testing.T) {
85-
t.Parallel()
86-
87-
q := dbauthz.New(dbfake.New(), &coderdtest.RecordingAuthorizer{}, slog.Make())
88-
_, err := q.Ping(context.Background())
89-
require.NoError(t, err, "must not error")
90-
}
91-
92-
// TestInTX is not perfect, just checks that it properly checks auth.
93-
func TestInTX(t *testing.T) {
94-
t.Parallel()
95-
96-
db := dbfake.New()
97-
q := dbauthz.New(db, &coderdtest.RecordingAuthorizer{
98-
Wrapped: &coderdtest.FakeAuthorizer{AlwaysReturn: xerrors.New("custom error")},
99-
}, slog.Make())
100-
actor := rbac.Subject{
101-
ID: uuid.NewString(),
102-
Roles: rbac.RoleNames{rbac.RoleOwner()},
103-
Groups: []string{},
104-
Scope: rbac.ScopeAll,
105-
}
106-
107-
w := dbgen.Workspace(t, db, database.Workspace{})
108-
ctx := dbauthz.WithAuthorizeContext(context.Background(), actor)
109-
err := q.InTx(func(tx database.Store) error {
110-
// The inner tx should use the parent's authz
111-
_, err := tx.GetWorkspaceByID(ctx, w.ID)
112-
return err
113-
}, nil)
114-
require.Error(t, err, "must error")
115-
require.ErrorAs(t, err, &dbauthz.NotAuthorizedError{}, "must be an authorized error")
116-
}
117-
118118
func must[T any](value T, err error) T {
119119
if err != nil {
120120
panic(err)

coderd/database/dbauthz/authz.go renamed to coderd/database/dbauthz/crud.go

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,15 @@
11
package dbauthz
22

33
import (
4-
"context"
5-
"database/sql"
6-
"fmt"
7-
84
"cdr.dev/slog"
5+
"context"
96

107
"golang.org/x/xerrors"
118

129
"github.com/coder/coder/coderd/rbac"
1310
)
1411

15-
var (
16-
// NoActorError wraps ErrNoRows for the api to return a 404. This is the correct
17-
// response when the user is not authorized.
18-
NoActorError = xerrors.Errorf("no authorization actor in context: %w", sql.ErrNoRows)
19-
)
2012

21-
// NotAuthorizedError is a sentinel error that unwraps to sql.ErrNoRows.
22-
// This allows the internal error to be read by the caller if needed. Otherwise
23-
// it will be handled as a 404.
24-
type NotAuthorizedError struct {
25-
Err error
26-
}
27-
28-
func (e NotAuthorizedError) Error() string {
29-
return fmt.Sprintf("unauthorized: %s", e.Err.Error())
30-
}
31-
32-
// Unwrap will always unwrap to a sql.ErrNoRows so the API returns a 404.
33-
// So 'errors.Is(err, sql.ErrNoRows)' will always be true.
34-
func (NotAuthorizedError) Unwrap() error {
35-
return sql.ErrNoRows
36-
}
37-
38-
func LogNotAuthorizedError(ctx context.Context, logger slog.Logger, err error) error {
39-
// Only log the errors if it is an UnauthorizedError error.
40-
internalError := new(rbac.UnauthorizedError)
41-
if err != nil && xerrors.As(err, internalError) {
42-
logger.Debug(ctx, "unauthorized",
43-
slog.F("internal", internalError.Internal()),
44-
slog.F("input", internalError.Input()),
45-
slog.Error(err),
46-
)
47-
}
48-
return NotAuthorizedError{
49-
Err: err,
50-
}
51-
}
5213

5314
// insert runs an rbac.ActionCreate on the rbac object argument before
5415
// running the insertFunc. The insertFunc is expected to return the object that

0 commit comments

Comments
 (0)