Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions config/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright The Notary Project Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"errors"
"fmt"
)

// ErrKeyNameEmpty is used when key name is empty.
var ErrKeyNameEmpty = errors.New("key name cannot be empty")

// KeyNotFoundError is used when key is not found in the signingkeys.json file.
type KeyNotFoundError struct {
KeyName string
}

// Error returns the error message.
func (e KeyNotFoundError) Error() string {
if e.KeyName != "" {
return fmt.Sprintf("signing key %s not found", e.KeyName)
}
return "signing key not found"
}
28 changes: 28 additions & 0 deletions config/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright The Notary Project Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import "testing"

func TestErrorKeyNotFound(t *testing.T) {
e := KeyNotFoundError{}
if e.Error() != "signing key not found" {
t.Fatalf("ErrorKeyNotFound.Error() = %v, want %v", e.Error(), "signing key not found")
}

e = KeyNotFoundError{KeyName: "testKey"}
if e.Error() != `signing key testKey not found` {
t.Fatalf("ErrorKeyNotFound.Error() = %v, want %v", e.Error(), "signing key testKey not found")
}
}
43 changes: 8 additions & 35 deletions config/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ type KeySuite struct {
*ExternalKey
}

var errorKeyNameEmpty = errors.New("key name cannot be empty")
var errKeyNotFound = errors.New("signing key not found")

