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>
This commit is contained in:
Andrei Aaron
2023-09-27 21:34:48 +03:00
committed by GitHub
parent c3801dc3d3
commit ba6f347d8d
82 changed files with 3362 additions and 3243 deletions
+71
View File
@@ -0,0 +1,71 @@
package signature
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"time"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/generate"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
)
func GetCosignSignatureTagForManifest(manifest ispec.Manifest) (string, error) {
manifestBlob, err := json.Marshal(manifest)
if err != nil {
return "", err
}
manifestDigest := godigest.FromBytes(manifestBlob)
return GetCosignSignatureTagForDigest(manifestDigest), nil
}
func GetCosignSignatureTagForDigest(manifestDigest godigest.Digest) string {
return manifestDigest.Algorithm().String() + "-" + manifestDigest.Encoded() + ".sig"
}
func SignImageUsingCosign(repoTag, port string) error {
cwd, err := os.Getwd()
if err != nil {
return err
}
defer func() { _ = os.Chdir(cwd) }()
tdir, err := os.MkdirTemp("", "cosign")
if err != nil {
return err
}
defer os.RemoveAll(tdir)
_ = os.Chdir(tdir)
// generate a keypair
os.Setenv("COSIGN_PASSWORD", "")
err = generate.GenerateKeyPairCmd(context.TODO(), "", "cosign", nil)
if err != nil {
return err
}
imageURL := fmt.Sprintf("localhost:%s/%s", port, repoTag)
const timeoutPeriod = 5
// sign the image
return sign.SignCmd(&options.RootOptions{Verbose: true, Timeout: timeoutPeriod * time.Minute},
options.KeyOpts{KeyRef: path.Join(tdir, "cosign.key"), PassFunc: generate.GetPass},
options.SignOptions{
Registry: options.RegistryOptions{AllowInsecure: true},
AnnotationOptions: options.AnnotationOptions{Annotations: []string{"tag=1.0"}},
Upload: true,
},
[]string{imageURL})
}
+469
View File
@@ -0,0 +1,469 @@
package signature
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io/fs"
"math"
"os"
"path"
"path/filepath"
"strings"
"sync"
"github.com/notaryproject/notation-core-go/signature/jws"
"github.com/notaryproject/notation-core-go/testhelper"
"github.com/notaryproject/notation-go"
notconfig "github.com/notaryproject/notation-go/config"
"github.com/notaryproject/notation-go/dir"
notreg "github.com/notaryproject/notation-go/registry"
"github.com/notaryproject/notation-go/signer"
"github.com/notaryproject/notation-go/verifier"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2/registry"
"oras.land/oras-go/v2/registry/remote"
"oras.land/oras-go/v2/registry/remote/auth"
tcommon "zotregistry.io/zot/pkg/test/common"
)
var (
ErrAlreadyExists = errors.New("already exists")
ErrKeyNotFound = errors.New("key not found")
ErrSignatureVerification = errors.New("signature verification failed")
)
var NotationPathLock = new(sync.Mutex) //nolint: gochecknoglobals
func LoadNotationPath(tdir string) {
dir.UserConfigDir = filepath.Join(tdir, "notation")
// set user libexec
dir.UserLibexecDir = dir.UserConfigDir
}
func GenerateNotationCerts(tdir string, certName string) error {
// generate RSA private key
bits := 2048
key, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return err
}
keyBytes, err := x509.MarshalPKCS8PrivateKey(key)
if err != nil {
return err
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})
rsaCertTuple := testhelper.GetRSASelfSignedCertTupleWithPK(key, "cert")
certBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rsaCertTuple.Cert.Raw})
// write private key
relativeKeyPath, relativeCertPath := dir.LocalKeyPath(certName)
configFS := dir.ConfigFS()
keyPath, err := configFS.SysPath(relativeKeyPath)
if err != nil {
return err
}
certPath, err := configFS.SysPath(relativeCertPath)
if err != nil {
return err
}
if err := tcommon.WriteFileWithPermission(keyPath, keyPEM, 0o600, false); err != nil { //nolint:gomnd
return fmt.Errorf("failed to write key file: %w", err)
}
// write self-signed certificate
if err := tcommon.WriteFileWithPermission(certPath, certBytes, 0o644, false); err != nil { //nolint:gomnd
return fmt.Errorf("failed to write certificate file: %w", err)
}
signingKeys, err := notconfig.LoadSigningKeys()
if err != nil {
return err
}
keySuite := notconfig.KeySuite{
Name: certName,
X509KeyPair: &notconfig.X509KeyPair{
KeyPath: keyPath,
CertificatePath: certPath,
},
}
// addKeyToSigningKeys
if tcommon.Contains(signingKeys.Keys, keySuite.Name) {
return ErrAlreadyExists
}
signingKeys.Keys = append(signingKeys.Keys, keySuite)
// Add to the trust store
trustStorePath := path.Join(tdir, fmt.Sprintf("notation/truststore/x509/ca/%s", certName))
if _, err := os.Stat(filepath.Join(trustStorePath, filepath.Base(certPath))); err == nil {
return ErrAlreadyExists
}
if err := os.MkdirAll(trustStorePath, 0o755); err != nil { //nolint:gomnd
return fmt.Errorf("GenerateNotationCerts os.MkdirAll failed: %w", err)
}
trustCertPath := path.Join(trustStorePath, fmt.Sprintf("%s%s", certName, dir.LocalCertificateExtension))
err = tcommon.CopyFile(certPath, trustCertPath)
if err != nil {
return err
}
// Save to the SigningKeys.json
if err := signingKeys.Save(); err != nil {
return err
}
return nil
}
func SignWithNotation(keyName string, reference string, tdir string) error {
ctx := context.TODO()
// getSigner
var newSigner notation.Signer
mediaType := jws.MediaTypeEnvelope
// ResolveKey
signingKeys, err := LoadNotationSigningkeys(tdir)
if err != nil {
return err
}
idx := tcommon.Index(signingKeys.Keys, keyName)
if idx < 0 {
return ErrKeyNotFound
}
key := signingKeys.Keys[idx]
if key.X509KeyPair != nil {
newSigner, err = signer.NewFromFiles(key.X509KeyPair.KeyPath, key.X509KeyPair.CertificatePath)
if err != nil {
return err
}
}
// prepareSigningContent
// getRepositoryClient
authClient := &auth.Client{
Credential: func(ctx context.Context, reg string) (auth.Credential, error) {
return auth.EmptyCredential, nil
},
Cache: auth.NewCache(),
ClientID: "notation",
}
authClient.SetUserAgent("notation/zot_tests")
plainHTTP := true
// Resolve referance
ref, err := registry.ParseReference(reference)
if err != nil {
return err
}
remoteRepo := &remote.Repository{
Client: authClient,
Reference: ref,
PlainHTTP: plainHTTP,
}
repositoryOpts := notreg.RepositoryOptions{}
sigRepo := notreg.NewRepositoryWithOptions(remoteRepo, repositoryOpts)
sigOpts := notation.SignOptions{
SignerSignOptions: notation.SignerSignOptions{
SignatureMediaType: mediaType,
PluginConfig: map[string]string{},
},
ArtifactReference: ref.String(),
}
_, err = notation.Sign(ctx, newSigner, sigRepo, sigOpts)
if err != nil {
return err
}
return nil
}
func VerifyWithNotation(reference string, tdir string) error {
// check if trustpolicy.json exists
trustpolicyPath := path.Join(tdir, "notation/trustpolicy.json")
if _, err := os.Stat(trustpolicyPath); errors.Is(err, os.ErrNotExist) {
trustPolicy := `
{
"version": "1.0",
"trustPolicies": [
{
"name": "good",
"registryScopes": [ "*" ],
"signatureVerification": {
"level" : "audit"
},
"trustStores": ["ca:good"],
"trustedIdentities": [
"*"
]
}
]
}`
file, err := os.Create(trustpolicyPath)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(trustPolicy)
if err != nil {
return err
}
}
// start verifying signatures
ctx := context.TODO()
// getRepositoryClient
authClient := &auth.Client{
Credential: func(ctx context.Context, reg string) (auth.Credential, error) {
return auth.EmptyCredential, nil
},
Cache: auth.NewCache(),
ClientID: "notation",
}
authClient.SetUserAgent("notation/zot_tests")
plainHTTP := true
// Resolve referance
ref, err := registry.ParseReference(reference)
if err != nil {
return err
}
remoteRepo := &remote.Repository{
Client: authClient,
Reference: ref,
PlainHTTP: plainHTTP,
}
repositoryOpts := notreg.RepositoryOptions{}
repo := notreg.NewRepositoryWithOptions(remoteRepo, repositoryOpts)
manifestDesc, err := repo.Resolve(ctx, ref.Reference)
if err != nil {
return err
}
if err := ref.ValidateReferenceAsDigest(); err != nil {
ref.Reference = manifestDesc.Digest.String()
}
// getVerifier
newVerifier, err := verifier.NewFromConfig()
if err != nil {
return err
}
remoteRepo = &remote.Repository{
Client: authClient,
Reference: ref,
PlainHTTP: plainHTTP,
}
repo = notreg.NewRepositoryWithOptions(remoteRepo, repositoryOpts)
configs := map[string]string{}
verifyOpts := notation.VerifyOptions{
ArtifactReference: ref.String(),
PluginConfig: configs,
MaxSignatureAttempts: math.MaxInt64,
}
_, outcomes, err := notation.Verify(ctx, newVerifier, repo, verifyOpts)
if err != nil || len(outcomes) == 0 {
return ErrSignatureVerification
}
return nil
}
func ListNotarySignatures(reference string, tdir string) ([]godigest.Digest, error) {
signatures := []godigest.Digest{}
ctx := context.TODO()
// getSignatureRepository
ref, err := registry.ParseReference(reference)
if err != nil {
return signatures, err
}
plainHTTP := true
// getRepositoryClient
authClient := &auth.Client{
Credential: func(ctx context.Context, registry string) (auth.Credential, error) {
return auth.EmptyCredential, nil
},
Cache: auth.NewCache(),
ClientID: "notation",
}
authClient.SetUserAgent("notation/zot_tests")
remoteRepo := &remote.Repository{
Client: authClient,
Reference: ref,
PlainHTTP: plainHTTP,
}
sigRepo := notreg.NewRepository(remoteRepo)
artifactDesc, err := sigRepo.Resolve(ctx, reference)
if err != nil {
return signatures, err
}
err = sigRepo.ListSignatures(ctx, artifactDesc, func(signatureManifests []ispec.Descriptor) error {
for _, sigManifestDesc := range signatureManifests {
signatures = append(signatures, sigManifestDesc.Digest)
}
return nil
})
return signatures, err
}
func LoadNotationSigningkeys(tdir string) (*notconfig.SigningKeys, error) {
var err error
var signingKeysInfo *notconfig.SigningKeys
filePath := path.Join(tdir, "notation/signingkeys.json")
file, err := os.Open(filePath)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
// create file
newSigningKeys := notconfig.NewSigningKeys()
newFile, err := os.Create(filePath)
if err != nil {
return newSigningKeys, err
}
defer newFile.Close()
encoder := json.NewEncoder(newFile)
encoder.SetIndent("", " ")
err = encoder.Encode(newSigningKeys)
return newSigningKeys, err
}
return nil, err
}
defer file.Close()
err = json.NewDecoder(file).Decode(&signingKeysInfo)
return signingKeysInfo, err
}
func LoadNotationConfig(tdir string) (*notconfig.Config, error) {
var configInfo *notconfig.Config
filePath := path.Join(tdir, "notation/signingkeys.json")
file, err := os.Open(filePath)
if err != nil {
return configInfo, err
}
defer file.Close()
err = json.NewDecoder(file).Decode(&configInfo)
if err != nil {
return configInfo, err
}
// set default value
configInfo.SignatureFormat = strings.ToLower(configInfo.SignatureFormat)
if configInfo.SignatureFormat == "" {
configInfo.SignatureFormat = "jws"
}
return configInfo, nil
}
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)
NotationPathLock.Lock()
defer NotationPathLock.Unlock()
LoadNotationPath(tdir)
// generate a keypair
err = GenerateNotationCerts(tdir, "notation-sign-test")
if err != nil {
return err
}
// sign the image
image := fmt.Sprintf("localhost:%s/%s", port, repoTag)
err = SignWithNotation("notation-sign-test", image, tdir)
return err
}
+464
View File
@@ -0,0 +1,464 @@
//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)
})
}