0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-02-03 23:09:41 -05:00
zot/pkg/test/signature/notation_test.go
Andrei Aaron ba6f347d8d
refactor(pkg/test): split logic in pkg/test/common.go into multiple packages (#1861)
Which could be imported independently. See more details:
1. "zotregistry.io/zot/pkg/test/common" - currently used as
   tcommon "zotregistry.io/zot/pkg/test/common" - inside pkg/test
   test "zotregistry.io/zot/pkg/test/common" - in tests
   . "zotregistry.io/zot/pkg/test/common" - in tests
Decouple zb from code in test/pkg in order to keep the size small.

2. "zotregistry.io/zot/pkg/test/image-utils" - curently used as
   . "zotregistry.io/zot/pkg/test/image-utils"

3. "zotregistry.io/zot/pkg/test/deprecated" -  curently used as
   "zotregistry.io/zot/pkg/test/deprecated"
This one will bre replaced gradually by image-utils in the future.

4. "zotregistry.io/zot/pkg/test/signature" - (cosign + notation) use as
   "zotregistry.io/zot/pkg/test/signature"

5. "zotregistry.io/zot/pkg/test/auth" - (bearer + oidc)  curently used as
   authutils "zotregistry.io/zot/pkg/test/auth"

 6. "zotregistry.io/zot/pkg/test/oci-utils" -  curently used as
   ociutils "zotregistry.io/zot/pkg/test/oci-utils"

Some unused functions were removed, some were replaced, and in
a few cases specific funtions were moved to the files they were used in.

Added an interface for the StoreController, this reduces the number of imports
of the entire image store, decreasing binary size for tests.
If the zb code was still coupled with pkg/test, this would have reflected in zb size.

Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
2023-09-27 11:34:48 -07:00

464 lines
13 KiB
Go

//go:build sync && scrub && metrics && search
// +build sync,scrub,metrics,search
package signature_test
import (
"encoding/json"
"fmt"
"os"
"path"
"testing"
notconfig "github.com/notaryproject/notation-go/config"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
tcommon "zotregistry.io/zot/pkg/test/common"
. "zotregistry.io/zot/pkg/test/image-utils"
signature "zotregistry.io/zot/pkg/test/signature"
)
func TestLoadNotationSigningkeys(t *testing.T) {
Convey("notation directory doesn't exist", t, func() {
_, err := signature.LoadNotationSigningkeys(t.TempDir())
So(err, ShouldNotBeNil)
})
Convey("wrong content of signingkeys.json", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
err := os.Mkdir(dir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(dir, "signingkeys.json")
err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
_, err = signature.LoadNotationSigningkeys(tempDir)
So(err, ShouldNotBeNil)
})
Convey("not enough permissions to access signingkeys.json", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
err := os.Mkdir(dir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(dir, "signingkeys.json")
err = os.WriteFile(filePath, []byte("some dummy file content"), 0o300) //nolint: gosec
So(err, ShouldBeNil)
_, err = signature.LoadNotationSigningkeys(tempDir)
So(err, ShouldNotBeNil)
})
Convey("signingkeys.json not exists so it is created successfully", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
err := os.Mkdir(dir, 0o777)
So(err, ShouldBeNil)
_, err = signature.LoadNotationSigningkeys(tempDir)
So(err, ShouldBeNil)
})
Convey("signingkeys.json not exists - error trying to create it", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
// create notation directory without write permissions
err := os.Mkdir(dir, 0o555)
So(err, ShouldBeNil)
_, err = signature.LoadNotationSigningkeys(tempDir)
So(err, ShouldNotBeNil)
})
}
func TestLoadNotationConfig(t *testing.T) {
Convey("directory doesn't exist", t, func() {
_, err := signature.LoadNotationConfig(t.TempDir())
So(err, ShouldNotBeNil)
})
Convey("wrong content of signingkeys.json", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
err := os.Mkdir(dir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(dir, "signingkeys.json")
err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
_, err = signature.LoadNotationConfig(tempDir)
So(err, ShouldNotBeNil)
})
Convey("check default value of signature format", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
err := os.Mkdir(dir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(dir, "signingkeys.json")
err = os.WriteFile(filePath, []byte("{\"SignatureFormat\": \"\"}"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
configInfo, err := signature.LoadNotationConfig(tempDir)
So(err, ShouldBeNil)
So(configInfo.SignatureFormat, ShouldEqual, "jws")
})
}
func TestSignWithNotation(t *testing.T) {
Convey("notation directory doesn't exist", t, func() {
err := signature.SignWithNotation("key", "reference", t.TempDir())
So(err, ShouldNotBeNil)
})
Convey("key not found", t, func() {
tempDir := t.TempDir()
dir := path.Join(tempDir, "notation")
err := os.Mkdir(dir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(dir, "signingkeys.json")
err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
err = signature.SignWithNotation("key", "reference", tempDir)
So(err, ShouldEqual, signature.ErrKeyNotFound)
})
Convey("not enough permissions to access notation/localkeys dir", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tdir)
err = signature.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o000)
So(err, ShouldBeNil)
err = signature.SignWithNotation("key", "reference", tdir)
So(err, ShouldNotBeNil)
err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o755)
So(err, ShouldBeNil)
})
Convey("error parsing reference", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tdir)
err = signature.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = signature.SignWithNotation("key", "invalidReference", tdir)
So(err, ShouldNotBeNil)
})
Convey("error signing", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tdir)
err = signature.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = signature.SignWithNotation("key", "localhost:8080/invalidreference:1.0", tdir)
So(err, ShouldNotBeNil)
})
}
func TestVerifyWithNotation(t *testing.T) {
Convey("notation directory doesn't exist", t, func() {
err := signature.VerifyWithNotation("reference", t.TempDir())
So(err, ShouldNotBeNil)
})
Convey("error parsing reference", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tdir)
err = signature.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = signature.VerifyWithNotation("invalidReference", tdir)
So(err, ShouldNotBeNil)
})
Convey("error trying to get manifest", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tdir)
err = signature.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = signature.VerifyWithNotation("localhost:8080/invalidreference:1.0", tdir)
So(err, ShouldNotBeNil)
})
Convey("invalid content of trustpolicy.json", t, func() {
// start a new server
port := tcommon.GetFreePort()
baseURL := tcommon.GetBaseURL(port)
dir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = dir
ctlr := api.NewController(conf)
cm := tcommon.NewControllerManager(ctlr)
// this blocks
cm.StartAndWait(port)
defer cm.StopServer()
repoName := "signed-repo"
tag := "1.0"
image := CreateRandomImage()
err := UploadImage(image, baseURL, repoName, tag)
So(err, ShouldBeNil)
tempDir := t.TempDir()
notationDir := path.Join(tempDir, "notation")
err = os.Mkdir(notationDir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(notationDir, "trustpolicy.json")
err = os.WriteFile(filePath, []byte("some dummy file content"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tempDir)
err = signature.VerifyWithNotation(fmt.Sprintf("localhost:%s/%s:%s", port, repoName, tag), tempDir)
So(err, ShouldNotBeNil)
})
}
func TestListNotarySignatures(t *testing.T) {
Convey("error parsing reference", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
_, err = signature.ListNotarySignatures("invalidReference", tdir)
So(err, ShouldNotBeNil)
})
Convey("error trying to get manifest", t, func() {
cwd, err := os.Getwd()
So(err, ShouldBeNil)
defer func() { _ = os.Chdir(cwd) }()
tdir := t.TempDir()
_ = os.Chdir(tdir)
_, err = signature.ListNotarySignatures("localhost:8080/invalidreference:1.0", tdir)
So(err, ShouldNotBeNil)
})
}
func TestGenerateNotationCerts(t *testing.T) {
Convey("write key file with permission", t, func() {
tempDir := t.TempDir()
notationDir := path.Join(tempDir, "notation")
err := os.Mkdir(notationDir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(notationDir, "localkeys")
err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tempDir)
err = signature.GenerateNotationCerts(t.TempDir(), "cert")
So(err, ShouldNotBeNil)
})
Convey("write cert file with permission", t, func() {
tempDir := t.TempDir()
notationDir := path.Join(tempDir, "notation", "localkeys")
err := os.MkdirAll(notationDir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(notationDir, "cert.crt")
err = os.WriteFile(filePath, []byte("{}"), 0o666) //nolint: gosec
So(err, ShouldBeNil)
err = os.Chmod(filePath, 0o000)
So(err, ShouldBeNil)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tempDir)
err = signature.GenerateNotationCerts(t.TempDir(), "cert")
So(err, ShouldNotBeNil)
err = os.Chmod(filePath, 0o755)
So(err, ShouldBeNil)
})
Convey("signingkeys.json file - not enough permission", t, func() {
tempDir := t.TempDir()
notationDir := path.Join(tempDir, "notation")
err := os.Mkdir(notationDir, 0o777)
So(err, ShouldBeNil)
filePath := path.Join(notationDir, "signingkeys.json")
_, err = os.Create(filePath) //nolint: gosec
So(err, ShouldBeNil)
err = os.Chmod(filePath, 0o000)
So(err, ShouldBeNil)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tempDir)
err = signature.GenerateNotationCerts(t.TempDir(), "cert")
So(err, ShouldNotBeNil)
err = os.Remove(filePath)
So(err, ShouldBeNil)
err = os.RemoveAll(path.Join(notationDir, "localkeys"))
So(err, ShouldBeNil)
signingKeysBuf, err := json.Marshal(notconfig.SigningKeys{})
So(err, ShouldBeNil)
err = os.WriteFile(filePath, signingKeysBuf, 0o555) //nolint:gosec // test code
So(err, ShouldBeNil)
err = signature.GenerateNotationCerts(t.TempDir(), "cert")
So(err, ShouldNotBeNil)
})
Convey("keysuite already exists in signingkeys.json", t, func() {
tempDir := t.TempDir()
notationDir := path.Join(tempDir, "notation")
err := os.Mkdir(notationDir, 0o777)
So(err, ShouldBeNil)
certName := "cert-test"
filePath := path.Join(notationDir, "signingkeys.json")
keyPath := path.Join(notationDir, "localkeys", certName+".key")
certPath := path.Join(notationDir, "localkeys", certName+".crt")
signingKeys := notconfig.SigningKeys{}
keySuite := notconfig.KeySuite{
Name: certName,
X509KeyPair: &notconfig.X509KeyPair{
KeyPath: keyPath,
CertificatePath: certPath,
},
}
signingKeys.Keys = []notconfig.KeySuite{keySuite}
signingKeysBuf, err := json.Marshal(signingKeys)
So(err, ShouldBeNil)
err = os.WriteFile(filePath, signingKeysBuf, 0o600)
So(err, ShouldBeNil)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tempDir)
err = signature.GenerateNotationCerts(t.TempDir(), certName)
So(err, ShouldNotBeNil)
})
Convey("truststore files", t, func() {
tempDir := t.TempDir()
notationDir := path.Join(tempDir, "notation")
err := os.Mkdir(notationDir, 0o777)
So(err, ShouldBeNil)
certName := "cert-test"
trustStorePath := path.Join(notationDir, fmt.Sprintf("truststore/x509/ca/%s", certName))
err = os.MkdirAll(trustStorePath, 0o755)
So(err, ShouldBeNil)
err = os.Chmod(path.Join(notationDir, "truststore/x509"), 0o000)
So(err, ShouldBeNil)
signature.NotationPathLock.Lock()
defer signature.NotationPathLock.Unlock()
signature.LoadNotationPath(tempDir)
err = signature.GenerateNotationCerts(tempDir, certName)
So(err, ShouldNotBeNil)
err = os.RemoveAll(path.Join(notationDir, "localkeys"))
So(err, ShouldBeNil)
err = os.Chmod(path.Join(notationDir, "truststore/x509"), 0o755)
So(err, ShouldBeNil)
_, err = os.Create(path.Join(trustStorePath, "cert-test.crt"))
So(err, ShouldBeNil)
err = signature.GenerateNotationCerts(tempDir, certName)
So(err, ShouldNotBeNil)
err = os.RemoveAll(path.Join(notationDir, "localkeys"))
So(err, ShouldBeNil)
err = os.Remove(path.Join(trustStorePath, "cert-test.crt"))
So(err, ShouldBeNil)
err = os.Chmod(path.Join(notationDir, "truststore/x509/ca", certName), 0o555)
So(err, ShouldBeNil)
err = signature.GenerateNotationCerts(tempDir, certName)
So(err, ShouldNotBeNil)
})
}