fix: call notation-go libs instead of using notation binary (#1104)

fix: add loading notation path

Signed-off-by: Andreea-Lupu <andreealupu1470@yahoo.com>
Co-authored-by: Roxana Nemulescu <roxana.nemulescu@gmail.com>
This commit is contained in:
Andreea Lupu
2023-02-13 20:43:52 +02:00
committed by GitHub
parent 2377d62344
commit ee95ab0ffc
21 changed files with 1731 additions and 333 deletions
+499 -14
View File
@@ -4,20 +4,34 @@ import (
"bytes"
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"io/fs"
"log"
"math"
"math/big"
"net/http"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"sync"
"time"
"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"
"github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -27,6 +41,9 @@ import (
"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
"gopkg.in/resty.v1"
"oras.land/oras-go/v2/registry"
"oras.land/oras-go/v2/registry/remote"
"oras.land/oras-go/v2/registry/remote/auth"
"zotregistry.io/zot/pkg/storage"
)
@@ -37,6 +54,8 @@ const (
SleepTime = 100 * time.Millisecond
)
var NotationPathLock = new(sync.Mutex) //nolint: gochecknoglobals
// which: manifest, config, layer
func GetTestBlobDigest(image, which string) godigest.Digest {
prePath := "../test/data"
@@ -61,8 +80,11 @@ func GetTestBlobDigest(image, which string) godigest.Digest {
}
var (
ErrPostBlob = errors.New("can't post blob")
ErrPutBlob = errors.New("can't put blob")
ErrPostBlob = errors.New("can't post blob")
ErrPutBlob = errors.New("can't put blob")
ErrAlreadyExists = errors.New("already exists")
ErrKeyNotFound = errors.New("key not found")
ErrSignatureVerification = errors.New("signature verification failed")
)
type Image struct {
@@ -667,11 +689,15 @@ func UploadImage(img Image, baseURL, repo string) error {
return err
}
_, err = resty.R().
resp, err = resty.R().
SetHeader("Content-type", "application/vnd.oci.image.manifest.v1+json").
SetBody(manifestBlob).
Put(baseURL + "/v2/" + repo + "/manifests/" + img.Tag)
if ErrStatusCode(resp.StatusCode()) != http.StatusCreated {
return ErrPutBlob
}
return err
}
@@ -745,6 +771,469 @@ func ReadLogFileAndSearchString(logPath string, stringToMatch string, timeout ti
}
}
func CopyFile(sourceFilePath, destFilePath string) error {
destFile, err := os.Create(destFilePath)
if err != nil {
return err
}
defer destFile.Close()
sourceFile, err := os.Open(sourceFilePath)
if err != nil {
return err
}
defer sourceFile.Close()
if _, err = io.Copy(destFile, sourceFile); err != nil {
return err
}
return nil
}
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 := 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 := 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 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 = 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 := 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,
}
sigRepo := notreg.NewRepository(remoteRepo)
sigOpts := notation.SignOptions{
ArtifactReference: ref.String(),
SignatureMediaType: mediaType,
PluginConfig: map[string]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,
}
repo := notreg.NewRepository(remoteRepo)
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.NewRepository(remoteRepo)
configs := map[string]string{}
verifyOpts := notation.RemoteVerifyOptions{
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)
artifectDesc, err := sigRepo.Resolve(ctx, reference)
if err != nil {
return signatures, err
}
err = sigRepo.ListSignatures(ctx, artifectDesc, 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 WriteFileWithPermission(path string, data []byte, perm fs.FileMode, overwrite bool) error {
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return err
}
flag := os.O_WRONLY | os.O_CREATE
if overwrite {
flag |= os.O_TRUNC
} else {
flag |= os.O_EXCL
}
file, err := os.OpenFile(path, flag, perm)
if err != nil {
return err
}
_, err = file.Write(data)
if err != nil {
file.Close()
return err
}
return file.Close()
}
func IsDigestReference(ref string) bool {
parts := strings.SplitN(ref, "/", 2) //nolint:gomnd
if len(parts) == 1 {
return false
}
index := strings.Index(parts[1], "@")
return index != -1
}
type isser interface {
Is(string) bool
}
// Index returns the index of the first occurrence of name in s,
// or -1 if not present.
func Index[E isser](s []E, name string) int {
for i, v := range s {
if v.Is(name) {
return i
}
}
return -1
}
// Contains reports whether name is present in s.
func Contains[E isser](s []E, name string) bool {
return Index(s, name) >= 0
}
func UploadImageWithBasicAuth(img Image, baseURL, repo, user, password string) error {
for _, blob := range img.Layers {
resp, err := resty.R().
@@ -883,17 +1372,13 @@ func SignImageUsingNotary(repoTag, port string) error {
_ = os.Chdir(tdir)
_, err = exec.LookPath("notation")
if err != nil {
return err
}
NotationPathLock.Lock()
defer NotationPathLock.Unlock()
os.Setenv("XDG_CONFIG_HOME", tdir)
LoadNotationPath(tdir)
// generate a keypair
cmd := exec.Command("notation", "cert", "generate-test", "--trust", "notation-sign-test")
err = cmd.Run()
err = GenerateNotationCerts(tdir, "notation-sign-test")
if err != nil {
return err
}
@@ -901,7 +1386,7 @@ func SignImageUsingNotary(repoTag, port string) error {
// sign the image
image := fmt.Sprintf("localhost:%s/%s", port, repoTag)
cmd = exec.Command("notation", "sign", "--key", "notation-sign-test", "--plain-http", image)
err = SignWithNotation("notation-sign-test", image, tdir)
return cmd.Run()
return err
}
+480 -1
View File
@@ -12,6 +12,7 @@ import (
"testing"
"time"
notconfig "github.com/notaryproject/notation-go/config"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
@@ -453,7 +454,7 @@ func TestUploadImage(t *testing.T) {
}
err := test.UploadImage(img, baseURL, "test")
So(err, ShouldBeNil)
So(err, ShouldNotBeNil)
})
Convey("Upload image with authentification", t, func() {
@@ -792,3 +793,481 @@ func TestInjectUploadImageWithBasicAuth(t *testing.T) {
})
})
}
func TestCopyFile(t *testing.T) {
Convey("destFilePath does not exist", t, func() {
err := test.CopyFile("/path/to/srcFile", "~/path/to/some/unexisting/destDir/file")
So(err, ShouldNotBeNil)
})
Convey("sourceFile does not exist", t, func() {
err := test.CopyFile("/path/to/some/unexisting/file", path.Join(t.TempDir(), "destFile.txt"))
So(err, ShouldNotBeNil)
})
}
func TestIsDigestReference(t *testing.T) {
Convey("not digest reference", t, func() {
res := test.IsDigestReference("notDigestReference/input")
So(res, ShouldBeFalse)
})
Convey("wrong input format", t, func() {
res := test.IsDigestReference("wrongInput")
So(res, ShouldBeFalse)
})
}
func TestLoadNotationSigningkeys(t *testing.T) {
Convey("notation directory doesn't exist", t, func() {
_, err := test.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 = test.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 = test.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 = test.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 = test.LoadNotationSigningkeys(tempDir)
So(err, ShouldNotBeNil)
})
}
func TestLoadNotationConfig(t *testing.T) {
Convey("directory doesn't exist", t, func() {
_, err := test.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 = test.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 := test.LoadNotationConfig(tempDir)
So(err, ShouldBeNil)
So(configInfo.SignatureFormat, ShouldEqual, "jws")
})
}
func TestSignWithNotation(t *testing.T) {
Convey("notation directory doesn't exist", t, func() {
err := test.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 = test.SignWithNotation("key", "reference", tempDir)
So(err, ShouldEqual, test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tdir)
err = test.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = os.Chmod(path.Join(tdir, "notation", "localkeys"), 0o000)
So(err, ShouldBeNil)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tdir)
err = test.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tdir)
err = test.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = test.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 := test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tdir)
err = test.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tdir)
err = test.GenerateNotationCerts(tdir, "key")
So(err, ShouldBeNil)
err = test.VerifyWithNotation("localhost:8080/invalidreference:1.0", tdir)
So(err, ShouldNotBeNil)
})
Convey("invalid content of trustpolicy.json", t, func() {
// start a new server
port := test.GetFreePort()
baseURL := test.GetBaseURL(port)
dir := t.TempDir()
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = dir
ctlr := api.NewController(conf)
cm := test.NewControllerManager(ctlr)
// this blocks
cm.StartAndWait(port)
defer cm.StopServer()
repoName := "signed-repo"
tag := "1.0"
cfg, layers, manifest, err := test.GetImageComponents(2)
So(err, ShouldBeNil)
err = test.UploadImage(
test.Image{
Config: cfg,
Layers: layers,
Manifest: manifest,
Tag: tag,
}, baseURL, repoName)
So(err, ShouldBeNil)
content, err := json.Marshal(manifest)
So(err, ShouldBeNil)
digest := godigest.FromBytes(content)
So(digest, ShouldNotBeNil)
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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tempDir)
err = test.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 = test.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 = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tempDir)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tempDir)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tempDir)
err = test.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)
So(err, ShouldBeNil)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tempDir)
err = test.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)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
test.LoadNotationPath(tempDir)
err = test.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 = test.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 = test.GenerateNotationCerts(tempDir, certName)
So(err, ShouldNotBeNil)
})
}