Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: add auditing for groups #4527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion coderd/audit/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ type Auditable interface {
database.TemplateVersion |
database.User |
database.Workspace |
database.GitSSHKey
database.GitSSHKey |
database.Group
}

// Map is a map of changed fields in an audited resource. It maps field names to
Expand Down
6 changes: 6 additions & 0 deletions coderd/audit/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func ResourceTarget[T Auditable](tgt T) string {
return typed.Name
case database.GitSSHKey:
return typed.PublicKey
case database.Group:
return typed.Name
default:
panic(fmt.Sprintf("unknown resource %T", tgt))
}
Expand All @@ -64,6 +66,8 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
return typed.ID
case database.GitSSHKey:
return typed.UserID
case database.Group:
return typed.ID
default:
panic(fmt.Sprintf("unknown resource %T", tgt))
}
Expand All @@ -83,6 +87,8 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
return database.ResourceTypeWorkspace
case database.GitSSHKey:
return database.ResourceTypeGitSshKey
case database.Group:
return database.ResourceTypeGroup
default:
panic(fmt.Sprintf("unknown resource %T", tgt))
}
Expand Down
63 changes: 23 additions & 40 deletions coderd/database/databasefake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -1457,34 +1457,6 @@ func (q *fakeQuerier) GetTemplates(_ context.Context) ([]database.Template, erro
return templates, nil
}

func (q *fakeQuerier) UpdateTemplateUserACLByID(_ context.Context, id uuid.UUID, acl database.TemplateACL) error {
q.mutex.RLock()
defer q.mutex.RUnlock()

for i, t := range q.templates {
if t.ID == id {
t = t.SetUserACL(acl)
q.templates[i] = t
return nil
}
}
return sql.ErrNoRows
}

func (q *fakeQuerier) UpdateTemplateGroupACLByID(_ context.Context, id uuid.UUID, acl database.TemplateACL) error {
q.mutex.RLock()
defer q.mutex.RUnlock()

for i, t := range q.templates {
if t.ID == id {
t = t.SetGroupACL(acl)
q.templates[i] = t
return nil
}
}
return sql.ErrNoRows
}

