mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 04:48:26 +08:00
fix(storage): deleting manifests with identical digests (#951)
Suppose we push two identical manifests (sharing same digest) but with different tags, then deleting by digest should throw an error otherwise we end up deleting all image tags (with gc) or dangling references (without gc) This behaviour is controlled via Authorization, added a new policy action named detectManifestsCollision which enables this behaviour Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> Signed-off-by: Petu Eusebiu <peusebiu@cisco.com> Co-authored-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
package requestcontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
glob "github.com/bmatcuk/doublestar/v4" //nolint:gci
|
||||
"zotregistry.io/zot/errors"
|
||||
)
|
||||
|
||||
type Key int
|
||||
|
||||
// request-local context key.
|
||||
@@ -12,7 +19,53 @@ func GetContextKey() *Key {
|
||||
|
||||
// AccessControlContext context passed down to http.Handlers.
|
||||
type AccessControlContext struct {
|
||||
GlobPatterns map[string]bool
|
||||
IsAdmin bool
|
||||
Username string
|
||||
// read method action
|
||||
ReadGlobPatterns map[string]bool
|
||||
// detectManifestCollision behaviour action
|
||||
DmcGlobPatterns map[string]bool
|
||||
IsAdmin bool
|
||||
Username string
|
||||
}
|
||||
|
||||
func GetAccessControlContext(ctx context.Context) (*AccessControlContext, error) {
|
||||
authzCtxKey := GetContextKey()
|
||||
if authCtx := ctx.Value(authzCtxKey); authCtx != nil {
|
||||
acCtx, ok := authCtx.(AccessControlContext)
|
||||
if !ok {
|
||||
return nil, errors.ErrBadType
|
||||
}
|
||||
|
||||
return &acCtx, nil
|
||||
}
|
||||
|
||||
return nil, nil //nolint: nilnil
|
||||
}
|
||||
|
||||
// returns either a user has or not rights on 'repository'.
|
||||
func (acCtx *AccessControlContext) matchesRepo(globPatterns map[string]bool, repository string) bool {
|
||||
var longestMatchedPattern string
|
||||
|
||||
// because of the longest path matching rule, we need to check all patterns from config
|
||||
for pattern := range globPatterns {
|
||||
matched, err := glob.Match(pattern, repository)
|
||||
if err == nil {
|
||||
if matched && len(pattern) > len(longestMatchedPattern) {
|
||||
longestMatchedPattern = pattern
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allowed := globPatterns[longestMatchedPattern]
|
||||
|
||||
return allowed
|
||||
}
|
||||
|
||||
// returns either a user has or not read rights on 'repository'.
|
||||
func (acCtx *AccessControlContext) CanReadRepo(repository string) bool {
|
||||
return acCtx.matchesRepo(acCtx.ReadGlobPatterns, repository)
|
||||
}
|
||||
|
||||
// returns either a user has or not detectManifestCollision rights on 'repository'.
|
||||
func (acCtx *AccessControlContext) CanDetectManifestCollision(repository string) bool {
|
||||
return acCtx.matchesRepo(acCtx.DmcGlobPatterns, repository)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user