Add PackageValidator tool for NuGet package inspection and validation#4407
Draft
paulmedynski wants to merge 3 commits into
Draft
Add PackageValidator tool for NuGet package inspection and validation#4407paulmedynski wants to merge 3 commits into
paulmedynski wants to merge 3 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new standalone maintainer CLI (tools/PackageValidator) to inspect .nupkg/.snupkg artifacts (versions, signing, dependencies, and symbols) using metadata-only inspection, plus a dedicated xUnit test project for the tool.
Changes:
- Added a
net10.0PackageValidator console app with JSON/human output and--fail-ongating. - Implemented inspection/validation components: nuspec/dependencies parsing, managed/native binary inspection, symbol-package resolution, and a rules engine emitting categorized findings.
- Added xUnit tests covering version range evaluation, expectation parsing, symbol/signing/version validations, and helper utilities.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/PackageValidator/PackageValidator.csproj | Defines the standalone CLI tool project and its package dependencies. |
| tools/PackageValidator/Directory.Build.props | Isolates build settings for the tool directory (central package management). |
| tools/PackageValidator/Directory.Packages.props | Centralizes tool package versions (System.CommandLine). |
| tools/PackageValidator/Program.cs | CLI surface: args/options, help augmentation, run orchestration, gating/exit codes. |
| tools/PackageValidator/PackageInspector.cs | Reads .nuspec, signature entry, and enumerates DLLs in a .nupkg. |
| tools/PackageValidator/AssemblyInspector.cs | Metadata-only inspection of managed assemblies + native fallback handling. |
| tools/PackageValidator/BinaryClassifier.cs | Categorizes binaries (implementation/reference/satellite/native/other) from paths. |
| tools/PackageValidator/Models.Common.cs | Shared model types (enums/findings/dependency models/native info). |
| tools/PackageValidator/Models.Report.cs | Report models for run/package/binary/symbol-package output. |
| tools/PackageValidator/Validator.cs | Intrinsic rule engine + cross-package dependency consistency checks. |
| tools/PackageValidator/VersionExpectations.cs | Parses/holds --expect-* inputs and resolves wildcard/id overrides. |
| tools/PackageValidator/VersionRange.cs | Minimal NuGet version-range evaluator used for dependency checks. |
| tools/PackageValidator/SymbolResolver.cs | Matches .snupkg PDBs to assemblies by GUID and verifies checksums. |
| tools/PackageValidator/PortablePdb.cs | Portable PDB GUID extraction + checksum verification support. |
| tools/PackageValidator/NativeVersionReader.cs | Reads native PE architecture and Win32 version-resource info (temp-file based). |
| tools/PackageValidator/HumanReporter.cs | Human-readable console renderer for reports/findings/summary. |
| tools/PackageValidator/Json.cs | Source-generated JSON serialization context/options for machine output. |
| tools/PackageValidator/tests/PackageValidator.Tests.csproj | Test project wiring (net10.0) and tool project reference. |
| tools/PackageValidator/tests/Directory.Build.props | Isolates build settings for the test directory. |
| tools/PackageValidator/tests/Directory.Packages.props | Centralizes test package versions (xUnit, test SDK). |
| tools/PackageValidator/tests/VersionRangeTests.cs | Unit tests for version-range evaluation behavior. |
| tools/PackageValidator/tests/VersionExpectationsTests.cs | Unit tests for expectation parsing and validation integration. |
| tools/PackageValidator/tests/ValidatorTests.cs | Unit tests for rules engine findings and batch dependency validation. |
| tools/PackageValidator/tests/BinaryClassifierTests.cs | Unit tests for binary path classification. |
| tools/PackageValidator/tests/AssemblyInspectorTests.cs | Unit tests for PKT computation and portable PDB helpers. |
A standalone .NET 10 CLI under tools/PackageValidator that inspects one or more .nupkg files and validates their versions, signing, and symbols using metadata-only reading (no assembly loading), so it works cross-platform and on assemblies built for TFMs the host does not run. Capabilities: - Package id/version, dependency groups, and NuGet signature from the .nuspec. - Per-assembly AssemblyVersion/FileVersion/InformationalVersion, culture, public key token, strong-name signing status, and target framework. - Native binary Win32 version info and architecture. - Binary classification (implementation/reference/satellite/native) so symbol coverage is judged only over implementation assemblies. - Sibling .snupkg symbol matching by debug GUID with portable-PDB checksum verification, embedded-symbol detection, and orphan/mismatch reporting. - Intrinsic validation rules emitting severity-tagged findings, plus optional --expect-package/file/assembly-version assertions for inter-package version-match validation. - Batch/directory input, JSON or human output, --fail-on exit-code gating, and a free-form Notes help section. - xUnit test project (41 tests). Exploratory maintainer tooling; isolated from the main build (its own Directory.Build.props / Directory.Packages.props).
Layout: - Move sources to src/ and tests to test/ to match the PackageCompatibility tool; share one Directory.*.props; add global.json (xUnit v3 / MTP). - Convert the test project to xUnit v3 (Exe + IsTestProject, xunit.v3). - Wire BuildPackageValidator(Test)/TestPackageValidator (and the PackageCompatibility equivalents) into build.proj; BuildTools builds tests. Review feedback (PR #4407): - NativeVersionReader: handle UnauthorizedAccessException/SecurityException on temp-file staging and cleanup instead of letting them escape. - Validator: flag a missing AssemblyFileVersion against --expect-file-version (and assembly version) instead of silently passing. - VersionRange: follow SemVer 2.0 precedence (prerelease ordering, ignore build metadata) instead of dropping the prerelease/metadata suffix. - PortablePdb: dispose the BinaryReader/MemoryStream in FindPdbIdOffset. Adds regression tests (48 total, all passing).
7a8dc98 to
eebc229
Compare
- Add XML docs, intent comments, and arrange/act/assert structure to the PackageValidator test classes, methods, and helpers. - Add a /tools/ solution folder to Microsoft.Data.SqlClient.slnx containing the PackageCompatibility and PackageValidator src and test projects.
Comment on lines
+35
to
+46
| range = range.Trim(); | ||
|
|
||
| // A bare version (no brackets) is a minimum-inclusive bound in NuGet semantics. | ||
| if (range[0] != '[' && range[0] != '(') | ||
| { | ||
| SemanticVersion? min = Parse(range); | ||
| return min is null ? null : Compare(target, min) >= 0; | ||
| } | ||
|
|
||
| bool minInclusive = range[0] == '['; | ||
| bool maxInclusive = range[^1] == ']'; | ||
| string inner = range[1..^1]; |
Comment on lines
+123
to
+127
| string[] parts = release.Split('.', StringSplitOptions.RemoveEmptyEntries); | ||
| if (parts.Length == 0) | ||
| { | ||
| return null; | ||
| } |
Comment on lines
+32
to
+37
| // Implementation assemblies live under lib/ or runtimes/<rid>/lib/. | ||
| if (normalized.StartsWith("lib/", StringComparison.OrdinalIgnoreCase) | ||
| || normalized.Contains("/lib/", StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| return BinaryKind.Implementation; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a standalone .NET 10 CLI under
tools/PackageValidatorthat inspects one or more.nupkgfiles and validates their versions, signing, and symbols using metadata-only reading (no assembly loading). This keeps it cross-platform and able to read assemblies built for TFMs the host does not run (e.g.net462from a Linux host).This is exploratory maintainer tooling that mirrors the
PackageCompatibilitytool layout (src/+test/, its ownDirectory.*.props/global.json) and is isolated from the main driver build.Capabilities
.nuspec.AssemblyVersion/FileVersion/InformationalVersion, culture, public key token, strong-name signing status, and target framework..snupkgsymbol matching by debug GUID with portable-PDB checksum verification, embedded-symbol detection, and orphan/mismatch reporting.--expect-package/file/assembly-versionassertions for inter-package version-match validation.--fail-onexit-code gating, and a free-form Notes help section.Command-line arguments
<paths>....nupkgfiles, or directories scanned recursively for.nupkgfiles.--json--no-snupkg.snupkgsymbol packages (embedded symbols are still evaluated).--fail-on <value>--expect-package-version [id=]VALUEVALUE. Repeatable.--expect-file-version [id=]VALUEVALUE. Repeatable.--expect-assembly-version [id=]VALUEVALUE. Repeatable.--fail-onaccepts a severity (error,warning,info), the tokenany, or a finding category:version-inconsistency,missing-symbols,symbol-mismatch,symbol-checksum-mismatch,symbol-orphan,symbol-duplicate,delay-signed,unsigned,package-unsigned,dependency-inconsistency,unexpected-package-version,unexpected-file-version,unexpected-assembly-version.--expect-*values are eitherVALUE(applies to every package in the run) orid=VALUE(applies only to the package whose id isid). A specific id overrides a bareVALUE(wildcard), and because the options repeat, a family-wide expectation can coexist with a per-package override — for example, assert one family file version while lettingMicrosoft.SqlServer.Serverdiffer. A missing version counts as a mismatch, so the assertion never silently passes.Exit codes:
0pass ·1runtime error ·2--fail-ongate tripped.These same details are printed in a free-form Notes section appended to
--help.Example output
Inspect a single package (human-readable)
PackageValidator Microsoft.Data.SqlClient.7.1.0-preview1.nupkgMachine-readable output (
--json)Per-binary object (symbols matched and checksum-verified against the sibling
.snupkg):{ "path": "lib/net8.0/Microsoft.Data.SqlClient.dll", "kind": "Implementation", "isManagedAssembly": true, "assemblyName": "Microsoft.Data.SqlClient", "assemblyVersion": "7.0.0.0", "fileVersion": "7.1.0.26176", "informationalVersion": "7.1.0-preview1+9c72dc0b4e8eed7fe6e83684e86800f9b4ac0b57", "targetFramework": ".NETCoreApp,Version=v8.0", "culture": "neutral", "publicKeyToken": "23ec7fc2d6eaa4a5", "signingStatus": "Signed", "debugId": "546ac289-357a-4bf7-8c42-dabbcb8963ec", "pdbChecksums": [ "SHA256:89c26a547a35f7fbcc42dabbcb8963ec78d7cd167992f9de97b134e4db63bc73" ], "hasEmbeddedSymbols": false, "hasSymbols": true, "hasSymbolPackageSymbols": true, "symbolPackageSymbolsMatch": true, "symbolPackageVerifiedByChecksum": true, "symbolPackageFile": "lib/net8.0/Microsoft.Data.SqlClient.pdb" }Gate a directory against expected versions (
--expect-*+--fail-on)Assert the family file version uniformly (with a per-package override for
Microsoft.SqlServer.Server) and fail on any error:On a build that stamps the file-version revision on only some family packages, the gate trips (exit code
2):On a build that stamps the revision uniformly, the same assertion passes (exit code
0).Tests
tools/PackageValidator/test— 48 tests covering public-key-token computation, binary classification, SemVer 2.0 range evaluation (including prerelease ordering), the rules engine, and expected-version assertions.build.proj:BuildPackageValidator/BuildPackageValidatorTest/TestPackageValidator(and the matchingPackageCompatibilitytest targets);BuildToolsnow builds the tools and their test projects.Notes
build.proj(BuildTools); no changes to the main driver or CI pipelines