diff --git a/pkg/onepassword/client/connect/connect.go b/pkg/onepassword/client/connect/connect.go index f528e5c..fc967a5 100644 --- a/pkg/onepassword/client/connect/connect.go +++ b/pkg/onepassword/client/connect/connect.go @@ -2,7 +2,9 @@ package connect import ( "context" + "errors" "fmt" + "time" "github.com/1Password/connect-sdk-go/connect" "github.com/1Password/connect-sdk-go/onepassword" @@ -30,7 +32,7 @@ func NewClient(config Config) *Connect { func (c *Connect) GetItemByID(ctx context.Context, vaultID, itemID string) (*model.Item, error) { connectItem, err := c.client.GetItemByUUID(itemID, vaultID) if err != nil { - return nil, fmt.Errorf("1Password Connect error: %w", err) + return nil, fmt.Errorf("GetItemByID 1Password Connect error: %w", err) } var item model.Item @@ -42,7 +44,7 @@ func (c *Connect) GetItemsByTitle(ctx context.Context, vaultID, itemTitle string // Get all items in the vault with the specified title connectItems, err := c.client.GetItemsByTitle(itemTitle, vaultID) if err != nil { - return nil, fmt.Errorf("1Password Connect error: %w", err) + return nil, fmt.Errorf("GetItemsByTitle 1Password Connect error: %w", err) } items := make([]model.Item, len(connectItems)) @@ -55,21 +57,38 @@ func (c *Connect) GetItemsByTitle(ctx context.Context, vaultID, itemTitle string return items, nil } +// GetFileContent retrieves the content of a file from a 1Password item. +// As the Connect has a delay when synchronizing files and returns a 500 error in this case, this function implements a retry mechanism. func (c *Connect) GetFileContent(ctx context.Context, vaultID, itemID, fileID string) ([]byte, error) { - bytes, err := c.client.GetFileContent(&onepassword.File{ - ContentPath: fmt.Sprintf("/v1/vaults/%s/items/%s/files/%s/content", vaultID, itemID, fileID), - }) - if err != nil { - return nil, fmt.Errorf("1Password Connect error: %w", err) + const maxRetries = 5 + const delay = 1 * time.Second + + var lastErr error + for i := 0; i < maxRetries; i++ { + bytes, err := c.client.GetFileContent(&onepassword.File{ + ContentPath: fmt.Sprintf("/v1/vaults/%s/items/%s/files/%s/content", vaultID, itemID, fileID), + }) + if err == nil { + return bytes, nil + } + + var connectErr *onepassword.Error + if errors.As(err, &connectErr) && connectErr.StatusCode == 500 { + lastErr = err + time.Sleep(delay) + continue + } + + return nil, fmt.Errorf("GetFileContent 1Password Connect error: %w", err) } - return bytes, nil + return nil, fmt.Errorf("GetFileContent failed after retries: %w", lastErr) } func (c *Connect) GetVaultsByTitle(ctx context.Context, vaultQuery string) ([]model.Vault, error) { connectVaults, err := c.client.GetVaultsByTitle(vaultQuery) if err != nil { - return nil, fmt.Errorf("1Password Connect error: %w", err) + return nil, fmt.Errorf("GetVaultsByTitle 1Password Connect error: %w", err) } var vaults []model.Vault