socket 1.1.118 → 1.1.120
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.
- package/CHANGELOG.md +13 -1
- package/README.md +1 -0
- package/dist/cli.js +622 -82
- package/dist/cli.js.map +1 -1
- package/dist/constants.js +4 -4
- package/dist/constants.js.map +1 -1
- package/dist/tsconfig.dts.tsbuildinfo +1 -1
- package/dist/types/commands/manifest/bazel/bazel-cquery.d.mts.map +1 -1
- package/dist/types/commands/manifest/bazel/bazel-query-runner.d.mts.map +1 -1
- package/dist/types/commands/manifest/bazel/bazel-repo-discovery.d.mts +28 -1
- package/dist/types/commands/manifest/bazel/bazel-repo-discovery.d.mts.map +1 -1
- package/dist/types/commands/manifest/bazel/cmd-manifest-bazel.d.mts +5 -0
- package/dist/types/commands/manifest/bazel/cmd-manifest-bazel.d.mts.map +1 -1
- package/dist/types/commands/manifest/bazel/extract_bazel_to_maven.d.mts +43 -3
- package/dist/types/commands/manifest/bazel/extract_bazel_to_maven.d.mts.map +1 -1
- package/dist/types/commands/manifest/generate_auto_manifest.d.mts.map +1 -1
- package/dist/types/commands/scan/cmd-scan-create.d.mts.map +1 -1
- package/dist/types/commands/scan/perform-reachability-analysis.d.mts +2 -0
- package/dist/types/commands/scan/perform-reachability-analysis.d.mts.map +1 -1
- package/dist/types/utils/auto-manifest-config.d.mts +55 -0
- package/dist/types/utils/auto-manifest-config.d.mts.map +1 -0
- package/dist/types/utils/dlx.d.mts +4 -3
- package/dist/types/utils/dlx.d.mts.map +1 -1
- package/dist/types/utils/socket-json.d.mts +1 -0
- package/dist/types/utils/socket-json.d.mts.map +1 -1
- package/dist/utils.js +136 -22
- package/dist/utils.js.map +1 -1
- 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
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
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
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
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',
|
|
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
|
-
|
|
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
|
|
3093
|
+
// name isn't declared. Treat as not-defined.
|
|
2954
3094
|
if (result.code === 0) {
|
|
2955
3095
|
return 'not-defined';
|
|
2956
3096
|
}
|
|
2957
|
-
//
|
|
2958
|
-
//
|
|
2959
|
-
|
|
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}:
|
|
3119
|
+
logger.logger.log(`[VERBOSE] discovery: probe @${repoName}: indeterminate (probe threw: ${e instanceof Error ? e.message : String(e)})`);
|
|
2973
3120
|
}
|
|
2974
|
-
return '
|
|
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
|
|
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
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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}:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.');
|
|
@@ -7246,7 +7745,7 @@ async function setupTabCompletion(targetName) {
|
|
|
7246
7745
|
};
|
|
7247
7746
|
}
|
|
7248
7747
|
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))));
|
|
7748
|
+
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
7749
|
const sourcePath = path.join(sourceDir, 'socket-completion.bash');
|
|
7251
7750
|
if (!fs$1.existsSync(sourcePath)) {
|
|
7252
7751
|
return {
|
|
@@ -9080,6 +9579,10 @@ const config$e = {
|
|
|
9080
9579
|
type: 'string',
|
|
9081
9580
|
description: 'Output directory for generated manifests; default: ./.socket/bazel-manifests/'
|
|
9082
9581
|
},
|
|
9582
|
+
perRepoTimeout: {
|
|
9583
|
+
type: 'number',
|
|
9584
|
+
description: 'Per-hub bazel cquery timeout in milliseconds; default: 120000'
|
|
9585
|
+
},
|
|
9083
9586
|
verbose: {
|
|
9084
9587
|
type: 'boolean',
|
|
9085
9588
|
description: 'Emit bounded Bazel diagnostics with argv, duration, exit status, and output sizes'
|
|
@@ -9122,6 +9625,12 @@ const config$e = {
|
|
|
9122
9625
|
$ ${command} --bazel=/usr/local/bin/bazelisk .
|
|
9123
9626
|
`
|
|
9124
9627
|
};
|
|
9628
|
+
|
|
9629
|
+
// The explicit `socket manifest bazel` command gives each hub more time than
|
|
9630
|
+
// the auto-manifest path: a user running it directly is waiting on this one
|
|
9631
|
+
// extraction, whereas auto-manifest must not stall the wider scan. Auto's
|
|
9632
|
+
// shorter default lives in extract_bazel_to_maven.mts.
|
|
9633
|
+
const EXPLICIT_PER_REPO_TIMEOUT_MS = 120_000;
|
|
9125
9634
|
const cmdManifestBazel = {
|
|
9126
9635
|
description: config$e.description,
|
|
9127
9636
|
hidden: config$e.hidden,
|
|
@@ -9145,9 +9654,17 @@ function evaluateEcosystemOutcomes(outcomes, isExplicit) {
|
|
|
9145
9654
|
const produced = outcomes.filter(o => (o.status === 'complete' || o.status === 'partial') && o.manifestPaths.length > 0);
|
|
9146
9655
|
const hardFailures = outcomes.filter(o => o.status === 'hardFailure');
|
|
9147
9656
|
const noDiscoveries = outcomes.filter(o => o.status === 'noEcosystem');
|
|
9657
|
+
|
|
9658
|
+
// Surface a machine-readable completeness signal for every produced
|
|
9659
|
+
// ecosystem so a partial upload is never presented as a complete one. The
|
|
9660
|
+
// per-workspace / per-hub detail is written to the manifest dir's
|
|
9661
|
+
// completeness summary by the extractor; this is the human-facing echo.
|
|
9662
|
+
for (const outcome of produced) {
|
|
9663
|
+
logger.logger.info(`Bazel ${outcome.ecosystem} extraction status: ${outcome.status} (complete=${outcome.complete}).`);
|
|
9664
|
+
}
|
|
9148
9665
|
for (const partial of outcomes) {
|
|
9149
9666
|
if (partial.status === 'partial') {
|
|
9150
|
-
logger.logger.warn(`Bazel ${partial.ecosystem} manifest generation was
|
|
9667
|
+
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
9668
|
}
|
|
9152
9669
|
}
|
|
9153
9670
|
if (!isExplicit) {
|
|
@@ -9183,17 +9700,20 @@ function evaluateEcosystemOutcomes(outcomes, isExplicit) {
|
|
|
9183
9700
|
function pypiOutcome(result) {
|
|
9184
9701
|
if (result.noEcosystemFound) {
|
|
9185
9702
|
return {
|
|
9703
|
+
complete: false,
|
|
9186
9704
|
manifestPaths: [],
|
|
9187
9705
|
status: 'noEcosystem'
|
|
9188
9706
|
};
|
|
9189
9707
|
}
|
|
9190
9708
|
if (result.ok && result.manifestPath) {
|
|
9191
9709
|
return {
|
|
9710
|
+
complete: true,
|
|
9192
9711
|
manifestPaths: [result.manifestPath],
|
|
9193
9712
|
status: 'complete'
|
|
9194
9713
|
};
|
|
9195
9714
|
}
|
|
9196
9715
|
return {
|
|
9716
|
+
complete: false,
|
|
9197
9717
|
manifestPaths: [],
|
|
9198
9718
|
status: 'hardFailure'
|
|
9199
9719
|
};
|
|
@@ -9232,6 +9752,7 @@ async function run$F(argv, importMeta, {
|
|
|
9232
9752
|
out,
|
|
9233
9753
|
verbose
|
|
9234
9754
|
} = cli.flags;
|
|
9755
|
+
let perRepoTimeout = cli.flags['perRepoTimeout'];
|
|
9235
9756
|
|
|
9236
9757
|
// Set defaults for any flag/arg that is not given. Check socket.json first.
|
|
9237
9758
|
if (!bazel) {
|
|
@@ -9279,6 +9800,16 @@ async function run$F(argv, importMeta, {
|
|
|
9279
9800
|
verbose = false;
|
|
9280
9801
|
}
|
|
9281
9802
|
}
|
|
9803
|
+
if (perRepoTimeout === undefined) {
|
|
9804
|
+
if (sockJson.defaults?.manifest?.bazel?.perRepoTimeout !== undefined) {
|
|
9805
|
+
perRepoTimeout = sockJson.defaults?.manifest?.bazel?.perRepoTimeout;
|
|
9806
|
+
logger.logger.info(`Using default --per-repo-timeout from ${constants.SOCKET_JSON}:`, perRepoTimeout);
|
|
9807
|
+
} else {
|
|
9808
|
+
// Explicit invocation default; longer than the auto-manifest default
|
|
9809
|
+
// because the user is waiting on this single extraction.
|
|
9810
|
+
perRepoTimeout = EXPLICIT_PER_REPO_TIMEOUT_MS;
|
|
9811
|
+
}
|
|
9812
|
+
}
|
|
9282
9813
|
if (verbose) {
|
|
9283
9814
|
logger.logger.group('- ', parentName, config$e.commandName, ':');
|
|
9284
9815
|
logger.logger.group('- flags:', cli.flags);
|
|
@@ -9327,9 +9858,11 @@ async function run$F(argv, importMeta, {
|
|
|
9327
9858
|
bin: bazel,
|
|
9328
9859
|
cwd,
|
|
9329
9860
|
out: out,
|
|
9861
|
+
perRepoTimeoutMs: perRepoTimeout,
|
|
9330
9862
|
verbose: Boolean(verbose)
|
|
9331
9863
|
});
|
|
9332
9864
|
outcomes.push({
|
|
9865
|
+
complete: mavenResult.complete,
|
|
9333
9866
|
ecosystem: 'maven',
|
|
9334
9867
|
manifestPaths: mavenResult.manifestPaths,
|
|
9335
9868
|
status: mavenResult.status
|
|
@@ -11004,7 +11537,7 @@ async function run$y(argv, importMeta, {
|
|
|
11004
11537
|
});
|
|
11005
11538
|
}
|
|
11006
11539
|
|
|
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)));
|
|
11540
|
+
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
11541
|
const CMD_NAME$q = constants.NPM;
|
|
11009
11542
|
const description$w = 'Wraps npm with Socket security scanning';
|
|
11010
11543
|
const hidden$q = false;
|
|
@@ -11090,7 +11623,7 @@ async function run$x(argv, importMeta, context) {
|
|
|
11090
11623
|
await spawnPromise;
|
|
11091
11624
|
}
|
|
11092
11625
|
|
|
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)));
|
|
11626
|
+
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
11627
|
const CMD_NAME$p = constants.NPX;
|
|
11095
11628
|
const description$v = 'Wraps npx with Socket security scanning';
|
|
11096
11629
|
const hidden$p = false;
|
|
@@ -13819,7 +14352,7 @@ async function run$m(argv, _importMeta, _context) {
|
|
|
13819
14352
|
}
|
|
13820
14353
|
}
|
|
13821
14354
|
|
|
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)));
|
|
14355
|
+
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
14356
|
const CMD_NAME$g = constants.PNPM;
|
|
13824
14357
|
const description$j = 'Wraps pnpm with Socket security scanning';
|
|
13825
14358
|
const hidden$g = true;
|
|
@@ -15650,6 +16183,13 @@ async function run$d(argv, importMeta, {
|
|
|
15650
16183
|
pendingHead: Boolean(pendingHead),
|
|
15651
16184
|
pullRequest: Number(pullRequest),
|
|
15652
16185
|
reach: {
|
|
16186
|
+
// Build-tool config for the reach-time resolution, mapped from socket.json
|
|
16187
|
+
// (per-ecosystem). Best-effort on plain --reach; under --auto-manifest the
|
|
16188
|
+
// config carries top-level failOnBuildToolError=true (fail-closed). Only
|
|
16189
|
+
// built when reachability runs.
|
|
16190
|
+
autoManifestConfig: reach ? utils.buildAutoManifestConfig(sockJson, {
|
|
16191
|
+
autoManifest: Boolean(autoManifest)
|
|
16192
|
+
}) : undefined,
|
|
15653
16193
|
excludePaths,
|
|
15654
16194
|
reachAnalysisMemoryLimit: Number(reachAnalysisMemoryLimit),
|
|
15655
16195
|
reachAnalysisTimeout: Number(reachAnalysisTimeout),
|
|
@@ -18608,7 +19148,7 @@ async function fetchThreatFeed({
|
|
|
18608
19148
|
return await utils.queryApiSafeJson(`orgs/${orgSlug}/threat-feed?${queryParams}`, 'the Threat Feed data');
|
|
18609
19149
|
}
|
|
18610
19150
|
|
|
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)));
|
|
19151
|
+
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
19152
|
async function outputThreatFeed(result, outputKind) {
|
|
18613
19153
|
if (!result.ok) {
|
|
18614
19154
|
process.exitCode = result.code ?? 1;
|
|
@@ -19377,7 +19917,7 @@ async function run$1(argv, importMeta, {
|
|
|
19377
19917
|
}
|
|
19378
19918
|
}
|
|
19379
19919
|
|
|
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)));
|
|
19920
|
+
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
19921
|
const CMD_NAME = constants.YARN;
|
|
19382
19922
|
const description = 'Wraps yarn with Socket security scanning';
|
|
19383
19923
|
const hidden = true;
|
|
@@ -19572,7 +20112,7 @@ const rootAliases = {
|
|
|
19572
20112
|
}
|
|
19573
20113
|
};
|
|
19574
20114
|
|
|
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)));
|
|
20115
|
+
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
20116
|
|
|
19577
20117
|
// Capture CLI start time at module level for global error handlers.
|
|
19578
20118
|
const cliStartTime = Date.now();
|
|
@@ -19601,7 +20141,7 @@ void (async () => {
|
|
|
19601
20141
|
name: constants.default.SOCKET_CLI_BIN_NAME,
|
|
19602
20142
|
argv: process.argv.slice(2),
|
|
19603
20143
|
importMeta: {
|
|
19604
|
-
url: `${require$$0.pathToFileURL(__filename$1)}`
|
|
20144
|
+
url: `${require$$0$1.pathToFileURL(__filename$1)}`
|
|
19605
20145
|
},
|
|
19606
20146
|
subcommands: rootCommands
|
|
19607
20147
|
}, {
|
|
@@ -19644,7 +20184,7 @@ void (async () => {
|
|
|
19644
20184
|
autoVersion: false,
|
|
19645
20185
|
flags: {},
|
|
19646
20186
|
importMeta: {
|
|
19647
|
-
url: `${require$$0.pathToFileURL(__filename$1)}`
|
|
20187
|
+
url: `${require$$0$1.pathToFileURL(__filename$1)}`
|
|
19648
20188
|
}
|
|
19649
20189
|
});
|
|
19650
20190
|
return !!cli.flags['json'];
|
|
@@ -19709,5 +20249,5 @@ process.on('unhandledRejection', async (reason, promise) => {
|
|
|
19709
20249
|
// eslint-disable-next-line n/no-process-exit
|
|
19710
20250
|
process.exit(1);
|
|
19711
20251
|
});
|
|
19712
|
-
//# debugId=
|
|
20252
|
+
//# debugId=c95bf38d-6368-425f-b593-0afd21e07f62
|
|
19713
20253
|
//# sourceMappingURL=cli.js.map
|