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 }