This repository has no description
1package rbac
2
3import (
4 "database/sql"
5 "slices"
6
7 adapter "github.com/Blank-Xu/sql-adapter"
8 "github.com/casbin/casbin/v2"
9 "github.com/casbin/casbin/v2/model"
10 "github.com/casbin/casbin/v2/util"
11 "tangled.org/core/api/tangled"
12)
13
14const (
15 TnglSpindle = "tngl_spindle"
16
17 Model = `
18[request_definition]
19r = sub, dom, obj, act
20
21[policy_definition]
22p = sub, obj, act
23
24[role_definition]
25g = _, _, _
26
27[policy_effect]
28e = some(where (p.eft == allow))
29
30[matchers]
31m = g(r.sub, p.sub, r.dom) && r.obj == p.obj && r.act == p.act
32`
33)
34
35type Enforcer struct {
36 e *casbin.SyncedEnforcer
37}
38
39func NewEnforcer(path string) (*Enforcer, error) {
40 m, err := model.NewModelFromString(Model)
41 if err != nil {
42 return nil, err
43 }
44
45 db, err := sql.Open("sqlite3", path+"?_foreign_keys=1&_journal_mode=WAL&_busy_timeout=5000")
46 if err != nil {
47 return nil, err
48 }
49
50 a, err := adapter.NewAdapter(db, "sqlite3", "acl_2")
51 if err != nil {
52 return nil, err
53 }
54
55 e, err := casbin.NewSyncedEnforcer(m, a)
56 if err != nil {
57 return nil, err
58 }
59
60 if err := seedTangledPolicies(e); err != nil {
61 return nil, err
62 }
63
64 return &Enforcer{e}, nil
65}
66
67func seedTangledPolicies(e *casbin.SyncedEnforcer) error {
68 // policies
69 _, err := e.AddPoliciesEx([][]string{
70 // sub | obj | act
71 {"repo:collaborator", TnglSpindle, tangled.RepoAddSecretNSID},
72 {"repo:collaborator", TnglSpindle, tangled.RepoRemoveSecretNSID},
73 {"repo:collaborator", TnglSpindle, tangled.RepoListSecretsNSID},
74 {"repo:collaborator", TnglSpindle, tangled.CiCancelPipelineNSID},
75 {"repo:collaborator", TnglSpindle, tangled.CiTriggerPipelineNSID},
76 })
77 if err != nil {
78 return err
79 }
80
81 // grouping policies
82 e.AddNamedDomainMatchingFunc("g", "keyMatch", util.KeyMatch)
83 _, err = e.AddGroupingPoliciesEx([][]string{
84 // sub | role | dom
85 {"repo:owner", "repo:collaborator", "*"}, // repo owner is collaborator
86 })
87 return err
88}
89
90func (e *Enforcer) EnableAutoSave(autoSave bool) {
91 e.e.EnableAutoSave(autoSave)
92}
93
94func (e *Enforcer) hasImplicitRoleForUser(name string, role string, domain ...string) (bool, error) {
95 roles, err := e.e.GetImplicitRolesForUser(name, domain...)
96 if err != nil {
97 return false, err
98 }
99 return slices.Contains(roles, role), nil
100}
101
102// setRoleForUser sets single user role for specified domain.
103// All existing users with that role will be removed.
104func (e *Enforcer) setRoleForUser(name string, role string, domain ...string) error {
105 currentUsers, err := e.e.GetUsersForRole(role, domain...)
106 if err != nil {
107 return err
108 }
109
110 for _, oldUser := range currentUsers {
111 _, err = e.e.DeleteRoleForUser(oldUser, role, domain...)
112 if err != nil {
113 return err
114 }
115 }
116
117 _, err = e.e.AddRoleForUser(name, role, domain...)
118 return err
119}