actions / actions/setup-dotnet

setup-dotnet fails on air-gapped runners for floating versions

Open
#762 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature request
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:

  1. Unconditional runtime pre-install. DotnetCoreInstaller.installDotnet() always runs the install script with --runtime dotnet --channel LTS first ("to get the latest stable version of the dotnet CLI"). This resolves Runtime/LTS/latest.version from builds.dotnet.microsoft.com (falling back to ci.dot.net) on every run, regardless of the requested version. On an air-gapped runner this fails immediately.

  2. Online latest.version resolution for floating/channel versions. A floating input such as 8.0.x is turned into a channel argument (8.0) rather than a concrete version. The install script then fetches Sdk/8.0/latest.version over 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.

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 directorysetup-dotnet does not consult the GitHub Actions tool cache (@actions/tool-cache) in its install path. So "preload the tool cache" (as works for actions/setup-java) does not apply here.
  • Even for a pinned version, the unconditional runtime pre-install (point 1) still makes an outbound latest.version request, 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.version resolution 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.