actions / actions/setup-dotnet
setup-dotnet fails on air-gapped runners for floating versions
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.2k
- Forks
- 572
- Avg merge
- 12d 20h
- Merged PRs (30d)
- 1
Description
Description:
On self-hosted runners without outbound internet access, actions/setup-dotnet fails to set up a .NET SDK when a floating version (e.g. 8.0.x, or a bare channel like 8.0) is requested, even when a satisfying SDK is already installed on the runner. Two separate steps in the install path make outbound requests before any check of what is already present locally:
-
Unconditional runtime pre-install.
DotnetCoreInstaller.installDotnet()always runs the install script with--runtime dotnet --channel LTSfirst ("to get the latest stable version of the dotnet CLI"). This resolvesRuntime/LTS/latest.versionfrombuilds.dotnet.microsoft.com(falling back toci.dot.net) on every run, regardless of the requested version. On an air-gapped runner this fails immediately.- Source:
src/installer.ts#L410-L417
- Source:
-
Online
latest.versionresolution for floating/channel versions. A floating input such as8.0.xis turned into a channel argument (8.0) rather than a concrete version. The install script then fetchesSdk/8.0/latest.versionover the network to resolve the exact patch, before it checks whether a matching SDK is already on disk. On an air-gapped runner this also fails.- Channel argument construction:
src/installer.ts#L120-L143 - Version-file fetch:
externals/install-dotnet.shget_version_from_latestversion_file
- Channel argument construction:
Representative failing log (floating versions 8.0.x/9.0.x/10.0.x, no outbound access):
install-dotnet.sh --skip-non-versioned-files --runtime dotnet --channel LTS
dotnet-install: Download attempt #1 has failed: Unable to download https://builds.dotnet.microsoft.com/dotnet/Runtime/LTS/latest.version.
... (retries, then falls back to https://ci.dot.net/public/Runtime/LTS/latest.version) ...
Warning: Failed to install dotnet runtime + cli, exit code: 1. dotnet_install: Error: Failed to resolve the exact version number.
install-dotnet.sh --skip-non-versioned-files --channel 8.0
dotnet-install: Download attempt #1 has failed: Unable to download https://builds.dotnet.microsoft.com/dotnet/Sdk/8.0/latest.version.
... (retries, then falls back to https://ci.dot.net/public/Sdk/8.0/latest.version) ...
Error: Failed to install dotnet, exit code: 1. dotnet_install: Error: Failed to resolve the exact version number.
Clarifying the "it already reuses the cache" behavior
When a fully pinned version (e.g. 8.0.422) is requested, the input becomes a concrete --version argument, no latest.version fetch is needed for the SDK, and the install script reports .NET Core SDK with version 'X' is already installed when it finds it on disk. This is why pinned-version runs succeed and appear to "reuse" an existing install.
However, note two things:
- This reuse is the install script detecting an SDK already present at the install directory —
setup-dotnetdoes not consult the GitHub Actions tool cache (@actions/tool-cache) in its install path. So "preload the tool cache" (as works foractions/setup-java) does not apply here. - Even for a pinned version, the unconditional runtime pre-install (point 1) still makes an outbound
latest.versionrequest, which fails on a fully air-gapped runner.
For floating/channel versions, the online resolution (point 2) happens before the on-disk check, so an already-satisfying local SDK is never given the chance to short-circuit the network call.
Justification:
This blocks any workflow that runs setup-dotnet with floating versions on air-gapped self-hosted runners. Notably, GitHub's Automatic Dependency Submission (ADS) for NuGet uses floating versions (8.0.x, 9.0.x, 10.0.x) and therefore always takes the online-resolution path, so it cannot be made to work offline by preinstalling SDKs or preloading the tool cache. This came up via a customer support escalation; the report is intentionally scoped to the general capability and contains no customer- or environment-specific details.
For comparison, actions/setup-java is usable in preloaded/offline scenarios because a satisfying local toolchain short-circuits the download.
Proposed behavior:
- Before performing online version resolution for a floating/channel request, check whether an already-installed SDK under the install directory (
DOTNET_ROOT/DotnetInstallDir) satisfies the requested version; if so, use it and skip the network call. - Make the runtime pre-install (point 1) tolerant of a runner with no outbound access — e.g. skip it when a suitable CLI/runtime is already present, or don't hard-require the online
latest.versionresolution for it. - (Secondary) Provide a supported way to point resolution/download at an internal mirror/feed (the install scripts already support an Azure feed override), so environments that maintain a mirror can resolve floating versions offline.
Are you willing to submit a PR?
Yes — happy to collaborate on this if the maintainers agree on the approach.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with DotnetCoreInstaller.installDotnet() in src/installer.ts, then trace channel construction at src/installer.ts#L120-L143 and get_version_from_latestversion_file in externals/install-dotnet.sh. Reproduce the floating-version and runtime requests on an air-gapped runner, and verify that satisfying local SDKs avoid network resolution while pinned-version behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- shell, typescript
- Domain
- ci-cd, devops, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100