2022-06-24 08:08:47 -05:00
|
|
|
//go:build lint
|
|
|
|
// +build lint
|
|
|
|
|
|
|
|
package lint
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
|
|
|
|
godigest "github.com/opencontainers/go-digest"
|
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
"zotregistry.io/zot/pkg/extensions/config"
|
|
|
|
"zotregistry.io/zot/pkg/log"
|
|
|
|
"zotregistry.io/zot/pkg/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Linter struct {
|
|
|
|
config *config.LintConfig
|
|
|
|
log log.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewLinter(config *config.LintConfig, log log.Logger) *Linter {
|
|
|
|
return &Linter{
|
|
|
|
config: config,
|
|
|
|
log: log,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (linter *Linter) CheckMandatoryAnnotations(repo string, manifestDigest godigest.Digest,
|
|
|
|
imgStore storage.ImageStore,
|
|
|
|
) (bool, error) {
|
|
|
|
if linter.config == nil {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if (linter.config != nil && !*linter.config.Enabled) || len(linter.config.MandatoryAnnotations) == 0 {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
mandatoryAnnotationsList := linter.config.MandatoryAnnotations
|
|
|
|
|
|
|
|
content, err := imgStore.GetBlobContent(repo, string(manifestDigest))
|
|
|
|
if err != nil {
|
|
|
|
linter.log.Error().Err(err).Msg("linter: unable to get image manifest")
|
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var manifest ispec.Manifest
|
|
|
|
|
|
|
|
if err := json.Unmarshal(content, &manifest); err != nil {
|
|
|
|
linter.log.Error().Err(err).Msg("linter: couldn't unmarshal manifest JSON")
|
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
2022-09-23 11:28:30 -05:00
|
|
|
mandatoryAnnotationsMap := make(map[string]bool)
|
|
|
|
for _, annotation := range mandatoryAnnotationsList {
|
|
|
|
mandatoryAnnotationsMap[annotation] = false
|
|
|
|
}
|
2022-06-24 08:08:47 -05:00
|
|
|
|
2022-09-23 11:28:30 -05:00
|
|
|
manifestAnnotations := manifest.Annotations
|
|
|
|
for annotation := range manifestAnnotations {
|
|
|
|
if _, ok := mandatoryAnnotationsMap[annotation]; ok {
|
|
|
|
mandatoryAnnotationsMap[annotation] = true
|
|
|
|
}
|
|
|
|
}
|
2022-06-24 08:08:47 -05:00
|
|
|
|
2022-09-23 11:28:30 -05:00
|
|
|
missingAnnotations := getMissingAnnotations(mandatoryAnnotationsMap)
|
|
|
|
if len(missingAnnotations) == 0 {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there are mandatory annotations missing in the manifest, get config and check these annotations too
|
|
|
|
configDigest := manifest.Config.Digest
|
2022-06-24 08:08:47 -05:00
|
|
|
|
2022-09-23 11:28:30 -05:00
|
|
|
content, err = imgStore.GetBlobContent(repo, string(configDigest))
|
|
|
|
if err != nil {
|
|
|
|
linter.log.Error().Err(err).Msg("linter: couldn't get config JSON " + string(configDigest))
|
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var imageConfig ispec.Image
|
|
|
|
if err := json.Unmarshal(content, &imageConfig); err != nil {
|
|
|
|
linter.log.Error().Err(err).Msg("linter: couldn't unmarshal config JSON " + string(configDigest))
|
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
configAnnotations := imageConfig.Config.Labels
|
|
|
|
|
|
|
|
for annotation := range configAnnotations {
|
|
|
|
if _, ok := mandatoryAnnotationsMap[annotation]; ok {
|
|
|
|
mandatoryAnnotationsMap[annotation] = true
|
2022-06-24 08:08:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-23 11:28:30 -05:00
|
|
|
missingAnnotations = getMissingAnnotations(mandatoryAnnotationsMap)
|
|
|
|
if len(missingAnnotations) > 0 {
|
|
|
|
linter.log.Error().Msgf("linter: manifest %s / config %s are missing annotations: %s",
|
|
|
|
string(manifestDigest), string(configDigest), missingAnnotations)
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2022-06-24 08:08:47 -05:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (linter *Linter) Lint(repo string, manifestDigest godigest.Digest,
|
|
|
|
imageStore storage.ImageStore,
|
|
|
|
) (bool, error) {
|
|
|
|
return linter.CheckMandatoryAnnotations(repo, manifestDigest, imageStore)
|
|
|
|
}
|
2022-09-23 11:28:30 -05:00
|
|
|
|
|
|
|
func getMissingAnnotations(mandatoryAnnotationsMap map[string]bool) []string {
|
|
|
|
var missingAnnotations []string
|
|
|
|
|
|
|
|
for annotation, flag := range mandatoryAnnotationsMap {
|
|
|
|
if !flag {
|
|
|
|
missingAnnotations = append(missingAnnotations, annotation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return missingAnnotations
|
|
|
|
}
|