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

    bugSomething isn't workingneeds-triageNew issue, not yet reviewed by maintainers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions