mirror of
https://github.com/project-zot/zot.git
synced 2026-06-16 04:17:55 +08:00
image level lint: enforce manifest mandatory annotations
closes #536 Signed-off-by: Lisca Ana-Roberta <ana.kagome@yahoo.com>
This commit is contained in:
committed by
Andrei Aaron
parent
3d72dad507
commit
87fc941b3c
@@ -11,6 +11,12 @@ type ExtensionConfig struct {
|
||||
Sync *sync.Config
|
||||
Metrics *MetricsConfig
|
||||
Scrub *ScrubConfig
|
||||
Lint *LintConfig
|
||||
}
|
||||
|
||||
type LintConfig struct {
|
||||
Enabled *bool
|
||||
MandatoryAnnotations []string
|
||||
}
|
||||
|
||||
type SearchConfig struct {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build lint
|
||||
// +build lint
|
||||
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/extensions/lint"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
|
||||
func GetLinter(config *config.Config, log log.Logger) *lint.Linter {
|
||||
if config.Extensions == nil {
|
||||
return lint.NewLinter(nil, log)
|
||||
}
|
||||
|
||||
return lint.NewLinter(config.Extensions.Lint, log)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build !lint
|
||||
// +build !lint
|
||||
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/extensions/lint"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
|
||||
func GetLinter(config *config.Config, log log.Logger) *lint.Linter {
|
||||
log.Warn().Msg("lint extension is disabled because given zot binary doesn't" +
|
||||
"include this feature please build a binary that does so")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build !lint
|
||||
// +build !lint
|
||||
|
||||
package lint
|
||||
|
||||
import (
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
)
|
||||
|
||||
type Linter struct{}
|
||||
|
||||
func (linter *Linter) Lint(repo string, manifestDigest godigest.Digest,
|
||||
imageStore storage.ImageStore,
|
||||
) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
//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
|
||||
}
|
||||
|
||||
annotations := manifest.Annotations
|
||||
|
||||
for _, annot := range mandatoryAnnotationsList {
|
||||
_, found := annotations[annot]
|
||||
|
||||
if !found {
|
||||
// if annotations are not found, return false but it's not an error
|
||||
linter.log.Error().Msgf("linter: missing %s annotations", annot)
|
||||
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (linter *Linter) Lint(repo string, manifestDigest godigest.Digest,
|
||||
imageStore storage.ImageStore,
|
||||
) (bool, error) {
|
||||
return linter.CheckMandatoryAnnotations(repo, manifestDigest, imageStore)
|
||||
}
|
||||
@@ -0,0 +1,645 @@
|
||||
//go:build lint
|
||||
// +build lint
|
||||
|
||||
package lint_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/lint"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
||||
const (
|
||||
username = "test"
|
||||
passphrase = "test"
|
||||
ServerCert = "../../test/data/server.cert"
|
||||
ServerKey = "../../test/data/server.key"
|
||||
CACert = "../../test/data/ca.crt"
|
||||
AuthorizedNamespace = "everyone/isallowed"
|
||||
UnauthorizedNamespace = "fortknox/notallowed"
|
||||
ALICE = "alice"
|
||||
AuthorizationNamespace = "authz/image"
|
||||
AuthorizationAllRepos = "**"
|
||||
)
|
||||
|
||||
func TestVerifyMandatoryAnnotations(t *testing.T) {
|
||||
// nolint: dupl
|
||||
Convey("Mandatory annotations disabled", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
enabled := false
|
||||
conf.Extensions = &extconf.ExtensionConfig{Lint: &extconf.LintConfig{}}
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{}
|
||||
conf.Extensions.Lint.Enabled = &enabled
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = dir
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
resp, err := resty.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
manifestBlob := resp.Body()
|
||||
var manifest ispec.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetBody(content).Put(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
})
|
||||
|
||||
// nolint: dupl
|
||||
Convey("Mandatory annotations enabled, but no list in config", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
enabled := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{Lint: &extconf.LintConfig{}}
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{}
|
||||
|
||||
conf.Extensions.Lint.Enabled = &enabled
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = dir
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
resp, err := resty.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
manifestBlob := resp.Body()
|
||||
var manifest ispec.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetBody(content).Put(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations verification passing", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
enabled := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{Lint: &extconf.LintConfig{}}
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{}
|
||||
|
||||
conf.Extensions.Lint.Enabled = &enabled
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{"annotation1", "annotation2", "annotation3"}
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = dir
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
resp, err := resty.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
manifestBlob := resp.Body()
|
||||
var manifest ispec.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "testPass1"
|
||||
manifest.Annotations["annotation2"] = "testPass2"
|
||||
manifest.Annotations["annotation3"] = "testPass3"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetBody(content).Put(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations incomplete in manifest", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
enabled := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{Lint: &extconf.LintConfig{}}
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{}
|
||||
|
||||
conf.Extensions.Lint.Enabled = &enabled
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{"annotation1", "annotation2", "annotation3"}
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = dir
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
resp, err := resty.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
manifestBlob := resp.Body()
|
||||
var manifest ispec.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "testFail1"
|
||||
manifest.Annotations["annotation3"] = "testFail3"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetBody(content).Put(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations verification passing - more annotations than the mandatory list", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
enabled := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{Lint: &extconf.LintConfig{}}
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{}
|
||||
conf.Extensions.Lint.Enabled = &enabled
|
||||
conf.Extensions.Lint.MandatoryAnnotations = []string{"annotation1", "annotation2", "annotation3"}
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = dir
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
resp, err := resty.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
||||
manifestBlob := resp.Body()
|
||||
var manifest ispec.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "testPassMore1"
|
||||
manifest.Annotations["annotation2"] = "testPassMore2"
|
||||
manifest.Annotations["annotation3"] = "testPassMore3"
|
||||
manifest.Annotations["annotation4"] = "testPassMore4"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetBody(content).Put(baseURL + "/v2/zot-test/manifests/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||
})
|
||||
}
|
||||
|
||||
func TestVerifyMandatoryAnnotationsFunction(t *testing.T) {
|
||||
Convey("Mandatory annotations disabled", t, func() {
|
||||
enabled := false
|
||||
|
||||
lintConfig := &extconf.LintConfig{
|
||||
Enabled: &enabled,
|
||||
MandatoryAnnotations: []string{},
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
|
||||
linter := lint.NewLinter(lintConfig, log.NewLogger("debug", ""))
|
||||
imgStore := storage.NewImageStore(dir, false, 0, false, false,
|
||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), linter)
|
||||
|
||||
indexContent, err := imgStore.GetIndexContent("zot-test")
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(indexContent, &index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := index.Manifests[0].Digest
|
||||
|
||||
pass, err := linter.CheckMandatoryAnnotations("zot-test", manifestDigest, imgStore)
|
||||
So(err, ShouldBeNil)
|
||||
So(pass, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations enabled, but no list in config", t, func() {
|
||||
enabled := true
|
||||
|
||||
lintConfig := &extconf.LintConfig{
|
||||
Enabled: &enabled,
|
||||
MandatoryAnnotations: []string{},
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
|
||||
linter := lint.NewLinter(lintConfig, log.NewLogger("debug", ""))
|
||||
imgStore := storage.NewImageStore(dir, false, 0, false, false,
|
||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), linter)
|
||||
|
||||
indexContent, err := imgStore.GetIndexContent("zot-test")
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(indexContent, &index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := index.Manifests[0].Digest
|
||||
|
||||
pass, err := linter.CheckMandatoryAnnotations("zot-test", manifestDigest, imgStore)
|
||||
So(err, ShouldBeNil)
|
||||
So(pass, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations verification passing", t, func() {
|
||||
enabled := true
|
||||
|
||||
lintConfig := &extconf.LintConfig{
|
||||
Enabled: &enabled,
|
||||
MandatoryAnnotations: []string{"annotation1", "annotation2", "annotation3"},
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
buf, err := ioutil.ReadFile(path.Join(dir, "zot-test", "index.json"))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := index.Manifests[0].Digest
|
||||
|
||||
var manifest ispec.Manifest
|
||||
buf, err = ioutil.ReadFile(path.Join(dir, "zot-test", "blobs",
|
||||
manifestDigest.Algorithm().String(), manifestDigest.Encoded()))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "testPass1"
|
||||
manifest.Annotations["annotation2"] = "testPass2"
|
||||
manifest.Annotations["annotation3"] = "testPass3"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
So(content, ShouldNotBeNil)
|
||||
|
||||
digest := godigest.FromBytes(content)
|
||||
So(digest, ShouldNotBeNil)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(dir, "zot-test", "blobs",
|
||||
digest.Algorithm().String(), digest.Encoded()), content, 0o600)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDesc := ispec.Descriptor{
|
||||
Size: int64(len(content)),
|
||||
Digest: digest,
|
||||
}
|
||||
|
||||
index.Manifests = append(index.Manifests, manifestDesc)
|
||||
|
||||
linter := lint.NewLinter(lintConfig, log.NewLogger("debug", ""))
|
||||
imgStore := storage.NewImageStore(dir, false, 0, false, false,
|
||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), linter)
|
||||
|
||||
pass, err := linter.CheckMandatoryAnnotations("zot-test", digest, imgStore)
|
||||
So(err, ShouldBeNil)
|
||||
So(pass, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations incomplete in manifest", t, func() {
|
||||
enabled := true
|
||||
|
||||
lintConfig := &extconf.LintConfig{
|
||||
Enabled: &enabled,
|
||||
MandatoryAnnotations: []string{"annotation1", "annotation2", "annotation3"},
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
buf, err := ioutil.ReadFile(path.Join(dir, "zot-test", "index.json"))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := index.Manifests[0].Digest
|
||||
|
||||
var manifest ispec.Manifest
|
||||
buf, err = ioutil.ReadFile(path.Join(dir, "zot-test", "blobs",
|
||||
manifestDigest.Algorithm().String(), manifestDigest.Encoded()))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "test1"
|
||||
manifest.Annotations["annotation3"] = "test3"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
So(content, ShouldNotBeNil)
|
||||
|
||||
digest := godigest.FromBytes(content)
|
||||
So(digest, ShouldNotBeNil)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(dir, "zot-test", "blobs",
|
||||
digest.Algorithm().String(), digest.Encoded()), content, 0o600)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDesc := ispec.Descriptor{
|
||||
Size: int64(len(content)),
|
||||
Digest: digest,
|
||||
}
|
||||
|
||||
index.Manifests = append(index.Manifests, manifestDesc)
|
||||
|
||||
linter := lint.NewLinter(lintConfig, log.NewLogger("debug", ""))
|
||||
imgStore := storage.NewImageStore(dir, false, 0, false, false,
|
||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), linter)
|
||||
|
||||
pass, err := linter.CheckMandatoryAnnotations("zot-test", digest, imgStore)
|
||||
So(err, ShouldBeNil)
|
||||
So(pass, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Mandatory annotations verification passing - more annotations than the mandatory list", t, func() {
|
||||
enabled := true
|
||||
|
||||
lintConfig := &extconf.LintConfig{
|
||||
Enabled: &enabled,
|
||||
MandatoryAnnotations: []string{"annotation1", "annotation2", "annotation3"},
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
buf, err := ioutil.ReadFile(path.Join(dir, "zot-test", "index.json"))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := index.Manifests[0].Digest
|
||||
|
||||
var manifest ispec.Manifest
|
||||
buf, err = ioutil.ReadFile(path.Join(dir, "zot-test", "blobs",
|
||||
manifestDigest.Algorithm().String(), manifestDigest.Encoded()))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "testPassMore1"
|
||||
manifest.Annotations["annotation2"] = "testPassMore2"
|
||||
manifest.Annotations["annotation3"] = "testPassMore3"
|
||||
manifest.Annotations["annotation4"] = "testPassMore4"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
So(content, ShouldNotBeNil)
|
||||
|
||||
digest := godigest.FromBytes(content)
|
||||
So(digest, ShouldNotBeNil)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(dir, "zot-test", "blobs",
|
||||
digest.Algorithm().String(), digest.Encoded()), content, 0o600)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDesc := ispec.Descriptor{
|
||||
Size: int64(len(content)),
|
||||
Digest: digest,
|
||||
}
|
||||
|
||||
index.Manifests = append(index.Manifests, manifestDesc)
|
||||
|
||||
linter := lint.NewLinter(lintConfig, log.NewLogger("debug", ""))
|
||||
imgStore := storage.NewImageStore(dir, false, 0, false, false,
|
||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), linter)
|
||||
|
||||
pass, err := linter.CheckMandatoryAnnotations("zot-test", digest, imgStore)
|
||||
So(err, ShouldBeNil)
|
||||
So(pass, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Cannot unmarshal manifest", t, func() {
|
||||
enabled := true
|
||||
|
||||
lintConfig := &extconf.LintConfig{
|
||||
Enabled: &enabled,
|
||||
MandatoryAnnotations: []string{"annotation1", "annotation2", "annotation3"},
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
err := test.CopyFiles("../../../test/data", dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
buf, err := ioutil.ReadFile(path.Join(dir, "zot-test", "index.json"))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := index.Manifests[0].Digest
|
||||
|
||||
var manifest ispec.Manifest
|
||||
buf, err = ioutil.ReadFile(path.Join(dir, "zot-test", "blobs",
|
||||
manifestDigest.Algorithm().String(), manifestDigest.Encoded()))
|
||||
So(err, ShouldBeNil)
|
||||
err = json.Unmarshal(buf, &manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest.Annotations = make(map[string]string)
|
||||
|
||||
manifest.Annotations["annotation1"] = "testUnmarshal1"
|
||||
manifest.Annotations["annotation2"] = "testUnmarshal2"
|
||||
manifest.Annotations["annotation3"] = "testUnmarshal3"
|
||||
|
||||
manifest.SchemaVersion = 2
|
||||
content, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
So(content, ShouldNotBeNil)
|
||||
|
||||
digest := godigest.FromBytes(content)
|
||||
So(digest, ShouldNotBeNil)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(dir, "zot-test", "blobs",
|
||||
digest.Algorithm().String(), digest.Encoded()), content, 0o600)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDesc := ispec.Descriptor{
|
||||
Size: int64(len(content)),
|
||||
Digest: digest,
|
||||
}
|
||||
|
||||
index.Manifests = append(index.Manifests, manifestDesc)
|
||||
|
||||
linter := lint.NewLinter(lintConfig, log.NewLogger("debug", ""))
|
||||
imgStore := storage.NewImageStore(dir, false, 0, false, false,
|
||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), linter)
|
||||
|
||||
err = os.Chmod(path.Join(dir, "zot-test", "blobs"), 0o000)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pass, err := linter.CheckMandatoryAnnotations("zot-test", digest, imgStore)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(pass, ShouldBeFalse)
|
||||
|
||||
err = os.Chmod(path.Join(dir, "zot-test", "blobs"), 0o755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func startServer(c *api.Controller) {
|
||||
// this blocks
|
||||
ctx := context.Background()
|
||||
if err := c.Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func stopServer(c *api.Controller) {
|
||||
ctx := context.Background()
|
||||
_ = c.Server.Shutdown(ctx)
|
||||
}
|
||||
@@ -224,10 +224,15 @@ func TestRunScrubRepo(t *testing.T) {
|
||||
|
||||
defer os.Remove(logFile.Name()) // clean up
|
||||
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
dir := t.TempDir()
|
||||
log := log.NewLogger("debug", logFile.Name())
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
imgStore := storage.NewImageStore(dir, true, 1*time.Second, true, true, log, metrics)
|
||||
imgStore := storage.NewImageStore(dir, true, 1*time.Second, true,
|
||||
true, log, metrics, nil)
|
||||
|
||||
err = test.CopyFiles("../../../test/data/zot-test", path.Join(dir, repoName))
|
||||
if err != nil {
|
||||
@@ -247,10 +252,16 @@ func TestRunScrubRepo(t *testing.T) {
|
||||
|
||||
defer os.Remove(logFile.Name()) // clean up
|
||||
|
||||
conf := config.New()
|
||||
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
dir := t.TempDir()
|
||||
log := log.NewLogger("debug", logFile.Name())
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
imgStore := storage.NewImageStore(dir, true, 1*time.Second, true, true, log, metrics)
|
||||
imgStore := storage.NewImageStore(dir, true, 1*time.Second, true,
|
||||
true, log, metrics, nil)
|
||||
|
||||
err = test.CopyFiles("../../../test/data/zot-test", path.Join(dir, repoName))
|
||||
if err != nil {
|
||||
@@ -277,10 +288,15 @@ func TestRunScrubRepo(t *testing.T) {
|
||||
|
||||
defer os.Remove(logFile.Name()) // clean up
|
||||
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
dir := t.TempDir()
|
||||
log := log.NewLogger("debug", logFile.Name())
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
imgStore := storage.NewImageStore(dir, true, 1*time.Second, true, true, log, metrics)
|
||||
imgStore := storage.NewImageStore(dir, true, 1*time.Second,
|
||||
true, true, log, metrics, nil)
|
||||
|
||||
err = test.CopyFiles("../../../test/data/zot-test", path.Join(dir, repoName))
|
||||
if err != nil {
|
||||
|
||||
@@ -264,8 +264,13 @@ func TestImageFormat(t *testing.T) {
|
||||
log := log.NewLogger("debug", "")
|
||||
dbDir := "../../../../test/data"
|
||||
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
defaultStore := storage.NewImageStore(dbDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
defaultStore := storage.NewImageStore(dbDir, false, storage.DefaultGCDelay,
|
||||
false, false, log, metrics, nil)
|
||||
storeController := storage.StoreController{DefaultStore: defaultStore}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log)
|
||||
|
||||
@@ -708,10 +713,16 @@ func TestUtilsMethod(t *testing.T) {
|
||||
|
||||
subRootDir := t.TempDir()
|
||||
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
defaultStore := storage.NewImageStore(rootDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
subStore := storage.NewImageStore(subRootDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
defaultStore := storage.NewImageStore(rootDir, false,
|
||||
storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
|
||||
subStore := storage.NewImageStore(subRootDir, false,
|
||||
storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
|
||||
subStoreMap := make(map[string]storage.ImageStore)
|
||||
|
||||
|
||||
@@ -92,7 +92,11 @@ func testSetup() error {
|
||||
log := log.NewLogger("debug", "")
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: storage.NewImageStore(dir, false, storage.DefaultGCDelay, false, false, log, metrics)}
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: storage.NewImageStore(dir, false, storage.DefaultGCDelay, false, false, log, metrics, nil)}
|
||||
|
||||
layoutUtils := common.NewBaseOciLayoutUtils(storeController, log)
|
||||
|
||||
@@ -334,12 +338,16 @@ func TestMultipleStoragePath(t *testing.T) {
|
||||
log := log.NewLogger("debug", "")
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
// Create ImageStore
|
||||
firstStore := storage.NewImageStore(firstRootDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
firstStore := storage.NewImageStore(firstRootDir, false, storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
|
||||
secondStore := storage.NewImageStore(secondRootDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
secondStore := storage.NewImageStore(secondRootDir, false, storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
|
||||
thirdStore := storage.NewImageStore(thirdRootDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
thirdStore := storage.NewImageStore(thirdRootDir, false, storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
|
||||
storeController := storage.StoreController{}
|
||||
|
||||
|
||||
@@ -97,10 +97,15 @@ func testSetup() error {
|
||||
return err
|
||||
}
|
||||
|
||||
conf := config.New()
|
||||
conf.Extensions = &extconf.ExtensionConfig{}
|
||||
conf.Extensions.Lint = &extconf.LintConfig{}
|
||||
|
||||
log := log.NewLogger("debug", "")
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
storeController := storage.StoreController{
|
||||
DefaultStore: storage.NewImageStore(rootDir, false, storage.DefaultGCDelay, false, false, log, metrics),
|
||||
DefaultStore: storage.NewImageStore(rootDir, false, storage.DefaultGCDelay,
|
||||
false, false, log, metrics, nil),
|
||||
}
|
||||
|
||||
digestInfo = digestinfo.NewDigestInfo(storeController, log)
|
||||
|
||||
@@ -274,7 +274,8 @@ func syncOneImage(imageChannel chan error, cfg Config, storeController storage.S
|
||||
imageChannel <- nil
|
||||
}
|
||||
|
||||
func syncRun(regCfg RegistryConfig, localRepo, remoteRepo, tag string, utils syncContextUtils,
|
||||
func syncRun(regCfg RegistryConfig,
|
||||
localRepo, remoteRepo, tag string, utils syncContextUtils,
|
||||
log log.Logger,
|
||||
) (bool, error) {
|
||||
upstreamImageRef, err := getImageRef(utils.upstreamAddr, remoteRepo, tag)
|
||||
|
||||
@@ -196,7 +196,8 @@ func syncCosignSignature(client *resty.Client, imageStore storage.ImageStore,
|
||||
}
|
||||
|
||||
// push manifest
|
||||
_, err = imageStore.PutImageManifest(localRepo, cosignTag, ispec.MediaTypeImageManifest, cosignManifestBuf)
|
||||
_, err = imageStore.PutImageManifest(localRepo, cosignTag,
|
||||
ispec.MediaTypeImageManifest, cosignManifestBuf)
|
||||
if err != nil {
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msg("couldn't upload cosign manifest")
|
||||
|
||||
@@ -296,7 +296,8 @@ func getUpstreamContext(regCfg *RegistryConfig, credentials Credentials) *types.
|
||||
}
|
||||
|
||||
// nolint:gocyclo // offloading some of the functionalities from here would make the code harder to follow
|
||||
func syncRegistry(ctx context.Context, regCfg RegistryConfig, upstreamURL string,
|
||||
func syncRegistry(ctx context.Context, regCfg RegistryConfig,
|
||||
upstreamURL string,
|
||||
storeController storage.StoreController, localCtx *types.SystemContext,
|
||||
policyCtx *signature.PolicyContext, credentials Credentials,
|
||||
retryOptions *retry.RetryOptions, log log.Logger,
|
||||
@@ -509,7 +510,6 @@ func syncRegistry(ctx context.Context, regCfg RegistryConfig, upstreamURL string
|
||||
}
|
||||
// push from cache to repo
|
||||
err = pushSyncedLocalImage(localRepo, tag, localCachePath, imageStore, log)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msgf("error while pushing synced cached image %s",
|
||||
@@ -573,7 +573,8 @@ func getLocalContexts(log log.Logger) (*types.SystemContext, *signature.PolicyCo
|
||||
return localCtx, policyContext, nil
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, cfg Config, storeController storage.StoreController,
|
||||
func Run(ctx context.Context, cfg Config,
|
||||
storeController storage.StoreController,
|
||||
wtgrp *goSync.WaitGroup, logger log.Logger,
|
||||
) error {
|
||||
var credentialsFile CredentialsFile
|
||||
|
||||
@@ -61,7 +61,9 @@ func TestInjectSyncUtils(t *testing.T) {
|
||||
|
||||
log := log.Logger{Logger: zerolog.New(os.Stdout)}
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
imageStore := storage.NewImageStore(t.TempDir(), false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
imageStore := storage.NewImageStore(t.TempDir(), false, storage.DefaultGCDelay,
|
||||
false, false, log, metrics, nil,
|
||||
)
|
||||
injected = test.InjectFailure(0)
|
||||
|
||||
_, err = getLocalCachePath(imageStore, testImage)
|
||||
@@ -147,7 +149,8 @@ func TestSyncInternal(t *testing.T) {
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
So(Run(ctx, cfg, storage.StoreController{}, new(goSync.WaitGroup), log.NewLogger("debug", "")), ShouldNotBeNil)
|
||||
So(Run(ctx, cfg, storage.StoreController{},
|
||||
new(goSync.WaitGroup), log.NewLogger("debug", "")), ShouldNotBeNil)
|
||||
|
||||
_, err = getFileCredentials("/invalid/path/to/file")
|
||||
So(err, ShouldNotBeNil)
|
||||
@@ -157,7 +160,8 @@ func TestSyncInternal(t *testing.T) {
|
||||
log := log.Logger{Logger: zerolog.New(os.Stdout)}
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
|
||||
imageStore := storage.NewImageStore(t.TempDir(), false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
imageStore := storage.NewImageStore(t.TempDir(), false, storage.DefaultGCDelay,
|
||||
false, false, log, metrics, nil)
|
||||
|
||||
err := os.Chmod(imageStore.RootDir(), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -340,7 +344,8 @@ func TestSyncInternal(t *testing.T) {
|
||||
log := log.Logger{Logger: zerolog.New(os.Stdout)}
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
|
||||
imageStore := storage.NewImageStore(storageDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
imageStore := storage.NewImageStore(storageDir, false, storage.DefaultGCDelay,
|
||||
false, false, log, metrics, nil)
|
||||
|
||||
refs := ReferenceList{[]artifactspec.Descriptor{
|
||||
{
|
||||
@@ -422,7 +427,8 @@ func TestSyncInternal(t *testing.T) {
|
||||
log := log.Logger{Logger: zerolog.New(os.Stdout)}
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
|
||||
imageStore := storage.NewImageStore(storageDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
imageStore := storage.NewImageStore(storageDir, false, storage.DefaultGCDelay,
|
||||
false, false, log, metrics, nil)
|
||||
|
||||
storeController := storage.StoreController{}
|
||||
storeController.DefaultStore = imageStore
|
||||
@@ -443,7 +449,8 @@ func TestSyncInternal(t *testing.T) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
testImageStore := storage.NewImageStore(testRootDir, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
testImageStore := storage.NewImageStore(testRootDir, false,
|
||||
storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
manifestContent, _, _, err := testImageStore.GetImageManifest(testImage, testImageTag)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
|
||||
@@ -862,6 +862,107 @@ func TestConfigReloader(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMandatoryAnnotations(t *testing.T) {
|
||||
Convey("Verify mandatory annotations failing - on demand disabled", t, func() {
|
||||
updateDuration, _ := time.ParseDuration("30m")
|
||||
|
||||
sctlr, srcBaseURL, _, _, _ := startUpstreamServer(t, false, false)
|
||||
|
||||
defer func() {
|
||||
sctlr.Shutdown()
|
||||
}()
|
||||
|
||||
regex := ".*"
|
||||
var semver bool
|
||||
tlsVerify := false
|
||||
|
||||
syncRegistryConfig := sync.RegistryConfig{
|
||||
Content: []sync.Content{
|
||||
{
|
||||
Prefix: testImage,
|
||||
Tags: &sync.Tags{
|
||||
Regex: ®ex,
|
||||
Semver: &semver,
|
||||
},
|
||||
},
|
||||
},
|
||||
URLs: []string{srcBaseURL},
|
||||
OnDemand: false,
|
||||
PollInterval: updateDuration,
|
||||
TLSVerify: &tlsVerify,
|
||||
}
|
||||
|
||||
defaultVal := true
|
||||
syncConfig := &sync.Config{
|
||||
Enable: &defaultVal,
|
||||
Registries: []sync.RegistryConfig{syncRegistryConfig},
|
||||
}
|
||||
|
||||
destPort := test.GetFreePort()
|
||||
destConfig := config.New()
|
||||
destClient := resty.New()
|
||||
|
||||
destBaseURL := test.GetBaseURL(destPort)
|
||||
|
||||
destConfig.HTTP.Port = destPort
|
||||
|
||||
destDir := t.TempDir()
|
||||
|
||||
destConfig.Storage.RootDirectory = destDir
|
||||
destConfig.Storage.Dedupe = false
|
||||
destConfig.Storage.GC = false
|
||||
|
||||
destConfig.Extensions = &extconf.ExtensionConfig{}
|
||||
destConfig.Extensions.Sync = syncConfig
|
||||
|
||||
logFile, err := ioutil.TempFile("", "zot-log*.txt")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
destConfig.Log.Output = logFile.Name()
|
||||
|
||||
lintEnabled := true
|
||||
destConfig.Extensions.Lint = &extconf.LintConfig{}
|
||||
destConfig.Extensions.Lint.Enabled = &lintEnabled
|
||||
destConfig.Extensions.Lint.MandatoryAnnotations = []string{"annot1", "annot2", "annot3"}
|
||||
|
||||
dctlr := api.NewController(destConfig)
|
||||
|
||||
go func() {
|
||||
// this blocks
|
||||
if err := dctlr.Run(context.Background()); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// wait till ready
|
||||
for {
|
||||
_, err := destClient.R().Get(destBaseURL)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
dctlr.Shutdown()
|
||||
}()
|
||||
|
||||
// give it time to set up sync
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
resp, err := destClient.R().Get(destBaseURL + "/v2/" + testImage + "/manifest/0.0.1")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 404)
|
||||
|
||||
data, err := os.ReadFile(logFile.Name())
|
||||
t.Logf("downstream log: %s", string(data))
|
||||
So(err, ShouldBeNil)
|
||||
So(string(data), ShouldContainSubstring, "couldn't upload manifest because of missing annotations")
|
||||
})
|
||||
}
|
||||
|
||||
func TestBadTLS(t *testing.T) {
|
||||
Convey("Verify sync TLS feature", t, func() {
|
||||
updateDuration, _ := time.ParseDuration("30m")
|
||||
|
||||
@@ -270,7 +270,9 @@ func pushSyncedLocalImage(localRepo, tag, localCachePath string,
|
||||
log.Info().Msgf("pushing synced local image %s/%s:%s to local registry", localCachePath, localRepo, tag)
|
||||
|
||||
metrics := monitoring.NewMetricsServer(false, log)
|
||||
cacheImageStore := storage.NewImageStore(localCachePath, false, storage.DefaultGCDelay, false, false, log, metrics)
|
||||
|
||||
cacheImageStore := storage.NewImageStore(localCachePath, false,
|
||||
storage.DefaultGCDelay, false, false, log, metrics, nil)
|
||||
|
||||
manifestContent, _, _, err := cacheImageStore.GetImageManifest(localRepo, tag)
|
||||
if err != nil {
|
||||
@@ -331,8 +333,16 @@ func pushSyncedLocalImage(localRepo, tag, localCachePath string,
|
||||
}
|
||||
}
|
||||
|
||||
_, err = imageStore.PutImageManifest(localRepo, tag, ispec.MediaTypeImageManifest, manifestContent)
|
||||
_, err = imageStore.PutImageManifest(localRepo, tag,
|
||||
ispec.MediaTypeImageManifest, manifestContent)
|
||||
if err != nil {
|
||||
if errors.Is(err, zerr.ErrImageLintAnnotations) {
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msg("couldn't upload manifest because of missing annotations")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msg("couldn't upload manifest")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user