Skip to content

[FEATURE] Thread dep_ref.port into credential resolution (git credential fill) #785

@edenfunf

Description

@edenfunf

Problem

DependencyReference.port is parsed and threaded through URL construction (#665), but is never propagated into the credential resolution path. git credential fill supports a port= field, but APM always sends bare hostname only:

# token_manager.py:111
input=f"protocol=https\nhost={host}\n\n"   # no port= line

Affected code path:

Layer File Gap
Auth resolver core/auth.py:210 resolve_for_dep() reads dep_ref.host, ignores dep_ref.port
Cache key core/auth.py:183 (host.lower(), org.lower()) — no port dimension
Host model core/auth.py:56 HostInfo has no port field
Credential fill core/token_manager.py:111 git credential fill input omits port=

Impact

When a user has the same hostname serving git on different ports with different credentials (e.g. bitbucket.corp.com:7999 for SSH and bitbucket.corp.com:7990 for HTTPS, each requiring distinct PATs), APM's pre-resolved token path (Method 1: authenticated HTTPS) may resolve the wrong credential.

Mitigating factor: for non-GitHub hosts, APM's token resolution typically returns None, and git's own clone process queries credential helpers with the full URL including port — so the direct clone path handles this correctly. The gap only affects the pre-resolved token path in _resolve_token.

Suggested fix

1. HostInfo — add port

@dataclass(frozen=True)
class HostInfo:
    host: str
    port: Optional[int] = None  # Non-standard git port
    kind: str
    has_public_repos: bool
    api_base: str

2. AuthResolver — port-aware cache key

key = (host.lower(), port, org.lower() if org else "")

3. resolve_for_dep — thread port

def resolve_for_dep(self, dep_ref):
    host = dep_ref.host or default_host()
    port = dep_ref.port
    org = dep_ref.repo_url.split("/")[0] if dep_ref.repo_url else None
    return self.resolve(host, org, port=port)

4. resolve_credential_from_git — pass port to git credential protocol

input_str = f"protocol=https\nhost={host}\n"
if port:
    input_str += f"port={port}\n"
input_str += "\n"

All new parameters default to None — fully backward compatible.

Limitation worth documenting

Not all credential helpers honor the port field. OS keychains and gh auth typically store credentials per-hostname. APM can pass the information correctly, but per-port discrimination ultimately depends on the helper implementation. A one-line note in docs/getting-started/authentication.md under "Git credential helper not found" would set expectations.

Context

Follow-up from PR #665 review (auth-expert panel finding). The port field was introduced on DependencyReference and LockedDependency but was only wired into URL construction, not credential resolution.

Refs: #661, #665

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions