0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-30 22:34:13 -05:00

fix: signatures now showing correctly (#954)

Signed-off-by: Ana-Roberta Lisca <ana.kagome@yahoo.com>
This commit is contained in:
Lisca Ana-Roberta 2022-11-15 19:06:25 +02:00 committed by GitHub
parent e96c80c344
commit 4e13619dc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 208 additions and 1 deletions

View file

@ -17,10 +17,15 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
notreg "github.com/notaryproject/notation-go/registry"
"github.com/sigstore/cosign/pkg/oci/remote"
zotErrors "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/storage/local"
)
@ -297,6 +302,33 @@ func (p *requestsPool) doJob(ctx context.Context, job *manifestJob) {
p.outputCh <- stringResult{"", err}
}
isSigned := false
cosignTag := strings.Replace(digestStr, ":", "-", 1) + "." + remote.SignatureTagSuffix
_, err = makeGETRequest(ctx, *job.config.servURL+"/v2/"+job.imageName+
"/manifests/"+cosignTag, job.username, job.password,
*job.config.verifyTLS, *job.config.debug, &job.manifestResp, job.config.resultWriter)
if err == nil {
isSigned = true
}
var referrers api.ReferenceList
if !isSigned {
_, err = makeGETRequest(ctx, fmt.Sprintf("%s/oras/artifacts/v1/%s/manifests/%s/referrers?artifactType=%s",
*job.config.servURL, job.imageName, digestStr, notreg.ArtifactTypeNotation), job.username, job.password,
*job.config.verifyTLS, *job.config.debug, &referrers, job.config.resultWriter)
if err == nil {
for _, reference := range referrers.References {
if reference.ArtifactType == notreg.ArtifactTypeNotation {
isSigned = true
break
}
}
}
}
size += uint64(manifestSize)
image := &imageStruct{}
@ -307,6 +339,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *manifestJob) {
image.Size = strconv.Itoa(int(size))
image.ConfigDigest = configDigest
image.Layers = layers
image.IsSigned = isSigned
str, err := image.string(*job.config.outputFormat, len(job.imageName), len(job.tagName))
if err != nil {

View file

@ -11,6 +11,7 @@ import (
"io"
"log"
"os"
"os/exec"
"path"
"regexp"
"strings"
@ -255,6 +256,46 @@ func TestSearchImageCmd(t *testing.T) {
})
}
func SignImageUsingNotary(repoTag, port string) error {
cwd, err := os.Getwd()
if err != nil {
return err
}
defer func() { _ = os.Chdir(cwd) }()
tdir, err := os.MkdirTemp("", "notation")
if err != nil {
return err
}
defer os.RemoveAll(tdir)
_ = os.Chdir(tdir)
_, err = exec.LookPath("notation")
if err != nil {
return err
}
os.Setenv("XDG_CONFIG_HOME", tdir)
// generate a keypair
cmd := exec.Command("notation", "cert", "generate-test", "--trust", "notation-sign-test")
err = cmd.Run()
if err != nil {
return err
}
// sign the image
image := fmt.Sprintf("localhost:%s/%s", port, repoTag)
cmd = exec.Command("notation", "sign", "--key", "notation-sign-test", "--plain-http", image)
return cmd.Run()
}
func TestSignature(t *testing.T) {
Convey("Test from real server", t, func() {
currentWorkingDir, err := os.Getwd()
@ -376,7 +417,140 @@ func TestSignature(t *testing.T) {
str := space.ReplaceAllString(buff.String(), " ")
actual := strings.TrimSpace(str)
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST SIGNED SIZE")
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 true")
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 true 15B")
t.Log("Test getting all images using rest calls to get catalog and individual manifests")
cmd = MockNewImageCommand(new(searchService))
buff = &bytes.Buffer{}
cmd.SetOut(buff)
cmd.SetErr(buff)
cmd.SetArgs(args)
err = cmd.Execute()
So(err, ShouldBeNil)
str = space.ReplaceAllString(buff.String(), " ")
actual = strings.TrimSpace(str)
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST SIGNED SIZE")
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 true 492B")
err = os.Chdir(currentWorkingDir)
So(err, ShouldBeNil)
})
Convey("Test with notation signature", t, func() {
currentWorkingDir, err := os.Getwd()
So(err, ShouldBeNil)
currentDir := t.TempDir()
err = os.Chdir(currentDir)
So(err, ShouldBeNil)
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = currentDir
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
// create a blob/layer
resp, _ := resty.R().Post(url + "/v2/repo7/blobs/uploads/")
loc := test.Location(url, resp)
content := []byte("this is a blob5")
digest := godigest.FromBytes(content)
_, _ = resty.R().SetQueryParam("digest", digest.String()).
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(loc)
// upload image config blob
resp, _ = resty.R().Post(url + "/v2/repo7/blobs/uploads/")
loc = test.Location(url, resp)
cblob, cdigest := test.GetImageConfig()
_, _ = resty.R().
SetContentLength(true).
SetHeader("Content-Length", fmt.Sprintf("%d", len(cblob))).
SetHeader("Content-Type", "application/octet-stream").
SetQueryParam("digest", cdigest.String()).
SetBody(cblob).
Put(loc)
// create a manifest
manifest := ispec.Manifest{
Config: ispec.Descriptor{
MediaType: "application/vnd.oci.image.config.v1+json",
Digest: cdigest,
Size: int64(len(cblob)),
},
Layers: []ispec.Descriptor{
{
MediaType: "application/vnd.oci.image.layer.v1.tar",
Digest: digest,
Size: int64(len(content)),
},
},
}
manifest.SchemaVersion = 2
content, err = json.Marshal(manifest)
So(err, ShouldBeNil)
_, _ = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(content).Put(url + "/v2/repo7/manifests/0.0.1")
err = SignImageUsingNotary("repo7:0.0.1", port)
So(err, ShouldBeNil)
t.Logf("%s", ctlr.Config.Storage.RootDirectory)
args := []string{"imagetest"}
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s","showspinner":false}]}`, url))
defer os.Remove(configPath)
cmd := NewImageCommand(new(searchService))
buff := &bytes.Buffer{}
cmd.SetOut(buff)
cmd.SetErr(buff)
cmd.SetArgs(args)
err = cmd.Execute()
So(err, ShouldBeNil)
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
actual := strings.TrimSpace(str)
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST SIGNED SIZE")
So(actual, ShouldContainSubstring, "repo7 0.0.1 883fc0c5 true 15B")
t.Log("Test getting all images using rest calls to get catalog and individual manifests")
cmd = MockNewImageCommand(new(searchService))
buff = &bytes.Buffer{}
cmd.SetOut(buff)
cmd.SetErr(buff)
cmd.SetArgs(args)
err = cmd.Execute()
So(err, ShouldBeNil)
str = space.ReplaceAllString(buff.String(), " ")
actual = strings.TrimSpace(str)
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST SIGNED SIZE")
So(actual, ShouldContainSubstring, "repo7 0.0.1 883fc0c5 true 492B")
err = os.Chdir(currentWorkingDir)
So(err, ShouldBeNil)