// SigningKeys reflects the signingkeys.json file.
type SigningKeys struct {
Default *string `json:"default,omitempty"`
Expand All @@ -67,13 +64,12 @@ func NewSigningKeys() *SigningKeys {
// Add adds new signing key
func (s *SigningKeys) Add(name, keyPath, certPath string, markDefault bool) error {
if name == "" {
return errorKeyNameEmpty
return ErrKeyNameEmpty
}
_, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return err
}

ks := KeySuite{
Name: name,
X509KeyPair: &X509KeyPair{
Expand All @@ -88,25 +84,20 @@ func (s *SigningKeys) Add(name, keyPath, certPath string, markDefault bool) erro
func (s *SigningKeys) AddPlugin(ctx context.Context, keyName, id, pluginName string, pluginConfig map[string]string, markDefault bool) error {
logger := log.GetLogger(ctx)
logger.Debugf("Adding key with name %v and plugin name %v", keyName, pluginName)

if keyName == "" {
return errorKeyNameEmpty
return ErrKeyNameEmpty
}

if id == "" {
return errors.New("missing key id")
}

if pluginName == "" {
return errors.New("plugin name cannot be empty")
}

mgr := plugin.NewCLIManager(dir.PluginFS())
_, err := mgr.Get(ctx, pluginName)
if err != nil {
return err
}

ks := KeySuite{
Name: keyName,
ExternalKey: &ExternalKey{
Expand All @@ -115,7 +106,6 @@ func (s *SigningKeys) AddPlugin(ctx context.Context, keyName, id, pluginName str
PluginConfig: pluginConfig,
},
}

if err = s.add(ks, markDefault); err != nil {
logger.Error("Failed to add key with error: %v", err)
return err
Expand All @@ -127,14 +117,12 @@ func (s *SigningKeys) AddPlugin(ctx context.Context, keyName, id, pluginName str
// Get returns signing key for the given name
func (s *SigningKeys) Get(keyName string) (KeySuite, error) {
if keyName == "" {
return KeySuite{}, errorKeyNameEmpty
return KeySuite{}, ErrKeyNameEmpty
}

idx := slices.IndexIsser(s.Keys, keyName)
if idx < 0 {
return KeySuite{}, errKeyNotFound
return KeySuite{}, KeyNotFoundError{KeyName: keyName}
}

return s.Keys[idx], nil
}

Expand All @@ -144,7 +132,6 @@ func (s *SigningKeys) GetDefault() (KeySuite, error) {
return KeySuite{}, errors.New("default signing key not set." +
" Please set default signing key or specify a key name")
}

return s.Get(*s.Default)
}

Expand All @@ -153,12 +140,11 @@ func (s *SigningKeys) Remove(keyName ...string) ([]string, error) {
var deletedNames []string
for _, name := range keyName {
if name == "" {
return deletedNames, errorKeyNameEmpty
return deletedNames, ErrKeyNameEmpty
}

idx := slices.IndexIsser(s.Keys, name)
if idx < 0 {
return deletedNames, errors.New(name + ": not found")
return deletedNames, KeyNotFoundError{KeyName: name}
}
s.Keys = slices.Delete(s.Keys, idx)
deletedNames = append(deletedNames, name)
Expand All @@ -172,13 +158,11 @@ func (s *SigningKeys) Remove(keyName ...string) ([]string, error) {
// UpdateDefault updates default signing key
func (s *SigningKeys) UpdateDefault(keyName string) error {
if keyName == "" {
return errorKeyNameEmpty
return ErrKeyNameEmpty
}

if !slices.ContainsIsser(s.Keys, keyName) {
return fmt.Errorf("key with name '%s' not found", keyName)
return KeyNotFoundError{KeyName: keyName}
}

s.Default = &keyName
return nil
}
Expand All @@ -189,11 +173,9 @@ func (s *SigningKeys) Save() error {
if err != nil {
return err
}

if err := validateKeys(s); err != nil {
return err
}

return save(path, s)
}

Expand All @@ -208,11 +190,9 @@ func LoadSigningKeys() (*SigningKeys, error) {
}
return nil, err
}

if err := validateKeys(&config); err != nil {
return nil, err
}

return &config, nil
}

Expand All @@ -224,11 +204,9 @@ func LoadExecSaveSigningKeys(fn func(keys *SigningKeys) error) error {
if err != nil {
return err
}

if err := fn(signingKeys); err != nil {
return err
}

return signingKeys.Save()
}

Expand All @@ -241,12 +219,10 @@ func (s *SigningKeys) add(key KeySuite, markDefault bool) error {
if slices.ContainsIsser(s.Keys, key.Name) {
return fmt.Errorf("signing key with name %q already exists", key.Name)
}

s.Keys = append(s.Keys, key)
if markDefault {
s.Default = &key.Name
}

return nil
}

Expand All @@ -262,17 +238,14 @@ func validateKeys(config *SigningKeys) error {
}
uniqueKeyNames.Add(key.Name)
}

if config.Default != nil {
defaultKey := *config.Default
if len(defaultKey) == 0 {
return fmt.Errorf("malformed %s: default key name cannot be empty", dir.PathSigningKeys)
}

if !uniqueKeyNames.Contains(defaultKey) {
return fmt.Errorf("malformed %s: default key '%s' not found", dir.PathSigningKeys, defaultKey)
}
}

return nil
}
50 changes: 37 additions & 13 deletions config/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"errors"
"os"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -310,14 +311,22 @@ func TestGet(t *testing.T) {
})

t.Run("NonExistent", func(t *testing.T) {
if _, err := sampleSigningKeysInfo.Get("nonExistent"); err == nil {
_, err := sampleSigningKeysInfo.Get("nonExistent")
if err == nil {
t.Error("expected Get() to fail for nonExistent key name")
}
if !errors.Is(err, KeyNotFoundError{KeyName: "nonExistent"}) {
t.Error("expected Get() to return ErrorKeyNotFound")
}
})

t.Run("InvalidName", func(t *testing.T) {
if _, err := sampleSigningKeysInfo.Get(""); err == nil {
t.Error("expected Get() to fail for invalid key name")
t.Run("EmptyName", func(t *testing.T) {
_, err := sampleSigningKeysInfo.Get("")
if err == nil {
t.Error("expected Get() to fail for empty key name")
}
if !errors.Is(err, ErrKeyNameEmpty) {
t.Error("expected Get() to return ErrorKeyNameEmpty")
}
})
}
Expand Down Expand Up @@ -358,14 +367,22 @@ func TestUpdateDefault(t *testing.T) {
})

t.Run("NonExistent", func(t *testing.T) {
if err := sampleSigningKeysInfo.UpdateDefault("nonExistent"); err == nil {
err := sampleSigningKeysInfo.UpdateDefault("nonExistent")
if err == nil {
t.Error("expected Get() to fail for nonExistent key name")
}
if !errors.Is(err, KeyNotFoundError{KeyName: "nonExistent"}) {
t.Error("expected Get() to return ErrorKeyNotFound")
}
})

t.Run("InvalidName", func(t *testing.T) {
if err := sampleSigningKeysInfo.UpdateDefault(""); err == nil {
t.Error("expected Get() to fail for invalid key name")
t.Run("EmptyName", func(t *testing.T) {
err := sampleSigningKeysInfo.UpdateDefault("")
if err == nil {
t.Error("expected Get() to fail for empty key name")
}
if !errors.Is(err, ErrKeyNameEmpty) {
t.Error("expected Get() to return ErrorKeyNameEmpty")
}
})
}
Expand All @@ -382,21 +399,28 @@ func TestRemove(t *testing.T) {
if _, err := testSigningKeysInfo.Get(testKeyName); err == nil {
t.Error("Delete() filed to delete key")
}

if keys[0] != testKeyName {
t.Error("Delete() deleted key name mismatch")
}
})

t.Run("NonExistent", func(t *testing.T) {
if _, err := testSigningKeysInfo.Remove(testKeyName); err == nil {
_, err := testSigningKeysInfo.Remove("nonExistent")
if err == nil {
t.Error("expected Get() to fail for nonExistent key name")
}
if !errors.Is(err, KeyNotFoundError{KeyName: "nonExistent"}) {
t.Error("expected Get() to return ErrorKeyNotFound")
}
})

t.Run("InvalidName", func(t *testing.T) {
if _, err := testSigningKeysInfo.Remove(""); err == nil {
t.Error("expected Get() to fail for invalid key name")
t.Run("EmptyName", func(t *testing.T) {
_, err := testSigningKeysInfo.Remove("")
if err == nil {
t.Error("expected Get() to fail for empty key name")
}
if !errors.Is(err, ErrKeyNameEmpty) {
t.Error("expected Get() to return ErrorKeyNameEmpty")
}
})
}
Expand Down
Loading
Loading