@@ -10,6 +10,7 @@ import (
1010 "fmt"
1111 "io"
1212 "log/slog"
13+ "net"
1314 "net/http"
1415 "regexp"
1516 "strings"
@@ -45,23 +46,31 @@ var (
4546 secretNameRegex = regexp .MustCompile (`^[a-zA-Z0-9_-]{1,255}$` )
4647)
4748
49+ // isNotOnGCP returns true if the error indicates we're definitely not running on GCP.
50+ // This includes DNS resolution failures and connection refused errors for the metadata server.
51+ func isNotOnGCP (err error ) bool {
52+ var dnsErr * net.DNSError
53+ var opErr * net.OpError
54+ return errors .As (err , & dnsErr ) || errors .As (err , & opErr )
55+ }
56+
4857// Fetch retrieves the latest version of a secret from the current project.
4958// The project ID is auto-detected from the GCP metadata server.
5059func Fetch (ctx context.Context , name string ) (string , error ) {
5160 if ! secretNameRegex .MatchString (name ) {
5261 return "" , errors .New ("invalid secret name format" )
5362 }
5463
55- p , err := getProjectID (ctx )
64+ p , err := projectID (ctx )
5665 if err != nil {
5766 return "" , err
5867 }
5968
6069 return FetchFromProject (ctx , p , name )
6170}
6271
63- // getProjectID fetches the project ID from the GCP metadata server.
64- func getProjectID (ctx context.Context ) (string , error ) {
72+ // projectID fetches the project ID from the GCP metadata server.
73+ func projectID (ctx context.Context ) (string , error ) {
6574 var p string
6675 var lastErr error
6776
@@ -84,6 +93,11 @@ func getProjectID(ctx context.Context) (string, error) {
8493 resp , err := httpClient .Do (req )
8594 if err != nil {
8695 lastErr = err
96+ // Don't retry if we're clearly not on GCP (DNS failure, connection refused)
97+ if isNotOnGCP (err ) {
98+ slog .Debug ("not running on GCP" , "error" , err )
99+ return "" , fmt .Errorf ("not running on GCP: %w" , err )
100+ }
87101 slog .Warn ("failed to get project ID" , "attempt" , attempt + 1 , "error" , err )
88102 continue
89103 }
@@ -117,8 +131,8 @@ func getProjectID(ctx context.Context) (string, error) {
117131 return p , nil
118132}
119133
120- // getAccessToken fetches an access token from the GCP metadata server.
121- func getAccessToken (ctx context.Context ) (string , error ) {
134+ // accessToken fetches an access token from the GCP metadata server.
135+ func accessToken (ctx context.Context ) (string , error ) {
122136 var t string
123137 var lastErr error
124138
@@ -141,6 +155,11 @@ func getAccessToken(ctx context.Context) (string, error) {
141155 resp , err := httpClient .Do (req )
142156 if err != nil {
143157 lastErr = err
158+ // Don't retry if we're clearly not on GCP (DNS failure, connection refused)
159+ if isNotOnGCP (err ) {
160+ slog .Debug ("not running on GCP" , "error" , err )
161+ return "" , fmt .Errorf ("not running on GCP: %w" , err )
162+ }
144163 slog .Warn ("failed to get access token" , "attempt" , attempt + 1 , "error" , err )
145164 continue
146165 }
@@ -185,7 +204,7 @@ func FetchFromProject(ctx context.Context, pid, name string) (string, error) {
185204 return "" , errors .New ("invalid secret name format" )
186205 }
187206
188- t , err := getAccessToken (ctx )
207+ t , err := accessToken (ctx )
189208 if err != nil {
190209 return "" , err
191210 }
@@ -268,7 +287,7 @@ func Store(ctx context.Context, name, value string) error {
268287 return errors .New ("invalid secret name format" )
269288 }
270289
271- p , err := getProjectID (ctx )
290+ p , err := projectID (ctx )
272291 if err != nil {
273292 return err
274293 }
@@ -286,7 +305,7 @@ func StoreInProject(ctx context.Context, pid, name, value string) error {
286305 return errors .New ("invalid secret name format" )
287306 }
288307
289- tok , err := getAccessToken (ctx )
308+ tok , err := accessToken (ctx )
290309 if err != nil {
291310 return err
292311 }
0 commit comments