Skip to content

Commit 80bde1e

Browse files
authored
chore: Ensure cancelled errors return proper (#6200)
The authz library returns a 404 if the authorization fails. If the context is cancelled, then a 404 message is inaccurate. Add a unit test to ensure context cancelled errors are raised properly
1 parent 860e282 commit 80bde1e

File tree

3 files changed

+32
-7
lines changed

3 files changed

+32
-7
lines changed

coderd/database/dbauthz/dbauthz.go

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func logNotAuthorizedError(ctx context.Context, logger slog.Logger, err error) e
6161
slog.Error(err),
6262
)
6363
}
64+
6465
return NotAuthorizedError{
6566
Err: err,
6667
}

coderd/database/dbauthz/querier.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -438,12 +438,16 @@ func (q *querier) canAssignRoles(ctx context.Context, orgID *uuid.UUID, added, r
438438
}
439439
}
440440

441-
if len(added) > 0 && q.authorizeContext(ctx, rbac.ActionCreate, roleAssign) != nil {
442-
return logNotAuthorizedError(ctx, q.log, xerrors.Errorf("not authorized to assign roles"))
441+
if len(added) > 0 {
442+
if err := q.authorizeContext(ctx, rbac.ActionCreate, roleAssign); err != nil {
443+
return err
444+
}
443445
}
444446

445-
if len(removed) > 0 && q.authorizeContext(ctx, rbac.ActionDelete, roleAssign) != nil {
446-
return logNotAuthorizedError(ctx, q.log, xerrors.Errorf("not authorized to delete roles"))
447+
if len(removed) > 0 {
448+
if err := q.authorizeContext(ctx, rbac.ActionDelete, roleAssign); err != nil {
449+
return err
450+
}
447451
}
448452

449453
for _, roleName := range grantedRoles {
@@ -1221,7 +1225,7 @@ func (q *querier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []uui
12211225
continue
12221226
}
12231227
// Otherwise, we cannot read the workspace, so we cannot read the agent.
1224-
return nil, logNotAuthorizedError(ctx, q.log, err)
1228+
return nil, err
12251229
}
12261230
return agents, nil
12271231
}

coderd/database/dbauthz/setup_test.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import (
99
"strings"
1010
"testing"
1111

12-
"golang.org/x/xerrors"
13-
1412
"github.com/google/uuid"
13+
"github.com/open-policy-agent/opa/topdown"
1514
"github.com/stretchr/testify/require"
1615
"github.com/stretchr/testify/suite"
16+
"golang.org/x/xerrors"
1717

1818
"cdr.dev/slog"
1919
"github.com/coder/coder/coderd/coderdtest"
@@ -225,6 +225,26 @@ func (s *MethodTestSuite) NotAuthorizedErrorTest(ctx context.Context, az *coderd
225225
s.ErrorAs(err, &dbauthz.NotAuthorizedError{}, "error should be NotAuthorizedError")
226226
}
227227
})
228+
229+
s.Run("Cancelled", func() {
230+
// Pass in a cancelled context
231+
ctx, cancel := context.WithCancel(ctx)
232+
cancel()
233+
az.AlwaysReturn = rbac.ForbiddenWithInternal(&topdown.Error{Code: topdown.CancelErr},
234+
rbac.Subject{}, "", rbac.Object{}, nil)
235+
236+
// If we have assertions, that means the method should FAIL
237+
// if RBAC will disallow the request. The returned error should
238+
// be expected to be a NotAuthorizedError.
239+
resp, err := callMethod(ctx)
240+
241+
// This is unfortunate, but if we are using `Filter` the error returned will be nil. So filter out
242+
// any case where the error is nil and the response is an empty slice.
243+
if err != nil || !hasEmptySliceResponse(resp) {
244+
s.Errorf(err, "method should an error with cancellation")
245+
s.ErrorIsf(err, context.Canceled, "error should match context.Cancelled")
246+
}
247+
})
228248
}
229249

230250
func hasEmptySliceResponse(values []reflect.Value) bool {

0 commit comments

Comments
 (0)