Skip to content

feat(manifest): socket manifest dotnet + centralized config-name globs (REA-627, REA-628)#1404

Draft
Jeppe Fredsgaard Blaabjerg (jfblaa) wants to merge 1 commit into
v1.xfrom
jfblaa/rea-627-socket-manifest-dotnet-compute-netnuget-sbom-reachability
Draft

feat(manifest): socket manifest dotnet + centralized config-name globs (REA-627, REA-628)#1404
Jeppe Fredsgaard Blaabjerg (jfblaa) wants to merge 1 commit into
v1.xfrom
jfblaa/rea-627-socket-manifest-dotnet-compute-netnuget-sbom-reachability

Conversation

@jfblaa

Copy link
Copy Markdown
Contributor

Closes REA-627. Closes REA-628.

Warning

Draft — do not merge until coana PR (REA-626) is released and the pinned coana version is bumped in this PR. The reachability sidecar emits nuget-tagged entries that the currently-released coana rejects (strict schema); a polyglot .NET+JVM --reach scan would break until coana ships REA-626. The SBOM-only path (no --reach) is coana-independent.

What

Brings .NET/NuGet to the Socket facts pipeline, at parity with the JVM tools (the .NET analog of REA-613). Previously nuget was only a package-scoring ecosystem — no manifest generation, no auto-detection, no reachability; the only path was a manual socket manifest cdxgen -t dotnet.

