This is an automated email from the ASF dual-hosted git repository.
laskoviymishka pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new c2e7ec00 fix(rest): surface failures refreshing expired credentials
(#1579)
c2e7ec00 is described below
commit c2e7ec004d09a3fccdcb9b61a221dc1f8d0f3004
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 5 18:57:26 2026 +0200
fix(rest): surface failures refreshing expired credentials (#1579)
* fix(rest): surface failures refreshing expired credentials
Signed-off-by: Minh Vu <[email protected]>
* fix(rest): distinguish initial and refreshed IO failures
Signed-off-by: Minh Vu <[email protected]>
* test(rest): preserve cached IO before credential expiry
* fix(rest): fail expired credential refreshes
---------
Signed-off-by: Minh Vu <[email protected]>
---
catalog/rest/vended_creds.go | 8 ++++----
catalog/rest/vended_creds_test.go | 29 +++++++++++++++++++++++++----
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/catalog/rest/vended_creds.go b/catalog/rest/vended_creds.go
index 44ec4882..66b8b9be 100644
--- a/catalog/rest/vended_creds.go
+++ b/catalog/rest/vended_creds.go
@@ -136,7 +136,7 @@ func (v *vendedCredentialRefresher) loadFS(ctx
context.Context) (iceio.IO, error
default:
freshCreds, err := v.fetchCreds(ctx, v.identifier)
if err != nil {
- return v.cachedIO, nil
+ return nil, fmt.Errorf("refresh vended credentials for
%s: %w", v.location, err)
}
config = maps.Clone(v.props)
@@ -145,11 +145,11 @@ func (v *vendedCredentialRefresher) loadFS(ctx
context.Context) (iceio.IO, error
newIO, err := iceio.LoadFS(ctx, config, v.location)
if err != nil {
- if v.cachedIO != nil {
- return v.cachedIO, nil
+ if v.cachedIO == nil {
+ return nil, err
}
- return nil, err
+ return nil, fmt.Errorf("load filesystem with refreshed
credentials for %s: %w", v.location, err)
}
v.cachedIO = newIO
diff --git a/catalog/rest/vended_creds_test.go
b/catalog/rest/vended_creds_test.go
index 059a149e..f9a65c62 100644
--- a/catalog/rest/vended_creds_test.go
+++ b/catalog/rest/vended_creds_test.go
@@ -46,12 +46,13 @@ func newTestRefresher(fetchCreds func(ctx context.Context,
ident []string) (iceb
func TestVendedCredsCachedIOReturnedWhenNotExpired(t *testing.T) {
t.Parallel()
+ refreshErr := errors.New("refresh unavailable")
var callCount atomic.Int32
r := newTestRefresher(func(ctx context.Context, ident []string)
(iceberg.Properties, error) {
callCount.Add(1)
- return iceberg.Properties{}, nil
+ return nil, refreshErr
})
// Seed cached IO and set expiry in the future.
@@ -153,7 +154,7 @@ func TestVendedCredsConcurrentAccess(t *testing.T) {
assert.NotNil(t, r.cachedIO, "cachedIO should be set after initial
load")
}
-func TestVendedCredsGracefulDegradation(t *testing.T) {
+func TestVendedCredsReturnsRefreshFailureForExpiredCredentials(t *testing.T) {
t.Parallel()
fetchErr := errors.New("network error")
@@ -170,8 +171,27 @@ func TestVendedCredsGracefulDegradation(t *testing.T) {
r.expiresAt = now.Add(-time.Second)
got, err := r.loadFS(context.Background())
- require.NoError(t, err, "should not return error when cached IO exists
and refresh fails")
- assert.Equal(t, existingIO, got, "should return cached IO on refresh
failure")
+ require.ErrorIs(t, err, fetchErr)
+ require.ErrorContains(t, err, "refresh vended credentials for
file:///tmp/test")
+ assert.Nil(t, got)
+}
+
+func TestVendedCredsReturnsLoadFailureForExpiredCredentials(t *testing.T) {
+ t.Parallel()
+
+ now := time.Now()
+ r := newTestRefresher(func(ctx context.Context, ident []string)
(iceberg.Properties, error) {
+ return iceberg.Properties{}, nil
+ })
+ r.nowFunc = func() time.Time { return now }
+ r.location = "notascheme://bucket/path"
+ r.cachedIO = iceio.LocalFS{}
+ r.expiresAt = now.Add(-time.Second)
+
+ got, err := r.loadFS(context.Background())
+ require.Error(t, err)
+ require.ErrorContains(t, err, "load filesystem with refreshed
credentials for notascheme://bucket/path")
+ assert.Nil(t, got)
}
func TestVendedCredsErrorWhenInitialLoadFails(t *testing.T) {
@@ -185,6 +205,7 @@ func TestVendedCredsErrorWhenInitialLoadFails(t *testing.T)
{
got, err := r.loadFS(context.Background())
require.Error(t, err)
+ assert.NotContains(t, err.Error(), "refreshed credentials")
assert.Nil(t, got)
}