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