mirror of
https://github.com/coder/coder.git
synced 2025-07-18 14:17:22 +00:00
fix(coderd): ensure correct RBAC when enqueueing notifications (#15478)
- Assert rbac in fake notifications enqueuer - Move fake notifications enqueuer to separate notificationstest package - Update dbauthz rbac policy to allow provisionerd and autostart to create and read notification messages - Update tests as required
This commit is contained in:
99
coderd/notifications/notificationstest/fake_enqueuer.go
Normal file
99
coderd/notifications/notificationstest/fake_enqueuer.go
Normal file
@ -0,0 +1,99 @@
|
||||
package notificationstest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/policy"
|
||||
)
|
||||
|
||||
type FakeEnqueuer struct {
|
||||
authorizer rbac.Authorizer
|
||||
mu sync.Mutex
|
||||
sent []*FakeNotification
|
||||
}
|
||||
|
||||
type FakeNotification struct {
|
||||
UserID, TemplateID uuid.UUID
|
||||
Labels map[string]string
|
||||
Data map[string]any
|
||||
CreatedBy string
|
||||
Targets []uuid.UUID
|
||||
}
|
||||
|
||||
// TODO: replace this with actual calls to dbauthz.
|
||||
// See: https://github.com/coder/coder/issues/15481
|
||||
func (f *FakeEnqueuer) assertRBACNoLock(ctx context.Context) {
|
||||
if f.mu.TryLock() {
|
||||
panic("Developer error: do not call assertRBACNoLock outside of a mutex lock!")
|
||||
}
|
||||
|
||||
// If we get here, we are locked.
|
||||
if f.authorizer == nil {
|
||||
f.authorizer = rbac.NewStrictCachingAuthorizer(prometheus.NewRegistry())
|
||||
}
|
||||
|
||||
act, ok := dbauthz.ActorFromContext(ctx)
|
||||
if !ok {
|
||||
panic("Developer error: no actor in context, you may need to use dbauthz.AsNotifier(ctx)")
|
||||
}
|
||||
|
||||
for _, a := range []policy.Action{policy.ActionCreate, policy.ActionRead} {
|
||||
err := f.authorizer.Authorize(ctx, act, a, rbac.ResourceNotificationMessage)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if rbac.IsUnauthorizedError(err) {
|
||||
panic(fmt.Sprintf("Developer error: not authorized to %s %s. "+
|
||||
"Ensure that you are using dbauthz.AsXXX with an actor that has "+
|
||||
"policy.ActionCreate on rbac.ResourceNotificationMessage", a, rbac.ResourceNotificationMessage.Type))
|
||||
}
|
||||
panic("Developer error: failed to check auth:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FakeEnqueuer) Enqueue(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, createdBy string, targets ...uuid.UUID) (*uuid.UUID, error) {
|
||||
return f.EnqueueWithData(ctx, userID, templateID, labels, nil, createdBy, targets...)
|
||||
}
|
||||
|
||||
func (f *FakeEnqueuer) EnqueueWithData(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) (*uuid.UUID, error) {
|
||||
return f.enqueueWithDataLock(ctx, userID, templateID, labels, data, createdBy, targets...)
|
||||
}
|
||||
|
||||
func (f *FakeEnqueuer) enqueueWithDataLock(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) (*uuid.UUID, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.assertRBACNoLock(ctx)
|
||||
|
||||
f.sent = append(f.sent, &FakeNotification{
|
||||
UserID: userID,
|
||||
TemplateID: templateID,
|
||||
Labels: labels,
|
||||
Data: data,
|
||||
CreatedBy: createdBy,
|
||||
Targets: targets,
|
||||
})
|
||||
|
||||
id := uuid.New()
|
||||
return &id, nil
|
||||
}
|
||||
|
||||
func (f *FakeEnqueuer) Clear() {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
f.sent = nil
|
||||
}
|
||||
|
||||
func (f *FakeEnqueuer) Sent() []*FakeNotification {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return append([]*FakeNotification{}, f.sent...)
|
||||
}
|
Reference in New Issue
Block a user