socket 1.1.119 → 1.1.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/cli.js +653 -96
  3. package/dist/cli.js.map +1 -1
  4. package/dist/constants.js +4 -4
  5. package/dist/constants.js.map +1 -1
  6. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  7. package/dist/types/commands/config/handle-config-get.d.mts.map +1 -1
  8. package/dist/types/commands/config/handle-config-set.d.mts.map +1 -1
  9. package/dist/types/commands/config/output-config-set.d.mts.map +1 -1
  10. package/dist/types/commands/manifest/bazel/bazel-cquery.d.mts.map +1 -1
  11. package/dist/types/commands/manifest/bazel/bazel-query-runner.d.mts.map +1 -1
  12. package/dist/types/commands/manifest/bazel/bazel-repo-discovery.d.mts +28 -1
  13. package/dist/types/commands/manifest/bazel/bazel-repo-discovery.d.mts.map +1 -1
  14. package/dist/types/commands/manifest/bazel/cmd-manifest-bazel.d.mts +5 -0
  15. package/dist/types/commands/manifest/bazel/cmd-manifest-bazel.d.mts.map +1 -1
  16. package/dist/types/commands/manifest/bazel/extract_bazel_to_maven.d.mts +43 -3
  17. package/dist/types/commands/manifest/bazel/extract_bazel_to_maven.d.mts.map +1 -1
  18. package/dist/types/commands/manifest/generate_auto_manifest.d.mts.map +1 -1
  19. package/dist/types/commands/scan/cmd-scan-create.d.mts.map +1 -1
  20. package/dist/types/commands/scan/perform-reachability-analysis.d.mts +2 -0
  21. package/dist/types/commands/scan/perform-reachability-analysis.d.mts.map +1 -1
  22. package/dist/types/utils/auto-manifest-config.d.mts +55 -0
  23. package/dist/types/utils/auto-manifest-config.d.mts.map +1 -0
  24. package/dist/types/utils/config.d.mts.map +1 -1
  25. package/dist/types/utils/meow-with-subcommands.d.mts.map +1 -1
  26. package/dist/types/utils/socket-json.d.mts +1 -0
  27. package/dist/types/utils/socket-json.d.mts.map +1 -1
  28. package/dist/utils.js +98 -12
  29. package/dist/utils.js.map +1 -1
  30. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var require$$0 = require('node:url');
4
+ var require$$0$1 = require('node:url');
5
5
  var vendor = require('./vendor.js');
6
6
  var require$$9 = require('../external/@socketsecurity/registry/lib/debug');
7
7
  var logger = require('../external/@socketsecurity/registry/lib/logger');
@@ -15,6 +15,7 @@ var words = require('../external/@socketsecurity/registry/lib/words');
15
15
  var fs$1 = require('node:fs');
16
16
  var arrays = require('../external/@socketsecurity/registry/lib/arrays');
17
17
  var prompts = require('../external/@socketsecurity/registry/lib/prompts');
18
+ var require$$0 = require('node:crypto');
18
19
  var os = require('node:os');
19
20
  var spawn = require('../external/@socketsecurity/registry/lib/spawn');
20
21
  var bin = require('../external/@socketsecurity/registry/lib/bin');
@@ -67,7 +68,7 @@ async function fetchRepoAnalyticsData(repo, time, options) {
67
68
 
68
69
  // Note: Widgets does not seem to actually work as code :'(
69
70
 
70
- const require$7 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
71
+ const require$7 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
71
72
  const METRICS = ['total_critical_alerts', 'total_high_alerts', 'total_medium_alerts', 'total_low_alerts', 'total_critical_added', 'total_medium_added', 'total_low_added', 'total_high_added', 'total_critical_prevented', 'total_high_prevented', 'total_medium_prevented', 'total_low_prevented'];
72
73
 
73
74
  // Note: This maps `new Date(date).getMonth()` to English three letters
@@ -503,7 +504,7 @@ async function fetchAuditLog(config, options) {
503
504
  });
504
505
  }
505
506
 
506
- const require$6 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
507
+ const require$6 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
507
508
  async function outputAuditLog(result, {
508
509
  logType,
509
510
  orgSlug,
@@ -1802,10 +1803,26 @@ async function performReachabilityAnalysis(options) {
1802
1803
  spinner?.start();
1803
1804
  spinner?.infoAndStop('Running reachability analysis with Coana...');
1804
1805
  const outputFilePath = outputPath || constants.default.DOT_SOCKET_DOT_FACTS_JSON;
1806
+
1807
+ // Coana reads `--auto-manifest-config` from a JSON file, so write the resolved
1808
+ // per-ecosystem build-tool config (mapped from socket.json) to a temp file and
1809
+ // pass its absolute path. Cleaned up in the finally below.
1810
+ let autoManifestConfigPath;
1811
+ const {
1812
+ autoManifestConfig
1813
+ } = reachabilityOptions;
1814
+ if (autoManifestConfig && !utils.isAutoManifestConfigEmpty(autoManifestConfig)) {
1815
+ autoManifestConfigPath = path.join(os.tmpdir(), `socket-auto-manifest-config-${require$$0.randomUUID()}.json`);
1816
+ await fs$1.promises.writeFile(autoManifestConfigPath, JSON.stringify(autoManifestConfig), 'utf8');
1817
+ }
1818
+
1805
1819
  // Build Coana arguments.
1806
1820
  const coanaArgs = ['run', analysisTarget, '--output-dir', path.dirname(outputFilePath), '--socket-mode', outputFilePath, '--disable-report-submission', ...(reachabilityOptions.reachAnalysisTimeout ? ['--analysis-timeout', `${reachabilityOptions.reachAnalysisTimeout}`] : []), ...(reachabilityOptions.reachAnalysisMemoryLimit ? ['--memory-limit', `${reachabilityOptions.reachAnalysisMemoryLimit}`] : []), ...(reachabilityOptions.reachConcurrency ? ['--concurrency', `${reachabilityOptions.reachConcurrency}`] : []), ...(reachabilityOptions.reachContinueOnAnalysisErrors ? ['--reach-continue-on-analysis-errors'] : []), ...(reachabilityOptions.reachContinueOnInstallErrors ? ['--reach-continue-on-install-errors'] : []), ...(reachabilityOptions.reachContinueOnMissingLockFiles ? ['--reach-continue-on-missing-lock-files'] : []), ...(reachabilityOptions.reachContinueOnNoSourceFiles ? ['--reach-continue-on-no-source-files'] : []), ...(reachabilityOptions.reachDebug ? ['--debug'] : []), ...(reachabilityOptions.reachDetailedAnalysisLogFile ? ['--print-analysis-log-file'] : []), ...(reachabilityOptions.reachDisableAnalytics ? ['--disable-analytics-sharing'] : []), ...(reachabilityOptions.reachDisableExternalToolChecks ? ['--disable-external-tool-checks'] : []), ...(reachabilityOptions.reachEnableAnalysisSplitting ? [] : ['--disable-analysis-splitting']), ...(tarHash ? ['--run-without-docker', '--manifests-tar-hash', tarHash] : []),
1807
1821
  // Empty reachEcosystems implies scanning all ecosystems.
1808
- ...(reachabilityOptions.reachEcosystems.length ? ['--purl-types', ...reachabilityOptions.reachEcosystems] : []), ...(reachabilityOptions.reachExcludePaths.length ? ['--exclude-dirs', ...reachabilityOptions.reachExcludePaths] : []), ...(reachabilityOptions.reachLazyMode ? ['--lazy-mode'] : []), ...(reachabilityOptions.reachSkipCache ? ['--skip-cache-usage'] : []), ...(reachabilityOptions.reachUseOnlyPregeneratedSboms ? ['--use-only-pregenerated-sboms'] : [])];
1822
+ ...(reachabilityOptions.reachEcosystems.length ? ['--purl-types', ...reachabilityOptions.reachEcosystems] : []), ...(reachabilityOptions.reachExcludePaths.length ? ['--exclude-dirs', ...reachabilityOptions.reachExcludePaths] : []), ...(reachabilityOptions.reachLazyMode ? ['--lazy-mode'] : []), ...(reachabilityOptions.reachSkipCache ? ['--skip-cache-usage'] : []), ...(reachabilityOptions.reachUseOnlyPregeneratedSboms ? ['--use-only-pregenerated-sboms'] : []),
1823
+ // Hand the per-ecosystem build-tool config (mapped from socket.json) to
1824
+ // Coana's reach-time resolution, as a temp JSON file path.
1825
+ ...(autoManifestConfigPath ? ['--auto-manifest-config', autoManifestConfigPath] : [])];
1809
1826
 
1810
1827
  // Build environment variables.
1811
1828
  const coanaEnv = {};
@@ -1817,43 +1834,53 @@ async function performReachabilityAnalysis(options) {
1817
1834
  if (branchName && branchName !== constants.default.SOCKET_DEFAULT_BRANCH) {
1818
1835
  coanaEnv['SOCKET_BRANCH_NAME'] = branchName;
1819
1836
  }
1820
-
1821
- // Run Coana with the manifests tar hash.
1822
- const coanaResult = await utils.spawnCoanaDlx(coanaArgs, orgSlug, {
1823
- coanaVersion: reachabilityOptions.reachVersion,
1824
- cwd,
1825
- env: coanaEnv,
1826
- spinner,
1827
- stdio: 'inherit'
1828
- });
1829
- if (wasSpinning) {
1830
- spinner.start();
1831
- }
1832
- if (!coanaResult.ok) {
1833
- const coanaVersion = reachabilityOptions.reachVersion || constants.default.ENV.INLINED_SOCKET_CLI_COANA_TECH_CLI_VERSION;
1834
- logger.logger.error(`Coana reachability analysis failed. Version: ${coanaVersion}, target: ${analysisTarget}, cwd: ${cwd}`);
1835
- if (coanaResult.message) {
1836
- logger.logger.error(`Details: ${coanaResult.message}`);
1837
+ try {
1838
+ // Run Coana with the manifests tar hash.
1839
+ const coanaResult = await utils.spawnCoanaDlx(coanaArgs, orgSlug, {
1840
+ coanaVersion: reachabilityOptions.reachVersion,
1841
+ cwd,
1842
+ env: coanaEnv,
1843
+ spinner,
1844
+ stdio: 'inherit'
1845
+ });
1846
+ if (wasSpinning) {
1847
+ spinner.start();
1848
+ }
1849
+ if (!coanaResult.ok) {
1850
+ const coanaVersion = reachabilityOptions.reachVersion || constants.default.ENV.INLINED_SOCKET_CLI_COANA_TECH_CLI_VERSION;
1851
+ logger.logger.error(`Coana reachability analysis failed. Version: ${coanaVersion}, target: ${analysisTarget}, cwd: ${cwd}`);
1852
+ if (coanaResult.message) {
1853
+ logger.logger.error(`Details: ${coanaResult.message}`);
1854
+ }
1855
+ return coanaResult;
1837
1856
  }
1838
- return coanaResult;
1839
- }
1840
1857
 
1841
- // Coana writes the facts file relative to the scan `cwd` (it is spawned
1842
- // with `cwd` above), so resolve the read path against `cwd` too. Reading
1843
- // the bare relative path would resolve against `process.cwd()` and miss
1844
- // the file whenever `cwd !== process.cwd()` (e.g. `--cwd <dir>`), silently
1845
- // dropping the tier 1 scan id and skipping finalize downstream.
1846
- const resolvedReportPath = path.resolve(cwd, outputFilePath);
1847
- return {
1848
- ok: true,
1849
- data: {
1850
- // Use the actual output filename for the scan. Keep this `cwd`-relative
1851
- // so the upload (which relativizes against `cwd`) and the post-success
1852
- // unlink (`path.resolve(cwd, reachabilityReport)`) keep working.
1853
- reachabilityReport: outputFilePath,
1854
- tier1ReachabilityScanId: utils.extractTier1ReachabilityScanId(resolvedReportPath)
1858
+ // Coana writes the facts file relative to the scan `cwd` (it is spawned
1859
+ // with `cwd` above), so resolve the read path against `cwd` too. Reading
1860
+ // the bare relative path would resolve against `process.cwd()` and miss
1861
+ // the file whenever `cwd !== process.cwd()` (e.g. `--cwd <dir>`), silently
1862
+ // dropping the tier 1 scan id and skipping finalize downstream.
1863
+ const resolvedReportPath = path.resolve(cwd, outputFilePath);
1864
+ return {
1865
+ ok: true,
1866
+ data: {
1867
+ // Use the actual output filename for the scan. Keep this `cwd`-relative
1868
+ // so the upload (which relativizes against `cwd`) and the post-success
1869
+ // unlink (`path.resolve(cwd, reachabilityReport)`) keep working.
1870
+ reachabilityReport: outputFilePath,
1871
+ tier1ReachabilityScanId: utils.extractTier1ReachabilityScanId(resolvedReportPath)
1872
+ }
1873
+ };
1874
+ } finally {
1875
+ // The run no longer needs the temp config file; best-effort cleanup.
1876
+ if (autoManifestConfigPath) {
1877
+ try {
1878
+ await fs$1.promises.unlink(autoManifestConfigPath);
1879
+ } catch {
1880
+ // File may already be gone or unwritable.
1881
+ }
1855
1882
  }
1856
- };
1883
+ }
1857
1884
  }
1858
1885
 
1859
1886
  // The point here is to attempt to detect the various supported manifest files
@@ -1982,6 +2009,10 @@ function buildBazelModShowVisibleReposArgv(opts) {
1982
2009
  function buildBazelModShowMavenExtensionArgv(opts) {
1983
2010
  const userFlags = splitBazelFlags(opts.bazelFlags);
1984
2011
  return [...buildStartupFlags(opts), 'mod', 'show_extension', '@rules_jvm_external//:extensions.bzl%maven',
2012
+ // A read-only scan must never rewrite the user's MODULE.bazel.lock; pin
2013
+ // the lockfile read-only before user flags, mirroring the query/cquery
2014
+ // argv builders.
2015
+ '--lockfile_mode=off',
1985
2016
  // Belt-and-suspenders output reducer mirroring the PyPI path: bias the
1986
2017
  // report toward the root module's usages. The authoritative pruning is
1987
2018
  // the importers-filter applied to the parsed output, so this is not
@@ -1990,7 +2021,11 @@ function buildBazelModShowMavenExtensionArgv(opts) {
1990
2021
  }
1991
2022
  function buildBazelModShowPipExtensionArgv(opts) {
1992
2023
  const userFlags = splitBazelFlags(opts.bazelFlags);
1993
- return [...buildStartupFlags(opts), 'mod', 'show_extension', '@rules_python//python/extensions:pip.bzl%pip', '--extension_usages=<root>', ...userFlags];
2024
+ return [...buildStartupFlags(opts), 'mod', 'show_extension', '@rules_python//python/extensions:pip.bzl%pip',
2025
+ // A read-only scan must never rewrite the user's MODULE.bazel.lock; pin
2026
+ // the lockfile read-only before user flags, mirroring the query/cquery
2027
+ // argv builders.
2028
+ '--lockfile_mode=off', '--extension_usages=<root>', ...userFlags];
1994
2029
  }
1995
2030
  function buildBazelArgv(queryStr, opts, output = 'build') {
1996
2031
  // Startup flags MUST precede the `query` subcommand.
@@ -2670,7 +2705,10 @@ async function runMetadataCqueryForRepo(args) {
2670
2705
  const err = e;
2671
2706
  const stdout = typeof err.stdout === 'string' ? err.stdout : '';
2672
2707
  const stderr = typeof err.stderr === 'string' ? err.stderr : '';
2673
- const timedOut = err.timedOut === true || err.killed === true || err.signal === 'SIGTERM' || err.signal === 'SIGKILL';
2708
+ // On a `timeout`, the registry spawn kills the child, so Node sets
2709
+ // `killed: true` and `signal: 'SIGTERM'` (or `SIGKILL`). There is no
2710
+ // `timedOut` flag on the real rejection, so do not test for one.
2711
+ const timedOut = err.killed === true || err.signal === 'SIGTERM' || err.signal === 'SIGKILL';
2674
2712
  const {
2675
2713
  artifacts,
2676
2714
  unresolvedLabels
@@ -2850,6 +2888,13 @@ const ROOT_MODULE_IMPORTER = '<root>';
2850
2888
  // modules that imported it (the `(imported by …)` annotation), merged across
2851
2889
  // every line the repo appears on.
2852
2890
 
2891
+ // `indeterminate` means the probe could not be classified: an unrecognized
2892
+ // non-zero exit, or the probe threw outright (the Bazel invocation itself
2893
+ // failed). It is NOT evidence that the repo is undefined — treating it as
2894
+ // `not-defined` would silently under-report a hub that may well hold Maven
2895
+ // deps. The orchestrator must propagate it so the run is never reported
2896
+ // `complete` when a probe was indeterminate.
2897
+
2853
2898
  // Conventional Maven hub names rules_jvm_external sets up under
2854
2899
  // WORKSPACE-mode invocations. Probing each one is cheap (a failed visibility
2855
2900
  // lookup never triggers a `repository_rule` fetch) so the orchestrator can
@@ -2879,6 +2924,101 @@ const SHOW_EXT_SECTION_HEADER_RE = /^## @@?[A-Za-z0-9._+~-]+\/\/:extensions\.bzl
2879
2924
  // generated per-artifact repos and are skipped.
2880
2925
  const FETCHED_HUB_BULLET_RE = /^ {2}- (?<name>\S+) \(imported by (?<importers>[^)]+)\)\s*$/;
2881
2926
 
2927
+ // `bazel mod show_extension @rules_jvm_external//:extensions.bzl%maven`
2928
+ // exits non-zero in two very different situations, and conflating them is
2929
+ // dangerous for a security tool:
2930
+ //
2931
+ // (a) `@rules_jvm_external` simply isn't in the root module's resolved
2932
+ // dependency graph. This is the COMMON case for any bzlmod repo that
2933
+ // doesn't use rules_jvm_external (no Maven at all). Bazel's ModCommand
2934
+ // resolves the extension argument up front via
2935
+ // `ExtensionArg.resolveToExtensionId`, which throws
2936
+ // `InvalidArgumentException` and exits non-zero before evaluating any
2937
+ // Starlark. This is NOT a failure to analyze; it is a positive,
2938
+ // authoritative "there is no maven extension here". It must map to
2939
+ // `not-defined` so the workspace cleanly contributes no Maven.
2940
+ //
2941
+ // (b) The module graph genuinely fails to evaluate: a Starlark eval error,
2942
+ // an unbound name (e.g. a MODULE.bazel referencing `PYTHON_VERSION` /
2943
+ // `pip` before definition), a syntax error, or the bazel binary itself
2944
+ // being missing/spawn-failed (normalized to code -1). Here we have NO
2945
+ // evidence about whether a maven extension exists, so it must map to
2946
+ // `indeterminate` and the run can never be reported complete.
2947
+ //
2948
+ // We classify by stderr shape. The exact wording differs across Bazel
2949
+ // versions; the regex families below are intentionally broad and SHOULD be
2950
+ // confirmed against live `bazel mod show_extension` output.
2951
+
2952
+ // Family (a): the extension / module is not resolvable in the dependency
2953
+ // graph — an argument-resolution error, not an evaluation failure. These all
2954
+ // mean "rules_jvm_external (and thus the maven extension) is not present",
2955
+ // i.e. legitimately not-defined. The `no module ... exists in the dependency
2956
+ // graph` branch is Bazel's verified real wording (`bazel mod show_extension`
2957
+ // against a bzlmod repo without rules_jvm_external: "No module with the
2958
+ // apparent repo name @rules_jvm_external exists in the dependency graph").
2959
+ const SHOW_EXT_NOT_IN_GRAPH_STDERR_RE = /(?:in extension argument|extension argument)?.*(?:not (?:found|resolvable|defined)|no such (?:module|repo(?:sitory)?)|cannot be resolved|is not (?:a )?(?:visible |known )?(?:module|repo(?:sitory)?|extension)|not in the (?:dependency )?graph|no module[^\n]*exists in the (?:dependency )?graph|unknown (?:module|extension)|does not (?:exist|use the extension))/i;
2960
+ // Bazel's canonical phrasing when the named module backing the extension
2961
+ // (here `rules_jvm_external`) isn't a dependency of the root module.
2962
+ const SHOW_EXT_MODULE_NOT_DEP_STDERR_RE = /(?:rules_jvm_external|module ['"`]?[A-Za-z0-9._+~-]+['"`]?).*(?:is not (?:a )?(?:direct )?dep(?:endenc(?:y|ies))?|not (?:a )?dependency)/i;
2963
+
2964
+ // Family (b): a genuine evaluation / load failure of the module graph. These
2965
+ // mean we could not determine whether a maven extension exists, so the result
2966
+ // is indeterminate, never a clean not-defined.
2967
+ const SHOW_EXT_EVAL_FAILURE_STDERR_RE = /(?:error (?:evaluating|loading|computing)|failed to (?:evaluate|load)|evaluation (?:of|failed)|cannot load|syntax error|name ['"`]?[A-Za-z0-9_]+['"`]? is not defined|variable ['"`]?[A-Za-z0-9_]+['"`]? (?:is|was) (?:referenced|not)|unbound|invalid MODULE\.bazel|MODULE\.bazel.*(?:error|failed)|Traceback|Error in)/i;
2968
+
2969
+ // Outcome of running `bazel mod show_extension` for the maven extension,
2970
+ // distinct from the per-repo `ProbeStatus`:
2971
+ // `not-defined` — authoritative: no maven extension in this workspace
2972
+ // (clean run with zero kept hubs, OR rules_jvm_external is
2973
+ // not in the dependency graph).
2974
+ // `indeterminate` — enumeration could not be performed (eval/load failure,
2975
+ // binary missing); the run must not be reported complete.
2976
+ // `defined` — the report parsed and yielded one or more root hubs;
2977
+ // the caller uses the parsed hub list directly.
2978
+
2979
+ // Classify a `bazel mod show_extension` result. `keptRootHubCount` is the
2980
+ // number of root-imported hubs the caller parsed from a code-0 run (see
2981
+ // `parseShowExtensionOutput` + the `<root>` importer filter); it disambiguates
2982
+ // the code-0 cases without re-parsing here.
2983
+ //
2984
+ // IMPORTANT (security correctness): a non-zero exit is the DEFAULT outcome for
2985
+ // every bzlmod repo that does not use rules_jvm_external, so we must NOT treat
2986
+ // non-zero as indeterminate by default. We only escalate to `indeterminate`
2987
+ // when stderr looks like a real evaluation/load failure; an argument/resolution
2988
+ // error about the missing extension is the legitimate no-Maven case.
2989
+ function classifyShowExtensionResult(result, keptRootHubCount) {
2990
+ if (result.code === 0) {
2991
+ // Clean run. Either it enumerated root hubs (`defined`) or it ran fine and
2992
+ // found no maven extension for the root (`not-defined`).
2993
+ return keptRootHubCount > 0 ? 'defined' : 'not-defined';
2994
+ }
2995
+ // A spawn failure / missing binary is normalized to code -1 upstream; there
2996
+ // is no usable stderr classification and we definitely could not enumerate.
2997
+ if (result.code === -1) {
2998
+ return 'indeterminate';
2999
+ }
3000
+ const {
3001
+ stderr
3002
+ } = result;
3003
+ // A genuine module-graph evaluation/load failure wins: we cannot conclude
3004
+ // anything about maven presence, so surface it as indeterminate.
3005
+ if (SHOW_EXT_EVAL_FAILURE_STDERR_RE.test(stderr)) {
3006
+ return 'indeterminate';
3007
+ }
3008
+ // The maven extension / rules_jvm_external is simply not in the dependency
3009
+ // graph: an argument-resolution error. This is the common no-Maven bzlmod
3010
+ // repo and is authoritatively not-defined.
3011
+ if (SHOW_EXT_NOT_IN_GRAPH_STDERR_RE.test(stderr) || SHOW_EXT_MODULE_NOT_DEP_STDERR_RE.test(stderr)) {
3012
+ return 'not-defined';
3013
+ }
3014
+ // Truly unrecognized non-zero exit. Bias toward not-defined: the dominant
3015
+ // real-world non-zero case is "extension not in the graph", and a missing
3016
+ // bullet here would otherwise abort the user's entire scan. We only reach
3017
+ // `indeterminate` above when stderr positively looks like an eval/load
3018
+ // failure, which is the case the flag exists for.
3019
+ return 'not-defined';
3020
+ }
3021
+
2882
3022
  // Pure parser for `bazel mod show_extension @rules_jvm_external//:extensions.bzl%maven`
2883
3023
  // stdout. Returns the hub repos listed under `Fetched repositories:` — i.e.
2884
3024
  // items annotated with `(imported by ...)` — each carrying the set of modules
@@ -2950,13 +3090,16 @@ function classifyProbeResult(result) {
2950
3090
  return 'empty';
2951
3091
  }
2952
3092
  // Code 0 with empty stdout: WORKSPACE-mode probes do this when the repo
2953
- // name isn't declared (Exp 5c). Treat as not-defined.
3093
+ // name isn't declared. Treat as not-defined.
2954
3094
  if (result.code === 0) {
2955
3095
  return 'not-defined';
2956
3096
  }
2957
- // Code 1 with no recognizable message: be conservative and call it
2958
- // not-defined so the orchestrator skips it without erroring the workspace.
2959
- return 'not-defined';
3097
+ // Non-zero exit with no recognizable message: the probe failed for a reason
3098
+ // we can't classify (Bazel infra error, analysis crash, unexpected stderr).
3099
+ // This is NOT proof the repo is undefined, so do NOT downgrade it to
3100
+ // not-defined — surface it as indeterminate so the orchestrator can flag
3101
+ // the workspace as not fully analyzable rather than silently skipping it.
3102
+ return 'indeterminate';
2960
3103
  }
2961
3104
 
2962
3105
  // Convenience: probe a single candidate and return its classified status,
@@ -2968,10 +3111,14 @@ async function probeCandidate(repoName, probe, verbose) {
2968
3111
  try {
2969
3112
  result = await probe(repoName);
2970
3113
  } catch (e) {
3114
+ // A thrown probe means the Bazel invocation itself failed; we have no
3115
+ // evidence about whether the repo exists. Surface it as indeterminate so
3116
+ // the run is not reported complete, rather than swallowing it as a
3117
+ // not-defined skip.
2971
3118
  if (verbose) {
2972
- logger.logger.log(`[VERBOSE] discovery: probe @${repoName}: not-defined (probe threw: ${e instanceof Error ? e.message : String(e)})`);
3119
+ logger.logger.log(`[VERBOSE] discovery: probe @${repoName}: indeterminate (probe threw: ${e instanceof Error ? e.message : String(e)})`);
2973
3120
  }
2974
- return 'not-defined';
3121
+ return 'indeterminate';
2975
3122
  }
2976
3123
  const status = classifyProbeResult(result);
2977
3124
  if (verbose) {
@@ -3154,9 +3301,34 @@ function findWorkspaceRoots(opts) {
3154
3301
  // (discovery threw, or every discovered hub failed).
3155
3302
  // Always an error for every caller.
3156
3303
 
3304
+ // Per-hub extraction state inside one workspace. Recorded so the CLI can emit
3305
+ // a machine-readable completeness signal instead of presenting a partial
3306
+ // extraction as complete.
3307
+ // - `populated` — the hub yielded >=1 artifact and a manifest was written.
3308
+ // - `empty` — the hub is defined but has no Maven targets.
3309
+ // - `not-defined` — the probed conventional name does not exist here.
3310
+ // - `skipped-lockfile` — a committed maven_install.json already covers this
3311
+ // hub, so the CLI deliberately did not re-emit it.
3312
+ // - `failed` — the hub's cquery errored, timed out, or its graph was
3313
+ // known-incomplete (dropped/pruned edges, --keep_going).
3314
+ // - `indeterminate` — discovery could not classify the hub (probe threw or
3315
+ // returned an unrecognized error); NOT evidence of absence.
3316
+
3317
+ // Per-workspace outcome. `load` distinguishes a workspace we could not even
3318
+ // read (`failed` — e.g. an unbound-var MODULE.bazel fragment) from one we
3319
+ // analyzed (`loaded`). A workspace that failed to load contributes to a
3320
+ // hard failure when nothing else was analyzable, and to a partial otherwise.
3321
+
3157
3322
  const DEFAULT_PER_REPO_TIMEOUT_MS = 60_000;
3158
3323
  const REAP_TIMEOUT_MS = 10_000;
3159
3324
 
3325
+ // Machine-readable completeness signal emitted alongside the synthetic
3326
+ // manifests. A `complete: false` summary tells a downstream consumer (e.g.
3327
+ // depscan) that the uploaded SBOM is known-incomplete so it must not be
3328
+ // treated as an authoritative full closure. Enforcement of this signal is a
3329
+ // separate downstream follow-up; the CLI only emits it.
3330
+ const COMPLETENESS_SUMMARY_FILE_NAME = 'socket-bazel-manifest-summary.json';
3331
+
3160
3332
  // Default directory-prune policy for the Bazel workspace walk. The
3161
3333
  // orchestrator applies this unconditionally so neither caller (the explicit
3162
3334
  // `socket manifest bazel` command nor `--auto-manifest`) can omit it and let
@@ -3302,6 +3474,102 @@ function dedupArtifactsByCoord(artifacts) {
3302
3474
  }
3303
3475
  return [...byCoord.values()];
3304
3476
  }
3477
+
3478
+ // The committed lockfile name the server-side walker already ingests for a
3479
+ // hub: `maven_install.json` for a hub literally named `maven`, else
3480
+ // `<hub>_maven_install.json`. Centralised so the gate and the synthetic
3481
+ // writer agree on the name.
3482
+ function hubManifestFileName(repoName) {
3483
+ return repoName === 'maven' ? 'maven_install.json' : `${repoName}_maven_install.json`;
3484
+ }
3485
+
3486
+ // Directory basenames the CLI itself writes synthetic manifests into. A file
3487
+ // living inside one of these is our own output, NOT a committed lockfile, no
3488
+ // matter which run wrote it: the auto-manifest sibling dir (flat layout) and
3489
+ // the explicit-command default output dir. The gate must never read a file in
3490
+ // one of these as evidence of committed coverage, or a stale prior-run
3491
+ // synthetic file would let a later run wrongly skip a hub.
3492
+ const CLI_SYNTHETIC_OUTPUT_DIR_NAMES = new Set(['.socket-auto-manifest', 'bazel-manifests']);
3493
+
3494
+ // Does a committed lockfile already cover THIS hub at THIS hub's own workspace
3495
+ // root? Each workspace is processed independently by the caller, and a
3496
+ // committed lockfile covers the workspace it lives IN — a nested workspace's
3497
+ // `maven_install.json` covers that nested hub, not this one. The server-side
3498
+ // walker ingests every committed `**/*_maven_install.json`, but each one only
3499
+ // covers its own workspace. So the gate checks DEPTH-0 only: a lockfile named
3500
+ // for this hub sitting directly in `workspaceRoot`. A recursive descent would
3501
+ // let an unrelated nested/fixture lockfile mask an uncovered root hub —
3502
+ // silently dropping its distinct coordinates.
3503
+ //
3504
+ // The CLI's own synthetic output is never a committed lockfile: we skip the
3505
+ // current run's `manifestDir` and any known synthetic output dir basename so a
3506
+ // stale prior-run file can't be misread as committed.
3507
+ function committedLockfileCovers(args) {
3508
+ const {
3509
+ fileName,
3510
+ manifestDir,
3511
+ workspaceRoot
3512
+ } = args;
3513
+ // The current run's synthetic output dir, resolved for an exact compare.
3514
+ const manifestDirResolved = path.resolve(manifestDir);
3515
+ const workspaceRootResolved = path.resolve(workspaceRoot);
3516
+ // The committed lockfile, if any, lives directly in the hub's own workspace
3517
+ // root — not in a nested workspace and not in the CLI's output dir.
3518
+ if (workspaceRootResolved === manifestDirResolved || CLI_SYNTHETIC_OUTPUT_DIR_NAMES.has(path.basename(workspaceRootResolved))) {
3519
+ // The workspace root IS an output location; nothing here is committed.
3520
+ return undefined;
3521
+ }
3522
+ let entries;
3523
+ try {
3524
+ entries = fs$1.readdirSync(workspaceRootResolved, {
3525
+ withFileTypes: true
3526
+ });
3527
+ } catch {
3528
+ return undefined;
3529
+ }
3530
+ for (const entry of entries) {
3531
+ if (entry.isFile() && entry.name === fileName) {
3532
+ return path.join(workspaceRootResolved, entry.name);
3533
+ }
3534
+ }
3535
+ return undefined;
3536
+ }
3537
+
3538
+ // Emit the machine-readable completeness summary next to the manifests. This
3539
+ // is the CLI's honest "is this SBOM complete?" signal in the emitted output;
3540
+ // it carries the run status plus the per-workspace / per-hub breakdown so a
3541
+ // downstream consumer can detect a known-incomplete upload. Best-effort: a
3542
+ // failure to write the summary must never sink an otherwise-usable run, so it
3543
+ // is logged (under verbose) and swallowed.
3544
+ async function writeCompletenessSummary(args) {
3545
+ const {
3546
+ artifactCount,
3547
+ complete,
3548
+ manifestDir,
3549
+ manifestPaths,
3550
+ status,
3551
+ verbose,
3552
+ workspaceOutcomes
3553
+ } = args;
3554
+ const summary = {
3555
+ artifactCount,
3556
+ complete,
3557
+ ecosystem: 'maven',
3558
+ manifestCount: manifestPaths.length,
3559
+ status,
3560
+ workspaces: workspaceOutcomes
3561
+ };
3562
+ try {
3563
+ fs$1.mkdirSync(manifestDir, {
3564
+ recursive: true
3565
+ });
3566
+ await fs$1.promises.writeFile(path.join(manifestDir, COMPLETENESS_SUMMARY_FILE_NAME), JSON.stringify(summary, null, 2), 'utf8');
3567
+ } catch (e) {
3568
+ if (verbose) {
3569
+ logger.logger.log(`[VERBOSE] completeness summary not written (${utils.getErrorCause(e)}); the run result still carries the signal`);
3570
+ }
3571
+ }
3572
+ }
3305
3573
  // Dedup, normalize, and write one hub's manifest. The path mirrors the
3306
3574
  // workspace tree: `<manifestDir>/<relPath>/<name>.json`, where `<name>` is
3307
3575
  // `maven_install.json` for a hub literally named `maven`, else
@@ -3332,7 +3600,7 @@ async function writeHubManifest(args) {
3332
3600
  prunedEdges
3333
3601
  };
3334
3602
  }
3335
- const fileName = repoName === 'maven' ? 'maven_install.json' : `${repoName}_maven_install.json`;
3603
+ const fileName = hubManifestFileName(repoName);
3336
3604
  const hubDir = relPath ? path.join(manifestDir, relPath) : manifestDir;
3337
3605
  fs$1.mkdirSync(hubDir, {
3338
3606
  recursive: true
@@ -3358,18 +3626,28 @@ async function writeHubManifest(args) {
3358
3626
  // On `show_extension` failure (or a parse that yields zero root hubs) under
3359
3627
  // Bzlmod, fall through to the conventional-name probe so partial discovery
3360
3628
  // is still possible.
3629
+
3361
3630
  async function discoverCandidatesForWorkspace(workspaceRoot, mode, queryOpts, verbose) {
3362
3631
  const candidates = [];
3632
+ const indeterminateProbes = [];
3363
3633
  let showExtensionSucceeded = false;
3634
+ let discoveryIndeterminate = false;
3364
3635
  if (mode.bzlmod) {
3365
3636
  const extResult = await runBazelModShowMavenExtension(queryOpts);
3366
- if (extResult.code === 0) {
3367
- // The maven extension generates a hub for EVERY module that uses it —
3368
- // the root's own `maven.install` hub(s) plus the rulesets' internal
3369
- // hubs (rules_jvm_external_deps, stardoc_maven, …). Keep only hubs
3370
- // imported by <root>; the rest are build-tooling, not the user's SBOM.
3371
- const entries = parseShowExtensionOutput(extResult.stdout);
3372
- const kept = entries.filter(e => e.importers.includes(ROOT_MODULE_IMPORTER));
3637
+ // The maven extension generates a hub for EVERY module that uses it — the
3638
+ // root's own `maven.install` hub(s) plus the rulesets' internal hubs
3639
+ // (rules_jvm_external_deps, stardoc_maven, …). Keep only hubs imported by
3640
+ // <root>; the rest are build-tooling, not the user's SBOM. On a non-zero
3641
+ // exit the output is empty, so `kept` is naturally empty too.
3642
+ const entries = parseShowExtensionOutput(extResult.stdout);
3643
+ const kept = entries.filter(e => e.importers.includes(ROOT_MODULE_IMPORTER));
3644
+ // Classify the run rather than treating ANY non-zero exit as a failure:
3645
+ // `bazel mod show_extension` exits non-zero on every bzlmod repo that
3646
+ // doesn't depend on rules_jvm_external (its argument resolution throws
3647
+ // before any Starlark runs), so a blanket non-zero=indeterminate would
3648
+ // wrongly flag the common no-Maven repo and abort the user's whole scan.
3649
+ const showExtStatus = classifyShowExtensionResult(extResult, kept.length);
3650
+ if (showExtStatus === 'defined') {
3373
3651
  candidates.push(...kept.map(e => e.name));
3374
3652
  // Gate the probe fallback on the KEPT count, not the raw parse: a
3375
3653
  // report listing only transitive ruleset hubs (all filtered out) must
@@ -3384,8 +3662,23 @@ async function discoverCandidatesForWorkspace(workspaceRoot, mode, queryOpts, ve
3384
3662
  }
3385
3663
  }
3386
3664
  }
3665
+ } else if (showExtStatus === 'indeterminate') {
3666
+ // The module graph itself could not be evaluated (Starlark eval error,
3667
+ // unbound name, syntax error, or a missing binary normalized to code
3668
+ // -1). We have NO evidence about whether custom-named maven hubs exist,
3669
+ // so mark discovery indeterminate — the run can never be reported
3670
+ // complete — while still falling through to the conventional probe for
3671
+ // best-effort coverage.
3672
+ discoveryIndeterminate = true;
3673
+ if (verbose) {
3674
+ logger.logger.log(`[VERBOSE] workspace ${workspaceRoot}: show_extension failed to evaluate the module graph (code=${extResult.code}); hub enumeration is indeterminate — falling back to conventional probe`);
3675
+ }
3387
3676
  } else if (verbose) {
3388
- logger.logger.log(`[VERBOSE] workspace ${workspaceRoot}: show_extension failed (code=${extResult.code}); falling back to conventional probe`);
3677
+ // `not-defined`: either a clean run with no root maven extension, or a
3678
+ // non-zero exit that merely means rules_jvm_external isn't in the
3679
+ // dependency graph. Both are authoritative "no maven here"; we still
3680
+ // probe conventional names for a hybrid WORKSPACE-maven repo.
3681
+ logger.logger.log(`[VERBOSE] workspace ${workspaceRoot}: show_extension reports no root maven extension (code=${extResult.code}); treating as not-defined — probing conventional hub names`);
3389
3682
  }
3390
3683
  }
3391
3684
  // Probe candidates the show_extension path could not authoritatively
@@ -3395,7 +3688,11 @@ async function discoverCandidatesForWorkspace(workspaceRoot, mode, queryOpts, ve
3395
3688
  const seen = new Set(candidates);
3396
3689
  const toProbe = (showExtensionSucceeded ? [] : [...CONVENTIONAL_MAVEN_REPO_NAMES]).filter(name => !seen.has(name));
3397
3690
  if (!toProbe.length) {
3398
- return candidates;
3691
+ return {
3692
+ candidates,
3693
+ discoveryIndeterminate,
3694
+ indeterminateProbes
3695
+ };
3399
3696
  }
3400
3697
  const probe = buildMavenProbeFor(queryOpts);
3401
3698
  for (const name of toProbe) {
@@ -3404,9 +3701,18 @@ async function discoverCandidatesForWorkspace(workspaceRoot, mode, queryOpts, ve
3404
3701
  if (status === 'populated') {
3405
3702
  candidates.push(name);
3406
3703
  seen.add(name);
3704
+ } else if (status === 'indeterminate') {
3705
+ // The probe failed for a reason we can't classify; we have no proof the
3706
+ // hub is absent. Record it so the run is flagged not-complete rather
3707
+ // than silently treating the hub as "no Maven here".
3708
+ indeterminateProbes.push(name);
3407
3709
  }
3408
3710
  }
3409
- return candidates;
3711
+ return {
3712
+ candidates,
3713
+ discoveryIndeterminate,
3714
+ indeterminateProbes
3715
+ };
3410
3716
  }
3411
3717
 
3412
3718
  // Best-effort reap of a Bazel server. Spawned with a short timeout so
@@ -3511,8 +3817,10 @@ async function extractBazelToMaven(opts) {
3511
3817
  }
3512
3818
  return {
3513
3819
  artifactCount: 0,
3820
+ complete: false,
3514
3821
  manifestPaths: [],
3515
- status: 'hardFailure'
3822
+ status: 'hardFailure',
3823
+ workspaceOutcomes: []
3516
3824
  };
3517
3825
  }
3518
3826
  logger.logger.info(`Using bazel: ${bin}`);
@@ -3533,6 +3841,16 @@ async function extractBazelToMaven(opts) {
3533
3841
  let anyRepos = false;
3534
3842
  let hubsSucceeded = 0;
3535
3843
  let hubsFailed = 0;
3844
+ // Per-workspace / per-hub analyzability breakdown backing the completeness
3845
+ // signal the CLI emits. A run is only `complete` when no workspace failed to
3846
+ // load, no probe was indeterminate, and every queried hub succeeded cleanly.
3847
+ const workspaceOutcomes = [];
3848
+ let anyIndeterminate = false;
3849
+ let anyWorkspaceLoadFailed = false;
3850
+ // A hub we deliberately skipped because a committed lockfile already covers
3851
+ // it. This is a SUCCESSFUL no-op (the server already ingests that lockfile),
3852
+ // so it must not be conflated with "discovered a hub we failed to extract".
3853
+ let anyHubCoveredByLockfile = false;
3536
3854
  try {
3537
3855
  // Always apply the default prune policy so no caller can forget it;
3538
3856
  // callers EXTEND it via ignoreDirNames/ignoreDirPrefixes.
@@ -3548,8 +3866,10 @@ async function extractBazelToMaven(opts) {
3548
3866
  logger.logger.warn(`No Bazel workspace found at ${cwd} or beneath (looked for MODULE.bazel / WORKSPACE / WORKSPACE.bazel).`);
3549
3867
  return {
3550
3868
  artifactCount: 0,
3869
+ complete: false,
3551
3870
  manifestPaths: [],
3552
- status: 'noEcosystem'
3871
+ status: 'noEcosystem',
3872
+ workspaceOutcomes: []
3553
3873
  };
3554
3874
  }
3555
3875
  if (verbose) {
@@ -3557,13 +3877,27 @@ async function extractBazelToMaven(opts) {
3557
3877
  }
3558
3878
  for (const workspaceRoot of workspaceRoots) {
3559
3879
  const relPath = path.relative(cwd, workspaceRoot);
3880
+ const hubOutcomes = [];
3560
3881
  let mode;
3561
3882
  try {
3562
3883
  mode = detectWorkspaceMode(workspaceRoot);
3563
3884
  } catch (e) {
3885
+ // A workspace we cannot even read is a load failure, NOT "no Maven
3886
+ // here": record it so the run is flagged not-complete (a hard failure
3887
+ // when nothing else was analyzable, partial otherwise) rather than
3888
+ // silently skipped.
3889
+ const reason = utils.getErrorCause(e);
3564
3890
  if (verbose) {
3565
- logger.logger.log(`[VERBOSE] workspace ${workspaceRoot}: detect failed (${utils.getErrorCause(e)}); skipping`);
3891
+ logger.logger.log(`[VERBOSE] workspace ${workspaceRoot}: load failed (${reason})`);
3566
3892
  }
3893
+ logger.logger.warn(`Workspace ${relPath || '.'}: failed to load (${reason}); it could not be analyzed.`);
3894
+ anyWorkspaceLoadFailed = true;
3895
+ workspaceOutcomes.push({
3896
+ hubs: [],
3897
+ load: 'failed',
3898
+ reason,
3899
+ relPath
3900
+ });
3567
3901
  continue;
3568
3902
  }
3569
3903
  logger.logger.info(`Workspace ${relPath || '.'}: bzlmod=${mode.bzlmod} workspace=${mode.workspace}`);
@@ -3577,11 +3911,63 @@ async function extractBazelToMaven(opts) {
3577
3911
  spawnCwd: workspaceRoot,
3578
3912
  verbose
3579
3913
  });
3580
-
3914
+ const {
3915
+ candidates,
3916
+ discoveryIndeterminate,
3917
+ indeterminateProbes
3918
+ } =
3581
3919
  // eslint-disable-next-line no-await-in-loop
3582
- const candidates = await discoverCandidatesForWorkspace(workspaceRoot, mode, queryOptsFor(outputUserRoot), verbose);
3920
+ await discoverCandidatesForWorkspace(workspaceRoot, mode, queryOptsFor(outputUserRoot), verbose);
3921
+ // Authoritative hub enumeration failed to execute (e.g. `bazel mod
3922
+ // show_extension` errored under Bzlmod): custom-named hubs may have been
3923
+ // missed, so the run can never be complete. Record it as an
3924
+ // indeterminate hub outcome under a synthetic name so the completeness
3925
+ // signal carries the gap.
3926
+ if (discoveryIndeterminate) {
3927
+ anyIndeterminate = true;
3928
+ hubOutcomes.push({
3929
+ hub: '(enumeration)',
3930
+ reason: 'show-extension-failed',
3931
+ state: 'indeterminate'
3932
+ });
3933
+ logger.logger.warn(`Workspace ${relPath || '.'}: Maven hub enumeration failed; custom-named hubs may be missing. The run is reported known-incomplete.`);
3934
+ }
3935
+ for (const indeterminate of indeterminateProbes) {
3936
+ anyIndeterminate = true;
3937
+ hubOutcomes.push({
3938
+ hub: indeterminate,
3939
+ reason: 'probe-indeterminate',
3940
+ state: 'indeterminate'
3941
+ });
3942
+ }
3583
3943
  logger.logger.info(`Workspace ${relPath || '.'}: discovered ${candidates.length} Maven repo(s): ${candidates.join(', ') || '(none)'}`);
3584
3944
  for (const repoName of candidates) {
3945
+ // Committed-lockfile gate: the server-side walker already ingests any
3946
+ // committed maven_install.json / <hub>_maven_install.json under the
3947
+ // workspace; the CLI's synthetic manifest is the COMPLEMENT, not a
3948
+ // duplicate. Skip emitting when a committed lockfile already covers
3949
+ // this hub. A skip is a successful no-op, so it runs BEFORE
3950
+ // `anyRepos` is flipped (which marks "a hub we needed to extract").
3951
+ const committed = committedLockfileCovers({
3952
+ fileName: hubManifestFileName(repoName),
3953
+ manifestDir,
3954
+ workspaceRoot
3955
+ });
3956
+ if (committed) {
3957
+ anyHubCoveredByLockfile = true;
3958
+ logger.logger.info(`@${repoName}: committed lockfile already covers this hub (${path.relative(cwd, committed) || committed}); skipping synthetic manifest.`);
3959
+ hubOutcomes.push({
3960
+ hub: repoName,
3961
+ reason: 'committed-lockfile',
3962
+ state: 'skipped-lockfile'
3963
+ });
3964
+ if (verbose) {
3965
+ logger.logger.log(`[VERBOSE] @${repoName}: skipped (committed lockfile at ${committed})`);
3966
+ }
3967
+ continue;
3968
+ }
3969
+ // We are about to extract this hub: it is a real candidate we must
3970
+ // analyze, so mark the ecosystem present.
3585
3971
  anyRepos = true;
3586
3972
  if (verbose) {
3587
3973
  logger.logger.log(`[VERBOSE] workspace ${relPath || '.'}: running metadata cquery for @${repoName} (timeout ${perRepoTimeoutMs}ms)`);
@@ -3597,6 +3983,11 @@ async function extractBazelToMaven(opts) {
3597
3983
  if (result.status === 'timeout') {
3598
3984
  logger.logger.warn(`@${repoName}: cquery timed out after ${perRepoTimeoutMs}ms; reaping server`);
3599
3985
  hubsFailed += 1;
3986
+ hubOutcomes.push({
3987
+ hub: repoName,
3988
+ reason: 'cquery-timeout',
3989
+ state: 'failed'
3990
+ });
3600
3991
  // eslint-disable-next-line no-await-in-loop
3601
3992
  await reapBazelServer(bin, outputUserRoot, verbose);
3602
3993
  // eslint-disable-next-line no-await-in-loop
@@ -3611,6 +4002,11 @@ async function extractBazelToMaven(opts) {
3611
4002
  if (result.status === 'error') {
3612
4003
  logger.logger.warn(`@${repoName}: cquery failed; skipping this hub`);
3613
4004
  hubsFailed += 1;
4005
+ hubOutcomes.push({
4006
+ hub: repoName,
4007
+ reason: 'cquery-error',
4008
+ state: 'failed'
4009
+ });
3614
4010
  continue;
3615
4011
  }
3616
4012
  // A scan must never silently upload a graph missing edges it knows
@@ -3642,6 +4038,11 @@ async function extractBazelToMaven(opts) {
3642
4038
  // discard the manifests other hubs already produced.
3643
4039
  logger.logger.warn(`@${repoName}: failed to write manifest (${utils.getErrorCause(e)}); skipping this hub`);
3644
4040
  hubsFailed += 1;
4041
+ hubOutcomes.push({
4042
+ hub: repoName,
4043
+ reason: 'manifest-write-failed',
4044
+ state: 'failed'
4045
+ });
3645
4046
  continue;
3646
4047
  }
3647
4048
  if (written.droppedArtifacts.length) {
@@ -3657,8 +4058,17 @@ async function extractBazelToMaven(opts) {
3657
4058
  totalArtifacts += written.artifactCount;
3658
4059
  if (hubPartial) {
3659
4060
  hubsFailed += 1;
4061
+ hubOutcomes.push({
4062
+ hub: repoName,
4063
+ reason: 'incomplete-graph',
4064
+ state: 'failed'
4065
+ });
3660
4066
  } else {
3661
4067
  hubsSucceeded += 1;
4068
+ hubOutcomes.push({
4069
+ hub: repoName,
4070
+ state: 'populated'
4071
+ });
3662
4072
  }
3663
4073
  if (verbose) {
3664
4074
  logger.logger.log(`[VERBOSE] @${repoName}: status=${result.status}, ${written.artifactCount} artifact(s) -> ${written.manifestPath}`);
@@ -3668,39 +4078,109 @@ async function extractBazelToMaven(opts) {
3668
4078
  // edges were dropped the partial signal still applies.
3669
4079
  if (hubPartial) {
3670
4080
  hubsFailed += 1;
4081
+ hubOutcomes.push({
4082
+ hub: repoName,
4083
+ reason: 'incomplete-graph',
4084
+ state: 'failed'
4085
+ });
4086
+ } else {
4087
+ hubOutcomes.push({
4088
+ hub: repoName,
4089
+ state: 'empty'
4090
+ });
3671
4091
  }
3672
4092
  if (verbose) {
3673
4093
  logger.logger.log(`[VERBOSE] @${repoName}: status=${result.status} (no manifest written)`);
3674
4094
  }
3675
4095
  }
3676
4096
  }
4097
+ workspaceOutcomes.push({
4098
+ hubs: hubOutcomes,
4099
+ load: 'loaded',
4100
+ relPath
4101
+ });
4102
+ if (verbose) {
4103
+ for (const outcome of hubOutcomes) {
4104
+ logger.logger.log(`[VERBOSE] workspace ${relPath || '.'} hub @${outcome.hub}: ${outcome.state}${outcome.reason ? ` (${outcome.reason})` : ''}`);
4105
+ }
4106
+ }
3677
4107
  }
3678
4108
  if (!manifestPaths.length) {
3679
- if (!anyRepos) {
4109
+ // Every discovered hub was already covered by a committed lockfile and
4110
+ // nothing else needed extraction: writing zero synthetic manifests is
4111
+ // the CORRECT complement, not a failure. The run is complete only when
4112
+ // no workspace failed to load and no probe was indeterminate.
4113
+ if (anyHubCoveredByLockfile && !anyRepos && !anyWorkspaceLoadFailed && !anyIndeterminate) {
4114
+ logger.logger.success('All discovered Maven hub(s) are already covered by committed lockfiles; nothing to generate.');
4115
+ await writeCompletenessSummary({
4116
+ artifactCount: 0,
4117
+ complete: true,
4118
+ manifestDir,
4119
+ manifestPaths: [],
4120
+ status: 'complete',
4121
+ verbose,
4122
+ workspaceOutcomes
4123
+ });
4124
+ return {
4125
+ artifactCount: 0,
4126
+ complete: true,
4127
+ manifestPaths: [],
4128
+ status: 'complete',
4129
+ workspaceOutcomes
4130
+ };
4131
+ }
4132
+ // Nothing was emitted. If nothing was analyzable at all (no repos to
4133
+ // extract, no committed-lockfile coverage, no workspace load failure, no
4134
+ // indeterminate probe) this is a genuine absence; otherwise it's a hard
4135
+ // failure — something was present but we could not extract it.
4136
+ if (!anyRepos && !anyWorkspaceLoadFailed && !anyIndeterminate && !anyHubCoveredByLockfile) {
3680
4137
  if (verbose) {
3681
4138
  logger.logger.info('No Maven artifacts extracted. failureCategory=no-supported-ecosystem');
3682
4139
  }
3683
4140
  return {
3684
4141
  artifactCount: 0,
4142
+ complete: false,
3685
4143
  manifestPaths: [],
3686
- status: 'noEcosystem'
4144
+ status: 'noEcosystem',
4145
+ workspaceOutcomes
3687
4146
  };
3688
4147
  }
3689
- logger.logger.fail('Discovered Maven repo(s) but wrote zero manifests. failureCategory=ecosystem-detected-but-empty');
4148
+ logger.logger.fail('Discovered or partially analyzed Maven workspace(s) but wrote zero manifests. failureCategory=ecosystem-detected-but-empty');
4149
+ await writeCompletenessSummary({
4150
+ artifactCount: 0,
4151
+ complete: false,
4152
+ manifestDir,
4153
+ manifestPaths: [],
4154
+ status: 'hardFailure',
4155
+ verbose,
4156
+ workspaceOutcomes
4157
+ });
3690
4158
  return {
3691
4159
  artifactCount: 0,
4160
+ complete: false,
3692
4161
  manifestPaths: [],
3693
- status: 'hardFailure'
4162
+ status: 'hardFailure',
4163
+ workspaceOutcomes
3694
4164
  };
3695
4165
  }
3696
- const status = hubsFailed ? 'partial' : 'complete';
4166
+
4167
+ // Manifests were written, so the run is not a hard failure. It is only
4168
+ // `complete` when every queried hub succeeded cleanly AND no workspace
4169
+ // failed to load AND no probe was indeterminate; any of those means the
4170
+ // emitted SBOM is known-incomplete (partial under the hybrid rule).
4171
+ const knownIncomplete = hubsFailed > 0 || anyWorkspaceLoadFailed || anyIndeterminate;
4172
+ const status = knownIncomplete ? 'partial' : 'complete';
3697
4173
  if (status === 'complete') {
3698
4174
  logger.logger.success(`Wrote ${manifestPaths.length} manifest(s), ${totalArtifacts} artifact(s) total.`);
3699
4175
  } else {
3700
- logger.logger.warn(`Wrote ${manifestPaths.length} manifest(s), ${totalArtifacts} artifact(s) total partial run: ${hubsSucceeded} hub(s) succeeded, ${hubsFailed} failed or incomplete.`);
4176
+ const loadNote = anyWorkspaceLoadFailed ? ', at least one workspace failed to load' : '';
4177
+ const indetNote = anyIndeterminate ? ', at least one hub could not be classified' : '';
4178
+ logger.logger.warn(`Wrote ${manifestPaths.length} manifest(s), ${totalArtifacts} artifact(s) total — partial run: ${hubsSucceeded} hub(s) succeeded, ${hubsFailed} failed or incomplete${loadNote}${indetNote}. The uploaded SBOM is known-incomplete.`);
3701
4179
  }
3702
4180
  if (verbose) {
3703
4181
  logger.logger.log('[VERBOSE] outputs:', {
4182
+ anyIndeterminate,
4183
+ anyWorkspaceLoadFailed,
3704
4184
  artifactCount: totalArtifacts,
3705
4185
  hubsFailed,
3706
4186
  hubsSucceeded,
@@ -3709,10 +4189,21 @@ async function extractBazelToMaven(opts) {
3709
4189
  status
3710
4190
  });
3711
4191
  }
4192
+ await writeCompletenessSummary({
4193
+ artifactCount: totalArtifacts,
4194
+ complete: status === 'complete',
4195
+ manifestDir,
4196
+ manifestPaths,
4197
+ status,
4198
+ verbose,
4199
+ workspaceOutcomes
4200
+ });
3712
4201
  return {
3713
4202
  artifactCount: totalArtifacts,
4203
+ complete: status === 'complete',
3714
4204
  manifestPaths,
3715
- status
4205
+ status,
4206
+ workspaceOutcomes
3716
4207
  };
3717
4208
  } catch (e) {
3718
4209
  logger.logger.fail(`Unexpected error in bazel2maven: ${utils.getErrorCause(e)}`);
@@ -3725,8 +4216,10 @@ async function extractBazelToMaven(opts) {
3725
4216
  }
3726
4217
  return {
3727
4218
  artifactCount: 0,
4219
+ complete: false,
3728
4220
  manifestPaths: [],
3729
- status: 'hardFailure'
4221
+ status: 'hardFailure',
4222
+ workspaceOutcomes
3730
4223
  };
3731
4224
  } finally {
3732
4225
  for (const dir of mintedRoots) {
@@ -4429,7 +4922,13 @@ async function generateAutoManifest({
4429
4922
  if (mavenResult.status === 'complete' || mavenResult.status === 'partial') {
4430
4923
  generatedFiles.push(...mavenResult.manifestPaths);
4431
4924
  if (mavenResult.status === 'partial') {
4432
- logger.logger.warn(`Bazel Maven manifest generation was partial (${mavenResult.manifestPaths.length} manifest(s) written); some hubs failed or had incomplete dependency graphs. Uploading what was generated.`);
4925
+ // Hybrid handling: still upload the partial SBOM, but be loud AND
4926
+ // leave a machine-readable trail. The extractor writes a completeness
4927
+ // summary (complete=false + per-hub/workspace breakdown) into the
4928
+ // manifest dir; that summary is the structured signal a downstream
4929
+ // consumer reads to know this upload is known-incomplete.
4930
+ const incomplete = mavenResult.workspaceOutcomes.flatMap(w => w.load === 'failed' ? [`${w.relPath || '.'} (workspace load failed)`] : w.hubs.filter(h => h.state === 'failed' || h.state === 'indeterminate').map(h => `${w.relPath || '.'}@${h.hub} (${h.state})`)).join(', ');
4931
+ logger.logger.warn(`WARNING: Bazel Maven manifest generation was PARTIAL (${mavenResult.manifestPaths.length} manifest(s) written); the uploaded SBOM is known-incomplete and may under-report dependencies. Incomplete: ${incomplete || 'see completeness summary'}. Uploading what was generated.`);
4433
4932
  }
4434
4933
  } else {
4435
4934
  logger.logger.info('No supported Bazel Maven ecosystem detected.');
@@ -5168,7 +5667,19 @@ async function handleConfigGet({
5168
5667
  key,
5169
5668
  outputKind
5170
5669
  }) {
5171
- const result = utils.getConfigValue(key);
5670
+ // A Socket API token supplied via the environment (SOCKET_CLI_API_TOKEN /
5671
+ // SOCKET_SECURITY_API_TOKEN and legacy aliases, all aggregated into
5672
+ // constants.ENV.SOCKET_CLI_API_TOKEN) takes precedence over any persisted or
5673
+ // --config value. The env token is no longer mirrored into the in-memory
5674
+ // config (so unrelated keys stay persistable via `config set`), so surface it
5675
+ // explicitly here to preserve "env token wins" for `config get apiToken`.
5676
+ const {
5677
+ ENV
5678
+ } = constants.default;
5679
+ const result = key === constants.CONFIG_KEY_API_TOKEN && !ENV.SOCKET_CLI_NO_API_TOKEN && ENV.SOCKET_CLI_API_TOKEN ? {
5680
+ ok: true,
5681
+ data: ENV.SOCKET_CLI_API_TOKEN
5682
+ } : utils.getConfigValue(key);
5172
5683
  await outputConfigGet(key, result, outputKind);
5173
5684
  }
5174
5685
 
@@ -5393,18 +5904,10 @@ async function outputConfigSet(result, outputKind) {
5393
5904
  logger.logger.log(`# Update config`);
5394
5905
  logger.logger.log('');
5395
5906
  logger.logger.log(result.message);
5396
- if (result.data) {
5397
- logger.logger.log('');
5398
- logger.logger.log(result.data);
5399
- }
5400
- } else {
5401
- logger.logger.log(`OK`);
5402
- logger.logger.log(result.message);
5403
- if (result.data) {
5404
- logger.logger.log('');
5405
- logger.logger.log(result.data);
5406
- }
5907
+ return;
5407
5908
  }
5909
+ logger.logger.log(`OK`);
5910
+ logger.logger.log(result.message);
5408
5911
  }
5409
5912
 
5410
5913
  async function handleConfigSet({
@@ -5419,11 +5922,24 @@ async function handleConfigSet({
5419
5922
  outputKind
5420
5923
  });
5421
5924
  const result = utils.updateConfigValue(key, value);
5422
- require$$9.debugFn('notice', `Config update ${result.ok ? 'succeeded' : 'failed'}`);
5925
+
5926
+ // `config set` is a one-shot command: an in-memory-only change is a no-op
5927
+ // because the process exits before anything reads it. updateConfigValue only
5928
+ // populates `data` when the config is read-only (a full --config /
5929
+ // SOCKET_CLI_CONFIG / SOCKET_CLI_NO_API_TOKEN override), so in that case
5930
+ // report a failure instead of a misleading success.
5931
+ const outcome = result.ok && result.data ? {
5932
+ ok: false,
5933
+ code: 1,
5934
+ message: `Config key '${key}' was not saved`,
5935
+ cause: result.data
5936
+ } : result;
5937
+ require$$9.debugFn('notice', `Config update ${outcome.ok ? 'succeeded' : 'failed'}`);
5423
5938
  require$$9.debugDir('inspect', {
5939
+ outcome,
5424
5940
  result
5425
5941
  });
5426
- await outputConfigSet(result, outputKind);
5942
+ await outputConfigSet(outcome, outputKind);
5427
5943
  }
5428
5944
 
5429
5945
  const CMD_NAME$u = 'set';
@@ -7246,7 +7762,7 @@ async function setupTabCompletion(targetName) {
7246
7762
  };
7247
7763
  }
7248
7764
  function getTabCompletionScriptRaw() {
7249
- const sourceDir = path.dirname(require$$0.fileURLToPath((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
7765
+ const sourceDir = path.dirname(require$$0$1.fileURLToPath((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
7250
7766
  const sourcePath = path.join(sourceDir, 'socket-completion.bash');
7251
7767
  if (!fs$1.existsSync(sourcePath)) {
7252
7768
  return {
@@ -9080,6 +9596,10 @@ const config$e = {
9080
9596
  type: 'string',
9081
9597
  description: 'Output directory for generated manifests; default: ./.socket/bazel-manifests/'
9082
9598
  },
9599
+ perRepoTimeout: {
9600
+ type: 'number',
9601
+ description: 'Per-hub bazel cquery timeout in milliseconds; default: 120000'
9602
+ },
9083
9603
  verbose: {
9084
9604
  type: 'boolean',
9085
9605
  description: 'Emit bounded Bazel diagnostics with argv, duration, exit status, and output sizes'
@@ -9122,6 +9642,12 @@ const config$e = {
9122
9642
  $ ${command} --bazel=/usr/local/bin/bazelisk .
9123
9643
  `
9124
9644
  };
9645
+
9646
+ // The explicit `socket manifest bazel` command gives each hub more time than
9647
+ // the auto-manifest path: a user running it directly is waiting on this one
9648
+ // extraction, whereas auto-manifest must not stall the wider scan. Auto's
9649
+ // shorter default lives in extract_bazel_to_maven.mts.
9650
+ const EXPLICIT_PER_REPO_TIMEOUT_MS = 120_000;
9125
9651
  const cmdManifestBazel = {
9126
9652
  description: config$e.description,
9127
9653
  hidden: config$e.hidden,
@@ -9145,9 +9671,17 @@ function evaluateEcosystemOutcomes(outcomes, isExplicit) {
9145
9671
  const produced = outcomes.filter(o => (o.status === 'complete' || o.status === 'partial') && o.manifestPaths.length > 0);
9146
9672
  const hardFailures = outcomes.filter(o => o.status === 'hardFailure');
9147
9673
  const noDiscoveries = outcomes.filter(o => o.status === 'noEcosystem');
9674
+
9675
+ // Surface a machine-readable completeness signal for every produced
9676
+ // ecosystem so a partial upload is never presented as a complete one. The
9677
+ // per-workspace / per-hub detail is written to the manifest dir's
9678
+ // completeness summary by the extractor; this is the human-facing echo.
9679
+ for (const outcome of produced) {
9680
+ logger.logger.info(`Bazel ${outcome.ecosystem} extraction status: ${outcome.status} (complete=${outcome.complete}).`);
9681
+ }
9148
9682
  for (const partial of outcomes) {
9149
9683
  if (partial.status === 'partial') {
9150
- logger.logger.warn(`Bazel ${partial.ecosystem} manifest generation was partial; the uploaded SBOM is known-incomplete.`);
9684
+ logger.logger.warn(`WARNING: Bazel ${partial.ecosystem} manifest generation was PARTIAL. The uploaded SBOM is known-incomplete and may under-report dependencies; review the completeness summary before relying on the results.`);
9151
9685
  }
9152
9686
  }
9153
9687
  if (!isExplicit) {
@@ -9183,17 +9717,20 @@ function evaluateEcosystemOutcomes(outcomes, isExplicit) {
9183
9717
  function pypiOutcome(result) {
9184
9718
  if (result.noEcosystemFound) {
9185
9719
  return {
9720
+ complete: false,
9186
9721
  manifestPaths: [],
9187
9722
  status: 'noEcosystem'
9188
9723
  };
9189
9724
  }
9190
9725
  if (result.ok && result.manifestPath) {
9191
9726
  return {
9727
+ complete: true,
9192
9728
  manifestPaths: [result.manifestPath],
9193
9729
  status: 'complete'
9194
9730
  };
9195
9731
  }
9196
9732
  return {
9733
+ complete: false,
9197
9734
  manifestPaths: [],
9198
9735
  status: 'hardFailure'
9199
9736
  };
@@ -9232,6 +9769,7 @@ async function run$F(argv, importMeta, {
9232
9769
  out,
9233
9770
  verbose
9234
9771
  } = cli.flags;
9772
+ let perRepoTimeout = cli.flags['perRepoTimeout'];
9235
9773
 
9236
9774
  // Set defaults for any flag/arg that is not given. Check socket.json first.
9237
9775
  if (!bazel) {
@@ -9279,6 +9817,16 @@ async function run$F(argv, importMeta, {
9279
9817
  verbose = false;
9280
9818
  }
9281
9819
  }
9820
+ if (perRepoTimeout === undefined) {
9821
+ if (sockJson.defaults?.manifest?.bazel?.perRepoTimeout !== undefined) {
9822
+ perRepoTimeout = sockJson.defaults?.manifest?.bazel?.perRepoTimeout;
9823
+ logger.logger.info(`Using default --per-repo-timeout from ${constants.SOCKET_JSON}:`, perRepoTimeout);
9824
+ } else {
9825
+ // Explicit invocation default; longer than the auto-manifest default
9826
+ // because the user is waiting on this single extraction.
9827
+ perRepoTimeout = EXPLICIT_PER_REPO_TIMEOUT_MS;
9828
+ }
9829
+ }
9282
9830
  if (verbose) {
9283
9831
  logger.logger.group('- ', parentName, config$e.commandName, ':');
9284
9832
  logger.logger.group('- flags:', cli.flags);
@@ -9327,9 +9875,11 @@ async function run$F(argv, importMeta, {
9327
9875
  bin: bazel,
9328
9876
  cwd,
9329
9877
  out: out,
9878
+ perRepoTimeoutMs: perRepoTimeout,
9330
9879
  verbose: Boolean(verbose)
9331
9880
  });
9332
9881
  outcomes.push({
9882
+ complete: mavenResult.complete,
9333
9883
  ecosystem: 'maven',
9334
9884
  manifestPaths: mavenResult.manifestPaths,
9335
9885
  status: mavenResult.status
@@ -11004,7 +11554,7 @@ async function run$y(argv, importMeta, {
11004
11554
  });
11005
11555
  }
11006
11556
 
11007
- const require$5 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
11557
+ const require$5 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
11008
11558
  const CMD_NAME$q = constants.NPM;
11009
11559
  const description$w = 'Wraps npm with Socket security scanning';
11010
11560
  const hidden$q = false;
@@ -11090,7 +11640,7 @@ async function run$x(argv, importMeta, context) {
11090
11640
  await spawnPromise;
11091
11641
  }
11092
11642
 
11093
- const require$4 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
11643
+ const require$4 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
11094
11644
  const CMD_NAME$p = constants.NPX;
11095
11645
  const description$v = 'Wraps npx with Socket security scanning';
11096
11646
  const hidden$p = false;
@@ -13819,7 +14369,7 @@ async function run$m(argv, _importMeta, _context) {
13819
14369
  }
13820
14370
  }
13821
14371
 
13822
- const require$3 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
14372
+ const require$3 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
13823
14373
  const CMD_NAME$g = constants.PNPM;
13824
14374
  const description$j = 'Wraps pnpm with Socket security scanning';
13825
14375
  const hidden$g = true;
@@ -15650,6 +16200,13 @@ async function run$d(argv, importMeta, {
15650
16200
  pendingHead: Boolean(pendingHead),
15651
16201
  pullRequest: Number(pullRequest),
15652
16202
  reach: {
16203
+ // Build-tool config for the reach-time resolution, mapped from socket.json
16204
+ // (per-ecosystem). Best-effort on plain --reach; under --auto-manifest the
16205
+ // config carries top-level failOnBuildToolError=true (fail-closed). Only
16206
+ // built when reachability runs.
16207
+ autoManifestConfig: reach ? utils.buildAutoManifestConfig(sockJson, {
16208
+ autoManifest: Boolean(autoManifest)
16209
+ }) : undefined,
15653
16210
  excludePaths,
15654
16211
  reachAnalysisMemoryLimit: Number(reachAnalysisMemoryLimit),
15655
16212
  reachAnalysisTimeout: Number(reachAnalysisTimeout),
@@ -18608,7 +19165,7 @@ async function fetchThreatFeed({
18608
19165
  return await utils.queryApiSafeJson(`orgs/${orgSlug}/threat-feed?${queryParams}`, 'the Threat Feed data');
18609
19166
  }
18610
19167
 
18611
- const require$2 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
19168
+ const require$2 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
18612
19169
  async function outputThreatFeed(result, outputKind) {
18613
19170
  if (!result.ok) {
18614
19171
  process.exitCode = result.code ?? 1;
@@ -19377,7 +19934,7 @@ async function run$1(argv, importMeta, {
19377
19934
  }
19378
19935
  }
19379
19936
 
19380
- const require$1 = require$$5.createRequire((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
19937
+ const require$1 = require$$5.createRequire((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
19381
19938
  const CMD_NAME = constants.YARN;
19382
19939
  const description = 'Wraps yarn with Socket security scanning';
19383
19940
  const hidden = true;
@@ -19572,7 +20129,7 @@ const rootAliases = {
19572
20129
  }
19573
20130
  };
19574
20131
 
19575
- const __filename$1 = require$$0.fileURLToPath((typeof document === 'undefined' ? require$$0.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
20132
+ const __filename$1 = require$$0$1.fileURLToPath((typeof document === 'undefined' ? require$$0$1.pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
19576
20133
 
19577
20134
  // Capture CLI start time at module level for global error handlers.
19578
20135
  const cliStartTime = Date.now();
@@ -19601,7 +20158,7 @@ void (async () => {
19601
20158
  name: constants.default.SOCKET_CLI_BIN_NAME,
19602
20159
  argv: process.argv.slice(2),
19603
20160
  importMeta: {
19604
- url: `${require$$0.pathToFileURL(__filename$1)}`
20161
+ url: `${require$$0$1.pathToFileURL(__filename$1)}`
19605
20162
  },
19606
20163
  subcommands: rootCommands
19607
20164
  }, {
@@ -19644,7 +20201,7 @@ void (async () => {
19644
20201
  autoVersion: false,
19645
20202
  flags: {},
19646
20203
  importMeta: {
19647
- url: `${require$$0.pathToFileURL(__filename$1)}`
20204
+ url: `${require$$0$1.pathToFileURL(__filename$1)}`
19648
20205
  }
19649
20206
  });
19650
20207
  return !!cli.flags['json'];
@@ -19709,5 +20266,5 @@ process.on('unhandledRejection', async (reason, promise) => {
19709
20266
  // eslint-disable-next-line n/no-process-exit
19710
20267
  process.exit(1);
19711
20268
  });
19712
- //# debugId=b1bb7e64-091d-4be2-bb99-bb2297bb5ec2
20269
+ //# debugId=85257911-3f47-4452-8e33-51ee5c9c6b59
19713
20270
  //# sourceMappingURL=cli.js.map