Skip to content

is_git_url() does not recognize the ssh:// scheme (plugin source ssh://… fails with 'Unable to parse') #3759

@jpshackelford

Description

@jpshackelford

Summary

is_git_url() in openhands/sdk/git/utils.py does not recognize the ssh:// URL scheme, so a plugin/extension source like:

ssh://git@bitbucket.example.com:7999/team/repo.git

drops through parse_extension_source() and fails at parse time with the misleading error:

ExtensionFetchError: Unable to parse extension source: ssh://git@bitbucket.example.com:7999/team/repo.git

The SCP-style spelling of the same repo (git@bitbucket.example.com:team/repo.git) is recognized and proceeds to git clone. So today the two equivalent SSH spellings behave inconsistently: the scp-form is fetched, the ssh://-scheme form is rejected as "unparseable" before any clone is attempted.

⚠️ How narrow is this? (please read before prioritizing)

This is a deliberately small edge case. It only matters for a user who is doing all of the following:

  1. Using a private plugin/extension repo reachable only over SSH (not HTTPS), AND
  2. Spelling the source with the ssh:// scheme specifically (the scp-style git@host:... form already works), AND
  3. Has manually provisioned an SSH key into the sandbox/runtime (e.g. started a sandbox, injected the SSH credential, then attached a conversation whose agent/plugins clone over SSH).

For the overwhelming majority of users, the supported and recommended path is an HTTPS URL with a token (which, combined with #3755, can reference a secret: https://x-token-auth:${TOKEN}@host/repo.git). This issue does not add SSH key provisioning, and it does not make SSH "just work" for hosted/SaaS users who have not injected a key. It only fixes the parse-level inconsistency so that an already-working SSH setup accepts the ssh:// spelling too.

Root cause

is_git_url() checks https://, http://, the scp regex ^[\w.-]+@[\w.-]+:, git://, and file:// — but never the ssh:// scheme. ssh://git@host:port/path matches none of those (the scp regex requires <user>@<host>: with no scheme prefix), so the source is classified as neither git nor local and raises Unable to parse.

normalize_git_url() and extract_repo_name() already handle the ssh:// string correctly; only the recognition check is missing.

Proposed fix

Add a single branch to is_git_url() recognizing the ssh:// scheme, so it is classified as SourceType.GIT and handed to the normal cached-clone path (which then succeeds iff the runtime has a usable SSH key — same as the scp-style form today). No behavior change for HTTPS/HTTPS-with-token, local paths, or hosted users without a key.

Acceptance criteria

  • is_git_url("ssh://git@host:7999/team/repo.git") returns True.
  • parse_extension_source("ssh://...") returns SourceType.GIT (no "Unable to parse").
  • Regression test covering the ssh:// scheme (incl. an explicit port).

This issue was created by an AI agent (OpenHands) on behalf of @jpshackelford.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcustomer-supportThis item has been reported by a customer and is being tracked as a support ticket.pluginsAbout plugins and their contents

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions