diff --git a/pkg/credentials/credential.go b/pkg/credentials/credential.go index fc247b38..c81adf2b 100644 --- a/pkg/credentials/credential.go +++ b/pkg/credentials/credential.go @@ -49,13 +49,15 @@ func (c Credential) toDockerAuthConfig() (types.AuthConfig, error) { func credentialFromDockerAuthConfig(authCfg types.AuthConfig) (Credential, error) { var cred Credential - if err := json.Unmarshal([]byte(authCfg.Password), &cred); err != nil || len(cred.Env) == 0 { - // Legacy: try unmarshalling into just an env map - var env map[string]string - if err := json.Unmarshal([]byte(authCfg.Password), &env); err != nil { - return Credential{}, err + if authCfg.Password != "" { + if err := json.Unmarshal([]byte(authCfg.Password), &cred); err != nil || len(cred.Env) == 0 { + // Legacy: try unmarshalling into just an env map + var env map[string]string + if err := json.Unmarshal([]byte(authCfg.Password), &env); err != nil { + return Credential{}, err + } + cred.Env = env } - cred.Env = env } // We used to hardcode the username as "gptscript" before CredentialType was introduced, so diff --git a/pkg/credentials/helper.go b/pkg/credentials/helper.go index 9776d8b9..e5cd34f6 100644 --- a/pkg/credentials/helper.go +++ b/pkg/credentials/helper.go @@ -2,6 +2,7 @@ package credentials import ( "errors" + "net/url" "regexp" "strings" @@ -71,9 +72,18 @@ func (h *HelperStore) GetAll() (map[string]types.AuthConfig, error) { contextPieces := strings.Split(ctx, ":") if len(contextPieces) > 1 { possiblePortNumber := contextPieces[len(contextPieces)-1] - if regexp.MustCompile(`\d+$`).MatchString(possiblePortNumber) { + if regexp.MustCompile(`^\d+$`).MatchString(possiblePortNumber) { // port number confirmed - toolName = toolName + ":" + possiblePortNumber + toolURL, err := url.Parse(toolName) + if err != nil { + return nil, err + } + + // Save the path so we can put it back after removing it. + path := toolURL.Path + toolURL.Path = "" + + toolName = toolURL.String() + ":" + possiblePortNumber + path ctx = strings.TrimSuffix(ctx, ":"+possiblePortNumber) } } diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index 7d7cff6e..6cb3644e 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -108,7 +108,7 @@ func (c *Client) clientFromURL(ctx context.Context, apiURL string) (*openai.Clie env := "GPTSCRIPT_PROVIDER_" + env2.ToEnvLike(parsed.Hostname()) + "_API_KEY" key := os.Getenv(env) - if key == "" { + if key == "" && !isLocalhost(apiURL) { var err error key, err = c.retrieveAPIKey(ctx, env, apiURL) if err != nil { @@ -179,3 +179,8 @@ func (c *Client) load(ctx context.Context, toolName string) (*openai.Client, err func (c *Client) retrieveAPIKey(ctx context.Context, env, url string) (string, error) { return prompt.GetModelProviderCredential(ctx, c.credStore, url, env, fmt.Sprintf("Please provide your API key for %s", url), append(gcontext.GetEnv(ctx), c.envs...)) } + +func isLocalhost(url string) bool { + return strings.HasPrefix(url, "http://localhost") || strings.HasPrefix(url, "http://127.0.0.1") || + strings.HasPrefix(url, "https://localhost") || strings.HasPrefix(url, "https://127.0.0.1") +} diff --git a/pkg/types/tool.go b/pkg/types/tool.go index b0af5183..e7af756f 100644 --- a/pkg/types/tool.go +++ b/pkg/types/tool.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "path/filepath" + "regexp" "slices" "sort" "strings" @@ -283,6 +284,10 @@ func ParseCredentialArgs(toolName string, input string) (string, string, map[str fields = fields[2:] } + if alias != "" && !isAlphaNumeric(alias) { + return "", "", nil, fmt.Errorf("credential alias must be alphanumeric") + } + if len(fields) == 0 { // Nothing left, so just return return originalName, alias, nil, nil } @@ -780,3 +785,7 @@ func FirstSet[T comparable](in ...T) (result T) { } return } + +func isAlphaNumeric(s string) bool { + return regexp.MustCompile(`^[a-zA-Z0-9_.]+$`).MatchString(s) +}