Honor --exclude-paths in JVM manifest generation and reachability analysis#1411
Merged
Jeppe Fredsgaard Blaabjerg (jfblaa) merged 3 commits intoJul 10, 2026
Merged
Conversation
…lysis The socket facts producers (gradle/maven/sbt) now skip wholly excluded subprojects: their configurations are not resolved and they emit no project records, so their dependencies stay out of the generated SBOM unless a kept subproject depends on them as a project dependency. Patterns are matched as anchored globs relative to the scan root, with zero-depth variants for leading `**/` so NIO glob matching agrees with the CLI's micromatch semantics. The producers also emit all source sets/configurations (not just main/test); source-file-level exclusion is applied by the reachability analysis. The manifest commands (auto/gradle/kotlin/maven/scala) expose --exclude-paths directly, and glob patterns the producers cannot parse (unbalanced brackets) are rejected at the CLI instead of crashing the build tool mid-run. Upgrades @coana-tech/cli to 15.8.7, which applies --exclude-dirs to JVM/.NET/Rust reachability analysis (ENG-5198).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Trailing globstar skips module dirs
- Updated Maven, Gradle, and sbt exclude matcher expansion so trailing /** patterns also match the module directory itself.
Or push these changes by commenting:
@cursor push 073166575a
Preview (073166575a)
diff --git a/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketSupport.java b/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketSupport.java
--- a/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketSupport.java
+++ b/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketSupport.java
@@ -108,8 +108,9 @@
/**
* NIO glob requires a slash-adjacent {@code **} to consume at least one path segment, but the
- * CLI's micromatch lets it match zero ({@code **}{@code /x} matches root-level {@code x}). Emit
- * every variant with {@code **}{@code /} occurrences dropped so both semantics hold.
+ * CLI's micromatch lets it match zero ({@code **}{@code /x} matches root-level {@code x};
+ * {@code x/**} matches {@code x}). Emit every variant with those zero-depth {@code **}
+ * occurrences dropped so both semantics hold.
*/
private static Set<String> zeroDepthVariants(String glob) {
Set<String> out = new LinkedHashSet<>();
@@ -118,6 +119,10 @@
while (!work.isEmpty()) {
String cur = work.poll();
if (!out.add(cur)) continue;
+ if (cur.endsWith("/**")) {
+ String collapsed = cur.substring(0, cur.length() - 3);
+ if (!collapsed.isEmpty()) work.add(collapsed);
+ }
int idx = cur.indexOf("**/");
while (idx >= 0) {
if (idx == 0 || cur.charAt(idx - 1) == '/') {
diff --git a/src/commands/manifest/scripts/socket-facts.init.gradle b/src/commands/manifest/scripts/socket-facts.init.gradle
--- a/src/commands/manifest/scripts/socket-facts.init.gradle
+++ b/src/commands/manifest/scripts/socket-facts.init.gradle
@@ -17,8 +17,8 @@
// Standard glob semantics (anchored to the scan root, matching the CLI flag): `x` is root-level, `**/x`
// matches at any depth. Mirrors the sbt/maven producers.
// NIO glob requires a slash-adjacent `**` to consume at least one path segment, but the CLI's
-// micromatch lets it match zero (`**/x` matches root-level `x`). Emit every variant with `**/`
-// occurrences dropped so both semantics hold.
+// micromatch lets it match zero (`**/x` matches root-level `x`; `x/**` matches `x`). Emit every
+// variant with those zero-depth `**` occurrences dropped so both semantics hold.
gradle.ext.socketZeroDepthVariants = { String glob ->
def out = new LinkedHashSet()
def work = new ArrayDeque()
@@ -26,6 +26,10 @@
while (!work.isEmpty()) {
def cur = work.poll()
if (!out.add(cur)) { continue }
+ if (cur.endsWith('/**')) {
+ def collapsed = cur.substring(0, cur.length() - 3)
+ if (!collapsed.isEmpty()) { work.add(collapsed) }
+ }
int idx = cur.indexOf('**/')
while (idx >= 0) {
if (idx == 0 || cur[idx - 1] == '/') {
diff --git a/src/commands/manifest/scripts/socket-facts.plugin.scala b/src/commands/manifest/scripts/socket-facts.plugin.scala
--- a/src/commands/manifest/scripts/socket-facts.plugin.scala
+++ b/src/commands/manifest/scripts/socket-facts.plugin.scala
@@ -414,14 +414,18 @@
}
// NIO glob requires a slash-adjacent `**` to consume at least one path segment, but the CLI's
- // micromatch lets it match zero (`**/x` matches root-level `x`). Emit every variant with `**/`
- // occurrences dropped so both semantics hold.
+ // micromatch lets it match zero (`**/x` matches root-level `x`; `x/**` matches `x`). Emit every
+ // variant with those zero-depth `**` occurrences dropped so both semantics hold.
private def zeroDepthVariants(glob: String): Seq[String] = {
val out = mutable.LinkedHashSet[String]()
val work = mutable.Queue(glob)
while (work.nonEmpty) {
val cur = work.dequeue()
if (out.add(cur)) {
+ if (cur.endsWith("/**")) {
+ val collapsed = cur.substring(0, cur.length - 3)
+ if (collapsed.nonEmpty) work.enqueue(collapsed)
+ }
var idx = cur.indexOf("**/")
while (idx >= 0) {
if (idx == 0 || cur.charAt(idx - 1) == '/') {You can send follow-ups to the cloud agent here.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2bef25d. Configure here.
Benjamin Barslev Nielsen (barslev)
approved these changes
Jul 10, 2026
… in exclude globs
…chability # Conflicts: # CHANGELOG.md # package.json # pnpm-lock.yaml
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
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
Fixes a customer-reported issue where
--exclude-pathswas not respected for JVM, .NET, and Rust reachability analysis. This PR is the socket-cli part of a cross-repo fix (Coana CLI15.8.7carries the engine-side changes) — ENG-5198.Manifest producers (gradle / maven / sbt)
**/patterns are expanded into zero-depth variants so NIO glob matching agrees with the CLI's micromatch semantics (**/testsalso matches a root-leveltests).main/test); source-file-level exclusion is applied downstream by the reachability analysis (--exclude-dirs).CLI
socket manifest {auto,gradle,kotlin,maven,scala}expose--exclude-paths.[/{, nested{}groups) are rejected up front with a clearInputErrorinstead of crashing the build tool mid-run.15.8.7, which honors--exclude-dirsin JVM/.NET/Rust reachability, filters framework resources (SPI registrations,spring.factories, Spring XML) in excluded dirs, and aligns glob semantics (*no longer crosses/).Testing
pnpm test:unit src/commands/scan/exclude-paths.test.mts— 40/40 (new validation cases pinned against Java's actual glob parser behavior).--exclude-paths '**/excluded-mod'(the previously broken root-level case): the excluded module and its dependencies are absent from the records; the sibling module is unaffected.build-jar.sh.tsgoand eslint clean.Note
Medium Risk
Changes dependency graph and reachability inputs for multi-module JVM builds when exclusions are used; incorrect glob semantics could omit needed modules, but behavior matches an existing scan flag and adds upfront validation.
Overview
Release 1.1.141 wires
--exclude-pathsthrough JVM manifest generation and tightens validation; Coana CLI bumps to 15.8.7 for reachability-side exclusions (JVM, .NET, Rust).socket manifest auto,gradle,kotlin,maven, andscalanow accept--exclude-paths, validate patterns up front viaassertValidExcludePaths, and pass them intorunManifestFacts/ auto-manifest (includingsocket scan create --auto-manifest). Gradle, Maven, and sbt producers skip wholly excluded reactor modules/subprojects (no project records, no resolution) while keeping module identity for cross-project deps on kept modules; glob handling adds zero-depth**/variants so NIO glob matches CLI micromatch. Gradle/sbt also emit all source sets/configurations (not only main/test) for downstream reachability filtering.Invalid globs that NIO cannot parse (unbalanced
[/{, nested{}) fail early withInputErrorinstead of crashing mid-build. Help snapshots and changelog document the new behavior.Reviewed by Cursor Bugbot for commit 2bef25d. Configure here.