Skip to content

Migrate SignFile Task to TaskEnvironment API#13173

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/migrate-signfile-task-api
Draft

Migrate SignFile Task to TaskEnvironment API#13173
Copilot wants to merge 3 commits intomainfrom
copilot/migrate-signfile-task-api

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 2, 2026

Context

SignFile task needed migration to support MSBuild's multithreaded execution model. Tasks must use TaskEnvironment for path resolution instead of relying on process working directory.

Changes Made

  • Add [MSBuildMultiThreadableTask] attribute and implement IMultiThreadableTask
  • Add TaskEnvironment property
  • Absolutize SigningTarget.ItemSpec via TaskEnvironment.GetAbsolutePath() before passing to SecurityUtilities.SignFile()
  • Handle ArgumentException from path resolution with appropriate error logging

Thread-safety fix for SecurityUtilities

SecurityUtilities.SignFile() transitively used process-global state, which is unsafe under multithreaded execution:

  1. GetPathToTool() used Directory.GetCurrentDirectory() as fallback for signtool.exe discovery
  2. SignPEFileInternal() created new ProcessStartInfo() without setting WorkingDirectory, inheriting process CWD
  3. SetDllDirectoryW() modified process-wide DLL search path during manifest signing

Fix: Thread TaskEnvironment through the entire SecurityUtilities.SignFileSignFileInternalSignPEFileSignPEFileInternal call chain via internal overloads. Public API signatures are unchanged (old methods delegate with taskEnvironment: null).

  • SignPEFileInternal now uses taskEnvironment.GetProcessStartInfo() as baseline ProcessStartInfo (inherits correct WorkingDirectory and environment variables from the task's project context)
  • GetPathToTool accepts a fallbackDirectory parameter instead of calling Directory.GetCurrentDirectory()
  • SetDllDirectoryW calls are serialized with a lock under #if RUNTIME_TYPE_NETCORE
  • Added TaskEnvironmentHelper.CreateMultithreadedForTest() helper for tests

Testing

  • GetPathToTool_WithFallbackDirectory_NeverUsesCwd — verifies fallback directory is never the process CWD
  • SignFile_WithTaskEnvironment_UsesTaskEnvironmentProjectDirectory — verifies MultiThreadedTaskEnvironmentDriver sets correct WorkingDirectory on ProcessStartInfo
  • Existing SignFile_Success tests unchanged

Notes

SignFile is Windows-only ([SupportedOSPlatform("windows")]), so unit tests are skipped on Linux CI runners.

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Hello @@copilot, I noticed that you’re changing an .swr file or any file under src/Package/MSBuild.VSSetup.. Please make sure to validate this change by an experimental VS insertion. This is accomplished by pushing to an exp/* branch, which requires write permissions to this repo.

Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
Copilot AI changed the title [WIP] Migrate SignFile task to TaskEnvironment API Migrate SignFile Task to TaskEnvironment API Feb 2, 2026
Copilot AI requested a review from JanProvaznik February 2, 2026 12:06
@JanProvaznik JanProvaznik marked this pull request as ready for review February 2, 2026 12:15
Copilot AI review requested due to automatic review settings February 2, 2026 12:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the SignFile task to use the TaskEnvironment API for path resolution to better support MSBuild’s multithreaded execution model.

Changes:

  • Mark SignFile as multithread-capable via [MSBuildMultiThreadableTask] and IMultiThreadableTask, adding a TaskEnvironment property.
  • Resolve SigningTarget.ItemSpec to an absolute path via TaskEnvironment.GetAbsolutePath(...) before signing.
  • Add handling/logging for ArgumentException thrown during path resolution.

Comment thread src/Tasks/SignFile.cs
Comment on lines 23 to +25
[SupportedOSPlatform("windows")]
public sealed class SignFile : Task
[MSBuildMultiThreadableTask]
public sealed class SignFile : Task, IMultiThreadableTask
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking SignFile as [MSBuildMultiThreadableTask] / IMultiThreadableTask looks unsafe because it calls SecurityUtilities.SignFile(...), which internally depends on process-global state (e.g., falls back to Directory.GetCurrentDirectory() when locating signtool and uses SetDllDirectoryW during manifest signing). In a multithreaded build this can lead to nondeterministic tool resolution or interference between concurrently executing tasks. Consider removing the multithreadable attribute/interface until SecurityUtilities can take/use TaskEnvironment (or otherwise avoid process-global current directory / DLL directory changes) for tool discovery and process execution.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valid concern

Comment thread src/Tasks/SignFile.cs
@JanProvaznik JanProvaznik marked this pull request as draft February 18, 2026 11:42
… in SecurityUtilities

The SignFile task migration to IMultiThreadableTask was unsafe because
SecurityUtilities.SignFile() transitively depended on process-global state:

1. GetPathToTool() used Directory.GetCurrentDirectory() as fallback for
   signtool.exe discovery — meaningless in multithreaded mode where each
   task has its own ProjectDirectory.

2. SignPEFileInternal() created ProcessStartInfo without setting
   WorkingDirectory — inheriting the process CWD.

3. SetDllDirectoryW() during manifest signing on .NET Core modified
   process-wide DLL search path — concurrent tasks would race.

Fix: instead of duplicating methods, refactor existing ones to accept a
projectDirectory parameter (null = use process CWD for back-compat):

- GetPathToTool(resources) delegates to GetPathToTool(resources, fallbackDir)
- SignPEFileInternal uses fallbackDir ?? Directory.GetCurrentDirectory()
  for both tool discovery and ProcessStartInfo.WorkingDirectory
- SetDllDirectoryW calls wrapped in lock(s_manifestSigningLock)
- SignFile task passes TaskEnvironment.ProjectDirectory.Value
- No default parameter values anywhere — all calls are explicit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JanProvaznik JanProvaznik marked this pull request as ready for review February 20, 2026 13:37
@JanProvaznik JanProvaznik marked this pull request as draft March 16, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants