Skip to content

Detect hidden PowerShell Gallery versions before publish#180

Merged
PrzemyslawKlys merged 1 commit intomainfrom
codex/hidden-gallery-version-detection
Mar 11, 2026
Merged

Detect hidden PowerShell Gallery versions before publish#180
PrzemyslawKlys merged 1 commit intomainfrom
codex/hidden-gallery-version-detection

Conversation

@PrzemyslawKlys
Copy link
Member

Summary

  • query the raw PowerShell Gallery OData feed so hidden/unlisted versions are still treated as existing
  • use that feed in module auto-version stepping and repository version preflight checks
  • add regression coverage for the exact case where PSGallery only shows 2.0.27 through Find-PSResource but still has hidden 3.0.0 in the package feed

Validation

  • dotnet test .\PowerForge.Tests\PowerForge.Tests.csproj -c Release --filter "ModuleVersionStepperTests|ModulePublisherRepositoryVersionTests|ModulePipelineRegressionParityTests|ModulePublisherRequiredModulesTests"
  • pwsh .\Module\Build\Build-Module.ps1 -NoSign

@PrzemyslawKlys PrzemyslawKlys added .NET Pull requests that update .NET code bug Something isn't working codex labels Mar 11, 2026
@claude
Copy link

claude bot commented Mar 11, 2026

PR Review - Detect hidden PowerShell Gallery versions before publish. Overall this is a well-motivated fix. Full review details below.

@PrzemyslawKlys PrzemyslawKlys merged commit c3b0995 into main Mar 11, 2026
6 checks passed
@PrzemyslawKlys PrzemyslawKlys deleted the codex/hidden-gallery-version-detection branch March 11, 2026 11:43
@claude
Copy link

claude bot commented Mar 11, 2026

PR Review: Detect hidden PowerShell Gallery versions before publish

This is a well-motivated fix for a real problem. Querying the raw OData feed is the right approach to detect unlisted versions invisible to Find-PSResource. Here are my observations:


Bugs / Correctness

1. Brittle unlisted-version detection via magic date string

In PowerShellGalleryVersionFeedClient.cs, the constant UnlistedPublishedMarker = "1900-01-01T00:00:00" relies on PSGallery undocumented sentinel-date convention. If the feed returns the date with fractional seconds (1900-01-01T00:00:00.0000000) or a timezone offset, the OrdinalIgnoreCase string comparison fails silently and the package is treated as listed - defeating the purpose. Consider parsing the date and checking dt.Year < 1901 instead.

2. Subtle usedUnlisted tracking

In TryResolveCurrentVersionFromPowerShellGalleryFeed, usedUnlisted reflects whether the final winning version was unlisted, not whether any unlisted version was seen. Logic is correct but subtle; a brief inline comment would help.


Code Quality

3. Synchronous HTTP via .GetAwaiter().GetResult()

PowerShellGalleryVersionFeedClient calls GetAsync().GetAwaiter().GetResult() in a loop. Deadlock risk with a synchronization context. Acceptable for build-tool CLI but worth documenting.

4. Significant test infrastructure duplication

FakePowerShellGalleryFeedHandler, StubPowerShellRunner, VisibleRepositoryItem, and Encode are copy-pasted verbatim between ModulePublisherRepositoryVersionTests.cs and ModuleVersionStepperTests.cs. Extract into a shared GalleryTestFixtures or TestHelpers class before they diverge.

5. Visibility widened for test access

EnsureVersionIsGreaterThanRepository was changed from private to internal solely for test access. Using [assembly: InternalsVisibleTo("PowerForge.Tests")] would make the intent explicit.

6. Unused _logger field

PowerShellGalleryVersionFeedClient stores _logger but never calls it. Wire it up or remove it until needed.


Missing Test Coverage

  • Direct unit tests for PowerShellGalleryVersionFeedClient: pagination boundary, malformed XML, HTTP error (non-200), cancellation/timeout, includePrerelease:false filtering.
  • Fallback behavior: inject a feed error, assert code falls back to the tool-based approach correctly.
  • Non-PSGallery repository: assert the feed client is NOT called for custom repos.
  • Page limit guard: the 100-page InvalidOperationException has no corresponding test.

Minor Nits

  • In ParseEntries, resolvedVersionText is assigned directly from versionText! with no transformation. The intermediate variable adds no clarity.
  • The OData single quotes in FindPackagesByIdTemplate are correct OData syntax; a comment noting this prevents accidental cleanup from breaking it.

Summary

Area Status
Core logic Sound approach
Unlisted detection Fragile magic-string date comparison
HTTP handling Sync-over-async, acceptable for build-tool CLI
Test duplication Significant copy-paste between test files
Test coverage Happy path only; error and edge cases missing
Security HTTPS, proper URL encoding, no XXE risk

The feature is valuable and the regression test covers the primary scenario. The two most important items to address: (1) fix the brittle string comparison for unlisted detection, (2) deduplicate test infrastructure.

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

Labels

bug Something isn't working codex .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant