From 3f9455cf5c96a57ad318f36c9c1d4e80281418fe Mon Sep 17 00:00:00 2001 From: Hakan Kurtulus Date: Sat, 5 Jun 2021 18:24:30 +0200 Subject: [PATCH] OS-10 | Use cobra-commander (#4) * OS-10 | Use cobra-commander * fix lints * Update README.md * GH actions * OS-10 | Use cobra-commander --- cmd/add.go | 17 ++-- cmd/get.go | 31 ++------ cmd/list.go | 17 ++-- go.mod | 1 + go.sum | 6 ++ internal/controller/manager.go | 44 +++++++++++ internal/controller/manager_test.go | 77 ++++++++++++++++++ internal/provider/bw.go | 31 +++++--- internal/provider/{api.go => interface.go} | 11 ++- internal/provider/mocks/interface_mock.go | 92 ++++++++++++++++++++++ internal/provider/op.go | 27 ++++--- 11 files changed, 277 insertions(+), 77 deletions(-) create mode 100644 internal/controller/manager.go create mode 100644 internal/controller/manager_test.go rename internal/provider/{api.go => interface.go} (64%) create mode 100644 internal/provider/mocks/interface_mock.go diff --git a/cmd/add.go b/cmd/add.go index 21ded33..777d760 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -7,7 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "github.com/omegion/ssh-manager/internal" + "github.com/omegion/ssh-manager/internal/controller" "github.com/omegion/ssh-manager/internal/provider" ) @@ -38,11 +38,11 @@ func setupAddCommand(cmd *cobra.Command) { } } -// Add creates SSH key into given provider. +// Add creates Manager key into given provider. func Add() *cobra.Command { cmd := &cobra.Command{ Use: "add", - Short: "Add SSH key to given provider.", + Short: "Add Manager key to given provider.", RunE: func(cmd *cobra.Command, args []string) error { name, _ := cmd.Flags().GetString("name") publicKeyFileName, _ := cmd.Flags().GetString("public-key") @@ -73,19 +73,12 @@ func Add() *cobra.Command { }, } - commander := internal.NewCommander() - - prv, err := decideProvider(&providerName, &commander) - if err != nil { - return err - } - - err = prv.Add(&item) + err = controller.NewManager(&providerName).Add(&item) if err != nil { return err } - log.Infoln(fmt.Sprintf("SSH Keys saved for %s.", name)) + log.Infoln(fmt.Sprintf("Manager Keys saved for %s.", name)) return nil }, diff --git a/cmd/get.go b/cmd/get.go index d48fc12..f039f15 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -6,9 +6,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "github.com/omegion/ssh-manager/internal" + "github.com/omegion/ssh-manager/internal/controller" "github.com/omegion/ssh-manager/internal/io" - "github.com/omegion/ssh-manager/internal/provider" ) // setupGetCommand sets default flags. @@ -25,32 +24,25 @@ func setupGetCommand(cmd *cobra.Command) { log.Fatalf("Lethal damage: %s\n\n", err) } - cmd.Flags().Bool("read-only", false, "Do not write fetched SSH keys") + cmd.Flags().Bool("read-only", false, "Do not write fetched Manager keys") } -// Get acquires SSH key from given provider. +// Get acquires Manager key from given provider. func Get() *cobra.Command { cmd := &cobra.Command{ Use: "get", - Short: "Get SSH key from given provider.", + Short: "Get Manager key from given provider.", RunE: func(cmd *cobra.Command, args []string) error { name, _ := cmd.Flags().GetString("name") providerName, _ := cmd.Flags().GetString("provider") readOnly, _ := cmd.Flags().GetBool("read-only") - commander := internal.NewCommander() - - prv, err := decideProvider(&providerName, &commander) - if err != nil { - return err - } - - item, err := prv.Get(name) + item, err := controller.NewManager(&providerName).Get(name) if err != nil { return err } - log.Infoln(fmt.Sprintf("SSH Keys are fetched for %s.", name)) + log.Infoln(fmt.Sprintf("Manager Keys are fetched for %s.", name)) for _, field := range item.Values { fileName := item.Name @@ -79,14 +71,3 @@ func Get() *cobra.Command { return cmd } - -func decideProvider(name *string, commander *internal.Commander) (provider.APIInterface, error) { - switch *name { - case provider.BitwardenCommand: - return provider.Bitwarden{Commander: *commander}, nil - case provider.OnePasswordCommand: - return provider.OnePassword{Commander: *commander}, nil - default: - return provider.Bitwarden{}, provider.NotFound{Name: name} - } -} diff --git a/cmd/list.go b/cmd/list.go index 2f34c98..16d0a96 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -4,7 +4,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "github.com/omegion/ssh-manager/internal" + "github.com/omegion/ssh-manager/internal/controller" ) // setupListCommand sets default flags. @@ -16,27 +16,20 @@ func setupListCommand(cmd *cobra.Command) { } } -// List acquires SSH keys from given provider. +// List acquires Manager keys from given provider. func List() *cobra.Command { cmd := &cobra.Command{ Use: "list", - Short: "List SSH keys from given provider.", + Short: "List Manager keys from given provider.", RunE: func(cmd *cobra.Command, args []string) error { providerName, _ := cmd.Flags().GetString("provider") - commander := internal.NewCommander() - - prv, err := decideProvider(&providerName, &commander) - if err != nil { - return err - } - - items, err := prv.List() + items, err := controller.NewManager(&providerName).List() if err != nil { return err } - log.Infoln("SSH Keys are fetched.") + log.Infoln("Manager Keys are fetched.") for _, item := range items { log.Infoln(item.Name) diff --git a/go.mod b/go.mod index 64e6336..b0e1401 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/omegion/ssh-manager go 1.16 require ( + github.com/golang/mock v1.5.0 github.com/omegion/cobra-commander v0.3.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.1.3 diff --git a/go.sum b/go.sum index c332e98..2cf18cf 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -187,6 +189,7 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -205,6 +208,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -265,7 +269,9 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/internal/controller/manager.go b/internal/controller/manager.go new file mode 100644 index 0000000..3d80362 --- /dev/null +++ b/internal/controller/manager.go @@ -0,0 +1,44 @@ +package controller + +import ( + "github.com/omegion/ssh-manager/internal" + "github.com/omegion/ssh-manager/internal/provider" +) + +// Manager is a controller for SSH providers. +type Manager struct { + Provider provider.Interface +} + +// NewManager is a factory for Manager. +func NewManager(providerName *string) *Manager { + return &Manager{Provider: getProviderByName(providerName)} +} + +// Add adds item to provider. +func (c Manager) Add(item *provider.Item) error { + return c.Provider.Add(item) +} + +// Get gets item from provider. +func (c Manager) Get(name string) (*provider.Item, error) { + return c.Provider.Get(name) +} + +// List lists items from provider. +func (c Manager) List() ([]*provider.Item, error) { + return c.Provider.List() +} + +func getProviderByName(name *string) provider.Interface { + commander := internal.NewCommander() + + switch *name { + case provider.BitwardenCommand: + return provider.Bitwarden{Commander: commander} + case provider.OnePasswordCommand: + return provider.OnePassword{Commander: commander} + default: + return provider.Bitwarden{Commander: commander} + } +} diff --git a/internal/controller/manager_test.go b/internal/controller/manager_test.go new file mode 100644 index 0000000..95e6795 --- /dev/null +++ b/internal/controller/manager_test.go @@ -0,0 +1,77 @@ +package controller + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + "github.com/omegion/ssh-manager/internal/provider" + "github.com/omegion/ssh-manager/internal/provider/mocks" +) + +func TestNewManager(t *testing.T) { + t.Run("bw provider", func(t *testing.T) { + providerName := provider.BitwardenCommand + manager := NewManager(&providerName) + + assert.Equal(t, providerName, manager.Provider.GetName()) + }) + + t.Run("op provider", func(t *testing.T) { + providerName := provider.OnePasswordCommand + manager := NewManager(&providerName) + + assert.Equal(t, providerName, manager.Provider.GetName()) + }) + + t.Run("unknown provider", func(t *testing.T) { + providerName := "unknown" + manager := NewManager(&providerName) + + assert.Equal(t, provider.BitwardenCommand, manager.Provider.GetName()) + }) +} + +func TestManager(t *testing.T) { + ctrl := gomock.NewController(t) + prvMock := mocks.NewMockInterface(ctrl) + + expectedItem := provider.Item{} + + var expectedItems []*provider.Item + + t.Run("add", func(t *testing.T) { + prvMock.EXPECT().Add(&expectedItem).Return(nil) + + manager := Manager{Provider: prvMock} + + err := manager.Add(&expectedItem) + + assert.NoError(t, err) + }) + + t.Run("get", func(t *testing.T) { + prvMock.EXPECT().Get(gomock.Any()).Return(&expectedItem, nil) + + manager := Manager{Provider: prvMock} + + item, err := manager.Get("test") + + assert.NoError(t, err) + assert.Equal(t, &expectedItem, item) + }) + + t.Run("get", func(t *testing.T) { + expectedItems = append(expectedItems, &provider.Item{Name: "test"}) + + prvMock.EXPECT().List().Return(expectedItems, nil) + + manager := Manager{Provider: prvMock} + + items, err := manager.List() + + assert.NoError(t, err) + assert.Len(t, items, 1) + }) +} diff --git a/internal/provider/bw.go b/internal/provider/bw.go index 10e798a..d7ce9cb 100644 --- a/internal/provider/bw.go +++ b/internal/provider/bw.go @@ -34,6 +34,11 @@ type BitwardenItem struct { Login string `json:"login"` } +// GetName returns name of the provider. +func (b Bitwarden) GetName() string { + return BitwardenCommand +} + // Add adds given item to Bitwarden. func (b Bitwarden) Add(item *Item) error { _, err := b.Get(item.Name) @@ -82,10 +87,10 @@ func (b Bitwarden) Add(item *Item) error { } // Get gets Item from Bitwarden with given item name. -func (b Bitwarden) Get(name string) (Item, error) { +func (b Bitwarden) Get(name string) (*Item, error) { err := b.Sync() if err != nil { - return Item{}, err + return &Item{}, err } command := b.Commander.Executor.CommandContext( @@ -104,7 +109,7 @@ func (b Bitwarden) Get(name string) (Item, error) { output, err := command.Output() if err != nil { - return Item{}, ExecutionFailedError{Command: "bw get", Message: stderr.String()} + return &Item{}, ExecutionFailedError{Command: "bw get", Message: stderr.String()} } var tmpItem struct { @@ -115,7 +120,7 @@ func (b Bitwarden) Get(name string) (Item, error) { err = json.Unmarshal(output, &tmpItem) if err != nil { - return Item{}, err + return &Item{}, err } item := Item{ @@ -127,22 +132,22 @@ func (b Bitwarden) Get(name string) (Item, error) { decodedRawNotes, err := base64.StdEncoding.DecodeString(tmpItem.Notes) if err != nil { - return Item{}, err + return &Item{}, err } err = json.Unmarshal(decodedRawNotes, &item.Values) if err != nil { - return Item{}, err + return &Item{}, err } - return item, nil + return &item, nil } // List lists all added SSH keys. -func (b Bitwarden) List() ([]Item, error) { +func (b Bitwarden) List() ([]*Item, error) { err := b.Sync() if err != nil { - return []Item{}, err + return []*Item{}, err } command := b.Commander.Executor.CommandContext( @@ -162,7 +167,7 @@ func (b Bitwarden) List() ([]Item, error) { output, err := command.Output() if err != nil { - return []Item{}, ExecutionFailedError{Command: "bw get", Message: stderr.String()} + return []*Item{}, ExecutionFailedError{Command: "bw get", Message: stderr.String()} } type tmpItem struct { @@ -175,13 +180,13 @@ func (b Bitwarden) List() ([]Item, error) { err = json.Unmarshal(output, &tmpItems) if err != nil { - return []Item{}, err + return []*Item{}, err } - items := make([]Item, 0) + items := make([]*Item, 0) for _, item := range tmpItems { - items = append(items, Item{ + items = append(items, &Item{ ID: *item.ID, Name: strings.Replace(item.Name, BitwardenDefaultPrefix, "", 1), }) diff --git a/internal/provider/api.go b/internal/provider/interface.go similarity index 64% rename from internal/provider/api.go rename to internal/provider/interface.go index 5fad13b..4c1d074 100644 --- a/internal/provider/api.go +++ b/internal/provider/interface.go @@ -5,11 +5,14 @@ import ( "encoding/json" ) -// APIInterface is an interface for all providers. -type APIInterface interface { +//nolint:lll // go generate is ugly. +//go:generate mockgen -destination=mocks/interface_mock.go -package=mocks github.com/omegion/ssh-manager/internal/provider Interface +// Interface is an interface for all providers. +type Interface interface { + GetName() string Add(item *Item) error - Get(name string) (Item, error) - List() ([]Item, error) + Get(name string) (*Item, error) + List() ([]*Item, error) } // Field is custom fields under Item. diff --git a/internal/provider/mocks/interface_mock.go b/internal/provider/mocks/interface_mock.go new file mode 100644 index 0000000..384ec4a --- /dev/null +++ b/internal/provider/mocks/interface_mock.go @@ -0,0 +1,92 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/omegion/ssh-manager/internal/provider (interfaces: Interface) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + gomock "github.com/golang/mock/gomock" + provider "github.com/omegion/ssh-manager/internal/provider" + reflect "reflect" +) + +// MockInterface is a mock of Interface interface +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// Add mocks base method +func (m *MockInterface) Add(arg0 *provider.Item) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Add", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Add indicates an expected call of Add +func (mr *MockInterfaceMockRecorder) Add(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockInterface)(nil).Add), arg0) +} + +// Get mocks base method +func (m *MockInterface) Get(arg0 string) (*provider.Item, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].(*provider.Item) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get +func (mr *MockInterfaceMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), arg0) +} + +// GetName mocks base method +func (m *MockInterface) GetName() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetName") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetName indicates an expected call of GetName +func (mr *MockInterfaceMockRecorder) GetName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetName", reflect.TypeOf((*MockInterface)(nil).GetName)) +} + +// List mocks base method +func (m *MockInterface) List() ([]*provider.Item, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List") + ret0, _ := ret[0].([]*provider.Item) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List +func (mr *MockInterfaceMockRecorder) List() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockInterface)(nil).List)) +} diff --git a/internal/provider/op.go b/internal/provider/op.go index e4b9b76..9967432 100644 --- a/internal/provider/op.go +++ b/internal/provider/op.go @@ -43,6 +43,11 @@ type OnePasswordItem struct { Overview OnePasswordItemOverview `json:"overview"` } +// GetName returns name of the provider. +func (o OnePassword) GetName() string { + return OnePasswordCommand +} + // Add adds given item to OnePassword. func (o OnePassword) Add(item *Item) error { _, err := o.Get(item.Name) @@ -81,7 +86,7 @@ func (o OnePassword) Add(item *Item) error { } // Get gets Item from OnePassword with given item name. -func (o OnePassword) Get(name string) (Item, error) { +func (o OnePassword) Get(name string) (*Item, error) { command := o.Commander.Executor.CommandContext( context.Background(), OnePasswordCommand, @@ -98,14 +103,14 @@ func (o OnePassword) Get(name string) (Item, error) { output, err := command.Output() if err != nil { - return Item{}, ExecutionFailedError{Command: "op get item", Message: stderr.String()} + return &Item{}, ExecutionFailedError{Command: "op get item", Message: stderr.String()} } var opItem OnePasswordItem err = json.Unmarshal(output, &opItem) if err != nil { - return Item{}, err + return &Item{}, err } item := Item{ @@ -117,19 +122,19 @@ func (o OnePassword) Get(name string) (Item, error) { decodedRawNotes, err := base64.StdEncoding.DecodeString(*opItem.Details.NotesPlain) if err != nil { - return Item{}, err + return &Item{}, err } err = json.Unmarshal(decodedRawNotes, &item.Values) if err != nil { - return Item{}, err + return &Item{}, err } - return item, nil + return &item, nil } // List lists all added SSH keys. -func (o OnePassword) List() ([]Item, error) { +func (o OnePassword) List() ([]*Item, error) { command := o.Commander.Executor.CommandContext( context.Background(), OnePasswordCommand, @@ -149,20 +154,20 @@ func (o OnePassword) List() ([]Item, error) { output, err := command.Output() if err != nil { - return []Item{}, ExecutionFailedError{Command: "op list", Message: stderr.String()} + return []*Item{}, ExecutionFailedError{Command: "op list", Message: stderr.String()} } var opItems []OnePasswordItem err = json.Unmarshal(output, &opItems) if err != nil { - return []Item{}, err + return []*Item{}, err } - items := make([]Item, 0) + items := make([]*Item, 0) for _, item := range opItems { - items = append(items, Item{ + items = append(items, &Item{ ID: *item.UUID, Name: strings.Replace(*item.Overview.Title, OnePasswordDefaultPrefix, "", 1), })