Skip to content

Allow IPC named pipe directory to be overridden on Unix#9846

Open
Evangelink wants to merge 8 commits into
mainfrom
dev/amauryleve/improved-train
Open

Allow IPC named pipe directory to be overridden on Unix#9846
Evangelink wants to merge 8 commits into
mainfrom
dev/amauryleve/improved-train

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes #9821

Problem

On Unix, the Microsoft.Testing.Platform IPC named pipe is backed by a Unix domain socket file on disk, and NamedPipeServer.GetPipeName hardcoded that file to live under /tmp. In sandboxed environments that block /tmp (the reporter hit this with Claude Code on macOS), dotnet test fails and the only workaround is to open up the whole /tmp folder to the sandbox.

Change

On Unix, the pipe directory is now resolved with this precedence:

  1. TESTINGPLATFORM_PIPE_DIRECTORY — new explicit opt-in override (guaranteed escape hatch).
  2. Path.GetTempPath() — honors TMPDIR on Unix, which is the standard POSIX knob and is usually a per-user, sandbox-allowed directory (so many setups are fixed with no extra configuration).
  3. /tmp — preserves the previous default when neither is set.

Windows is unchanged (it uses the kernel pipe namespace, not the filesystem).

Guards

Because the location is now user-influenced:

  • Path length (always): Unix domain socket paths are capped by sun_path (~104 bytes on macOS, ~108 on Linux). We validate against the smaller 103-byte budget and fail with an actionable, localized message. This matters most for a deep TMPDIR on macOS (/var/folders/…/T/ + a GUID).
  • Writability (override only): when the explicit override is used we create the directory if needed and probe write access with a short-lived file, failing fast with a clear message instead of a cryptic socket bind error. TMPDIR//tmp are OS-managed and skipped to avoid extra I/O and a behavior change on every pipe creation.

Compatibility notes

The design deliberately keeps the existing invariant: the process that creates the pipe resolves the directory locally and hands the fully-resolved path to the peer (via env var, command-line arg, or the dotnet-test handshake); peers use that path verbatim and never recompute it. As a result:

  • No protocol version bump is needed — a TESTINGPLATFORM_PIPE_DIRECTORY/TMPDIR difference between two processes is harmless because only the creator's resolution is ever used.
  • The logic is self-contained in NamedPipeServer.cs, which dotnet/sdk vendors, so the dotnet test entrypoint picks this up on the next vendor sync with no separate SDK design work.

An XML-doc note on GetPipeName captures this invariant so the directory is never turned into a shared convention that both sides derive independently (which would couple SDK and test-host versions).

Localization

Two new strings added to PlatformResources.resx with hand-maintained accessors in the !IS_CORE_MTP block; .xlf regenerated for all 14 languages via UpdateXlf.

Tests

Added 8 MSTest cases in IPCTests.cs covering override precedence, TMPDIR fallback, /tmp fallback, and the length guard (within/exceeds). Resolution and length-check logic was split into internal seams so they are testable on Windows CI, where the Unix branch of GetPipeName never runs. Full IPCTests class passes locally (net8.0).

On Unix the IPC named pipe is backed by a Unix domain socket file that was
always created under /tmp. Sandboxed environments (e.g. Claude Code on macOS)
that block /tmp cannot run `dotnet test`. Resolve the directory as:

  1. TESTINGPLATFORM_PIPE_DIRECTORY (explicit opt-in override)
  2. Path.GetTempPath() (honors TMPDIR on Unix)
  3. /tmp (previous default)

Add a sun_path length guard (always) and a writability probe (override only),
both failing with actionable, localized messages. Keep the logic self-contained
in NamedPipeServer.cs so it flows into dotnet/sdk on the next vendor sync, and
document the "creator resolves, full path is passed, peers never recompute"
invariant so the directory never becomes a shared convention that couples SDK
and test-host versions.

Fixes #9821

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ae434eba-3cad-4c61-a1da-ef252ae87f48
Copilot AI review requested due to automatic review settings July 11, 2026 12:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds configurable Unix IPC socket directories for sandbox compatibility while preserving Windows behavior.

