1package agent
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 providerauth "github.com/patriceckhart/zot/packages/provider/auth"
9)
10
11func isolateGoogleVertexADC(t *testing.T) string {
12 t.Helper()
13 root := t.TempDir()
14 t.Setenv("HOME", root)
15 t.Setenv("APPDATA", root)
16 path, err := providerauth.GoogleApplicationDefaultCredentialsPath()
17 if err != nil {
18 t.Fatalf("GoogleApplicationDefaultCredentialsPath: %v", err)
19 }
20 return path
21}
22
23// TestResolveCredentialGoogleVertexAPIKey confirms that GOOGLE_CLOUD_API_KEY
24// takes top priority for the google-vertex provider and is returned with
25// method "apikey".
26func TestResolveCredentialGoogleVertexAPIKey(t *testing.T) {
27 t.Setenv("ZOT_HOME", t.TempDir())
28 isolateGoogleVertexADC(t)
29 t.Setenv("GOOGLE_CLOUD_API_KEY", "gcp-key-123")
30 t.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "")
31
32 cred, method, _, err := ResolveCredentialFull("google-vertex", "")
33 if err != nil {
34 t.Fatalf("ResolveCredentialFull failed: %v", err)
35 }
36 if cred != "gcp-key-123" {
37 t.Errorf("cred = %q, want %q", cred, "gcp-key-123")
38 }
39 if method != "apikey" {
40 t.Errorf("method = %q, want apikey", method)
41 }
42}
43
44// TestResolveCredentialGoogleVertexApplicationCredentialsEnv confirms that
45// when GOOGLE_APPLICATION_CREDENTIALS is set (service account JSON path),
46// resolution returns the "<adc>" sentinel with method "apikey", matching
47// the real NewVertex client's ADC-based auth flow.
48func TestResolveCredentialGoogleVertexApplicationCredentialsEnv(t *testing.T) {
49 t.Setenv("ZOT_HOME", t.TempDir())
50 isolateGoogleVertexADC(t)
51 t.Setenv("GOOGLE_CLOUD_API_KEY", "")
52 t.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/service-account.json")
53
54 cred, method, _, err := ResolveCredentialFull("google-vertex", "")
55 if err != nil {
56 t.Fatalf("ResolveCredentialFull failed: %v", err)
57 }
58 if cred != "<adc>" {
59 t.Errorf("cred = %q, want <adc>", cred)
60 }
61 if method != "apikey" {
62 t.Errorf("method = %q, want apikey", method)
63 }
64}
65
66// TestResolveCredentialGoogleVertexDefaultADCFile confirms that, absent any
67// env vars, the presence of the platform-specific default gcloud ADC file is
68// detected and resolves to the "<adc>" sentinel.
69func TestResolveCredentialGoogleVertexDefaultADCFile(t *testing.T) {
70 t.Setenv("ZOT_HOME", t.TempDir())
71 adcPath := isolateGoogleVertexADC(t)
72 t.Setenv("GOOGLE_CLOUD_API_KEY", "")
73 t.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "")
74
75 if err := os.MkdirAll(filepath.Dir(adcPath), 0o755); err != nil {
76 t.Fatal(err)
77 }
78 if err := os.WriteFile(adcPath, []byte(`{"type":"authorized_user"}`), 0o600); err != nil {
79 t.Fatal(err)
80 }
81
82 cred, method, _, err := ResolveCredentialFull("google-vertex", "")
83 if err != nil {
84 t.Fatalf("ResolveCredentialFull failed: %v", err)
85 }
86 if cred != "<adc>" {
87 t.Errorf("cred = %q, want <adc>", cred)
88 }
89 if method != "apikey" {
90 t.Errorf("method = %q, want apikey", method)
91 }
92}
93
94// TestResolveCredentialGoogleVertexPrecedence confirms GOOGLE_CLOUD_API_KEY
95// wins over GOOGLE_APPLICATION_CREDENTIALS and the default ADC file when
96// multiple credential sources are present simultaneously.
97func TestResolveCredentialGoogleVertexPrecedence(t *testing.T) {
98 t.Setenv("ZOT_HOME", t.TempDir())
99 adcPath := isolateGoogleVertexADC(t)
100 t.Setenv("GOOGLE_CLOUD_API_KEY", "explicit-key")
101 t.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/sa.json")
102
103 if err := os.MkdirAll(filepath.Dir(adcPath), 0o755); err != nil {
104 t.Fatal(err)
105 }
106 if err := os.WriteFile(adcPath, []byte(`{"type":"authorized_user"}`), 0o600); err != nil {
107 t.Fatal(err)
108 }
109
110 cred, method, _, err := ResolveCredentialFull("google-vertex", "")
111 if err != nil {
112 t.Fatalf("ResolveCredentialFull failed: %v", err)
113 }
114 if cred != "explicit-key" {
115 t.Errorf("cred = %q, want explicit-key (API key must win over ADC)", cred)
116 }
117 if method != "apikey" {
118 t.Errorf("method = %q, want apikey", method)
119 }
120}
121
122// TestResolveCredentialGoogleVertexNoCredentials confirms that when none of
123// the Vertex credential sources are present (no env vars, no ADC file, no
124// auth.json entry), resolution fails with an error rather than silently
125// returning an empty credential.
126func TestResolveCredentialGoogleVertexNoCredentials(t *testing.T) {
127 t.Setenv("ZOT_HOME", t.TempDir())
128 isolateGoogleVertexADC(t)
129 t.Setenv("GOOGLE_CLOUD_API_KEY", "")
130 t.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "")
131
132 cred, method, _, err := ResolveCredentialFull("google-vertex", "")
133 if err == nil {
134 t.Fatalf("expected error, got cred=%q method=%q", cred, method)
135 }
136 if cred != "" || method != "" {
137 t.Errorf("expected empty cred/method on error, got cred=%q method=%q", cred, method)
138 }
139}