func (q *fakeQuerier) GetTemplateUserRoles(_ context.Context, id uuid.UUID) ([]database.TemplateUser, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
Expand All @@ -1501,10 +1473,8 @@ func (q *fakeQuerier) GetTemplateUserRoles(_ context.Context, id uuid.UUID) ([]d
return nil, sql.ErrNoRows
}

acl := template.UserACL()

users := make([]database.TemplateUser, 0, len(acl))
for k, v := range acl {
users := make([]database.TemplateUser, 0, len(template.UserACL))
for k, v := range template.UserACL {
user, err := q.GetUserByID(context.Background(), uuid.MustParse(k))
if err != nil && xerrors.Is(err, sql.ErrNoRows) {
return nil, xerrors.Errorf("get user by ID: %w", err)
Expand Down Expand Up @@ -1544,10 +1514,8 @@ func (q *fakeQuerier) GetTemplateGroupRoles(_ context.Context, id uuid.UUID) ([]
return nil, sql.ErrNoRows
}

acl := template.GroupACL()

groups := make([]database.TemplateGroup, 0, len(acl))
for k, v := range acl {
groups := make([]database.TemplateGroup, 0, len(template.GroupACL))
for k, v := range template.GroupACL {
group, err := q.GetGroupByID(context.Background(), uuid.MustParse(k))
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
return nil, xerrors.Errorf("get group by ID: %w", err)
Expand Down Expand Up @@ -2047,11 +2015,9 @@ func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl
MaxTtl: arg.MaxTtl,
MinAutostartInterval: arg.MinAutostartInterval,
CreatedBy: arg.CreatedBy,
UserACL: arg.UserACL,
GroupACL: arg.GroupACL,
}
template = template.SetUserACL(database.TemplateACL{})
template = template.SetGroupACL(database.TemplateACL{
arg.OrganizationID.String(): []rbac.Action{rbac.ActionRead},
})
q.templates = append(q.templates, template)
return template, nil
}
Expand Down Expand Up @@ -2470,6 +2436,23 @@ func (q *fakeQuerier) UpdateTemplateDeletedByID(_ context.Context, arg database.
return sql.ErrNoRows
}

func (q *fakeQuerier) UpdateTemplateACLByID(_ context.Context, arg database.UpdateTemplateACLByIDParams) (database.Template, error) {
q.mutex.Lock()
defer q.mutex.Unlock()

for i, template := range q.templates {
if template.ID == arg.ID {
template.GroupACL = arg.GroupACL
template.UserACL = arg.UserACL

q.templates[i] = template
return template, nil
}
}

return database.Template{}, sql.ErrNoRows
}

func (q *fakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) error {
q.mutex.Lock()
defer q.mutex.Unlock()
Expand Down
19 changes: 19 additions & 0 deletions coderd/database/drivers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,22 @@ func (a *Actions) Scan(src interface{}) error {
func (a *Actions) Value() (driver.Value, error) {
return json.Marshal(a)
}

// TemplateACL is a map of ids to permissions.
type TemplateACL map[string][]rbac.Action
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be a map[uuid.UUID][]rbac.Action?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly but it involves a lot of code changes, i'll try it out in a separate pr


func (t *TemplateACL) Scan(src interface{}) error {
switch v := src.(type) {
case string:
return json.Unmarshal([]byte(v), &t)
case []byte, json.RawMessage:
//nolint
return json.Unmarshal(v.([]byte), &t)
}

return xerrors.Errorf("unexpected type %T", src)
}

func (t TemplateACL) Value() (driver.Value, error) {
return json.Marshal(t)
}
3 changes: 2 additions & 1 deletion coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- You cannot safely remove values from enums https://www.postgresql.org/docs/current/datatype-enum.html
-- You cannot create a new type and do a rename because objects depend on this type now.
5 changes: 5 additions & 0 deletions coderd/database/migrations/000063_resource_type_group.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
BEGIN;

ALTER TYPE resource_type ADD VALUE IF NOT EXISTS 'group';

COMMIT;
58 changes: 2 additions & 56 deletions coderd/database/modelmethods.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,11 @@
package database

import (
"encoding/json"
"fmt"

"github.com/coder/coder/coderd/rbac"
)

const AllUsersGroup = "Everyone"

// TemplateACL is a map of user_ids to permissions.
type TemplateACL map[string][]rbac.Action

func (t Template) UserACL() TemplateACL {
var acl TemplateACL
if len(t.userACL) == 0 {
return acl
}

err := json.Unmarshal(t.userACL, &acl)
if err != nil {
panic(fmt.Sprintf("failed to unmarshal template.userACL: %v", err.Error()))
}

return acl
}

func (t Template) GroupACL() TemplateACL {
var acl TemplateACL
if len(t.groupACL) == 0 {
return acl
}

err := json.Unmarshal(t.groupACL, &acl)
if err != nil {
panic(fmt.Sprintf("failed to unmarshal template.userACL: %v", err.Error()))
}

return acl
}

func (t Template) SetGroupACL(acl TemplateACL) Template {
raw, err := json.Marshal(acl)
if err != nil {
panic(fmt.Sprintf("marshal user acl: %v", err))
}

t.groupACL = raw
return t
}

func (t Template) SetUserACL(acl TemplateACL) Template {
raw, err := json.Marshal(acl)
if err != nil {
panic(fmt.Sprintf("marshal user acl: %v", err))
}

t.userACL = raw
return t
}

func (s APIKeyScope) ToRBAC() rbac.Scope {
switch s {
case APIKeyScopeAll:
Expand All @@ -74,8 +20,8 @@ func (s APIKeyScope) ToRBAC() rbac.Scope {
func (t Template) RBACObject() rbac.Object {
obj := rbac.ResourceTemplate
return obj.InOrg(t.OrganizationID).
WithACLUserList(t.UserACL()).
WithGroupACL(t.GroupACL())
WithACLUserList(t.UserACL).
WithGroupACL(t.GroupACL)
}

func (TemplateVersion) RBACObject(template Template) rbac.Object {
Expand Down
47 changes: 0 additions & 47 deletions coderd/database/modelqueries.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package database

import (
"context"
"encoding/json"
"fmt"
"strings"

Expand All @@ -23,8 +22,6 @@ type customQuerier interface {
}

type templateQuerier interface {
UpdateTemplateUserACLByID(ctx context.Context, id uuid.UUID, acl TemplateACL) error
UpdateTemplateGroupACLByID(ctx context.Context, id uuid.UUID, acl TemplateACL) error
GetTemplateGroupRoles(ctx context.Context, id uuid.UUID) ([]TemplateGroup, error)
GetTemplateUserRoles(ctx context.Context, id uuid.UUID) ([]TemplateUser, error)
}
Expand All @@ -34,28 +31,6 @@ type TemplateUser struct {
Actions Actions `db:"actions"`
}

func (q *sqlQuerier) UpdateTemplateUserACLByID(ctx context.Context, id uuid.UUID, acl TemplateACL) error {
raw, err := json.Marshal(acl)
if err != nil {
return xerrors.Errorf("marshal user acl: %w", err)
}

const query = `
UPDATE
templates
SET
user_acl = $2
WHERE
id = $1`

_, err = q.db.ExecContext(ctx, query, id.String(), raw)
if err != nil {
return xerrors.Errorf("update user acl: %w", err)
}

return nil
}

func (q *sqlQuerier) GetTemplateUserRoles(ctx context.Context, id uuid.UUID) ([]TemplateUser, error) {
const query = `
SELECT
Expand Down Expand Up @@ -100,28 +75,6 @@ type TemplateGroup struct {
Actions Actions `db:"actions"`
}

func (q *sqlQuerier) UpdateTemplateGroupACLByID(ctx context.Context, id uuid.UUID, acl TemplateACL) error {
raw, err := json.Marshal(acl)
if err != nil {
return xerrors.Errorf("marshal user acl: %w", err)
}

const query = `
UPDATE
templates
SET
group_acl = $2
WHERE
id = $1`

_, err = q.db.ExecContext(ctx, query, id.String(), raw)
if err != nil {
return xerrors.Errorf("update user acl: %w", err)
}

return nil
}

func (q *sqlQuerier) GetTemplateGroupRoles(ctx context.Context, id uuid.UUID) ([]TemplateGroup, error) {
const query = `
SELECT
Expand Down
5 changes: 3 additions & 2 deletions coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading