Skip to content

Harden OpenTelemetry release readiness: docs, tests, spec-compliant env parsing - #10865

Merged
Amaury Levé (Evangelink) merged 6 commits into
mainfrom
dev/amauryleve/otel-release-hardening
Aug 31, 2026
Merged

Harden OpenTelemetry release readiness: docs, tests, spec-compliant env parsing#10865
Amaury Levé (Evangelink) merged 6 commits into
mainfrom
dev/amauryleve/otel-release-hardening

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Summary

Release-hardening for the OpenTelemetry extension ahead of MSTest 4.4 / MTP 2.4, focused on the two turnkey helpers that were promoted from [TPEXP] to stable API this cycle — AddTestingPlatformResource and AddOpenTelemetryProviderFromEnvironment — plus the sensitive-data documentation gap raised in #8411.

No breaking public API changes: the stable helpers stay stable, and the one behavioral change is a spec-compliance fix on how OTEL_SDK_DISABLED is parsed.

Motivation

  • [MTP Diagnostic Analysis] OpenTelemetry exports raw file paths, stdout/stderr, and stack traces without filtering #8411 asked that the docs "call out exactly which fields are exported." On current main the result pipeline already truncates large string attributes (TESTINGPLATFORM_OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT, 8 KB default), gates stdout/stderr behind TESTINGPLATFORM_OTEL_CAPTURE_TEST_OUTPUT, and strips credentials from vcs.repository.url.full. The genuine remaining gap was accurate documentation of what is exported — nothing leaves the process without an exporter you configure, so documentation (not a default behavior change) is the right release posture.
  • The two newly-stable helpers had no direct unit tests.

Changes

  • Docs (PACKAGE.md) — added a "Data exported and controlling sensitive values" table enumerating each attribute that can carry sensitive data (source/artifact file paths, stdout/stderr, exception message/stack trace, test.metadata.*, resource provenance) and the exact control for each. Truncation is described precisely: only captured output, result explanation and exception text are truncated; file/artifact/metadata values are exported verbatim.
  • Testability refactor — extracted AddOpenTelemetryProviderFromEnvironment's OTEL_* decision into a pure internal ResolveEnvironmentConfiguration seam so it is unit-testable without a live builder. Behavior-preserving; new internal members declared in InternalAPI.Unshipped.txt.
  • OTEL_SDK_DISABLED spec compliance — the turnkey helper now honors the OpenTelemetry boolean convention: only a case-insensitive "true" disables the SDK, so "1" and other spellings leave it enabled. The CI-marker parsing in TestingPlatformResourceDetector (GitHub/Azure/GitLab/Jenkins) is intentionally left untouched.
  • Tests (new)TestingPlatformResourceDetectorTests (service name, host/OS/arch/runtime attributes, CI provider detection + precedence, credential stripping) and OpenTelemetryProviderExtensionsTests (AddTestingPlatformResource resource build, null guards, the full env-decision matrix, and an observable end-to-end trace through the real OpenTelemetry SDK asserting exported span tags + resource attributes).

Testing

  • .\build.cmd -c Debug -projects Microsoft.Testing.Extensions.UnitTests.csproj — clean (0 warnings, 0 errors) across all TFMs.
  • 29/29 OpenTelemetry unit tests pass on net9.0 and net472.

Closes #8411.

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

Address the remaining OpenTelemetry release-readiness work for the newly
stable AddTestingPlatformResource and AddOpenTelemetryProviderFromEnvironment
helpers.

- Document exactly which OpenTelemetry fields can carry sensitive data
  (source/artifact file paths, stdout/stderr, exception message/stack trace)
  and how to control each, addressing issue #8411's documentation ask.
- Extract the OTEL_* environment-variable decision of
  AddOpenTelemetryProviderFromEnvironment into a pure internal
  ResolveEnvironmentConfiguration seam so it is unit-testable without a live
  builder. No public API or behavior change.
- Add direct tests for TestingPlatformResourceDetector (service name, host/OS/
  runtime attributes, CI provider detection, credential stripping), for
  AddTestingPlatformResource, for the env-driven decision, and an observable
  end-to-end trace through the real OpenTelemetry SDK.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…D parsing

Code-review follow-up on the OpenTelemetry release-hardening change.

- PACKAGE.md: fix the "Data exported" table. Drop the incorrect claim that
  every string attribute is truncated (file, artifact and metadata values are
  emitted verbatim); correct the legacy metadata prefix to
  test.metadataProperty.*; list the legacy exception twins
  (test.result.exception.type/message/stacktrace) and the span status
  description; and note the resource attributes (host, OS, CI provenance) that
  ride on every span.
- AddOpenTelemetryProviderFromEnvironment: make OTEL_SDK_DISABLED honor the
  OpenTelemetry boolean convention — only a case-insensitive "true" disables
  the SDK, so "1" and other spellings leave it enabled. CI-marker parsing in
  TestingPlatformResourceDetector is intentionally left untouched.
- Tests: assert the spec-compliant OTEL_SDK_DISABLED behavior (case-insensitive
  "true" disables; "1"/"yes"/"false"/"" do not).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 29, 2026 09:17
The sensitive-data section rewrite left PACKAGE.md without a final newline,
tripping markdownlint MD047. Append exactly one trailing newline.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@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.

Expert Review — 22-Dimension Verdict

# Dimension Verdict Notes
1 Algorithmic Correctness ✅ LGTM IsTrue behavioral change (dropping "1") is intentional spec-compliance, well-documented in comments. ResolveEnvironmentConfiguration logic faithfully preserves existing decision tree.
2 Threading & Concurrency ✅ LGTM EnvironmentConfiguration is a readonly struct (immutable). End-to-end test exporter properly locks the shared _activities list.
3 Security & IPC Contract Safety ✅ LGTM No new file operations, deserialization, or command-line handling. The PACKAGE.md docs accurately describe credential stripping and sensitive-data controls.
4 Public API & Binary Compat ✅ LGTM No public API changes. New internal members (ResolveEnvironmentConfiguration, EnvironmentConfiguration) correctly declared in InternalAPI.Unshipped.txt. Struct uses get (not init).
5 Performance & Allocations ✅ LGTM The refactoring introduces one struct allocation per call (stack-allocated). No regressions.
6 Cross-TFM Compatibility ✅ LGTM StringComparison.OrdinalIgnoreCase and string.Trim() are available on all target TFMs (netstandard2.0+).
7 Resource & IDisposable Mgmt ✅ LGTM End-to-end test properly disposes TracerProvider, OpenTelemetryPlatformService, and OpenTelemetryResultHandler with using.
8 Defensive Coding ✅ LGTM Null guard on builder preserved. Func<string, string?> delegate cleanly abstracts env access.
9 Localization & Resources N/A No .resx or .xlf changes.
10 Test Isolation ✅ LGTM [DoNotParallelize] on both test classes. TestingPlatformResourceDetectorTests.WithEnvironment saves and restores every observed env var in a finally block. OpenTelemetryProviderExtensionsTests env-decision tests use a pure Func<string, string?> — no env mutation.
11 Assertion Quality ✅ LGTM Tests use MSTest assertions (matching BannedSymbols.txt which bans AwesomeAssertions). Assertions are specific (AreEqual, IsTrue, IsFalse, ContainsKey).
12 Flakiness Patterns ✅ LGTM No timing-dependent assertions. End-to-end test uses GUID-prefixed activity names to avoid ambient pollution.
13 Test Completeness ✅ LGTM Comprehensive coverage: SDK-disabled (case variations, non-true values), endpoint-only, exporter-only, none-override, comma-separated exporters, delegate-without-exporter, null-guard, CI providers (GitHub/Azure/GitLab/Jenkins), precedence, credential stripping, resource attributes, end-to-end trace.
14 Data-Driven Test Coverage ✅ LGTM [DataRow] used for OTEL_SDK_DISABLED case variations including edge cases (" true ", "1", "yes", "false", "").
15 Code Structure ✅ LGTM Clean extraction into pure function + value type. No deep nesting.
16 Naming & Conventions ✅ LGTM Test method names are descriptive and follow Method_Condition_Outcome pattern.
17 Documentation Accuracy ✅ LGTM XML doc comments on all new internal members. PACKAGE.md table is accurate and detailed. Comment on IsTrue clearly explains the spec difference vs. CI-marker parsing.
18 Analyzer & Code Fix Quality N/A No analyzer changes.
19 IPC Wire Compatibility N/A No serialization/wire changes.
20 Build Infrastructure N/A No build/dependency changes.
21 Scope & PR Discipline ✅ LGTM Coherent scope: docs + testability refactor + spec fix + tests for the same feature area. References #8411.
22 PowerShell Scripting N/A No .ps1 changes.

Findings

1 NITPACKAGE.md lost its trailing newline (SA1518 violation). See inline comment.

Overall this is a well-structured PR: the testability refactor is clean, the behavioral change (IsTrue spec compliance) is well-documented, the test coverage is thorough with proper isolation, and the sensitive-data documentation fills a genuine gap.

Comment thread src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/PACKAGE.md Outdated

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.

Copilot review overview

Review tier: Balanced
Findings: 2 Medium severity · 1 Low severity

New issues introduced by this change (3)
Severity Finding
Medium severity src/​Platform/​Microsoft.Testing.Extensions.OpenTelemetry/​OpenTelemetryProviderExtensions.csTrim() makes &quot; true &quot; disable the SDK, but the OpenTelemetry Boolean specification allows only…
Medium severity src/​Platform/​Microsoft.Testing.Extensions.OpenTelemetry/​OpenTelemetryProviderExtensions.cs — There is still no positive test of AddOpenTelemetryProviderFromEnvironment itself: the resolver…
Low severity src/​Platform/​Microsoft.Testing.Extensions.OpenTelemetry/​PACKAGE.md — This sensitive-data inventory is incomplete. test.case.name, test.case.id/test.case.parent.id
What changed in this PR

Hardens the OpenTelemetry extension for release through documentation, test coverage, and environment parsing changes.

Changes:

  • Documents potentially sensitive telemetry fields and controls.
  • Extracts environment configuration resolution for testing.
  • Adds resource detection and OpenTelemetry pipeline tests.
File Description
PACKAGE.md Documents exported sensitive values.
OpenTelemetryProviderExtensions.cs Refactors environment parsing and SDK-disable handling.
InternalAPI.Unshipped.txt Tracks new internal APIs.
OpenTelemetryProviderExtensionsTests.cs Tests configuration and tracing behavior.
TestingPlatformResourceDetectorTests.cs Tests resource and CI attributes.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/PACKAGE.md
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Expert test review — PR #10865

GradeTestMutationNotesHow to improve
F (0–59) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
StripsCredentialsFromRepositoryUrl
0/1 killed Input literal "******dev.azure.com/..." has no ://, so the strip logic is a no-op and never exercises the claimed behavior. Use a real credentialed URL, e.g. (dev.azure.com/redacted)
B (80–89) new OpenTelemetryProviderExtensionsTests.
EndToEnd_
InstrumentationAndResource_
ExportSpanWithSemanticConventionTagsAndResource
5/6 killed Strong end-to-end coverage of tags/resource, but body mixes tag and resource assertions in one long (~50-line) test. Split resource-attribute assertions into a second focused test using the same exporter/provider setup.
A (90–100) new OpenTelemetryProviderExtensionsTests.
AddTestingPlatformResource_
WithNullBuilder_
Throws
1/1 killed Exact exception type asserted on the public null-guard contract.
A (90–100) new OpenTelemetryProviderExtensionsTests.
AddTestingPlatformResource_
AttachesPlatformAttributesToTheBuiltResource
4/4 killed Verifies presence, non-blank service name, machine name, and runtime name — covers the resource-building contract.
A (90–100) new OpenTelemetryProviderExtensionsTests.
AddOpenTelemetryProviderFromEnvironment_
WithNullBuilder_
Throws
1/1 killed Exact exception type asserted on the public null-guard contract.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WhenSdkDisabled_
RegistersNothingEvenWithEndpointAndDelegates
5/5 killed Asserts all five configuration flags land false despite endpoint + delegates present, matching the documented override contract.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
TreatsCaseInsensitiveTrueSdkDisabledAsDisabled
1/1 killed Data-driven case coverage (true/True/TRUE/tRuE/" true ") for the disabled parsing branch.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
TreatsNonTrueSdkDisabledValuesAsEnabled
3/3 killed Pairs non-"true" spellings with an endpoint, proving the SDK stayed enabled rather than merely not crashing.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithNoExporterAndNoDelegates_
RegistersNothing
1/1 killed Covers the no-signal baseline case for ShouldRegisterProvider.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithOtlpEndpointOnly_
EnablesBothProvidersAndExporters
4/4 killed Verifies all four flags flip together from endpoint-only input.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithTracesExporterOtlpOnly_
EnablesOnlyTracing
4/4 killed Confirms tracing-only isolation — metrics flags stay false, protecting the per-signal split.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithExporterNone_
OverridesAnEndpoint
2/2 killed Proves an explicit "none" wins over a configured endpoint.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithCommaSeparatedExporterList_
StillEnablesOtlp
1/1 killed Verifies the comma-separated exporter list parsing correctly matches "otlp" among multiple values.
A (90–100) new OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithTracingDelegateButNoExporter_
ConfiguresProviderWithoutOtlp
3/3 killed Confirms a caller delegate alone triggers provider configuration without turning on OTLP.
A (90–100) new TestingPlatformResourceDetectorTests.
GetServiceName_
WithOtelServiceNameSet_
ReturnsThatValue
1/1 killed Directly checks the environment-override branch of the public contract.
A (90–100) new TestingPlatformResourceDetectorTests.
GetServiceName_
WithBlankOtelServiceName_
FallsBackToEntryAssemblyName
1/1 killed Confirms whitespace-only override is treated as unset, matching the blank-string fallback contract.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
AlwaysIncludeProcessAndHostAttributes
5/5 killed Checks five distinct process/host attribute values against real runtime data.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
MapsHostArchitectureToOpenTelemetrySpelling
1/1 killed Mirrors the production switch to compute the expected value, catching any mapping drift.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
WithNoCiProvider_
DoesNotEmitCiProviderName
1/1 killed Verifies the negative case — no CI attribute is emitted absent any provider marker.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForGitHubActions_
EmitsGitHubCiAttributes
7/7 killed Exercises every mapped attribute for the GitHub Actions branch.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForAzurePipelines_
EmitsAzureCiAttributes
7/7 killed Exercises every mapped attribute for the Azure Pipelines branch with a clean (non-credentialed) URL.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForGitLab_
EmitsGitLabCiAttributes
7/7 killed Exercises every mapped attribute for the GitLab branch.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForJenkins_
EmitsJenkinsCiAttributes
6/6 killed Exercises every mapped attribute for the Jenkins branch, distinguished from others by its non-boolean gating variable.
A (90–100) new TestingPlatformResourceDetectorTests.
GetResourceAttributes_
WhenGitHubAndAzureBothSet_
PrefersGitHubActions
1/1 killed Directly protects the provider-precedence ordering in GetCiAttributes.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Suggestions on the Files
changed tab can be applied with one click. Re-run with
/review-tests.

🤖 Automated content by GitHub Copilot. Generated by the Test Reviewer on PR (on open / sync) workflow. · auto · 171.8 AIC · ⌖ 1.43 AIC · ⊞ 16.9K · [◷]( · )

@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 Test Reviewer on PR (on open / sync) workflow. · auto · 171.8 AIC · ⌖ 1.43 AIC · ⊞ 16.9K ·

@Evangelink Amaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Aug 31, 2026
@Evangelink
Amaury Levé (Evangelink) enabled auto-merge (squash) August 31, 2026 07:24
…uller docs

Follow-up on review feedback for the OpenTelemetry release-hardening PR.

- OTEL_SDK_DISABLED parsing no longer trims: only an exact case-insensitive
  "true" disables the SDK, per the OpenTelemetry boolean convention. A
  whitespace-padded " true " now correctly leaves the SDK enabled, and the
  test that asserted the old behavior was moved to the enabled-values test.
- Add a positive test of the public AddOpenTelemetryProviderFromEnvironment
  that drives a real TestApplicationBuilder, triggers the registered factory
  via TelemetryManager.BuildOTelProvider, and asserts the provider is built
  and the caller delegate runs; plus a no-op assertion when the SDK is
  disabled.
- PACKAGE.md: extend the exported-data inventory with test.case.name,
  test.case.id / test.case.parent.id (and legacy twins) and
  test.step.<id>.description, all exported verbatim.

Build clean; 30/30 OpenTelemetry unit tests pass on net9.0 and net472;
markdownlint reports 0 errors.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 31, 2026 07:48
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Expert test review — PR #10865

Scope: 2 new test files (25 test methods) covering OpenTelemetryProviderExtensions and TestingPlatformResourceDetector. All prior review findings from copilot-pull-request-reviewer / github-actions / github-code-quality on this PR (missing positive test for AddOpenTelemetryProviderFromEnvironment, OTEL_SDK_DISABLED trim/spec-compliance, PACKAGE.md sensitive-data inventory, CA2000/dispose ownership, StyleCop newline) are already resolved as of commit 115daefc8, so this pass focuses on the remaining test-quality gaps.

GradeTestMutationNotesHow to improve
B (80–89) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithCommaSeparatedExporterList_
StillEnablesOtlp
2/3 killed Only asserts UseOtlpTracing; a mutant that flips configureTracingProvider independently would survive. Also assert configuration.ConfigureTracingProvider is true.
B (80–89) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
WhenGitHubAndAzureBothSet_
PrefersGitHubActions
1/2 killed Only checks cicd.provider.name; doesn't verify Azure-specific attributes (e.g. cicd.pipeline.name from BUILD_DEFINITIONNAME) are absent. Assert !attributes.ContainsKey("vcs.repository.url.full") to prove the Azure branch didn't also run.
A (90–100) new OpenTelemetryProviderExtensionsTests.
AddOpenTelemetryProviderFromEnvironment_
RegistersProviderWithDelegateAndSkipsWhenSdkDisabled
4/4 killed Positive test exercising the real public entry point end-to-end (builder → factory → delegate invocation), plus the disabled no-op path.
A (90–100) new OpenTelemetryProviderExtensionsTests.
EndToEnd_InstrumentationAndResource_
ExportSpanWithSemanticConventionTagsAndResource
6/6 killed Real SDK pipeline exercised; asserts semantic-convention tags and resource attributes; correctly scoped via unique name prefix and [DoNotParallelize].
A (90–100) new remaining 21 tests across both files (null-arg guards, SDK-disabled precedence, exporter-selection matrix, CI-provider attribute mapping, credential stripping, architecture mapping) killed on relevant mutants Each test targets one clear behavior with precise value assertions and correct environment isolation via snapshot/restore helpers.

No new inline suggestions posted this run — the two B-grade gaps above are completeness nits (an extra assertion), not correctness bugs, and every previously-flagged actionable finding on this PR is already fixed in the current head.

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

🤖 Automated content by GitHub Copilot. Generated by the Test Reviewer on PR (on open / sync) workflow. · auto · 149.8 AIC · ⌖ 0.803 AIC · ⊞ 16.9K · [◷]( · )

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.

Copilot review overview

Review tier: Balanced
Findings: None

Issues resolved since last review (3)
Severity Finding
Low severity src/​Platform/​Microsoft.Testing.Extensions.OpenTelemetry/​PACKAGE.md — This sensitive-data inventory is incomplete. test.case.name, test.case.id/test.case.parent.idView resolved comment
Medium severity src/​Platform/​Microsoft.Testing.Extensions.OpenTelemetry/​OpenTelemetryProviderExtensions.cs — There is still no positive test of AddOpenTelemetryProviderFromEnvironment itself: the resolver… View resolved comment
Medium severity src/​Platform/​Microsoft.Testing.Extensions.OpenTelemetry/​OpenTelemetryProviderExtensions.csTrim() makes &quot; true &quot; disable the SDK, but the OpenTelemetry Boolean specification allows only… View resolved comment
Suppressed comments (1)

src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/OpenTelemetryProviderExtensions.cs:164

  • The resolver tests do not execute this metrics callback, and the only public-path test passes a tracing delegate with both exporters set to none. Consequently, replacing ConfigureMetricsProvider or UseOtlpMetrics here with the tracing flags would leave the entire suite green. Add a metrics-only public-path test that verifies the platform meter/exporter is actually wired, not just that the resolver returns the expected booleans.
                if (configuration.ConfigureMetricsProvider)

Two non-blocking test-review suggestions:
- ResolveEnvironmentConfiguration_WithCommaSeparatedExporterList_StillEnablesOtlp
  now also asserts ConfigureTracingProvider, so a mutant flipping it
  independently of UseOtlpTracing is killed.
- GetResourceAttributes_WhenGitHubAndAzureBothSet_PrefersGitHubActions now sets
  an Azure-only marker (BUILD_REPOSITORY_URI) and asserts vcs.repository.url.full
  is absent, proving the GitHub branch wins and the Azure branch never runs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 31, 2026 08:02
@github-actions

This comment has been minimized.

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.

Copilot review overview

Review tier: Balanced
Findings: None

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/PACKAGE.md:75

  • This row says the whole group is truncated, but exception.type, error.type, and the legacy exception type are passed through verbatim; only the explanation, message, status description, and stack-trace values use _options.Truncate (OpenTelemetryResultHandler.ResultHandling.cs:49-89). Distinguish those behaviors so the sensitive-data guidance is accurate.
| `code.stacktrace`, `test.case.result.explanation` (`test.result.explanation`), the `exception` span event (`exception.type` / `exception.message` / `exception.stacktrace`), the span status description, and the legacy `test.result.exception.type` / `test.result.exception.message` / `test.result.exception.stacktrace` | Exception message and stack-trace text. | Truncated to `TESTINGPLATFORM_OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT`. Disable the legacy twins with `TESTINGPLATFORM_OTEL_EMIT_LEGACY_ATTRIBUTES=0`. |

src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/OpenTelemetryProviderExtensions.cs:205

  • The enabled metrics-delegate branch is not tested: every resolver test passes hasMetricsDelegate: false, except disabled cases that return before this expression. Removing hasMetricsDelegate here would therefore go undetected, and the public-helper test likewise verifies only the tracing delegate. Add an enabled metrics-delegate case that expects metrics configuration without OTLP.
        bool configureMetricsProvider = useOtlpMetrics || hasMetricsDelegate;

src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/PACKAGE.md:77

  • The PR promises an exact inventory, but this resource row names only a subset. AddTestingPlatformResource also emits service.*, host.arch, os.type, process.*, and test.assembly.name, while CI detection emits specific pipeline/task/repository keys. Enumerate these fields so users can assess all provenance exported by the stable helper.
| Resource `vcs.repository.url.full`, plus the other resource attributes (`host.name`, `os.description`, and in CI the `cicd.*` / `vcs.*` pipeline, branch and commit — see *Resource attributes* above) | The machine, OS and CI provenance attached to every span and metric point. | User-info credentials in the repository URL (`https://user:token@host/...`) are stripped before export. |

Per the parallel-safety audit: OpenTelemetryProviderExtensionsTests carried a
class-level [DoNotParallelize], but only two methods touch process-global
state - the one that mutates real environment variables and the end-to-end
test that stands up a real TracerProvider on the shared platform
ActivitySource. Move the attribute onto just those two methods so the nine
pure ResolveEnvironmentConfiguration tests and the null-guard tests rejoin the
parallel set.

The env-reading AddTestingPlatformResource test can safely parallelize because
every environment-variable *mutator* in this assembly
(AddOpenTelemetryProviderFromEnvironment_..., AzureFoundryChatClientProviderTests,
TestingPlatformResourceDetectorTests) is [DoNotParallelize] and runs in the
serial tail, so it never overlaps the parallel reader. TestingPlatformResource-
DetectorTests is intentionally kept on class-level [DoNotParallelize] rather
than migrated to [ResourceLock(EnvironmentVariables)]: moving its mutations
into the parallel set would require the now-parallel reader to take the same
lock, a broader coupling not worth introducing here.

Verified: build clean; full Microsoft.Testing.Extensions.UnitTests assembly
green across three consecutive runs (1522 passed, 7 skipped); OTel tests pass
on net9.0 and net472.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 31, 2026 08:17
@github-actions

Copy link
Copy Markdown
Contributor

🧵 Parallel-safety audit — PR #10865

Parallelization — assembly audited:

Test assembly Scope Workers Analyzer coverage
Microsoft.Testing.Extensions.UnitTests MethodLevel ([assembly: Parallelize(Scope = MethodLevel, Workers = 0)] in Program.cs) CPU count coverable once the parallel-safety analyzers ship (attribute-based opt-in)

Findings: A (global-state) 0 · B (paths) 0 · C (declaration) 0 · D (over-serialization) 0 — by severity: Critical 0 · High 0 · Warning 0 · Info 0.

This PR's only change is scoping [DoNotParallelize] from class-level down to the two stateful methods in OpenTelemetryProviderExtensionsTests (AddOpenTelemetryProviderFromEnvironment_RegistersProviderWithDelegateAndSkipsWhenSdkDisabled, which calls the real Environment.SetEnvironmentVariable, and EndToEnd_InstrumentationAndResource_ExportSpanWithSemanticConventionTagsAndResource, which stands up a real TracerProvider on the shared platform ActivitySource). I verified the reconciliation is sound:

  • Every one of the nine now-parallel ResolveEnvironmentConfiguration_* tests routes through a pure Func<string, string?> fake (the local Env(...) helper) rather than Environment.GetEnvironmentVariable, so they never touch process-global state — correctly left out of [DoNotParallelize].
  • The two remaining tests that do mutate real environment variables or the shared ActivitySource/TracerProvider (category A) both correctly carry the moved [DoNotParallelize].
  • Cross-checked against sibling [DoNotParallelize]-tagged classes in the same assembly (TestingPlatformResourceDetectorTests, AzureFoundryChatClientProviderTests) — no key/attribute near-misses, and the PR's own commit message documents that every environment-variable mutator in the assembly stays in the serial tail so it can't overlap the now-parallel readers.
  • TestingPlatformResourceDetectorTests (unchanged by this PR) correctly keeps its class-level [DoNotParallelize], since every method in it mutates the same observed environment-variable set.

No unsafe call sites, near-misses, or coverage gaps found in the changed lines. This is a clean readiness/throughput improvement with no correctness risk introduced.

Advisory only — heuristic, non-blocking. Re-run with /parallel-audit. This audit answers "is it parallel-safe?"; for testability, smells, or flakiness see the detect-static-dependencies / test-smell-detection / test-anti-patterns analyses.

🤖 Automated content by GitHub Copilot. Generated by the Parallel-safety audit on PR (on open / sync) workflow. · auto · 88.3 AIC · ⌖ 0.973 AIC · ⊞ 24.8K · [◷]( · )

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Expert test review — PR #10865

All 25 new test methods across the two new files (OpenTelemetryProviderExtensionsTests.cs, TestingPlatformResourceDetectorTests.cs) were reviewed. This PR has already been through two review cycles (copilot-pull-request-reviewer, github-actions, github-code-quality) and every prior finding was either fixed or is a confirmed false positive (notably the GetResourceAttributes_StripsCredentialsFromRepositoryUrl "no ://" flag — the actual literal contains a real user:token@ credentialed URL; the tool preview redacts it visually, but the test passes and genuinely exercises RemoveUrlUserInfo). No new high-confidence, actionable findings were identified in this pass, so no inline suggestions are posted.

GradeTestMutationNotesHow to improve
B (80–89) new OpenTelemetryProviderExtensionsTests.
AddOpenTelemetryProviderFromEnvironment_
RegistersProviderWithDelegateAndSkipsWhenSdkDisabled
2/2 killed Verifies two distinct scenarios (enabled+delegate, then SDK-disabled) in one method body. Split into two focused test methods, one per scenario, for clearer failure attribution.
B (80–89) new OpenTelemetryProviderExtensionsTests.
EndToEnd_
InstrumentationAndResource_
ExportSpanWithSemanticConventionTagsAndResource
6/6 killed Body runs ~55 lines; single scenario but exercises many facets (tags, resource, handler lifecycle) at once. Extract span-tag assertions and resource-attribute assertions into two smaller end-to-end tests.
A (90–100) OpenTelemetryProviderExtensionsTests.
AddTestingPlatformResource_
WithNullBuilder_
Throws
1/1 killed Focused null-guard exception test.
A (90–100) OpenTelemetryProviderExtensionsTests.
AddTestingPlatformResource_
AttachesPlatformAttributesToTheBuiltResource
4/4 killed Asserts service.name presence, host.name equality and hard-coded runtime name.
A (90–100) OpenTelemetryProviderExtensionsTests.
AddOpenTelemetryProviderFromEnvironment_
WithNullBuilder_
Throws
1/1 killed Focused null-guard exception test.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WhenSdkDisabled_
RegistersNothingEvenWithEndpointAndDelegates
5/5 killed Confirms SDK-disabled wins over endpoint and both delegates, with all five flags asserted.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
TreatsCaseInsensitiveTrueSdkDisabledAsDisabled
1/1 killed Data-driven case-insensitivity check for the disabling spelling.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
TreatsNonTrueSdkDisabledValuesAsEnabled
2/2 killed Pairs each non-"true" spelling with an endpoint to prove the SDK stayed enabled, not just default-false.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithNoExporterAndNoDelegates_
RegistersNothing
1/1 killed Baseline no-op case, correctly asserted.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithOtlpEndpointOnly_
EnablesBothProvidersAndExporters
4/4 killed All four resulting flags checked for the endpoint-only opt-in path.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithTracesExporterOtlpOnly_
EnablesOnlyTracing
4/4 killed Confirms tracing-only opt-in and metrics staying off.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithExporterNone_
OverridesAnEndpoint
2/2 killed Proves explicit "none" beats a configured endpoint.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithCommaSeparatedExporterList_
StillEnablesOtlp
2/2 killed Verifies the comma-separated exporter list parsing branch.
A (90–100) OpenTelemetryProviderExtensionsTests.
ResolveEnvironmentConfiguration_
WithTracingDelegateButNoExporter_
ConfiguresProviderWithoutOtlp
3/3 killed Confirms a caller delegate alone still configures the provider without OTLP.
A (90–100) TestingPlatformResourceDetectorTests.
GetServiceName_
WithOtelServiceNameSet_
ReturnsThatValue
1/1 killed Direct override check with environment reset via helper.
A (90–100) TestingPlatformResourceDetectorTests.
GetServiceName_
WithBlankOtelServiceName_
FallsBackToEntryAssemblyName
1/1 killed Correctly asserts fallback to the real entry-assembly name rather than a canned value.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
AlwaysIncludeProcessAndHostAttributes
6/6 killed Covers host.name, runtime name/description, os.description and two key-existence checks.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
MapsHostArchitectureToOpenTelemetrySpelling
1/1 killed Computes expected value independently via the same switch shape rather than hard-coding one arch.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
WithNoCiProvider_
DoesNotEmitCiProviderName
1/1 killed Negative check that no CI provider key leaks when all CI env vars are cleared.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForGitHubActions_
EmitsGitHubCiAttributes
7/7 killed All seven GitHub-mapped attributes asserted individually.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForAzurePipelines_
EmitsAzureCiAttributes
7/7 killed All seven Azure-mapped attributes asserted individually.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForGitLab_
EmitsGitLabCiAttributes
7/7 killed All seven GitLab-mapped attributes asserted individually.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
ForJenkins_
EmitsJenkinsCiAttributes
6/6 killed All six Jenkins-mapped attributes asserted individually.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
StripsCredentialsFromRepositoryUrl
1/1 killed Real credentialed URL input (confirmed against source, not the redacted preview); verifies userinfo stripping precisely.
A (90–100) TestingPlatformResourceDetectorTests.
GetResourceAttributes_
WhenGitHubAndAzureBothSet_
PrefersGitHubActions
2/2 killed Uses absence of an Azure-only marker attribute to prove precedence, not just presence of GitHub attributes.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Suggestions on the Files
changed tab can be applied with one click. Re-run with
/review-tests.

🤖 Automated content by GitHub Copilot. Generated by the Test Reviewer on PR (on open / sync) workflow. · auto · 134.1 AIC · ⌖ 1.32 AIC · ⊞ 16.9K · [◷]( · )

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.

Copilot review overview

Review tier: Balanced
Findings: None

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/PACKAGE.md:77

  • This catch-all still does not disclose the exact resource fields exported, which is the documentation gap this PR closes. AddService also emits service.name, service.version, and a generated service.instance.id, while the detector emits host.arch, os.type, process.pid, runtime fields, and test.assembly.name; these can expose application or execution-environment details but are absent here. Please enumerate the concrete resource attribute names and state that only URL user-info is stripped.
| Resource `vcs.repository.url.full`, plus the other resource attributes (`host.name`, `os.description`, and in CI the `cicd.*` / `vcs.*` pipeline, branch and commit — see *Resource attributes* above) | The machine, OS and CI provenance attached to every span and metric point. | User-info credentials in the repository URL (`https://user:token@host/...`) are stripped before export. |

test/UnitTests/Microsoft.Testing.Extensions.UnitTests/OpenTelemetryProviderExtensionsTests.cs:242

  • The metrics-only branches remain untested. The endpoint test reaches metrics through the shared fallback, while every hasMetricsDelegate: true case returns early because the SDK is disabled; therefore regressions that ignore OTEL_METRICS_EXPORTER or hasMetricsDelegate would pass. Add symmetric metrics-exporter and metrics-delegate cases.
    public void ResolveEnvironmentConfiguration_WithTracingDelegateButNoExporter_ConfiguresProviderWithoutOtlp()
    {
        EnvironmentConfiguration configuration = OpenTelemetryProviderExtensions.ResolveEnvironmentConfiguration(
            Env([]),
            hasTracingDelegate: true,
            hasMetricsDelegate: false);

        Assert.IsTrue(configuration.ConfigureTracingProvider);
        Assert.IsFalse(configuration.UseOtlpTracing);
        Assert.IsFalse(configuration.ConfigureMetricsProvider);
    }

@Evangelink
Amaury Levé (Evangelink) merged commit 272749e into main Aug 31, 2026
32 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/otel-release-hardening branch August 31, 2026 10:00
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.

[MTP Diagnostic Analysis] OpenTelemetry exports raw file paths, stdout/stderr, and stack traces without filtering

3 participants