Skip to content

Global DOTNET_ROLL_FORWARD=Major in SDK images can silently change test runtime behavior #7255

Description

@Frytaaa

Describe the bug

The official .NET SDK image sets DOTNET_ROLL_FORWARD=Major globally as a PowerShell workaround. This affects unrelated .NET workloads such as dotnet test and can cause older TFM tests, e.g. net8.0, to execute on the .NET 10 runtime without the target runtime being installed.

This can make CI compatibility tests look successful even though the actual target runtime was not tested.

Which .NET image(s) are you using?

mcr.microsoft.com/dotnet/sdk:10.0

Steps to reproduce

  1. Use a .NET SDK container image that contains only the latest runtime, for example a .NET 10 SDK image.

  2. Check the installed runtimes and environment:

dotnet --list-runtimes
printenv | grep DOTNET_ROLL_FORWARD

Observed in the SDK container:

DOTNET_ROLL_FORWARD=Major
Microsoft.NETCore.App 10.x is installed
Microsoft.NETCore.App 8.x is not installed
  1. Create or use a test project targeting an older TFM, for example:
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
  1. Run the tests inside the SDK container:
dotnet test --configuration Release
  1. The net8.0 test assembly can execute successfully even though the .NET 8 runtime is not installed, because it rolls forward to the .NET 10 runtime.

Example output:

Running tests from .../bin/Release/net8.0/...Tests.dll (net10.0|x64)
  1. If DOTNET_ROLL_FORWARD is unset or changed to Minor, the same net8.0 test execution fails with the expected missing runtime error when .NET 8 is not installed.

Other information

Description

The official .NET SDK container image sets DOTNET_ROLL_FORWARD=Major globally. I understand this appears to be intentional as a PowerShell workaround, but because the variable is global it affects all .NET applications executed inside the SDK container, not only PowerShell.

This can be surprising in CI pipelines. For multi-targeted NuGet/package libraries, tests targeting older TFMs may pass even though the corresponding runtime is not installed. For example, a net8.0 test assembly can run on the .NET 10 runtime inside a .NET 10 SDK image.

From a compatibility-testing perspective, this is misleading. The pipeline result looks like net8.0 was tested successfully, but actually the net8.0 assembly was executed on .NET 10.

What other issues did you find before opening this one?

I found the PowerShell-related workaround that appears to be the reason for setting DOTNET_ROLL_FORWARD=Major in the SDK image. The issue here is not PowerShell itself, but the global side effect on unrelated workloads such as dotnet test.

What error messages do you see?

When running the same test outside the SDK container, or with DOTNET_ROLL_FORWARD unset/changed to Minor, the expected error is:

You must install or update .NET to run this application.

Framework: 'Microsoft.NETCore.App', version '8.0.0'
The following frameworks were found:
  10.0.x

Inside the SDK container, the test can instead pass because of:

DOTNET_ROLL_FORWARD=Major

and test output can show something like:

Running tests from .../bin/Release/net8.0/...Tests.dll (net10.0|x64)

When does this issue occur? Does it occur consistently?

It occurs consistently when using an SDK container image where:

  • DOTNET_ROLL_FORWARD=Major is set globally,
  • only the newer runtime is installed,
  • and an older target framework test/application is executed.

Do you know of any workarounds?

Yes. For strict compatibility testing, override the variable during test execution:

export DOTNET_ROLL_FORWARD=Minor
dotnet test --configuration Release

Then install all runtimes that should actually be tested, for example .NET 8 runtime for net8.0 tests and .NET 10 runtime for net10.0 tests.

Using DOTNET_ROLL_FORWARD=Major can be acceptable as an explicit migration shortcut, but it should not be easy to mistake this for true runtime compatibility testing.

What is the container host OS and version?

This was observed in Azure DevOps using Linux job containers based on the .NET SDK image. The behavior is caused by the environment inside the SDK container, so the host OS is likely not the main factor.

Example environment from the container:

DOTNET_RUNNING_IN_CONTAINER=true
DOTNET_SDK_VERSION=10.0.300
DOTNET_VERSION=10.0.8
DOTNET_ROLL_FORWARD=Major

Suggested improvement

Please consider one of the following:

  • Document this behavior prominently for SDK image users.
  • Add guidance for CI/test scenarios that require strict target-runtime validation.
  • Consider whether the PowerShell workaround can be scoped more narrowly instead of setting DOTNET_ROLL_FORWARD=Major globally.

Output of docker version

Output of docker info

Metadata

Metadata

Assignees

Labels

area-dockerfilesConcerns the official .NET Dockerfiles or Dockerfile templatesneeds-announcementAn announcement is needed to discuss customer impact

Type

No fields configured for Bug.

Projects

Status
In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions