github.com/supabase/cli@v1.168.1/internal/utils/access_token_test.go (about)

     1  package utils
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/spf13/afero"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  	"github.com/supabase/cli/internal/testing/apitest"
    11  	"github.com/supabase/cli/internal/testing/fstest"
    12  	"github.com/supabase/cli/internal/utils/credentials"
    13  	"github.com/zalando/go-keyring"
    14  )
    15  
    16  func TestLoadToken(t *testing.T) {
    17  	keyring.MockInit()
    18  	token := string(apitest.RandomAccessToken(t))
    19  
    20  	t.Run("loads token from env var", func(t *testing.T) {
    21  		t.Setenv("SUPABASE_ACCESS_TOKEN", token)
    22  		// Setup in-memory fs
    23  		fsys := afero.NewMemMapFs()
    24  		// Run test
    25  		loaded, err := LoadAccessTokenFS(fsys)
    26  		// Check error
    27  		assert.NoError(t, err)
    28  		assert.Equal(t, token, loaded)
    29  	})
    30  
    31  	t.Run("throws error on invalid token", func(t *testing.T) {
    32  		t.Setenv("SUPABASE_ACCESS_TOKEN", "invalid")
    33  		// Setup in-memory fs
    34  		fsys := afero.NewMemMapFs()
    35  		// Run test
    36  		loaded, err := LoadAccessTokenFS(fsys)
    37  		// Check error
    38  		assert.ErrorIs(t, err, ErrInvalidToken)
    39  		assert.Empty(t, loaded)
    40  	})
    41  
    42  	t.Run("throws error on missing token", func(t *testing.T) {
    43  		// Setup in-memory fs
    44  		fsys := afero.NewMemMapFs()
    45  		// Run test
    46  		loaded, err := LoadAccessTokenFS(fsys)
    47  		// Check error
    48  		assert.ErrorIs(t, err, ErrMissingToken)
    49  		assert.Empty(t, loaded)
    50  	})
    51  }
    52  
    53  func TestLoadTokenFallback(t *testing.T) {
    54  	t.Run("fallback loads from file", func(t *testing.T) {
    55  		path, err := getAccessTokenPath()
    56  		assert.NoError(t, err)
    57  		// Setup in-memory fs
    58  		fsys := afero.NewMemMapFs()
    59  		require.NoError(t, afero.WriteFile(fsys, path, []byte{}, 0600))
    60  		// Run test
    61  		token, err := fallbackLoadToken(fsys)
    62  		// Check error
    63  		assert.NoError(t, err)
    64  		assert.Empty(t, token)
    65  	})
    66  
    67  	t.Run("throws error on home dir failure", func(t *testing.T) {
    68  		// Setup in-memory fs
    69  		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
    70  		// Setup empty home directory
    71  		t.Setenv("HOME", "")
    72  		// Run test
    73  		token, err := fallbackLoadToken(fsys)
    74  		// Check error
    75  		assert.ErrorContains(t, err, "$HOME is not defined")
    76  		assert.Empty(t, token)
    77  	})
    78  
    79  	t.Run("throws error on read failure", func(t *testing.T) {
    80  		path, err := getAccessTokenPath()
    81  		assert.NoError(t, err)
    82  		// Setup in-memory fs
    83  		fsys := &fstest.OpenErrorFs{DenyPath: path}
    84  		// Run test
    85  		token, err := fallbackLoadToken(fsys)
    86  		// Check error
    87  		assert.ErrorContains(t, err, "permission denied")
    88  		assert.Empty(t, token)
    89  	})
    90  }
    91  
    92  func TestSaveToken(t *testing.T) {
    93  	keyring.MockInit()
    94  	token := string(apitest.RandomAccessToken(t))
    95  
    96  	t.Run("saves token to keyring", func(t *testing.T) {
    97  		// Setup in-memory fs
    98  		fsys := afero.NewMemMapFs()
    99  		// Run test
   100  		assert.NoError(t, SaveAccessToken(token, fsys))
   101  		// Validate saved token
   102  		saved, err := LoadAccessTokenFS(fsys)
   103  		assert.NoError(t, err)
   104  		assert.Equal(t, token, saved)
   105  	})
   106  
   107  	t.Run("throws error on invalid token", func(t *testing.T) {
   108  		// Setup in-memory fs
   109  		fsys := afero.NewMemMapFs()
   110  		// Run test
   111  		err := SaveAccessToken("invalid", fsys)
   112  		// Check error
   113  		assert.ErrorIs(t, err, ErrInvalidToken)
   114  	})
   115  }
   116  
   117  func TestSaveTokenFallback(t *testing.T) {
   118  	token := string(apitest.RandomAccessToken(t))
   119  
   120  	t.Run("fallback saves to file", func(t *testing.T) {
   121  		// Setup in-memory fs
   122  		fsys := afero.NewMemMapFs()
   123  		// Run test
   124  		assert.NoError(t, fallbackSaveToken(token, fsys))
   125  		// Validate saved token
   126  		path, err := getAccessTokenPath()
   127  		assert.NoError(t, err)
   128  		contents, err := afero.ReadFile(fsys, path)
   129  		assert.NoError(t, err)
   130  		assert.Equal(t, []byte(token), contents)
   131  	})
   132  
   133  	t.Run("throws error on home dir failure", func(t *testing.T) {
   134  		// Setup in-memory fs
   135  		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
   136  		// Setup empty home directory
   137  		t.Setenv("HOME", "")
   138  		// Run test
   139  		err := fallbackSaveToken(token, fsys)
   140  		// Check error
   141  		assert.ErrorContains(t, err, "$HOME is not defined")
   142  	})
   143  
   144  	t.Run("throws error on permission denied", func(t *testing.T) {
   145  		// Setup in-memory fs
   146  		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
   147  		// Run test
   148  		err := fallbackSaveToken(token, fsys)
   149  		// Check error
   150  		assert.ErrorContains(t, err, "operation not permitted")
   151  	})
   152  
   153  	t.Run("throws error on write failure", func(t *testing.T) {
   154  		home, err := os.UserHomeDir()
   155  		assert.NoError(t, err)
   156  		// Setup in-memory fs
   157  		fsys := &fstest.OpenErrorFs{DenyPath: home}
   158  		// Run test
   159  		err = fallbackSaveToken(token, fsys)
   160  		// Check error
   161  		assert.ErrorContains(t, err, "permission denied")
   162  	})
   163  }
   164  
   165  func TestDeleteToken(t *testing.T) {
   166  	t.Run("deletes both keyring and fallback", func(t *testing.T) {
   167  		token := string(apitest.RandomAccessToken(t))
   168  		require.NoError(t, credentials.Set(AccessTokenKey, token))
   169  		// Setup in-memory fs
   170  		fsys := afero.NewMemMapFs()
   171  		require.NoError(t, fallbackSaveToken(token, fsys))
   172  		// Run test
   173  		err := DeleteAccessToken(fsys)
   174  		// Check error
   175  		assert.NoError(t, err)
   176  		_, err = credentials.Get(AccessTokenKey)
   177  		assert.ErrorIs(t, err, keyring.ErrNotFound)
   178  		path, err := getAccessTokenPath()
   179  		assert.NoError(t, err)
   180  		exists, err := afero.Exists(fsys, path)
   181  		assert.NoError(t, err)
   182  		assert.False(t, exists)
   183  	})
   184  
   185  	t.Run("throws error if not logged in", func(t *testing.T) {
   186  		// Setup in-memory fs
   187  		fsys := afero.NewMemMapFs()
   188  		// Run test
   189  		err := DeleteAccessToken(fsys)
   190  		// Check error
   191  		assert.ErrorIs(t, err, ErrNotLoggedIn)
   192  	})
   193  
   194  	t.Run("throws error on home dir failure", func(t *testing.T) {
   195  		// Setup in-memory fs
   196  		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
   197  		// Setup empty home directory
   198  		t.Setenv("HOME", "")
   199  		// Run test
   200  		err := DeleteAccessToken(fsys)
   201  		// Check error
   202  		assert.ErrorContains(t, err, "$HOME is not defined")
   203  	})
   204  }