Changes:

  • Adds override/temp-directory resolution and safety guards.
  • Adds localized diagnostics and environment-variable support.
  • Adds unit tests and regenerated localization files.
Show a summary per file
File Description
test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs Tests directory resolution and path-length limits.
src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs Implements Unix pipe-directory selection and validation.
src/Platform/Microsoft.Testing.Platform/Helpers/EnvironmentVariableConstants.cs Defines the pipe-directory override variable.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.cs Adds resource accessors.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx Adds localized diagnostic source strings.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf Updates Czech localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf Updates German localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf Updates Spanish localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf Updates French localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf Updates Italian localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf Updates Japanese localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf Updates Korean localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf Updates Polish localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf Updates Brazilian Portuguese localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf Updates Russian localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf Updates Turkish localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf Updates Simplified Chinese localization.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf Updates Traditional Chinese localization.

Review details

  • Files reviewed: 18/18 changed files
  • Comments generated: 6
  • Review effort level: Medium

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
@github-actions

This comment has been minimized.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Overall: Solid, well-motivated change. The design is sound — the single-resolver invariant (creator resolves, peer uses verbatim) is the right architecture and the XML doc captures it well. The guards (path length + writability probe) are practical and the error messages are actionable.

Findings by severity

Severity Dimension Finding
MAJOR Test Completeness (#13) EnsureDirectoryIsWritable has no unit tests — it has meaningful branching worth covering
MODERATE Data-Driven (#14) Missing " " (whitespace) [DataRow] for tempPath in the /tmp fallback test
NIT Algorithmic (#1) The /tmp fallback in ResolvePipeDirectory is effectively dead code in production (only reachable via the testable overload) — worth a clarifying comment
NIT Security (#3) Consider Path.GetFullPath() normalization on the explicit override for path hygiene

Dimensions checked and clean

✅ Threading & Concurrency — no shared mutable state; all new methods are static/pure or local I/O
✅ Public API — class is internal [Embedded]; constants are public on an internal class (effectively internal); no PublicAPI.Unshipped.txt update needed
✅ IPC Wire Compatibility — no wire format changes; directory resolution is local-only
✅ Performance — GetPipeName is not a hot path; probe I/O only on explicit override
✅ Resource/IDisposable — probe file uses using + File.Delete
✅ Localization — .resx entries added correctly; .xlf regenerated; accessors placed in the !IS_CORE_MTP block (correct — these are needed by extension projects that link the file)
✅ Naming & Conventions — test names describe scenario and outcome
✅ Scope & PR Discipline — focused change, no unrelated refactoring
✅ Build Infrastructure — no dependency changes

No blocking issues found.

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs
Comment thread test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

The build failed with 14 errors (deduplicated to 7 unique issues) in Microsoft.Testing.Platform.csproj, all in two files. Downstream projects (AzureFoundry, AzureDevOpsReport) failed as cascading dependencies.

Root Cause 1: Banned API usage (RS0030) — 3 issues

In NamedPipeServer.cs, the PR uses APIs that are banned in this project:

Line Banned API Required Replacement
213 Environment.GetEnvironmentVariable(...) Use IEnvironment abstraction
220, 226 string.IsNullOrWhiteSpace(...) Use RoslynString.IsNullOrWhiteSpace(...)

Fix for line 213: The private ResolvePipeDirectory() overload should use the _environment field or accept an IEnvironment parameter instead of calling Environment directly.

Fix for lines 220 & 226: Replace string.IsNullOrWhiteSpace(...) with RoslynString.IsNullOrWhiteSpace(...) in ResolvePipeDirectory(string?, string?).

Root Cause 2: Undeclared public API (RS0051) — 4 issues

New internal/public symbols must be declared in PublicAPI.Unshipped.txt:

Line Symbol
NamedPipeServer.cs:31 const MaxUnixDomainSocketPathLengthInBytes = 103
NamedPipeServer.cs:218 static ResolvePipeDirectory(string?, string?)
NamedPipeServer.cs:261 static EnsurePathLengthWithinLimit(string!)
EnvironmentVariableConstants.cs:19 const TESTINGPLATFORM_PIPE_DIRECTORY

Fix: Either add these symbols to PublicAPI/PublicAPI.Unshipped.txt, or — if they aren't meant to be public API — consider whether internal visibility with [InternalsVisibleTo] is sufficient (the internal keyword is already used, so this is likely an [InternalsVisibleTo]-exposed symbol that the analyzer still tracks).

Summary of required changes

  1. Replace Environment.GetEnvironmentVariable on line 213 with the IEnvironment abstraction
  2. Replace string.IsNullOrWhiteSpaceRoslynString.IsNullOrWhiteSpace on lines 220 and 226
  3. Add the 4 new symbols to PublicAPI/PublicAPI.Unshipped.txt

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 61.6 AIC · ⌖ 4.9 AIC · ⊞ 7.3K · [◷]( · )

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 61.6 AIC · ⌖ 4.9 AIC · ⊞ 7.3K ·

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs Outdated
…ests

- Replace banned System.Environment / string.IsNullOrWhiteSpace with
  SystemEnvironment / RoslynString to fix RS0030.
- Declare the four new internal symbols in InternalAPI.Unshipped.txt (RS0016).
- Normalize an explicit override with Path.GetFullPath so a relative
  TESTINGPLATFORM_PIPE_DIRECTORY resolves to a rooted socket path and honors
  the "full path handed to peers" invariant (also collapses '..').
- Clarify that the '/tmp' fallback is only reachable via the test overload.
- Add unit tests for EnsureDirectoryIsWritable (create-missing happy path and
  non-creatable error path) and a whitespace DataRow for the tempPath fallback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ae434eba-3cad-4c61-a1da-ef252ae87f48
Copilot AI review requested due to automatic review settings July 11, 2026 12:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 19/19 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
@github-actions

This comment has been minimized.

…ed-train

# Conflicts:
#	src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txt
Copilot AI review requested due to automatic review settings July 11, 2026 12:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 19/19 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
@github-actions

This comment has been minimized.

NamedPipeServer.cs is glob-compiled (IPC\*.cs) into HangDump, Retry,
TrxReport, and both MSBuild projects, so the earlier fixes must build there:

- Read TESTINGPLATFORM_PIPE_DIRECTORY via System.Environment with a scoped
  RS0030 suppression instead of `new SystemEnvironment()`. Only the MSBuild
  task project links SystemEnvironment.cs; the other shared-source consumers
  do not, so the wrapper would not compile there. Reading directly also keeps
  the file self-contained for the dotnet/sdk vendor copy.
- Normalize the selected directory with Path.GetFullPath in every precedence
  branch (not just the explicit override): Path.GetTempPath() can surface a
  relative TMPDIR, which NamedPipeServerStream rejects and which would violate
  the fully-resolved-path invariant. The write probe stays override-only.
- Declare the new EnvironmentVariableConstants / NamedPipeServer /
  PlatformResources members in the HangDump, Retry, TrxReport, and
  Extensions.MSBuild InternalAPI.Unshipped baselines (they compile these shared
  files and keep their baselines in sync with core), so RS0016 stays green.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ae434eba-3cad-4c61-a1da-ef252ae87f48
Copilot AI review requested due to automatic review settings July 11, 2026 13:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 23/23 changed files
  • Comments generated: 2
  • Review effort level: Medium

…consumers

The earlier baseline update missed some projects that link the shared files:

- EnvironmentVariableConstants.cs is also linked into HotReload -> add the new
  TESTINGPLATFORM_PIPE_DIRECTORY const there.
- PlatformResources.cs (the !IS_CORE_MTP accessors) is linked into nine
  API-tracked extensions -> add the two new NamedPipe* accessor signatures to
  HtmlReport, CtrfReport, JUnitReport, VideoRecorder, and CrashDump (the other
  four were done previously).

Verified each affected project builds clean with
-warnaserror:RS0016,RS0017,RS0025,RS0037.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ae434eba-3cad-4c61-a1da-ef252ae87f48
Copilot AI review requested due to automatic review settings July 11, 2026 13:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 29/29 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment thread src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx Outdated
@github-actions

This comment has been minimized.

@Evangelink Evangelink added the state/needs-review Awaiting review from the team. label Jul 11, 2026
Copilot AI review requested due to automatic review settings July 11, 2026 20:49
…cedence

The two diagnostics suggested setting TMPDIR, but TESTINGPLATFORM_PIPE_DIRECTORY
always wins, so that advice is misleading when the override is the cause:

- Writability error is emitted only for the explicit override, so drop the
  TMPDIR mention and tell users to fix the override or unset it to fall back to
  the default temp directory.
- Path-too-long can come from any source, so clarify that TMPDIR only helps
  when the override is not set.

Regenerated the XLF files for all 14 languages.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ae434eba-3cad-4c61-a1da-ef252ae87f48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 29/29 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread test/UnitTests/Microsoft.Testing.Platform.UnitTests/IPC/IPCTests.cs
Copilot AI review requested due to automatic review settings July 11, 2026 20:52
@Evangelink Evangelink enabled auto-merge (squash) July 11, 2026 20:52
…unting

The existing path-length tests used only ASCII, so a buggy character-count
implementation would still pass. Add a test with 40 '好' (3-byte) chars plus a
prefix: 45 characters (under the 103 limit) but 125 UTF-8 bytes (over it),
proving the guard measures sun_path bytes rather than characters.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ae434eba-3cad-4c61-a1da-ef252ae87f48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 29/29 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 11, 2026 20:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 29/29 changed files
  • Comments generated: 1
  • Review effort level: Medium

// rooted names as socket paths (it rejects separators in non-rooted names). The invariant also requires
// handing peers a fully-resolved path. This additionally collapses any '..' segments. '/tmp' and an
// already-absolute temp path are unchanged.
directory = Path.GetFullPath(directory);
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9846

GradeTestNotes
C (70–79) new IPCTests.
EnsurePathLengthWithinLimit_
WhenWithinLimit_
DoesNotThrow
No explicit assertions; relies on implicit "does not throw" for a void guard — consider adding a comment to document the intent, e.g. // Assert: no exception thrown.
A (90–100) new IPCTests.
EnsureDirectoryIsWritable_
WhenDirectoryCannotBeCreated_
ThrowsInvalidOperationException
Clever setup blocks dir creation deterministically; exact ThrowsExactly(InvalidOperationException). No issues found.
A (90–100) new IPCTests.
EnsureDirectoryIsWritable_
WhenDirectoryMissingButCreatable_
CreatesItAndDoesNotThrow
Uses Path.GetTempPath() to avoid hard-coded paths; try/finally ensures cleanup; Directory.Exists asserts the meaningful side effect.
A (90–100) new IPCTests.
EnsurePathLengthWithinLimit_
WhenExceedsLimit_
Throws
Exact exception type; short and focused. No issues found.
A (90–100) new IPCTests.
EnsurePathLengthWithinLimit_
WhenMultibyteExceedsByteLimitButNotCharLimit_
Throws
Setup assertions confirm test invariants (char count vs byte count); comment clearly explains the Unicode edge case; exact exception type.
A (90–100) new IPCTests.
ResolvePipeDirectory_
WhenNeitherOverrideNorTempPathAvailable_
FallsBackToTmp
Data-driven (null/empty/whitespace); two meaningful assertions on both tuple fields. No issues found.
A (90–100) new IPCTests.
ResolvePipeDirectory_
WhenOverrideMissing_
FallsBackToTempPath
Data-driven (null/empty/whitespace); AreEqual + IsFalse cover both returned fields. No issues found.
A (90–100) new IPCTests.
ResolvePipeDirectory_
WhenOverrideProvided_
UsesOverrideAsExplicit
Clear AAA; AreEqual + IsTrue verify both fields of the returned tuple. No issues found.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 57.5 AIC · ⌖ 5.17 AIC · ⊞ 9.6K · [◷]( · )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-review Awaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow IPC named pipe directory to be overridden via environment variable

3 participants