Skip to content

Commit

Permalink
feat: permission and casbin rule
Browse files Browse the repository at this point in the history
[skip ci]
  • Loading branch information
adityathebe committed Sep 23, 2024
1 parent ee1de5f commit 7d875bf
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
35 changes: 35 additions & 0 deletions job/permission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package job

import (
"github.com/flanksource/duty/context"
"github.com/flanksource/duty/models"
"gorm.io/gorm/clause"
)

func SyncPermissionToCasbinRule(ctx context.Context) error {
var permissions []models.Permission
if err := ctx.DB().Find(&permissions).Error; err != nil {
return err
}

for _, permission := range permissions {
rule := permissionToCasbinRule(permission)
if err := ctx.DB().Clauses(clause.OnConflict{OnConstraint: "casbin_rule_idx", UpdateAll: true}).Create(&rule).Error; err != nil {
return err
}
}

return nil
}

func permissionToCasbinRule(permission models.Permission) models.CasbinRule {
m := models.CasbinRule{
PType: "p",
V0: permission.Principal(),
V1: "", // the principal (v0) handles this
V2: permission.Action,
V3: permission.Effect(),
}

return m
}
74 changes: 74 additions & 0 deletions models/permission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package models

import (
"fmt"
"strings"
"time"

"github.com/google/uuid"
)

type CasbinRule struct {
ID int64 `gorm:"primaryKey;autoIncrement"`
PType string `json:"ptype"`
V0 string `json:"v0"`
V1 string `json:"v1"`
V2 string `json:"v2"`
V3 string `json:"v3"`
V4 string `json:"v4"`
V5 string `json:"v5"`
}

type Permission struct {
ID uuid.UUID `json:"id" gorm:"default:generate_ulid()"`
Action string `json:"action"`
CanaryID *uuid.UUID `json:"canary_id,omitempty"`
ComponentID *uuid.UUID `json:"component_id,omitempty"`
ConfigID *uuid.UUID `json:"config_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
CreatedBy uuid.UUID `json:"created_by"`
Deny bool `json:"deny"`
Description string `json:"description"`
PersonID *uuid.UUID `json:"person_id,omitempty"`
PlaybookID *uuid.UUID `json:"playbook_id,omitempty"`
TeamID *uuid.UUID `json:"team_id,omitempty"`
Until *time.Time `json:"until"`
UpdatedAt *time.Time `json:"updated_at"`
UpdatedBy *uuid.UUID `json:"updated_by"`
}

func (t *Permission) Principal() string {
var rule []string

if t.PersonID != nil {
rule = append(rule, fmt.Sprintf("r.sub.id == %s", t.PersonID.String()))
} else if t.TeamID != nil {
rule = append(rule, fmt.Sprintf("r.sub.id == %s", t.TeamID.String()))
}

if t.ComponentID != nil {
rule = append(rule, fmt.Sprintf("r.component.id == %s", t.ComponentID.String()))
}

if t.ConfigID != nil {
rule = append(rule, fmt.Sprintf("r.config.id == %s", t.ConfigID.String()))
}

if t.CanaryID != nil {
rule = append(rule, fmt.Sprintf("r.canary.id == %s", t.CanaryID.String()))
}

if t.PlaybookID != nil {
rule = append(rule, fmt.Sprintf("r.playbook.id == %s", t.PlaybookID.String()))
}

return strings.Join(rule, " && ")
}

func (t *Permission) Effect() string {
if t.Deny {
return "deny"
}

return "allow"
}
62 changes: 62 additions & 0 deletions models/permission_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package models

import (
"testing"

"github.com/google/uuid"
"github.com/samber/lo"
)

func TestPermission_Principal(t *testing.T) {
tests := []struct {
name string
perm Permission
expected string
}{
{
name: "PersonID only",
perm: Permission{
PersonID: lo.ToPtr(uuid.MustParse("11111111-1111-1111-1111-111111111111")),
},
expected: "r.sub.id == 11111111-1111-1111-1111-111111111111",
},
{
name: "TeamID only",
perm: Permission{
TeamID: lo.ToPtr(uuid.MustParse("22222222-2222-2222-2222-222222222222")),
},
expected: "r.sub.id == 22222222-2222-2222-2222-222222222222",
},
{
name: "Multiple fields",
perm: Permission{
PersonID: lo.ToPtr(uuid.MustParse("33333333-3333-3333-3333-333333333333")),
ConfigID: lo.ToPtr(uuid.MustParse("55555555-5555-5555-5555-555555555555")),
},
expected: "r.sub.id == 33333333-3333-3333-3333-333333333333 && r.config.id == 55555555-5555-5555-5555-555555555555",
},
{
name: "Multiple fields II",
perm: Permission{
PersonID: lo.ToPtr(uuid.MustParse("66666666-6666-6666-6666-666666666666")),
ConfigID: lo.ToPtr(uuid.MustParse("88888888-8888-8888-8888-888888888888")),
PlaybookID: lo.ToPtr(uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")),
},
expected: "r.sub.id == 66666666-6666-6666-6666-666666666666 && r.config.id == 88888888-8888-8888-8888-888888888888 && r.playbook.id == aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
},
{
name: "No fields set",
perm: Permission{},
expected: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.perm.Principal()
if tt.expected != result {
t.Errorf("Expected %s, got %s", tt.expected, result)
}
})
}
}

0 comments on commit 7d875bf

Please sign in to comment.