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
8 changes: 6 additions & 2 deletions packages/util/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ func WriteToFile(fileName string, dataToWrite []byte, filePerm os.FileMode) erro
}

func ValidateInfisicalAPIConnection() (ok bool) {
_, err := http.Get(fmt.Sprintf("%v/status", config.INFISICAL_URL))
return err == nil
resp, err := http.Get(fmt.Sprintf("%v/status", config.INFISICAL_URL))
Comment thread
jakehulberg marked this conversation as resolved.
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode >= 200 && resp.StatusCode < 300
Comment thread
jakehulberg marked this conversation as resolved.
}

func GetRestyClientWithCustomHeaders() (*resty.Client, error) {
Expand Down
27 changes: 27 additions & 0 deletions packages/util/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,33 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectCo
errorToReturn = err
secretsToReturn = res.Secrets
}

// cache secrets on success, fallback to cached secrets on connection/server failure
if errorToReturn == nil && params.WorkspaceId != "" {
if backupEncryptionKey, err := GetBackupEncryptionKey(); err == nil {
WriteBackupSecrets(params.WorkspaceId, params.Environment, params.SecretsPath, backupEncryptionKey, secretsToReturn)
}
} else if errorToReturn != nil && params.WorkspaceId != "" {
// Only fall back to cache for connection errors or server errors (5xx).
// Do not mask client errors (4xx) like 401/403 which indicate auth issues.
shouldFallback := true
var apiErr *api.APIError
if errors.As(errorToReturn, &apiErr) && apiErr.StatusCode >= 400 && apiErr.StatusCode < 500 {
shouldFallback = false
}
Comment on lines +386 to +390

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 4xx masking still active for service tokens when --projectId is passed

GetPlainTextSecretsViaServiceToken wraps any error from CallGetServiceTokenDetailsV2 with fmt.Errorf("unable to get service token details. [err=%v]", err) β€” using %v, not %w. That strips the error chain, so errors.As(errorToReturn, &apiErr) always returns false for this error path, leaving shouldFallback = true. If a user runs infisical run --projectId=<id> --token=<service-token> ... and the token is revoked (the API returns 401), the 4xx guard is bypassed and the fallback silently serves stale cached secrets instead of surfacing the auth error. The fix that was applied to the Universal Auth path (which directly propagates the typed *api.APIError) does not cover service tokens due to this wrapping.


if shouldFallback {
backupEncryptionKey, _ := GetBackupEncryptionKey()
if backupEncryptionKey != nil {
backedUpSecrets, err := ReadBackupSecrets(params.WorkspaceId, params.Environment, params.SecretsPath, backupEncryptionKey)
if len(backedUpSecrets) > 0 {
PrintWarning("Unable to fetch the latest secret(s) due to connection error, serving secrets from last successful fetch. For more info, run with --debug")
secretsToReturn = backedUpSecrets
errorToReturn = err
}
}
}
}
Comment thread
jakehulberg marked this conversation as resolved.
}

return secretsToReturn, errorToReturn
Expand Down
Loading