Skip to content

[FEATURE] Opt-out for anonymous-first HTTPS on github.com behind TLS-inspecting proxies with no revocation info #2545

Open

Description

@rgarciapariente

Is your feature request related to a problem? Please describe.

AuthResolver.uses_public_github_anonymous_first() (introduced in #2406, 0.27.0; refined in #2422, 0.28.0) unconditionally tries HTTPS anonymously first for any exact-host github.com dependency, with no opt-out. The anonymous attempt runs in a from-scratch isolated Git environment (GIT_CONFIG_NOSYSTEM=1 + empty GIT_CONFIG_GLOBAL + disabled credential.helper), which ignores the user's real ~/.gitconfig (including http.sslBackend and any corporate TLS trust configuration).

On networks behind a TLS-inspecting proxy (e.g. Netskope) whose intercepting certificate chain carries no CRL Distribution Point and no Authority Information Access (OCSP) extensions at all (verified with openssl x509 -text on leaf, intermediate, and root — not just "unreachable", genuinely absent), the isolated environment's connection attempt fails with a network/TLS-classified error (schannel: CRYPT_E_NO_REVOCATION_CHECK, or a hang). is_public_github_auth_failure() correctly does not classify this as an auth failure, so APM neverresolves/tries a credential — and with --allow-protocol-fallback it jumps straight to SSH. If SSH is also blocked (common on corporate firewalls), install fails completely with "Could not connect to github.com (network error, not an auth failure)".

Critically, a plain git clone on the same machine/network succeeds instantly, because it uses the OS git credential helper and the use

r's real ~/.gitconfig (http.sslBackend=schannel, resolving against the Windows certificate store where the corporate root CA is installed) — the exact configuration the isolated environment discards.

This is a regression relative to 0.26.0, whose legacy --allow-protocol-fallback chain unconditionally tried a final "plain HTTPS" leg deferring to the OS git config/credential helper, which happened to succeed in this exact scenario.

Describe the solution you'd like

An opt-out (CLI flag and/or env var, e.g. --auth-first / APM_GITHUB_AUTH_FIRST=1) to restore auth-first / environment-inheriting behavior for exact-host github.com, for users who already have a working git config/credentials but are behind a network where the isolated anonymous-first environment cannot complete a TLS handshake at all.

Describe alternatives you've considered

  • Downgrading to apm <0.27.0 — works, but loses newer fixes/features.

  • Declaring dependencies with explicit ssh:// URLs to sidestep the HTTPS path — plausible, untested, and still depends on SSH connectivity (often blocked; workable via ssh.github.com:443 but non-obvious).

  • Manually restoring TLS trust for the isolated environment via GIT_SSL_CAINFO + forcing http.sslbackend=openssl (these specific env vars survive AuthResolver's isolation, unlike gitconfig-based settings) — works, but required deep reverse-engineering of auth.py to discover; not discoverable by a typical user hitting this.

  • http.schannelCheckRevoke=false — does not reliably help when the CA chain has no revocation info at all (confirmed on 2.45.1.windows.1); matches several long-standing, unresolved community reports of the same git-for-windows/schannel limitation (SO 65636426, SO 45556189).

Additional context

Activity

  1. github-actions commented on Aug 10, 2026

    @github-actions

    Thank you for the detailed report, @rgarciapariente -- this is an excellent bug writeup with clear root-cause analysis and alternatives considered.


    Triage Panel Verdict

    Summary

    AuthResolver's anonymous-first isolated git environment (introduced in #2406, refined in #2422) strips GIT_CONFIG_NOSYSTEM, clears GIT_CONFIG_GLOBAL, and disables credential.helper. On Windows behind a TLS-inspecting proxy whose intercepting CA chain carries no CRL/OCSP revocation info, this isolated environment cannot complete a TLS handshake -- whereas a plain git clone on the same machine succeeds because it uses the OS git credential helper and the user's real ~/.gitconfig (http.sslBackend=schannel + Windows certificate store). The result is a complete install failure, a regression from 0.26.0, and a severe discoverability gap (workarounds require reverse-engineering auth.py).

    Decision: ACCEPT

    This is a legitimate enterprise-blocking regression affecting users behind corporate TLS-inspecting proxies (Netskope and equivalents). The proposed opt-out (--auth-first / APM_GITHUB_AUTH_FIRST=1) is the right shape: explicit user consent to trade the credential-isolation security property for environment-inheriting behavior.

    Panel notes by dimension

    DevX UX Expert

    • Regression from 0.26.0 -- --allow-protocol-fallback's "plain HTTPS leg" previously deferred to OS git config, accidentally making this work.
    • Proposed flag name --auth-first is clear. Consider also surfacing a diagnostic hint in the existing "network error, not an auth failure" error path pointing users to the opt-out.
    • The GIT_SSL_CAINFO / http.sslbackend=openssl workaround surviving isolation (because env vars bypass gitconfig stripping) is worth documenting as a power-user escape hatch in the error message.

    Supply Chain Security Expert

    • The isolation was deliberate: anonymous-first prevents credential leakage to unverified servers. The opt-out reintroduces this risk.
    • Recommended implementation guard: when --auth-first / APM_GITHUB_AUTH_FIRST=1 is active, emit a one-time [!] APM_GITHUB_AUTH_FIRST is set: git credentials will be forwarded on the first HTTPS attempt warning so the security tradeoff is visible.
    • Prefer inheriting OS TLS config only (not full credential helper) as a narrower fix if feasible; full env inheritance is the fallback.
    • This touches AuthResolver -- implementation must pass scripts/lint-auth-signals.sh.

    APM CEO

    • High-priority enterprise regression. Well-scoped, minimal proposal. Accept.
    • Implementation needs a brief design sketch (flag vs. env var vs. both, interaction with --allow-protocol-fallback) before coding to avoid a second round of auth-surface churn.

    Recommended labels

    Dimension Label Rationale
    Theme theme/security Auth surface; TLS isolation tradeoff
    Area area/cli CLI flag + env var proposal
    Priority priority/high Enterprise users completely blocked
    Status status/triaged Accepted; needs-design before implementation

    Existing type/feature label retained (human-applied; the regression aspect could also justify type/bug, but this label is accurate and was set by a maintainer -- panel recommends adding type/bug as a complementary label for the regression dimension, but defers to maintainer discretion).

    Suggested next action

    1. A brief design comment (maintainer or contributor) on the opt-out API shape: flag only, env var only, or both; interaction with --allow-protocol-fallback; whether to narrow isolation to TLS-config-only first.
    2. Assign to the next minor or patch milestone once design is settled.
    3. Implementation must update AuthResolver + add regression test for the TLS-proxy scenario (mock or documented manual repro steps).

    Triage status: agentic proposal pending human ratification.
    Silence is approval. Maintainers can:

    • Override any label or milestone above by editing it directly --
      human edits are authoritative and will not be reverted on
      subsequent runs.
    • Re-trigger triage by applying the status/needs-triage label, or
      by removing status/triaged to enroll the issue in the next
      daily sweep.

    Posted by the Triage Panel workflow. See .apm/skills/apm-triage-panel for the panel skill.

    Generated by Triage Panel · 44 AIC · ⌖ 5.06 AIC · ⊞ 9.2K · ◷

  2. added
    area/cliCLI command surface, flags, help text (cross-cutting).
    priority/highHuman-set high priority; not scope approval, a release commitment or a required milestone.
    status/triagedAutomated advice completed; deduplication only. Not human approval; silence is not approval.
    theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.
    on Aug 10, 2026
  3. rgarciapariente commented on Sep 10, 2026

    @rgarciapariente
    Author

    Design proposal: opt-out for anonymous-first isolation (#2545)

    Answering the panel's three sub-questions.

    1. API shape → both flag and env var, reusing the --allow-protocol-fallback pattern

    APM already has a tested opt-out of this exact class: --allow-protocol-fallback /
    APM_ALLOW_PROTOCOL_FALLBACK / apm config set allow-protocol-fallback
    (config.py:337-458, commands/install.py:970-974, commands/config.py:25-70). Reuse it verbatim:

    • Flag --auth-first (is_flag=True, default=False), env APM_GITHUB_AUTH_FIRST (tri-state parser,
      same as _parse_allow_protocol_fallback_env), persisted key github_auth_first.
    • Resolution order identical to get_apm_allow_protocol_fallback(): flag > env > config > False
      (add a sibling get_apm_github_auth_first()).

    Both — flag for one-off/CI, env for wrapper scripts, config for "always behind this proxy".

    Naming caveat: --auth-first describes the mechanism (attempt order), not the effect
    (inherit my system git/TLS config). If the narrow fix below lands, the residual opt-out is really
    "inherit my full git env incl. credential helper", so --no-github-isolation / --inherit-git-config
    may read more honestly. Open question — happy to keep --auth-first for continuity.

    2. Interaction with --allow-protocol-fallback → orthogonal, applied earlier

    They compose, don't conflict:

    • --allow-protocol-fallback governs what happens after the anonymous HTTPS attempt fails
      (whether to jump HTTPS → SSH).
    • --auth-first acts before that: the opt-out must be threaded inside
      AuthResolver.uses_public_github_anonymous_first() so it returns False for exact-host github.com.
      That method is the single decision point consulted by ~13 call sites (validation, clone engine,
      downloader, ref resolution) — its own docstring keeps the decision there "so ... [they] cannot drift
      into separate host checks", so the opt-out belongs there, not at an individual
      try_with_fallback(unauth_first=...) call site.
    • Neither flag requires or excludes the other. Add a regression test (alongside
      tests/unit/test_transport_selection.py:12) over the 4 combinations of
      {auth-first} × {allow-protocol-fallback}.

    3. Narrow to TLS-config-only first → yes, ship it as the default; keep --auth-first as the broad escape hatch

    1. Narrow fix (default): build_public_github_anonymous_git_env() (core/auth.py:1313-1343)
      zeroes the whole git config (GIT_CONFIG_NOSYSTEM=1 + empty GIT_CONFIG_GLOBAL), discarding TLS
      trust settings together with credential.helper — two unrelated concerns in one mechanism. We
      already split them elsewhere: noninteractive_env() takes preserve_config_isolation and
      suppress_credential_helpers separately (deps/git_auth_env.py:116-168). Inherit only the user's
      real http.sslBackend + http.sslCAInfo (the settings that make a plain git clone succeed
      in this scenario — per the report http.schannelCheckRevoke does not help), while still forcing
      credential.helper= / http.extraheader= empty.
      • Security framing: this keeps the credential-leakage vector closed (helpers stay disabled); it
        does relax the "hermetic TLS" property so the anonymous attempt honors the user's own CA trust —
        same CAs a plain git clone already uses. Worth an explicit call-out for the supply-chain review.
      • Implementation cost (not trivial): the values live in the real gitconfig, so we must query the
        non-isolated config (git config --get http.sslBackend, …) and re-inject via
        GIT_CONFIG_COUNT/KEY_n/VALUE_n. We must not point GIT_CONFIG_GLOBAL at the real file
        (that would drag credential.helper back in). Cross-platform care needed.
    2. Broad escape hatch: --auth-first / APM_GITHUB_AUTH_FIRST stays for cases the narrow fix
      doesn't cover, with the one-time warning the panel suggested:
      [!] APM_GITHUB_AUTH_FIRST is set: git credentials will be forwarded on the first HTTPS attempt.

    This fixes the common TLS-proxy case by default with no credential-leakage regression, and gives power
    users an explicit, warned opt-out — as two independently reviewable/revertable AuthResolver changes.

    Implementation note

    Both changes touch AuthResolver → must pass scripts/lint-auth-signals.sh; the new env var is read
    only in config.py (no direct os.getenv() in app code). Test both the flag matrix and the
    default TLS-inheritance path independently.

  4. added
    triage/recommendedAutomated advice completed; not human scope approval.
    and removed
    status/triagedAutomated advice completed; deduplication only. Not human approval; silence is not approval.
    on Sep 12, 2026
  5. rgarciapariente commented on Sep 16, 2026

    @rgarciapariente
    Author

    I've added the following PR #2999 with an implementation proposal. Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/cliCLI command surface, flags, help text (cross-cutting).priority/highHuman-set high priority; not scope approval, a release commitment or a required milestone.status/deferredNot invited for implementation now; no release commitment.theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.triage/recommendedAutomated advice completed; not human scope approval.type/featureNew capability, new flag, new primitive.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions