Skip to content

[BUG] apm install fails validation for SSH-accessible generic Git hosts (non-GitHub/non-ADO) #583

@zzoubian

Description

@zzoubian

Describe the bug
apm install fails the pre-install validation step when targeting a self-hosted Git server (e.g., a GitLab instance) that is accessible via SSH but not via unauthenticated HTTPS. The validation probes the repository with git ls-remote over HTTPS only, receives a 401/fatal prompt-disabled error, and rejects the package — even though the subsequent clone would succeed over SSH using the user's configured SSH keys.

To Reproduce

  1. Have a repository hosted on a self-hosted Git server (e.g., git.example.org) accessible via SSH keys but not unauthenticated HTTPS.
  2. Run:
    apm install git@git.example.org:org/group/repo.git
  3. See error...
    [*] Validating 1 package...
    Trying git ls-remote for git.example.org
    git ls-remote rc=128: fatal: could not read Username for 'https://git.example.org': terminal prompts disabled
    [x] git@git.example.org:org/group/repo.git -- not accessible or doesn't exist
    All packages failed validation. Nothing to install.

Expected behavior
Validation succeeds and the package is installed. APM should try SSH (git ls-remote git@host:path.git) before falling back to HTTPS for generic (non-GitHub, non-ADO) hosts — the same transport preference already used in the clone step (_clone_with_fallback).

Root cause

In install.py, the _package_exists_and_accessible function always calls git ls-remote with an HTTPS URL for generic hosts, even though no token is available and HTTPS may require credentials. The actual clone path (_clone_with_fallback) already tries SSH first for generic hosts, creating an inconsistency between validation and installation.

Suggested Fix

# For generic hosts, try SSH first (no credentials needed when SSH
# keys are configured) before falling back to HTTPS.
urls_to_try = []
if is_generic:
    ssh_url = ado_downloader._build_repo_url(
        dep_ref.repo_url, use_ssh=True, dep_ref=dep_ref
    )
    urls_to_try = [ssh_url, package_url]   # package_url is the HTTPS fallback
else:
    urls_to_try = [package_url]

result = None
for probe_url in urls_to_try:
    result = subprocess.run(
        ["git", "ls-remote", "--heads", "--exit-code", probe_url],
        capture_output=True, text=True, timeout=30, env=validate_env,
    )
    if result.returncode == 0:
        break

Additional context
The regression window is narrow: the bug only surfaces when all three of the following are true:

The host is not github.com or dev.azure.com (generic host path)
No APM-managed token is configured for the host (GITHUB_APM_PAT / ADO_APM_PAT are absent)
The repository is accessible via SSH but requires credentials over HTTPS

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedDirection approved, safe to start workbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions