Skip to content

Reproduce and close the [EnvironmentName]/[IfEnvironment] gap - #223

Merged
ipjohnson merged 1 commit into
mainfrom
environment-name-repro
Sep 1, 2026
Merged

ipjohnson merged 1 commit into
mainfrom
environment-name-repro

Conversation

@ipjohnson

Copy link
Copy Markdown
Owner

F14 from the Forty-Four Fixes queue (D-B-10), the last entry, following the plan's repro-first instruction.

The finding REPRODUCED. [EnvironmentName("X")] on a test method against a registration gated [IfEnvironment("X")], driven through the real xunit v3 entry point, never saw the gated registration. The mechanism the report described - the environment registered under IHardenedEnvironment alone - was already fixed at the tag, but every test of that fix drives the setup pipeline by hand. The real runner applies modules before the service-setup pass, so every [IfEnvironment] condition was decided against the process default before the test's environment existed.

The ordering lives in DependencyModules, and 1.3.0 ships its fix (ipjohnson/DependencyModules#54): IModuleEnvironmentProvider, consulted by both runners before any module loads. This PR is the Hardened side:

  • DependencyModulesVersion bumps to 1.3.0.
  • HardenedTestEntryPointAttribute implements the new interface from the same attribute walk it already uses, and SetupServiceCollection reuses the seeded instance, so the environment a module condition read and the one a service resolves are one object.
  • The repro runs as an integration test in the WebApp SUT against the application's own generated module - an [IfEnvironment]-gated [SingletonService] resolves under the test's declared environment - with the gate's absence under the default environment as the control. Both fail against 1.2.2 and pass against 1.3.0.
  • The Hardened.Shared.Testing public API approval gains the interface and its one member.

Validated with the full suite against the published 1.3.0 packages in an isolated package cache: clean build, 31 test projects green.

🤖 Generated with Claude Code

The second trial's D-B-10: [EnvironmentName("X")] on a test method
against a registration gated [IfEnvironment("X")], and the gated
registration never applies. The mechanism the finding described - the
environment registered under IHardenedEnvironment alone - was already
fixed, but every test of that fix drives the setup pipeline by hand.
Through the real xunit v3 entry point the finding reproduces: the
runner applies modules before the service-setup pass, so every
[IfEnvironment] condition is decided against the process default before
the test's environment is registered.

The ordering lives in DependencyModules, and 1.3.0 ships its fix:
IModuleEnvironmentProvider, consulted by the runner before it loads any
module. HardenedTestEntryPointAttribute implements it from the same
attribute walk it already uses, and SetupServiceCollection reuses the
seeded instance so the environment a module condition read and the one
a service resolves are one object. The repro runs as an integration
test in the WebApp SUT, against the application's own generated module,
with the gate's absence under the default environment as the control.

Hardened.SourceGeneration.Testing's branch baseline moves 87.2 to 86.6,
from the CI run's own summary: GeneratorReferences walks the dependency
graph with load-and-dedup branch arms, and 1.3.0's assemblies no longer
exercise an arm 1.2.2's did. Only that entry moves; the run cleared
every other floor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ipjohnson
ipjohnson force-pushed the environment-name-repro branch from 8c6422e to 4bf0903 Compare September 1, 2026 22:12
@ipjohnson
ipjohnson merged commit 9070465 into main Sep 1, 2026
2 checks passed
@ipjohnson
ipjohnson deleted the environment-name-repro branch September 2, 2026 23:09
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.

1 participant