Skip to content

fix(scan): fail closed instead of crashing Coana when --dynamic-sbom-inference finds no JVM build root - #1486

Merged
Jeppe Fredsgaard Blaabjerg (jfblaa) merged 4 commits into
v1.xfrom
jfblaa/rea-710-socket-cli-dynamic-sbom-inference-crashes-coana-when-target
Aug 7, 2026
Merged

fix(scan): fail closed instead of crashing Coana when --dynamic-sbom-inference finds no JVM build root#1486
Jeppe Fredsgaard Blaabjerg (jfblaa) merged 4 commits into
v1.xfrom
jfblaa/rea-710-socket-cli-dynamic-sbom-inference-crashes-coana-when-target

Conversation

@jfblaa

@jfblaa Jeppe Fredsgaard Blaabjerg (jfblaa) commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • socket scan create --reach --dynamic-sbom-inference on a target with no Gradle/sbt/Maven build root at all (e.g. a plain npm workspace) crashed Coana with --maven-use-only-socket-facts requires --compute-artifacts-sidecar to also be provided.
  • Root cause: --maven-use-only-socket-facts was passed to Coana whenever dynamicSbomInference was true, regardless of whether a sidecar was actually generated.
  • Fix: an empty sidecar ({}) is now always written whenever dynamicSbomInference is on, and --maven-use-only-socket-facts is always passed alongside it. This matters beyond just preventing the crash: without a sidecar to back it, dropping the flag entirely would let Coana silently fall back to resolving the Maven ecosystem from whatever else it finds (a stray CDX/SPDX SBOM, etc.), defeating the whole point of --dynamic-sbom-inference. An empty sidecar instead makes Coana correctly report nothing reachable there.
  • Separately, socket scan create --dynamic-sbom-inference (and its manifest-side siblings, see below) now fail closed with a clear message when the recursive scan finds no Gradle/sbt/Maven build root at all anywhere under the target — the flag doesn't apply there, so this is very likely a mistake (wrong --cwd, or the flag copied into the wrong project). This is a distinct, narrower check from the sidecar fix above: build roots that are legitimately discovered but end up empty (no resolvable dependencies) or skippedDisabled (disabled via socket.json) don't trigger it — those are expected outcomes, already warned about individually, and now handled correctly by the empty-sidecar fallback rather than aborting the scan.
  • Same treatment applied to the two sibling commands, for consistency with socket manifest auto's existing "nothing detected" failure:
    • socket manifest dynamic-sbom-inference (previously printed Generated 0 Socket facts file(s). with exit 0 even when nothing was found).
    • socket manifest setup --dynamic-sbom-inference (previously printed Recursive setup complete. with exit 0 even when nothing was found).

Linear: REA-710

Test plan

  • New tests in perform-reachability-analysis.test.mts covering: no sidecar entries + dynamicSbomInference on (writes an empty sidecar, still passes both flags), a real sidecar, and dynamicSbomInference off.
  • New test in handle-create-new-scan.test.mts asserting the abort when zero build roots are discovered, and a regression test proving discovered-but-empty/disabled roots do NOT wrongly abort.
  • New test file handle-manifest-dynamic-sbom-inference.test.mts covering the no-build-root / partial-failure / success cases.
  • New tests in setup-recursive-manifest-config.test.mts covering the fail-closed case and the "excluded, not absent" case.
  • pnpm test:unit across src/commands/manifest + src/commands/scan — 463/463 pass
  • pnpm run check:tsc clean
  • pnpm run lint clean

…inference finds no JVM build root

Coana was rejecting the run with "--maven-use-only-socket-facts requires
--compute-artifacts-sidecar to also be provided" whenever the flag was
passed with no sidecar to back it, which happened silently on any target
with zero Gradle/sbt/Maven build roots (the sidecar only gets entries
when at least one such root generates facts).

- Only pass --maven-use-only-socket-facts to Coana when a sidecar was
  actually generated, not merely because the user passed
  --dynamic-sbom-inference.
- Abort earlier with a clear InputError when --dynamic-sbom-inference
  finds no Gradle/sbt/Maven build root at all, rather than silently
  proceeding as a normal scan with no indication the flag had no effect.

Linear: REA-710

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1876e5e. Configure here.

Comment thread src/commands/scan/handle-create-new-scan.mts Outdated
…ild root exists

socket manifest dynamic-sbom-inference and socket manifest setup
--dynamic-sbom-inference both silently succeeded when the recursive scan
found zero Gradle/sbt/Maven build roots anywhere - printing "Generated 0
Socket facts file(s)." or "Recursive setup complete." with exit 0, giving
no indication the flag had no effect. Same class of mistake
`socket manifest auto` already treats as a hard failure when it detects
nothing for any ecosystem.

Both now fail with a clear message when no build root is found at all.
A target where build roots exist but --exclude-paths excludes all of them
is left alone (a deliberate user choice, not "none exist").

Follow-up to the equivalent scan create fix (REA-710 / #1486).
…und"

The fail-closed check was keying off zero generated facts paths, which
also covers legitimate non-fatal outcomes (empty, skippedDisabled) that
are already warned about elsewhere. A target with discovered but
disabled/empty build roots was wrongly told no build root existed at
all. Now keys off outcomes.length itself - zero candidates discovered,
not zero generated.
…triction

When dynamicSbomInference finds no build root, or every discovered one
ends up empty/skippedDisabled, the sidecar previously stayed unwritten
and --maven-use-only-socket-facts was dropped entirely. That let Coana
fall back to resolving the Maven ecosystem from whatever else it found
(a stray CDX/SPDX SBOM, etc.), silently defeating the flag's purpose.

Now an empty sidecar is always written under dynamicSbomInference, and
--maven-use-only-socket-facts is always passed alongside it, so Coana
correctly reports nothing reachable there instead of substituting an
unintended source.

@mtorp Martin Torp (mtorp) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✅

@jfblaa
Jeppe Fredsgaard Blaabjerg (jfblaa) merged commit 4feb10d into v1.x Aug 7, 2026
8 of 10 checks passed
@jfblaa
Jeppe Fredsgaard Blaabjerg (jfblaa) deleted the jfblaa/rea-710-socket-cli-dynamic-sbom-inference-crashes-coana-when-target branch August 7, 2026 10:39
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