Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Bolt's Journal

## 2026-03-09 - GCP ID Token Credentials Caching & Proxy Overhead
**Learning:** Invoking Google Cloud credential discovery (`google.FindDefaultCredentials`) inside `GetIDToken` for every forwarded request via the local reverse proxy introduces massive disk I/O and configuration parsing latency (~300ms per request). Standardizing thread-safe lazy credentials caching via `sync.Mutex` ensures subsequent ID token generation requests are nearly instantaneous because they reuse the cached credentials' thread-safe `TokenSource` which handles in-memory token caching and refreshes automatically.
**Action:** Always identify and cache underlying `google.Credentials` and `TokenSource` configurations across performance-critical request paths instead of repeatedly invoking credential discovery.

## 2026-03-08 - GCP Logging Client Caching & Connection Longevity
**Learning:** Establishing the GCP Stackdriver Logging client requires repeated Google credential discovery and connection establishment, causing high latency (~300ms) inside a reactive TUI interface. Caching `logadmin.Client` instances via a project-aware map with thread-safe `sync.Mutex` ensures subsequent streaming and log extraction operations are instantaneous. Crucially, calling `Close()` on individual stream terminations must be a no-op to prevent premature teardown of connection pools shared across other active streaming views.
**Action:** Keep GCP Logging clients cached globally by project and handle connection termination via a no-op `Close` method, while adding test-isolation resets in unit tests.
Expand Down
25 changes: 22 additions & 3 deletions internal/run/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"os/user"
"path/filepath"
"strings"
"sync"

api_region "github.com/JulienBreux/run-cli/internal/run/api/region"
"github.com/JulienBreux/run-cli/internal/run/model/common/info"
Expand Down Expand Up @@ -130,12 +131,30 @@ func parseConfig(path string) (info.Info, error) {
}, nil
}

var (
credsMu sync.Mutex
cachedCreds *google.Credentials
findDefaultCredentials = google.FindDefaultCredentials
)

// GetIDToken retrieves an identity token for the given audience using Google Cloud credentials.
// It caches the credentials structure in a thread-safe manner to prevent repetitive credential discovery
// disk read and metadata server lookup overhead (~300ms latency) on every subsequent call.
var GetIDToken = func(ctx context.Context) (string, error) {
creds, err := google.FindDefaultCredentials(ctx, scopes...)
if err != nil {
return "", fmt.Errorf("failed to find default credentials: %w", err)
credsMu.Lock()
if cachedCreds == nil {
// Use a background context to ensure credential discovery is not canceled
// if a request-scoped context is canceled.
bgCtx := context.Background()
creds, err := findDefaultCredentials(bgCtx, scopes...)
if err != nil {
credsMu.Unlock()
return "", fmt.Errorf("failed to find default credentials: %w", err)
}
cachedCreds = creds
}
creds := cachedCreds
credsMu.Unlock()

token, err := creds.TokenSource.Token()
if err != nil {
Expand Down
64 changes: 64 additions & 0 deletions internal/run/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ limitations under the License.
package auth

import (
"context"
"os"
"path/filepath"
"testing"

api_region "github.com/JulienBreux/run-cli/internal/run/api/region"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)

func TestGetInfo(t *testing.T) {
Expand Down Expand Up @@ -133,3 +136,64 @@ func TestGetInfo_Defaults(t *testing.T) {
t.Errorf("Expected default Region 'all', got '%s'", info.Region)
}
}

type mockTokenSource struct {
token *oauth2.Token
}

func (m *mockTokenSource) Token() (*oauth2.Token, error) {
return m.token, nil
}

func TestGetIDToken_Caching(t *testing.T) {
// Reset/save global variables
origFindDefaultCredentials := findDefaultCredentials
origCachedCreds := cachedCreds
defer func() {
findDefaultCredentials = origFindDefaultCredentials
cachedCreds = origCachedCreds
}()

// Mock token source and extra fields
baseToken := &oauth2.Token{
AccessToken: "mock-access-token",
}
mockToken := baseToken.WithExtra(map[string]interface{}{
"id_token": "mock-id-token",
})
mockTS := &mockTokenSource{
token: mockToken,
}

callCount := 0
findDefaultCredentials = func(ctx context.Context, scopes ...string) (*google.Credentials, error) {
callCount++
return &google.Credentials{
TokenSource: mockTS,
}, nil
}

// First call (cache miss)
cachedCreds = nil // Ensure cache is empty
token, err := GetIDToken(context.Background())
if err != nil {
t.Fatalf("GetIDToken failed: %v", err)
}
if token != "mock-id-token" {
t.Errorf("Expected token 'mock-id-token', got '%s'", token)
}

// Second call (cache hit)
token, err = GetIDToken(context.Background())
if err != nil {
t.Fatalf("GetIDToken second call failed: %v", err)
}
if token != "mock-id-token" {
t.Errorf("Expected token 'mock-id-token', got '%s'", token)
}

// Verify discovery was only called once
if callCount != 1 {
t.Errorf("Expected findDefaultCredentials to be called exactly 1 time, called %d times", callCount)
}
}
Loading