-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add config package & optimize dir package (#90)
Signed-off-by: Junjie Gao <junjiegao@microsoft.com>
- Loading branch information
Showing
12 changed files
with
650 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package config | ||
|
||
import ( | ||
"encoding/json" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/notaryproject/notation-go/dir" | ||
) | ||
|
||
var ( | ||
// ConfigPath is the path for config.json | ||
ConfigPath string | ||
// SigningKeysPath is the path for signingkeys.json | ||
SigningKeysPath string | ||
) | ||
|
||
func init() { | ||
ConfigPath = dir.Path.Config() | ||
SigningKeysPath = dir.Path.SigningKeyConfig() | ||
} | ||
|
||
// save stores the cfg struct to file | ||
func save(filePath string, cfg interface{}) error { | ||
dir := filepath.Dir(filePath) | ||
if err := os.MkdirAll(dir, 0700); err != nil { | ||
return err | ||
} | ||
file, err := os.Create(filePath) | ||
if err != nil { | ||
return err | ||
} | ||
defer file.Close() | ||
encoder := json.NewEncoder(file) | ||
encoder.SetIndent("", " ") | ||
return encoder.Encode(cfg) | ||
} | ||
|
||
// load reads file, parses json and stores in cfg struct | ||
func load(filePath string, cfg interface{}) error { | ||
file, err := os.Open(filePath) | ||
if err != nil { | ||
return err | ||
} | ||
defer file.Close() | ||
return json.NewDecoder(file).Decode(cfg) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package config | ||
|
||
import ( | ||
"errors" | ||
"io/fs" | ||
) | ||
|
||
// CertificateReference is a named file path. | ||
type CertificateReference struct { | ||
Name string `json:"name"` | ||
Path string `json:"path"` | ||
} | ||
|
||
// Is checks whether the given name is equal with the Name variable | ||
func (c CertificateReference) Is(name string) bool { | ||
return c.Name == name | ||
} | ||
|
||
// Config reflects the config.json file. | ||
// Specification: https://github.com/notaryproject/notation/pull/76 | ||
type Config struct { | ||
VerificationCertificates VerificationCertificates `json:"verificationCerts"` | ||
InsecureRegistries []string `json:"insecureRegistries"` | ||
CredentialsStore string `json:"credsStore,omitempty"` | ||
CredentialHelpers map[string]string `json:"credHelpers,omitempty"` | ||
} | ||
|
||
// VerificationCertificates is a collection of public certs used for verification. | ||
type VerificationCertificates struct { | ||
Certificates []CertificateReference `json:"certs"` | ||
} | ||
|
||
// NewConfig creates a new config file | ||
func NewConfig() *Config { | ||
return &Config{ | ||
InsecureRegistries: []string{}, | ||
} | ||
} | ||
|
||
// Save stores the config to file | ||
func (c *Config) Save() error { | ||
return save(ConfigPath, c) | ||
} | ||
|
||
// LoadConfig reads the config from file or return a default config if not found. | ||
func LoadConfig() (*Config, error) { | ||
var config Config | ||
err := load(ConfigPath, &config) | ||
if err != nil { | ||
if errors.Is(err, fs.ErrNotExist) { | ||
return NewConfig(), nil | ||
} | ||
return nil, err | ||
} | ||
return &config, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package config | ||
|
||
import ( | ||
"path/filepath" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/notaryproject/notation-go/dir" | ||
) | ||
|
||
const ( | ||
configPath = "./testdata/config.json" | ||
nonexistentPath = "./testdata/nonexistent.json" | ||
) | ||
|
||
var sampleConfig = &Config{ | ||
VerificationCertificates: VerificationCertificates{ | ||
Certificates: []CertificateReference{ | ||
{ | ||
Name: "wabbit-networks", | ||
Path: "/home/demo/.config/notation/certificate/wabbit-networks.crt", | ||
}, | ||
{ | ||
Name: "import.acme-rockets", | ||
Path: "/home/demo/.config/notation/certificate/import.acme-rockets.crt", | ||
}, | ||
}, | ||
}, | ||
InsecureRegistries: []string{ | ||
"registry.wabbit-networks.io", | ||
}, | ||
} | ||
|
||
func TestLoadFile(t *testing.T) { | ||
t.Cleanup(func() { | ||
// restore path | ||
ConfigPath = dir.Path.Config() | ||
}) | ||
type args struct { | ||
filePath string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want *Config | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "load config file", | ||
args: args{filePath: configPath}, | ||
want: sampleConfig, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "load default config file", | ||
args: args{filePath: nonexistentPath}, | ||
want: NewConfig(), | ||
wantErr: false, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
ConfigPath = tt.args.filePath | ||
got, err := LoadConfig() | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("loadFile() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("loadFile() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestSaveFile(t *testing.T) { | ||
t.Cleanup(func() { | ||
// restore path | ||
ConfigPath = dir.Path.Config() | ||
}) | ||
root := t.TempDir() | ||
ConfigPath = filepath.Join(root, "config.json") | ||
sampleConfig.Save() | ||
config, err := LoadConfig() | ||
if err != nil { | ||
t.Fatal("Load config file from temp dir failed") | ||
} | ||
if !reflect.DeepEqual(sampleConfig, config) { | ||
t.Fatal("save config file failed.") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package config | ||
|
||
import ( | ||
"errors" | ||
"io/fs" | ||
) | ||
|
||
// X509KeyPair contains the paths of a public/private key pair files. | ||
type X509KeyPair struct { | ||
KeyPath string `json:"keyPath,omitempty"` | ||
CertificatePath string `json:"certPath,omitempty"` | ||
} | ||
|
||
// ExternalKey contains the necessary information to delegate | ||
// the signing operation to the named plugin. | ||
type ExternalKey struct { | ||
ID string `json:"id,omitempty"` | ||
PluginName string `json:"pluginName,omitempty"` | ||
PluginConfig map[string]string `json:"pluginConfig,omitempty"` | ||
} | ||
|
||
// KeySuite is a named key suite. | ||
type KeySuite struct { | ||
Name string `json:"name"` | ||
|
||
*X509KeyPair | ||
*ExternalKey | ||
} | ||
|
||
// Is checks whether the given name is equal with the Name variable | ||
func (k KeySuite) Is(name string) bool { | ||
return k.Name == name | ||
} | ||
|
||
// SigningKeys reflects the signingkeys.json file. | ||
type SigningKeys struct { | ||
Default string `json:"default"` | ||
Keys []KeySuite `json:"keys"` | ||
} | ||
|
||
// Save config to file | ||
func (s *SigningKeys) Save() error { | ||
return save(SigningKeysPath, s) | ||
} | ||
|
||
// NewSigningKeys creates a new signingkeys config file | ||
func NewSigningKeys() *SigningKeys { | ||
return &SigningKeys{Keys: []KeySuite{}} | ||
} | ||
|
||
// LoadSigningKeys reads the config from file | ||
// or return a default config if not found. | ||
func LoadSigningKeys() (*SigningKeys, error) { | ||
var config SigningKeys | ||
err := load(SigningKeysPath, &config) | ||
if err != nil { | ||
if errors.Is(err, fs.ErrNotExist) { | ||
return NewSigningKeys(), nil | ||
} | ||
return nil, err | ||
} | ||
return &config, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package config | ||
|
||
import ( | ||
"path/filepath" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/notaryproject/notation-go/dir" | ||
) | ||
|
||
const ( | ||
signingKeysPath = "./testdata/signingkeys.json" | ||
) | ||
|
||
var sampleSigningKeysInfo = &SigningKeys{ | ||
Default: "wabbit-networks", | ||
Keys: []KeySuite{ | ||
{ | ||
Name: "wabbit-networks", | ||
X509KeyPair: &X509KeyPair{ | ||
KeyPath: "/home/demo/.config/notation/localkeys/wabbit-networks.key", | ||
CertificatePath: "/home/demo/.config/notation/localkeys/wabbit-networks.crt", | ||
}, | ||
}, | ||
{ | ||
Name: "import.acme-rockets", | ||
X509KeyPair: &X509KeyPair{ | ||
KeyPath: "/home/demo/.config/notation/localkeys/import.acme-rockets.key", | ||
CertificatePath: "/home/demo/.config/notation/localkeys/import.acme-rockets.crt", | ||
}, | ||
}, | ||
{ | ||
Name: "external-key", | ||
ExternalKey: &ExternalKey{ | ||
|
||
ID: "id1", | ||
PluginName: "pluginX", | ||
PluginConfig: map[string]string{ | ||
"key": "value", | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
func TestLoadSigningKeysInfo(t *testing.T) { | ||
t.Cleanup(func() { | ||
// restore path | ||
SigningKeysPath = dir.Path.SigningKeyConfig() | ||
}) | ||
type args struct { | ||
filePath string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want *SigningKeys | ||
}{ | ||
{ | ||
name: "read signingkeys info", | ||
args: args{filePath: signingKeysPath}, | ||
want: sampleSigningKeysInfo, | ||
}, | ||
{ | ||
name: "get default signingkeys info", | ||
args: args{filePath: nonexistentPath}, | ||
want: NewSigningKeys(), | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
SigningKeysPath = tt.args.filePath | ||
got, err := LoadSigningKeys() | ||
if err != nil { | ||
t.Errorf("LoadSigningKeysInfo() error = %v", err) | ||
return | ||
} | ||
if !reflect.DeepEqual(tt.want, got) { | ||
t.Fatal("singingKeysInfo test failed.") | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestSaveSigningKeys(t *testing.T) { | ||
t.Cleanup(func() { | ||
// restore path | ||
SigningKeysPath = dir.Path.SigningKeyConfig() | ||
}) | ||
root := t.TempDir() | ||
SigningKeysPath = filepath.Join(root, "signingkeys.json") | ||
sampleSigningKeysInfo.Save() | ||
info, err := LoadSigningKeys() | ||
if err != nil { | ||
t.Fatal("Load signingkeys.json from temp dir failed.") | ||
} | ||
if !reflect.DeepEqual(sampleSigningKeysInfo, info) { | ||
t.Fatal("Save signingkeys.json failed.") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"verificationCerts": { | ||
"certs": [ | ||
{ | ||
"name": "wabbit-networks", | ||
"path": "/home/demo/.config/notation/certificate/wabbit-networks.crt" | ||
}, | ||
{ | ||
"name": "import.acme-rockets", | ||
"path": "/home/demo/.config/notation/certificate/import.acme-rockets.crt" | ||
} | ||
] | ||
}, | ||
"insecureRegistries": [ | ||
"registry.wabbit-networks.io" | ||
] | ||
} |
Oops, something went wrong.