socket manifest dotnet (REA-627)

  • New command + auto-manifest detection (top-level .sln/.slnx/.csproj/.fsproj/.vbproj) + setup-wizard entry; socket.json defaults.manifest.dotnet.*.
  • Bundled C# tool (scripts/dotnet-tool/): one MSBuild session — evaluate → in-process restore → read project.assets.json via NuGet.ProjectModel — emitting the shared records TSV.
    • Ships no NuGet/MSBuild runtime assemblies: compile-low/run-high against the locator-selected SDK (net6 floor, RollForward LatestMajor), so it works across installed SDKs and avoids the ref/def assembly clash that breaks multi-SDK hosts.
    • Restore forces TreatWarningsAsErrors=false so NU19xx security-advisory warnings don't abort the run.
    • packages.config supported (flat pinned closure + developmentDependency→dev + HintPath DLLs; downloads missing pinned artifacts via the project's configured feeds/credential providers).
    • Fail-closed: emits failure/unscannable records that raise the CLI exit code; every emitted artifact path is guaranteed to exist.
  • Flags: --target-frameworks / --exclude-target-frameworks (TFM globs; RID targets match under their base TFM); --dotnet-opts (MSBuild -p: props applied to the whole session).
  • Reachability sidecar emits nuget-tagged ResolvedComponents (consumed by coana REA-626).
  • Resolution summary reports scanned target frameworks across N projects (per-project attribution under --verbose).
  • CI leg builds the C# tool; provenance build bundles it like the Maven extension jar.

Centralized config-name glob compilation (REA-628)

  • Compile --include-configs/--exclude-configs globs → anchored regex sources once in config-glob.mts; the gradle/sbt/maven scripts and the dotnet tool all consume the compiled patterns. Removes the per-language globToRegex (Groovy/Scala/Java) and adds a cross-language vector test suite. Rides in this PR because the .NET tool is a fourth consumer of the shared patterns.

Testing

Unit tests (config-glob vectors, dotnet records→assemble, detection, auto-manifest branch, command snapshots); accuracy sweep vs. native-restore ground truth across 17 real .NET repos (~99.6% avg recall, exact real-package versions, packages.config 100%). pnpm check clean.

Follow-ups before un-drafting

  • coana REA-626 merged + released
  • bump pinned coana version in this PR
  • CHANGELOG entry

…s (REA-627, REA-628)

Bring .NET/NuGet to the Socket facts pipeline, at parity with the JVM tools.

socket manifest dotnet (REA-627):
- New command + auto-manifest detection (top-level .sln/.slnx/.csproj/.fsproj/
  .vbproj) and setup-wizard entry; socket.json defaults.manifest.dotnet.*.
- Bundled C# tool (socket-facts-dotnet): one MSBuild session — evaluate,
  in-process restore, read project.assets.json via NuGet.ProjectModel —
  emitting the shared records TSV. Ships no NuGet/MSBuild runtime assemblies
  (compile-low/run-high against the locator-selected SDK; net6 floor,
  RollForward LatestMajor), so it works across installed SDK versions. Restore
  forces TreatWarningsAsErrors=false so NU19xx security advisories don't abort
  the run. packages.config supported (flat closure + HintPath DLLs, with
  pinned-artifact download via the project's configured feeds). Fail-closed:
  emits failure records that raise the CLI exit code; every emitted artifact
  path is guaranteed to exist.
- --target-frameworks / --exclude-target-frameworks (TFM globs; RID targets
  match under their base TFM); --dotnet-opts (MSBuild -p: props applied to the
  whole session). Reachability sidecar emits nuget-tagged ResolvedComponents.
- Resolution summary reports scanned target frameworks across N projects, with
  per-project attribution under --verbose.

Centralized config-name glob compilation (REA-628):
- Compile --include-configs/--exclude-configs globs to anchored regex sources
  once in config-glob.mts; the gradle/sbt/maven scripts and the dotnet tool
  consume the compiled patterns. Removes the per-language globToRegex
  (Groovy/Scala/Java) and adds a cross-language vector test suite.

Gated on coana REA-626 (nuget sidecar consumer): the coana version pin is
bumped and this is un-drafted once coana releases.
@socket-security

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn Critical
Critical CVE: NuGet Client Security Feature Bypass Vulnerability in nuget nuget.packaging

CVE: GHSA-68w7-72jg-6qpp NuGet Client Security Feature Bypass Vulnerability (CRITICAL)

Affected versions: = 6.7.0, 6.8.0; >= 4.6.0 < 5.11.6; >= 6.0.0 < 6.0.6; >= 6.3.0 < 6.3.4; >= 6.4.0 < 6.4.3; >= 6.6.0 < 6.6.2; >= 6.7.0 < 6.7.1; >= 6.8.0 < 6.8.1

Patched version: 6.0.6

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/nuget.packaging@6.0.0

ℹ Read more on: This package | This alert | What is a critical CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore nuget/nuget.packaging@6.0.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@socket-security-staging

Copy link
Copy Markdown

Caution

Review the following alerts detected in dependencies.

According to your organization's Security Policy, you must resolve all "Block" alerts before proceeding. It is recommended to resolve "Warn" alerts too. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Block Critical
Critical CVE: NuGet Client Security Feature Bypass Vulnerability in nuget nuget.packaging

CVE: GHSA-68w7-72jg-6qpp NuGet Client Security Feature Bypass Vulnerability (CRITICAL)

Affected versions: = 6.7.0, 6.8.0; >= 4.6.0 < 5.11.6; >= 6.0.0 < 6.0.6; >= 6.3.0 < 6.3.4; >= 6.4.0 < 6.4.3; >= 6.6.0 < 6.6.2; >= 6.7.0 < 6.7.1; >= 6.8.0 < 6.8.1

Patched version: 6.0.6

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/nuget.packaging@6.0.0

ℹ Read more on: This package | This alert | What is a critical CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity-Staging ignore nuget/nuget.packaging@6.0.0. You can also ignore all packages with @SocketSecurity-Staging ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: NuGet Client Remote Code Execution Vulnerability in nuget nuget.common

CVE: GHSA-6qmf-mmc7-6c2p NuGet Client Remote Code Execution Vulnerability (HIGH)

Affected versions: = 6.5.0, 6.6.0; >= 6.0.0 < 6.0.5; >= 6.2.0 < 6.2.4; >= 6.3.0 < 6.3.3; >= 6.4.0 < 6.4.2; >= 6.5.0 < 6.5.1; >= 6.6.0 < 6.6.1; >= 4.6.0 < 5.11.5

Patched version: 6.0.5

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/nuget.common@6.0.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity-Staging ignore nuget/nuget.common@6.0.0. You can also ignore all packages with @SocketSecurity-Staging ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: NuGet Client Remote Code Execution Vulnerability in nuget nuget.protocol

CVE: GHSA-6qmf-mmc7-6c2p NuGet Client Remote Code Execution Vulnerability (HIGH)

Affected versions: = 6.5.0, 6.6.0; >= 6.0.0 < 6.0.5; >= 6.2.0 < 6.2.4; >= 6.3.0 < 6.3.3; >= 6.4.0 < 6.4.2; >= 6.5.0 < 6.5.1; >= 6.6.0 < 6.6.1; >= 4.7.0 < 5.11.5

Patched version: 6.0.5

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/nuget.protocol@6.0.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity-Staging ignore nuget/nuget.protocol@6.0.0. You can also ignore all packages with @SocketSecurity-Staging ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: NuGet Elevation of Privilege Vulnerability in nuget nuget.protocol

CVE: GHSA-g3q9-xf95-8hp5 NuGet Elevation of Privilege Vulnerability (HIGH)

Affected versions: >= 4.6.0 < 4.9.6; >= 5.0.0 < 5.7.3; >= 5.8.0 < 5.9.3; >= 5.10.0 < 5.11.3; >= 6.0.0 < 6.0.3; >= 6.1.0 < 6.2.2; >= 6.3.0 < 6.3.1

Patched version: 6.0.3

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/nuget.protocol@6.0.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity-Staging ignore nuget/nuget.protocol@6.0.0. You can also ignore all packages with @SocketSecurity-Staging ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: Microsoft Security Advisory CVE-2024-38095 | .NET Denial of Service Vulnerability in nuget system.formats.asn1

CVE: GHSA-447r-wph3-92pm Microsoft Security Advisory CVE-2024-38095 | .NET Denial of Service Vulnerability (HIGH)

Affected versions: >= 5.0.0-preview.7.20364.11 < 6.0.1; >= 7.0.0-preview.1.22076.8 < 8.0.1

Patched version: 6.0.1

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/nuget.packaging@6.0.0nuget/system.formats.asn1@5.0.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity-Staging ignore nuget/system.formats.asn1@5.0.0. You can also ignore all packages with @SocketSecurity-Staging ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: Microsoft Security Advisory CVE-2024-43485 | .NET Denial of Service Vulnerability in nuget system.text.json

CVE: GHSA-8g4q-xg66-9fp4 Microsoft Security Advisory CVE-2024-43485 | .NET Denial of Service Vulnerability (HIGH)

Affected versions: >= 8.0.0 < 8.0.5; >= 6.0.0 < 6.0.10

Patched version: 6.0.10

From: src/commands/manifest/scripts/dotnet-tool/socket-facts-dotnet.csprojnuget/microsoft.build@17.3.2nuget/system.text.json@6.0.0

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity-Staging ignore nuget/system.text.json@6.0.0. You can also ignore all packages with @SocketSecurity-Staging ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@jdalton

Copy link
Copy Markdown
Collaborator

Jeppe Fredsgaard Blaabjerg (@jfblaa) Would this live better in the coana cli?

@jdalton

John-David Dalton (jdalton) commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Six verified issues, most severe first. Each one is traced to the exact lines on this branch and checked against the v1.x base (and the pinned coana builds where that mattered). Two things that looked like bugs turned out fine — they're at the bottom so nobody re-chases them.

🔴 1. Windows line endings corrupt the last field of every record the C# tool emits

RecordsWriter.cs writes records with StreamWriter.WriteLine. On Windows that ends each line with \r\n. The TypeScript parser in records.mts splits the stream on '\n' only and never strips the '\r', so on a Windows machine every record's final field arrives with a stray \r character stuck to it.

The grammar puts meaningful data in that last position, so everything breaks quietly at once:

  • Every root record's prod flag parses as "1\r", which bool() reads as false — all roots get demoted to dev.
  • Every node's direct flag does the same — direct vs. transitive info is lost.
  • Every edge's child id becomes "pkg:1.0\r", which matches no node key — the whole dependency graph flattens.
  • Every file/projectTgt path fails the exists-check filter — the reachability sidecar loses all artifacts.

No error is raised anywhere; the scan "succeeds" with wrong data. The other three emitters already guard against this — the Gradle init script joins with '\n' explicitly and the Scala plugin appends '\n' — so the new C# writer is the one deviant. Windows is squarely in scope: the tool and CLI both carry Windows-specific handling elsewhere.

Fix idea 💡: set _writer.NewLine = "\n" in the RecordsWriter constructor. Worth also trimming a trailing \r per line in records.mts so the parser tolerates any future emitter that forgets — belt and suspenders on both sides of the protocol.

🟠 2. The sidecar schema break is wider than the draft warning says — every reachability scan fails, not just polyglot ones

The draft warning says a polyglot .NET+JVM --reach scan would break until the coana side ships. It's actually all of them. sidecar.mts now stamps ecosystem on every entry unconditionally — maven entries included. Both relevant pinned coana builds (15.6.7 on this branch, 15.8.4 on current v1.x) validate the sidecar with a schema that rejects any key it doesn't know, and neither knows ecosystem. The parse throws.

So a plain single-ecosystem Gradle or Maven --reach scan on this branch dies at the sidecar handoff, with no .NET anywhere in sight. The draft gate itself is right (don't merge until the coana release + pin bump), but anyone testing this branch should know the real blast radius.

Fix idea 💡: correct the PR body to say all --reach scans are gated — or only emit ecosystem once the pinned coana accepts it, which keeps pure-JVM reach working on this branch today.

🟠 3. A tool crash after partial output still exits 0 — a truncated SBOM is reported as success

The C# tool's catch-all prints to stderr and returns exit code 1, leaving whatever records were already flushed on disk — and writes no failure record. On the TypeScript side, the only check of that non-zero exit requires components AND projects AND failures AND unscannables to ALL be empty before treating the run as crashed.

Walk through what that means: the tool crashes while reading project 3 of 5. Projects 1–2 are already in the records file, so the all-empty guard passes, the CLI writes .socket.facts.json, logs success, and exits 0 — with projects 3–5 silently missing. The tool's own comment promises "the CLI treats it as a crashed build", but that stops being true the moment any partial output exists.

Fix idea 💡: emit a failure record from the catch-all (the record stream is still open there), or treat a non-zero tool exit as blocking on the TypeScript side no matter how much partial output landed.

🟠 4. A failed restore can report success with stale data

After the restore build, errors that belong to restore-unsupported projects are deliberately skipped as noise — but they stay in the error collection. The "restore failed" fallback record only fires when that collection is empty. Put those together: a restore that failed with only noise-classified errors emits no failure record at all.

The stale-assets backstop then turns quiet into wrong. If an earlier successful restore left obj/project.assets.json behind, the file-exists check passes and the tool reports that stale dependency closure as a fresh, successful scan — exit 0, zero failure records. The trigger is the exact scenario the noise filter's own comment cites: a solution with a legacy web project whose VS-only imports fail evaluation on Linux, in a checkout that restored successfully once before.

Fix idea 💡: gate the fallback on "no failure records were emitted" rather than the raw captured-error count — count what you reported, not what you caught.

🟠 5. A leftover packages.config silently wins over the real PackageReference graph

IsRestoreSupported checks for a packages.config file FIRST and returns false before ever looking at the project's PackageReference items; ReadProject routes the same way. A project that migrated to PackageReference but still has a leftover packages.config in its directory — a common migration remnant — gets scanned via the flat legacy path. The stale pinned list from the leftover file becomes the reported closure (all direct, no edges) while the project's actual dependency graph is never emitted. No failure record, exit 0.

NuGet itself resolves this the other way around: its restore-style logic checks PackageReference items before the packages.config file, so real dotnet restore on such a project restores the PackageReference graph. The tool's comment says it mirrors NuGet's eligibility model; the order is inverted.

Fix idea 💡: match NuGet's precedence (PackageReference first, packages.config as the fallback), and emit a warning or failure record when a project has both — that state is worth surfacing no matter which side wins.

🟠 6. Polyglot repos overwrite one ecosystem's facts with another's

Every facts leg writes the same <cwd>/.socket.facts.json with a plain overwrite, and the auto-manifest order is sbt → gradle → dotnet → maven. A repo with both a top-level .csproj and a pom.xml runs the dotnet leg, then the maven leg lands last and wipes the dotnet facts. Same story in a gradle+dotnet repo, where dotnet wipes gradle. The reachability sidecar accumulates across legs; the facts SBOM has no equivalent merge, and the scan flow reads the file once after all legs finish.

This collision already exists on v1.x — a gradle+maven repo clobbers today — so this PR extends it to a fourth leg rather than introducing it. But mixed .NET+JVM repos are this PR's headline scenario, so the pre-existing gap goes live for exactly the users the feature targets.

Fix idea 💡: accumulate facts across legs the way the sidecar already does — merge components/projects per leg into one document, written once at the end. That fixes the pre-existing gradle+maven case in the same motion.

🟡 Smaller items
  • 🟡 The TSV record grammar is hand-maintained in four languages (the comment in records.mts, plus the Groovy, Scala/Java, and C# emitters) with positional empty-string placeholders and no shared definition or cross-language golden test. Item 1 (Windows line endings) is exactly the drift this invites — one emitter deviating from the protocol with nothing to catch it. A shared vector file all four emitters' tests consume would pin the contract.
  • 🟡 A stray top-level .csproj on a machine without the dotnet SDK now aborts the whole auto-manifest run (spawn ENOENT → abort). The JVM legs already behave this way when their tools are missing, and the detection comment shows this was a considered trade — but a cheap SDK-presence precheck with a clean "skipping dotnet: no SDK found" (or a pointer at defaults.manifest.dotnet.disabled) would spare the newly-detected repos a hard failure.
  • 🟡 packages.config artifact downloads run one at a time and buffer each whole .nupkg into a MemoryStream. Large packages (CUDA/ML runtimes ship multi-hundred-MB nupkgs) can OOM the tool on constrained runners — landing in the same catch-all path as item 3 (crash exits 0). Bounded-concurrency downloads spooled to temp files bound both time and memory.
  • 🟡 MSBuild evaluation work repeats more than the "one MSBuild session" framing suggests: a fresh ProjectCollection per project in the read pass (which defeats shared SDK import caching), one extra inner-build evaluation per TargetFramework alias under --with-files, MaxNodeCount left at 1 so multiple top-level entries restore serially, and a timeout unwind that waits up to 30s per submission, one after another. Big multi-targeting solutions pay all of these at once.
  • 🟡 The success summary hand-codes ecosystem === 'dotnet' ? 'target framework(s)' : 'configuration(s)' while this same PR adds the per-ecosystem configNoun to the resolution-report dialect. The next ecosystem has to remember a buried ternary or its summary quietly says "configuration(s)". Read the noun from the dialect.
  • 🟡 The ".NET root marker" file-set (sln/slnx/csproj/fsproj/vbproj) is defined twice — DOTNET_ROOT_FILE_RE in TypeScript and Discover()/IsProjectFile in C# — with no test tying them together. Adding a project type to one side only desynchronizes detection from scanning.
  • 🟡 purlTypeForTool maps every non-dotnet tool to maven via a binary ternary. An exhaustive per-tool map makes the compiler force a decision for tool Trigger-report #5, instead of letting a future ecosystem silently assemble maven-typed components.
  • 🟡 classifyNugetFailure string-matches C# loader-failure signatures ("could not load file or assembly", an HRESULT) in TypeScript. When the C# side's failure wording shifts, misclassification sends users chasing feed problems. The tool already owns the failure record — let it self-classify with a category field.
  • 🟡 The config-glob header claims identical behavior across JS, Java, and .NET regex engines, but only a JS vitest suite exercises the vectors. Four consumers lean on that claim; running the same vector table under Java and .NET in the existing compat smokes would make it true by test rather than by assertion. One latent divergence exists already — .NET's $ also matches before a trailing newline — though today's config/TFM names can't carry one, which is why this is a test ask and not a bug report.
  • 🟡 An uncompilable pattern used to degrade to a literal match (matches almost nothing); the shared contract now drops it, and since an empty include list means include-everything, a dropped include inverts into scanning all configurations. The CLI validates each source it emits, so this only bites out-of-band callers driving the shipped scripts directly — worth one line in the contract comment stating the direction change is intentional.
  • 🟡 populateFilesFor is forwarded to all three JVM tools but not to the dotnet tool (no flag in ToolOptions.cs). Nothing in the CLI sets it today, so this is a latent contract gap rather than a live bug — worth closing when the coana-side integration lands, since coana's own invocations are the intended caller.
  • 🟡 EmitProjectTargets uses one-arg Path.GetFullPath(targetPath) (anchored to the tool's working directory) where the bare-project and packages.config paths use the two-arg form anchored to the project directory. MSBuild guarantees an absolute TargetPath on the affected path, so this is a consistency fix, not a bug — the two-arg form just removes the trap.
  • 🟡 Duplication that will drift: the flag → socket.json-default → hardcoded-default ladder is copy-pasted a fifth time in cmd-manifest-dotnet.mts (~75 lines); the setup wizard inlines a fourth copy of the prompt/assign/delete block that setupFactsOptions already parameterizes; convertDotnetToFacts is a fourth rename-only passthrough; and assertDotnetToolBuilt clones assertMavenExtensionBuilt with different error text. Each is small; together they make the sixth ecosystem a ~200-line copy-paste tax.
🟢 Verified fine: two things that looked like bugs but aren't
  • 🟢 Windows caret-mangling of the compiled regex patterns (^(?:...)$ passed as -P/-D values) can't happen: the spawn chain never uses a shell, so arguments reach the JVM untouched, and .bat/.cmd resolution either fails loudly or is rejected by Node's EINVAL hardening. There is no silent regex-corruption path.
  • 🟢 The hand-rolled glob compiler in config-glob.mts is not a duplication of micromatch: micromatch compiles * to [^/]*? (which breaks the composite net8.0/win-x64 names the dotnet tool deliberately matches) and doesn't support [!...] negation at all. It computes different answers, not just different syntax. The bespoke portable-subset compiler is the right call.

Items 1 (Windows line endings) and 3–5 (the fail-closed trio) are the ones to settle before un-drafting — item 1 (Windows line endings) because it's a one-line fix for a whole platform, and items 3 (crash exits 0), 4 (stale-restore success) and 5 (packages.config precedence) because they all break the same promise the tool's design leans on: a wrong scan never exits green. Item 2 (sidecar scope) just needs the PR body corrected so branch testers know what to expect.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants