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:
-
Use a repository containing an SCP-style SSH submodule URL:
[submodule "dependency"]
path = dependency
url = git@github.com:example/private-dependency
-
Check out the repository using actions/checkout, with submodules: true, token authentication covering both repositories, and the default persist-credentials: true.
-
Let the job complete, including checkout’s post-job cleanup.
-
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.
-
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:
actions/checkoutinstalls 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: falseand 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:
Use a repository containing an SCP-style SSH submodule URL:
Check out the repository using
actions/checkout, withsubmodules: true, token authentication covering both repositories, and the defaultpersist-credentials: true.Let the job complete, including checkout’s post-job cleanup.
In a subsequent job, check out the parent repository with
submodules: false, then load an SSH key with access to the dependency usingwebfactory/ssh-agent.Initialize or fetch the dependency:
The submodule can retain this setting in
.git/modules/dependency/config:Its stored remote remains SSH, but its effective URL becomes HTTPS:
The request fails with an error such as:
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, commitd23441a48e516b6c34aea4fa41551a30e30af803:configureSubmoduleAuth()installs the local HTTPS rewrite.removeAuth()removes SSH and token authentication, but does not remove that rewrite.submodules: false, leaving the cached rewrite without submodule credentials.This lifecycle was reproduced using the exact shipped bundle’s authentication helpers, real local Git submodule fixtures, and a dummy token.
git submodule syncalone 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:
ssh://do not work, including this comment identifying the prefix-specific rewrite.ssh://URLs would extend rewriting to explicit SSH URLs, so changing URL spelling would not be a durable workaround.