dehub/accessctl/filter_pattern.go
mediocregopher 1f422511d5 completely refactor accessctl (again)
---
type: change
message: |-
  completely refactor accessctl (again)

  This time it's using an actual access control list system, rather than whatever
  it was doing before. The new system uses a Filter type, rather than Condition,
  to decide which acl element should have its action (allow or deny) applied. This
  makes testing way easier, since all the different matching conditions are now
  individual filters, and so are tested individually.
change_hash: AFgN0hormIlO0VWkLKnAdSDZeVRbh0Wj8LLXOMVQEK+L
credentials:
- type: pgp_signature
  pub_key_id: 95C46FA6A41148AC
  body: iQIzBAABAgAdFiEEJ6tQKp6olvZKJ0lwlcRvpqQRSKwFAl5yoi8ACgkQlcRvpqQRSKwo/g//QkSA80APnPtwcibNeaoUwduH1Xim8pmi5JScKGsOypYkE0Iy+fO3fRNz4r7Tm6qNn7O04fDsiXlxPojxn7+NDFCQArVgoJk3jVTRDBW7LpahWJsYPP1SBjGtaR9o0bOpclXblTMIcteTkLM94AeASqLaEY8StO+5PX/82AkFRQ8E6m9R2HCmgwbBhqwWp8936x8ekMFbSSi0TMIyV4rpd0wj4mjvjjBwa3ArGmH/ynwabPCFuuqMT6996N1zoDn5EqZA5jGrf+Q7rxsI6t1bOnLmg9NGMQYRaZLAVZrp5P6G5XR3et4Gz/2AphAEgYJM3yLbEjZW6Daa77CgTNHXde7gCaWqyfcKlVGPi29/O+2IXhpjwxHwGpsBgEdX9227zapL+jwSAOdUVj8n6C8I8BGqpT7rTwA53yxlbSwXlkttvAn/lGT5X4lK74YfkzMXMEBZKzsb/dQEPyP2Y+AG6z2D4Bs/4szsCiUXF9aG2Yx1o45lVXTTdPUNLIsnhBjM7usbQRg8i5kC+OC9AVCi8E+lf0/Qgp0cUb6QLH47bHvDTH7UluY1bgSLZy+Zjaisvl3a0aK/UspywWN/fFgOrz2cDw232n8IC+Zi4LSKm7dXDRFbC1JNzrwAPP1ifboOrltwKroOsDNaVGhX8ABahNjmrUO4JgE7gvX+zxXb+/I=
  account: mediocregopher
2020-03-18 16:35:32 -06:00

93 lines
2.5 KiB
Go

package accessctl
import (
"errors"
"fmt"
"github.com/bmatcuk/doublestar"
)
// StringMatcher is used to match against a string. It can use one of several
// methods to match. Only one field should be filled at a time.
type StringMatcher struct {
// Pattern, if set, indicates that the Match method should succeed if this
// doublestar pattern matches against the string.
Pattern string `yaml:"pattern,omitempty"`
// Patterns, if set, indicates that the Match method should succeed if at
// least one of these doublestar patterns matches against the string.
Patterns []string `yaml:"patterns,omitempty"`
}
func doublestarMatch(pattern, str string) (bool, error) {
ok, err := doublestar.Match(pattern, str)
if err != nil {
return false, fmt.Errorf("matching %q on pattern %q: %w",
str, pattern, err)
}
return ok, nil
}
// Match operates similarly to the Match method of the FilterInterface, except
// it only takes in strings.
func (m StringMatcher) Match(str string) error {
switch {
case m.Pattern != "":
if ok, err := doublestarMatch(m.Pattern, str); err != nil {
return err
} else if !ok {
return ErrFilterNoMatch{
Err: fmt.Errorf("pattern %q does not match %q", m.Pattern, str),
}
}
return nil
case len(m.Patterns) > 0:
for _, pattern := range m.Patterns {
if ok, err := doublestarMatch(pattern, str); err != nil {
return err
} else if ok {
return nil
}
}
return ErrFilterNoMatch{
Err: fmt.Errorf("no patterns in %+v match %q", m.Patterns, str),
}
default:
return errors.New(`one of the following fields must be set: "pattern", "patterns"`)
}
}
// FilterBranch matches a CommitRequest's Branch field using a double-star
// pattern.
type FilterBranch struct {
StringMatcher StringMatcher `yaml:",inline"`
}
var _ FilterInterface = FilterBranch{}
// MatchCommit implements the method for FilterInterface.
func (f FilterBranch) MatchCommit(req CommitRequest) error {
return f.StringMatcher.Match(req.Branch)
}
// FilterFilesChanged matches a CommitRequest's FilesChanged field using a
// double-star pattern. It only matches if all of the CommitRequest's
// FilesChanged match.
type FilterFilesChanged struct {
StringMatcher StringMatcher `yaml:",inline"`
}
var _ FilterInterface = FilterFilesChanged{}
// MatchCommit implements the method for FilterInterface.
func (f FilterFilesChanged) MatchCommit(req CommitRequest) error {
for _, path := range req.FilesChanged {
if err := f.StringMatcher.Match(path); err != nil {
return err
}
}
return nil
}