keychain: always ensure the default key is generated

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2021-06-17 17:05:14 +02:00
parent a4e31949a3
commit 687c0e33a4
3 changed files with 54 additions and 18 deletions

View File

@ -12,6 +12,7 @@ import (
"go.dagger.io/dagger/cmd/dagger/cmd/input" "go.dagger.io/dagger/cmd/dagger/cmd/input"
"go.dagger.io/dagger/cmd/dagger/cmd/output" "go.dagger.io/dagger/cmd/dagger/cmd/output"
"go.dagger.io/dagger/cmd/dagger/logger" "go.dagger.io/dagger/cmd/dagger/logger"
"go.dagger.io/dagger/keychain"
) )
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
@ -25,8 +26,16 @@ func init() {
rootCmd.PersistentFlags().StringP("environment", "e", "", "Select an environment") rootCmd.PersistentFlags().StringP("environment", "e", "", "Select an environment")
rootCmd.PersistentFlags().StringP("workspace", "w", "", "Specify a workspace (defaults to current git repository)") rootCmd.PersistentFlags().StringP("workspace", "w", "", "Specify a workspace (defaults to current git repository)")
rootCmd.PersistentPreRun = func(*cobra.Command, []string) { rootCmd.PersistentPreRun = func(cmd *cobra.Command, _ []string) {
lg := logger.New()
ctx := lg.WithContext(cmd.Context())
go checkVersion() go checkVersion()
err := keychain.EnsureDefaultKey(ctx)
if err != nil {
lg.Fatal().Err(err).Msg("failed to generate default key")
}
} }
rootCmd.PersistentPostRun = func(*cobra.Command, []string) { rootCmd.PersistentPostRun = func(*cobra.Command, []string) {
warnVersion() warnVersion()

View File

@ -14,43 +14,65 @@ import (
) )
func Path() (string, error) { func Path() (string, error) {
keysFile, err := homedir.Expand("~/.config/dagger/keys.txt") return homedir.Expand("~/.config/dagger/keys.txt")
}
func EnsureDefaultKey(ctx context.Context) error {
keysFile, err := Path()
if err != nil { if err != nil {
return "", err return err
} }
// if the keys file doesn't exist, attempt a migration // If the keys file already exists, there's nothing to do.
if _, err := os.Stat(keysFile); errors.Is(err, os.ErrNotExist) { _, err = os.Stat(keysFile)
migrateKeys(keysFile) if err == nil {
return nil
} }
return keysFile, nil // If we got a different error than not existent, abort
if !errors.Is(err, os.ErrNotExist) {
return err
}
// Attempt a migration from the old keys file
migrated, err := migrateKeys(ctx, keysFile)
if err != nil {
return err
}
// If we migrated a previous identity, stop here.
if migrated {
return nil
}
// Otherwise, generate a new key
log.Ctx(ctx).Debug().Msg("generating default key pair")
_, err = Generate(ctx)
return err
} }
// migrateKeys attempts a migration from `~/.dagger/keys.txt` to `~/.config/dagger/keys.txt` // migrateKeys attempts a migration from `~/.dagger/keys.txt` to `~/.config/dagger/keys.txt`
func migrateKeys(keysFile string) error { func migrateKeys(ctx context.Context, keysFile string) (bool, error) {
oldKeysFile, err := homedir.Expand("~/.dagger/keys.txt") oldKeysFile, err := homedir.Expand("~/.dagger/keys.txt")
if err != nil { if err != nil {
return err return false, err
} }
if _, err := os.Stat(oldKeysFile); err != nil { if _, err := os.Stat(oldKeysFile); err != nil {
return err return false, nil
} }
if err := os.MkdirAll(filepath.Dir(keysFile), 0700); err != nil { if err := os.MkdirAll(filepath.Dir(keysFile), 0700); err != nil {
return err return false, err
} }
return os.Rename(oldKeysFile, keysFile) log.Ctx(ctx).Info().Msg("migrating keychain")
return true, os.Rename(oldKeysFile, keysFile)
} }
func Default(ctx context.Context) (string, error) { func Default(ctx context.Context) (string, error) {
keys, err := List(ctx) keys, err := List(ctx)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) {
return Generate(ctx)
}
return "", err return "", err
} }
if len(keys) == 0 { if len(keys) == 0 {
@ -85,7 +107,7 @@ func Generate(ctx context.Context) (string, error) {
pubkey := k.Recipient().String() pubkey := k.Recipient().String()
log.Ctx(ctx).Debug().Str("publicKey", pubkey).Msg("generating keypair") log.Ctx(ctx).Debug().Str("publicKey", pubkey).Msg("keypair generated")
return pubkey, nil return pubkey, nil
} }
@ -98,7 +120,7 @@ func List(ctx context.Context) ([]*age.X25519Identity, error) {
f, err := os.Open(keysFile) f, err := os.Open(keysFile)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open keys file file %q: %w", keysFile, err) return nil, fmt.Errorf("failed to open keys file %q: %w", keysFile, err)
} }
ids, err := age.ParseIdentities(f) ids, err := age.ParseIdentities(f)
if err != nil { if err != nil {
@ -107,7 +129,7 @@ func List(ctx context.Context) ([]*age.X25519Identity, error) {
keys := make([]*age.X25519Identity, 0, len(ids)) keys := make([]*age.X25519Identity, 0, len(ids))
for _, id := range ids { for _, id := range ids {
key, ok := ids[0].(*age.X25519Identity) key, ok := id.(*age.X25519Identity)
if !ok { if !ok {
return nil, fmt.Errorf("internal error: unexpected identity type: %T", id) return nil, fmt.Errorf("internal error: unexpected identity type: %T", id)
} }

View File

@ -8,12 +8,15 @@ import (
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.dagger.io/dagger/keychain"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
func TestWorkspace(t *testing.T) { func TestWorkspace(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
keychain.EnsureDefaultKey(ctx)
root, err := os.MkdirTemp(os.TempDir(), "dagger-*") root, err := os.MkdirTemp(os.TempDir(), "dagger-*")
require.NoError(t, err) require.NoError(t, err)
@ -60,6 +63,8 @@ func TestWorkspace(t *testing.T) {
func TestEncryption(t *testing.T) { func TestEncryption(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
keychain.EnsureDefaultKey(ctx)
readManifest := func(st *State) *State { readManifest := func(st *State) *State {
data, err := os.ReadFile(path.Join(st.Path, manifestFile)) data, err := os.ReadFile(path.Join(st.Path, manifestFile))
require.NoError(t, err) require.NoError(t, err)