1f422511d5
--- 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
103 lines
2.9 KiB
Go
103 lines
2.9 KiB
Go
package accessctl
|
|
|
|
import (
|
|
"dehub/typeobj"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// ErrFilterNoMatch is returned from a FilterInterface's Match method when the
|
|
// given request was not matched to the filter due to the request itself (as
|
|
// opposed to some error in the filter's definition).
|
|
type ErrFilterNoMatch struct {
|
|
Err error
|
|
}
|
|
|
|
func (err ErrFilterNoMatch) Error() string {
|
|
return fmt.Sprintf("matching with filter: %s", err.Err.Error())
|
|
}
|
|
|
|
// FilterInterface describes the methods that all Filters must implement.
|
|
type FilterInterface interface {
|
|
// MatchCommit returns nil if the CommitRequest is matched by the filter,
|
|
// otherwise it returns an error (ErrFilterNoMatch if the error is due to
|
|
// the CommitRequest).
|
|
MatchCommit(CommitRequest) error
|
|
}
|
|
|
|
// Filter represents an access control filter being defined in the Config. Only
|
|
// one of its fields may be filled at a time.
|
|
type Filter struct {
|
|
Signature *FilterSignature `type:"signature"`
|
|
Branch *FilterBranch `type:"branch"`
|
|
FilesChanged *FilterFilesChanged `type:"files_changed"`
|
|
CommitType *FilterCommitType `type:"commit_type"`
|
|
Not *FilterNot `type:"not"`
|
|
}
|
|
|
|
// MarshalYAML implements the yaml.Marshaler interface.
|
|
func (f Filter) MarshalYAML() (interface{}, error) {
|
|
return typeobj.MarshalYAML(f)
|
|
}
|
|
|
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
|
func (f *Filter) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
return typeobj.UnmarshalYAML(f, unmarshal)
|
|
}
|
|
|
|
// Interface returns the FilterInterface encapsulated by this Filter.
|
|
func (f Filter) Interface() (FilterInterface, error) {
|
|
el, _, err := typeobj.Element(f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return el.(FilterInterface), nil
|
|
}
|
|
|
|
// Type returns a string describing what type of Filter this object
|
|
// encapsulates, based on which of its fields are filled in.
|
|
func (f Filter) Type() (string, error) {
|
|
_, typeStr, err := typeobj.Element(f)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return typeStr, nil
|
|
}
|
|
|
|
// FilterCommitType filters by what type of commit is being requested. Exactly
|
|
// one of its fields should be filled.
|
|
type FilterCommitType struct {
|
|
Type string `yaml:"commit_type"`
|
|
Types []string `yaml:"commit_types"`
|
|
}
|
|
|
|
var _ FilterInterface = FilterCommitType{}
|
|
|
|
// MatchCommit implements the method for FilterInterface.
|
|
func (f FilterCommitType) MatchCommit(req CommitRequest) error {
|
|
switch {
|
|
case f.Type != "":
|
|
if f.Type != req.Type {
|
|
return ErrFilterNoMatch{
|
|
Err: fmt.Errorf("commit type %q does not match filter's type %q",
|
|
req.Type, f.Type),
|
|
}
|
|
}
|
|
return nil
|
|
|
|
case len(f.Types) > 0:
|
|
for _, typ := range f.Types {
|
|
if typ == req.Type {
|
|
return nil
|
|
}
|
|
}
|
|
return ErrFilterNoMatch{
|
|
Err: fmt.Errorf("commit type %q does not match any of filter's types %+v",
|
|
req.Type, f.Types),
|
|
}
|
|
|
|
default:
|
|
return errors.New(`one of the following fields must be set: "commit_type", "commit_types"`)
|
|
}
|
|
}
|