Monorepo for Tangled tangled.org

appview/validator: limit label ops to collaborators

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 96de6d14 34e02d1f

verified
Changed files
+33 -6
appview
+1 -1
appview/ingester.go
··· 1008 1008 if !ok { 1009 1009 return fmt.Errorf("failed to find label def for key: %s, expected: %q", o.OperandKey, slices.Collect(maps.Keys(actx.Defs))) 1010 1010 } 1011 - if err := i.Validator.ValidateLabelOp(def, &o); err != nil { 1011 + if err := i.Validator.ValidateLabelOp(def, repo, &o); err != nil { 1012 1012 return fmt.Errorf("failed to validate labelop: %w", err) 1013 1013 } 1014 1014 }
+11 -1
appview/labels/labels.go
··· 23 23 "tangled.org/core/appview/validator" 24 24 "tangled.org/core/appview/xrpcclient" 25 25 "tangled.org/core/log" 26 + "tangled.org/core/rbac" 26 27 "tangled.org/core/tid" 27 28 ) 28 29 ··· 32 33 db *db.DB 33 34 logger *slog.Logger 34 35 validator *validator.Validator 36 + enforcer *rbac.Enforcer 35 37 } 36 38 37 39 func New( ··· 39 41 pages *pages.Pages, 40 42 db *db.DB, 41 43 validator *validator.Validator, 44 + enforcer *rbac.Enforcer, 42 45 ) *Labels { 43 46 logger := log.New("labels") 44 47 ··· 48 51 db: db, 49 52 logger: logger, 50 53 validator: validator, 54 + enforcer: enforcer, 51 55 } 52 56 } 53 57 ··· 86 90 repoAt := r.Form.Get("repo") 87 91 subjectUri := r.Form.Get("subject") 88 92 93 + repo, err := db.GetRepo(l.db, db.FilterEq("at_uri", repoAt)) 94 + if err != nil { 95 + fail("Failed to get repository.", err) 96 + return 97 + } 98 + 89 99 // find all the labels that this repo subscribes to 90 100 repoLabels, err := db.GetRepoLabels(l.db, db.FilterEq("repo_at", repoAt)) 91 101 if err != nil { ··· 157 167 158 168 for i := range labelOps { 159 169 def := actx.Defs[labelOps[i].OperandKey] 160 - if err := l.validator.ValidateLabelOp(def, &labelOps[i]); err != nil { 170 + if err := l.validator.ValidateLabelOp(def, repo, &labelOps[i]); err != nil { 161 171 fail(fmt.Sprintf("Invalid form data: %s", err), err) 162 172 return 163 173 }
+1 -1
appview/state/router.go
··· 274 274 } 275 275 276 276 func (s *State) LabelsRouter(mw *middleware.Middleware) http.Handler { 277 - ls := labels.New(s.oauth, s.pages, s.db, s.validator) 277 + ls := labels.New(s.oauth, s.pages, s.db, s.validator, s.enforcer) 278 278 return ls.Router(mw) 279 279 } 280 280
+1 -1
appview/state/state.go
··· 79 79 cache := cache.New(config.Redis.Addr) 80 80 sess := session.New(cache) 81 81 oauth := oauth.NewOAuth(config, sess) 82 - validator := validator.New(d, res) 82 + validator := validator.New(d, res, enforcer) 83 83 84 84 posthog, err := posthog.NewWithConfig(config.Posthog.ApiKey, posthog.Config{Endpoint: config.Posthog.Endpoint}) 85 85 if err != nil {
+15 -1
appview/validator/label.go
··· 95 95 return nil 96 96 } 97 97 98 - func (v *Validator) ValidateLabelOp(labelDef *models.LabelDefinition, labelOp *models.LabelOp) error { 98 + func (v *Validator) ValidateLabelOp(labelDef *models.LabelDefinition, repo *models.Repo, labelOp *models.LabelOp) error { 99 99 if labelDef == nil { 100 100 return fmt.Errorf("label definition is required") 101 101 } 102 + if repo == nil { 103 + return fmt.Errorf("repo is required") 104 + } 102 105 if labelOp == nil { 103 106 return fmt.Errorf("label operation is required") 107 + } 108 + 109 + // validate permissions: only collaborators can apply labels currently 110 + // 111 + // TODO: introduce a repo:triage permission 112 + ok, err := v.enforcer.IsPushAllowed(labelOp.Did, repo.Knot, repo.DidSlashRepo()) 113 + if err != nil { 114 + return fmt.Errorf("failed to enforce permissions: %w", err) 115 + } 116 + if !ok { 117 + return fmt.Errorf("unauhtorized label operation") 104 118 } 105 119 106 120 expectedKey := labelDef.AtUri().String()
+4 -1
appview/validator/validator.go
··· 4 4 "tangled.org/core/appview/db" 5 5 "tangled.org/core/appview/pages/markup" 6 6 "tangled.org/core/idresolver" 7 + "tangled.org/core/rbac" 7 8 ) 8 9 9 10 type Validator struct { 10 11 db *db.DB 11 12 sanitizer markup.Sanitizer 12 13 resolver *idresolver.Resolver 14 + enforcer *rbac.Enforcer 13 15 } 14 16 15 - func New(db *db.DB, res *idresolver.Resolver) *Validator { 17 + func New(db *db.DB, res *idresolver.Resolver, enforcer *rbac.Enforcer) *Validator { 16 18 return &Validator{ 17 19 db: db, 18 20 sanitizer: markup.NewSanitizer(), 19 21 resolver: res, 22 + enforcer: enforcer, 20 23 } 21 24 }