Sitelet https://github.com/actions/checkout/issues/2582
Skip to content

SSH-to-HTTPS submodule rewrite survives credential cleanup and breaks subsequent jobs on self-hosted runners #2582

Description

@camilo-celis

actions/checkout installs an SSH-to-HTTPS URL rewrite when checking out submodules using token authentication. Its post-job cleanup removes the authentication credentials but leaves the rewrite in the submodule’s local Git configuration.

On a persistent self-hosted runner, a subsequent job can inherit that rewrite even when it uses submodules: false and configures SSH authentication separately. Git then attempts an unauthenticated HTTPS connection instead of using the loaded SSH key.

Reproduction

Run these sequentially using the same repository checkout on the same self-hosted runner:

  1. Use a repository containing an SCP-style SSH submodule URL:

    [submodule "dependency"]
        path = dependency
        url = git@github.com:example/private-dependency
  2. Check out the repository using actions/checkout, with submodules: true, token authentication covering both repositories, and the default persist-credentials: true.

  3. Let the job complete, including checkout’s post-job cleanup.

  4. In a subsequent job, check out the parent repository with submodules: false, then load an SSH key with access to the dependency using webfactory/ssh-agent.

  5. Initialize or fetch the dependency:

    git submodule update --init -- dependency
    git -C dependency ls-remote origin

The submodule can retain this setting in .git/modules/dependency/config:

[url "https://github.com/"]
    insteadOf = git@github.com:

Its stored remote remains SSH, but its effective URL becomes HTTPS:

Stored:    git@github.com:example/private-dependency
Effective: https://github.com/example/private-dependency

The request fails with an error such as:

fatal: could not read Username for 'https://github.com': No such device or address

If the pinned commit is already cached, initialization can succeed without network access, with the failure appearing only during a subsequent fetch or remote lookup.

Expected behavior

Checkout-created authentication configuration should not leave subsequent jobs using an unintended transport after its credentials have been removed.

Ideally, cleanup should restore the previous configuration, removing checkout-added rewrite values while preserving pre-existing user configuration.

Observed implementation behavior

Verified against actions/checkout@v6, commit d23441a48e516b6c34aea4fa41551a30e30af803:

This lifecycle was reproduced using the exact shipped bundle’s authentication helpers, real local Git submodule fixtures, and a dummy token. git submodule sync alone did not remove the rewrite.

The production failures are consistent with this mechanism, although the precise historical job that introduced the affected runners’ configuration has not been identified.

Related issues and discussions

These appear related, but do not explicitly describe this cross-job rewrite-cleanup sequence:

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions