@socketsecurity/cli-with-sentry 1.1.96 → 1.1.98

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 (41) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cli.js +1468 -78
  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/manifest/bazel/bazel-bin-detect.d.mts +11 -0
  8. package/dist/types/commands/manifest/bazel/bazel-bin-detect.d.mts.map +1 -0
  9. package/dist/types/commands/manifest/bazel/bazel-build-parser.d.mts +34 -0
  10. package/dist/types/commands/manifest/bazel/bazel-build-parser.d.mts.map +1 -0
  11. package/dist/types/commands/manifest/bazel/bazel-java-shim.d.mts +10 -0
  12. package/dist/types/commands/manifest/bazel/bazel-java-shim.d.mts.map +1 -0
  13. package/dist/types/commands/manifest/bazel/bazel-output-base-check.d.mts +7 -0
  14. package/dist/types/commands/manifest/bazel/bazel-output-base-check.d.mts.map +1 -0
  15. package/dist/types/commands/manifest/bazel/bazel-python-shim.d.mts +9 -0
  16. package/dist/types/commands/manifest/bazel/bazel-python-shim.d.mts.map +1 -0
  17. package/dist/types/commands/manifest/bazel/bazel-query-runner.d.mts +41 -0
  18. package/dist/types/commands/manifest/bazel/bazel-query-runner.d.mts.map +1 -0
  19. package/dist/types/commands/manifest/bazel/bazel-repo-discovery.d.mts +34 -0
  20. package/dist/types/commands/manifest/bazel/bazel-repo-discovery.d.mts.map +1 -0
  21. package/dist/types/commands/manifest/bazel/bazel-workspace-detect.d.mts +13 -0
  22. package/dist/types/commands/manifest/bazel/bazel-workspace-detect.d.mts.map +1 -0
  23. package/dist/types/commands/manifest/bazel/cmd-manifest-bazel.d.mts +9 -0
  24. package/dist/types/commands/manifest/bazel/cmd-manifest-bazel.d.mts.map +1 -0
  25. package/dist/types/commands/manifest/bazel/extract_bazel_to_maven.d.mts +33 -0
  26. package/dist/types/commands/manifest/bazel/extract_bazel_to_maven.d.mts.map +1 -0
  27. package/dist/types/commands/manifest/cmd-manifest.d.mts.map +1 -1
  28. package/dist/types/commands/manifest/detect-manifest-actions.d.mts +1 -0
  29. package/dist/types/commands/manifest/detect-manifest-actions.d.mts.map +1 -1
  30. package/dist/types/commands/manifest/generate_auto_manifest.d.mts +4 -1
  31. package/dist/types/commands/manifest/generate_auto_manifest.d.mts.map +1 -1
  32. package/dist/types/commands/scan/handle-create-new-scan.d.mts.map +1 -1
  33. package/dist/types/utils/api.d.mts +5 -3
  34. package/dist/types/utils/api.d.mts.map +1 -1
  35. package/dist/types/utils/coana.d.mts +35 -0
  36. package/dist/types/utils/coana.d.mts.map +1 -1
  37. package/dist/types/utils/socket-json.d.mts +10 -0
  38. package/dist/types/utils/socket-json.d.mts.map +1 -1
  39. package/dist/utils.js +131 -28
  40. package/dist/utils.js.map +1 -1
  41. package/package.json +2 -2
package/dist/utils.js CHANGED
@@ -16,10 +16,14 @@ var path = require('node:path');
16
16
  var regexps = require('../external/@socketsecurity/registry/lib/regexps');
17
17
  var prompts = require('../external/@socketsecurity/registry/lib/prompts');
18
18
  var spawn = require('../external/@socketsecurity/registry/lib/spawn');
19
+ var fs = require('node:fs');
20
+ var fs$2 = require('node:fs/promises');
21
+ var promises$1 = require('node:stream/promises');
22
+ var node_zlib = require('node:zlib');
19
23
  var fs$1 = require('../external/@socketsecurity/registry/lib/fs');
20
24
  var require$$5 = require('node:module');
21
25
  var require$$3 = require('node:https');
22
- var fs = require('node:fs');
26
+ var web = require('node:stream/web');
23
27
  var require$$13 = require('../external/@socketsecurity/registry/lib/url');
24
28
  var agent = require('../external/@socketsecurity/registry/lib/agent');
25
29
  var bin = require('../external/@socketsecurity/registry/lib/bin');
@@ -2051,9 +2055,11 @@ function getHttpsAgent() {
2051
2055
  return _httpsAgent;
2052
2056
  }
2053
2057
 
2054
- // Wrapper around fetch that supports extra CA certificates via SSL_CERT_FILE.
2055
- // Uses node:https.request with a custom agent when extra CA certs are needed,
2056
- // falling back to regular fetch() otherwise. Follows redirects like fetch().
2058
+ // All outbound API requests use node:https.request rather than global fetch.
2059
+ // This ensures no body timeout is applied large streaming ND-JSON responses
2060
+ // (e.g. full scan results) can transfer without a hard deadline. When
2061
+ // SSL_CERT_FILE is configured, a custom HttpsAgent carrying the extra CA
2062
+ // certificates is passed; otherwise the default agent is used.
2057
2063
 
2058
2064
  // Internal httpsRequest-based fetch with redirect support.
2059
2065
  function _httpsRequestFetch(url, init, agent, redirectCount) {
@@ -2109,27 +2115,42 @@ function _httpsRequestFetch(url, init, agent, redirectCount) {
2109
2115
  }, agent, redirectCount + 1));
2110
2116
  return;
2111
2117
  }
2112
- const chunks = [];
2113
- res.on('data', chunk => chunks.push(chunk));
2114
- res.on('end', () => {
2115
- const body = Buffer.concat(chunks);
2116
- const responseHeaders = new Headers();
2117
- for (const [key, value] of Object.entries(res.headers)) {
2118
- if (typeof value === 'string') {
2119
- responseHeaders.set(key, value);
2120
- } else if (Array.isArray(value)) {
2121
- for (const v of value) {
2122
- responseHeaders.append(key, v);
2123
- }
2118
+ // Build response headers immediately on receipt.
2119
+ const responseHeaders = new Headers();
2120
+ for (const [key, value] of Object.entries(res.headers)) {
2121
+ if (typeof value === 'string') {
2122
+ responseHeaders.set(key, value);
2123
+ } else if (Array.isArray(value)) {
2124
+ for (const v of value) {
2125
+ responseHeaders.append(key, v);
2124
2126
  }
2125
2127
  }
2126
- resolve(new Response(body, {
2127
- status: statusCode ?? 0,
2128
- statusText: res.statusMessage ?? '',
2129
- headers: responseHeaders
2130
- }));
2128
+ }
2129
+ // Resolve with a streaming body as soon as headers are available,
2130
+ // matching fetch() semantics. Callers that pipe response.body (e.g.
2131
+ // streamDownloadWithFetch) receive a live ReadableStream rather than
2132
+ // a fully-buffered Buffer.
2133
+ const body = new web.ReadableStream({
2134
+ start(controller) {
2135
+ res.on('data', chunk => {
2136
+ controller.enqueue(chunk);
2137
+ });
2138
+ res.on('end', () => {
2139
+ controller.close();
2140
+ });
2141
+ res.on('error', err => {
2142
+ controller.error(err);
2143
+ });
2144
+ },
2145
+ cancel() {
2146
+ res.destroy();
2147
+ }
2131
2148
  });
2132
- res.on('error', reject);
2149
+ resolve(new Response(body, {
2150
+ status: statusCode ?? 0,
2151
+ statusText: res.statusMessage ?? '',
2152
+ headers: responseHeaders
2153
+ }));
2133
2154
  });
2134
2155
  if (init.body) {
2135
2156
  req.write(init.body);
@@ -2139,11 +2160,7 @@ function _httpsRequestFetch(url, init, agent, redirectCount) {
2139
2160
  });
2140
2161
  }
2141
2162
  async function apiFetch(url, init = {}) {
2142
- const agent = getHttpsAgent();
2143
- if (!agent) {
2144
- return await fetch(url, init);
2145
- }
2146
- return await _httpsRequestFetch(url, init, agent, 0);
2163
+ return await _httpsRequestFetch(url, init, getHttpsAgent(), 0);
2147
2164
  }
2148
2165
  /**
2149
2166
  * Get command requirements from requirements.json based on command path.
@@ -4724,6 +4741,11 @@ function* walkNestedMap(map, keys = []) {
4724
4741
  * Manages reachability analysis via Coana tech CLI.
4725
4742
  *
4726
4743
  * Key Functions:
4744
+ * - compressSocketFactsForUpload: Brotli-compress any .socket.facts.json
4745
+ * entries in scanPaths just before upload, returning swapped paths plus a
4746
+ * cleanup callback. Coana keeps writing plain JSON; the on-the-wire form
4747
+ * to depscan is brotli (api-v0 decodes at the multipart boundary).
4748
+ * - extractReachabilityErrors: Extract per-component reachability errors
4727
4749
  * - extractTier1ReachabilityScanId: Extract scan ID from socket facts file
4728
4750
  *
4729
4751
  * Integration:
@@ -4732,6 +4754,86 @@ function* walkNestedMap(map, keys = []) {
4732
4754
  * - Extracts tier 1 reachability scan identifiers
4733
4755
  */
4734
4756
 
4757
+ const {
4758
+ DOT_SOCKET_DOT_FACTS_JSON
4759
+ } = constants.default;
4760
+ /**
4761
+ * For each `.socket.facts.json` in `scanPaths`, stream-brotli-compress a
4762
+ * sibling `.socket.facts.json.br` next to the original file and swap its
4763
+ * path in. Other paths pass through unchanged. Missing files also pass
4764
+ * through unchanged (the upload will fail downstream with the same error
4765
+ * it would have).
4766
+ *
4767
+ * Streaming + worker-thread compression keeps the event loop responsive:
4768
+ * default brotli quality (11) on a 60+MB facts file takes multiple seconds
4769
+ * of CPU, which would otherwise freeze the spinner / signal handlers /
4770
+ * any concurrent work.
4771
+ *
4772
+ * The `.br` lives next to the source rather than under the OS temp dir
4773
+ * because depscan's multipart ingest (`addStreamEntry`) rejects entries
4774
+ * whose names contain `..` traversal segments. The SDK computes the
4775
+ * multipart entry name via `path.relative(cwd, brPath)`, so an OS-tmpdir
4776
+ * temp path turns into `../../../var/folders/...` and gets dropped as
4777
+ * `unmatchedFiles`. Sibling-write keeps the relative path inside cwd, and
4778
+ * keeps the directory shape symmetric with the plain `.socket.facts.json`
4779
+ * upload (depscan strips only the `.br` suffix at ingest, so
4780
+ * `<dir>/.socket.facts.json.br` and `<dir>/.socket.facts.json` resolve to
4781
+ * the same storage path).
4782
+ *
4783
+ * Concurrent scans against the same source directory are already racy on
4784
+ * `.socket.facts.json` itself (coana writes to a single path), so the
4785
+ * sibling `.br` doesn't introduce a new race.
4786
+ *
4787
+ * Caller MUST `await cleanup()` (typically in a `finally` block) once the
4788
+ * upload completes — successful or not — to remove the sibling files.
4789
+ */
4790
+ async function compressSocketFactsForUpload(scanPaths) {
4791
+ const brPaths = [];
4792
+ const cleanup = async () => {
4793
+ const targets = brPaths.splice(0);
4794
+ // `recursive: true` defends against the (defensive) case where a sibling
4795
+ // path was somehow created as a directory — `rm` would otherwise throw
4796
+ // on the first such entry and skip the rest. `force: true` no-ops on
4797
+ // missing paths so the function stays idempotent.
4798
+ await Promise.all(targets.map(t => fs$2.rm(t, {
4799
+ recursive: true,
4800
+ force: true
4801
+ })));
4802
+ };
4803
+ // Use `allSettled` (not `all`) so a failure in one entry doesn't leak the
4804
+ // others' in-flight pipelines past our `catch`. If we used `all`, the
4805
+ // first rejection would bubble out while sibling pipelines were still
4806
+ // writing bytes — `cleanup()` would race with those writes and could
4807
+ // remove a `.br` only to have it re-created after we returned.
4808
+ const results = await Promise.allSettled(scanPaths.map(async p => {
4809
+ if (path.basename(p) !== DOT_SOCKET_DOT_FACTS_JSON) {
4810
+ return p;
4811
+ }
4812
+ if (!fs.existsSync(p)) {
4813
+ return p;
4814
+ }
4815
+ const brPath = `${p}.br`;
4816
+ // Track the sibling path BEFORE the pipeline starts so a
4817
+ // partially-written `.br` is removed even if the pipeline rejects.
4818
+ // `rm({ force: true })` no-ops on missing files, so tracking before
4819
+ // creation is safe.
4820
+ brPaths.push(brPath);
4821
+ await promises$1.pipeline(fs.createReadStream(p), node_zlib.createBrotliCompress(), fs.createWriteStream(brPath));
4822
+ return brPath;
4823
+ }));
4824
+ const failure = results.find(r => r.status === 'rejected');
4825
+ if (failure) {
4826
+ // All pipelines have settled, so cleanup() can safely remove every
4827
+ // `.br` we tracked (succeeded or partial) without racing live writes.
4828
+ await cleanup();
4829
+ throw failure.reason;
4830
+ }
4831
+ const paths = results.map(r => r.value);
4832
+ return {
4833
+ paths,
4834
+ cleanup
4835
+ };
4836
+ }
4735
4837
  function extractReachabilityErrors(socketFactsFile) {
4736
4838
  const json = fs$1.readJsonSync(socketFactsFile, {
4737
4839
  throws: false
@@ -7822,6 +7924,7 @@ exports.checkCommandInput = checkCommandInput;
7822
7924
  exports.cmdFlagValueToArray = cmdFlagValueToArray;
7823
7925
  exports.cmdFlagsToString = cmdFlagsToString;
7824
7926
  exports.cmdPrefixMessage = cmdPrefixMessage;
7927
+ exports.compressSocketFactsForUpload = compressSocketFactsForUpload;
7825
7928
  exports.convertCveToGhsa = convertCveToGhsa;
7826
7929
  exports.convertPurlToGhsas = convertPurlToGhsas;
7827
7930
  exports.createEnum = createEnum;
@@ -7946,5 +8049,5 @@ exports.updateConfigValue = updateConfigValue;
7946
8049
  exports.walkNestedMap = walkNestedMap;
7947
8050
  exports.webLink = webLink;
7948
8051
  exports.writeSocketJson = writeSocketJson;
7949
- //# debugId=2070e850-060e-4077-8aaa-c4564f5f74e5
8052
+ //# debugId=e3aec7ef-9385-4b5c-be2e-ba11a8c6f580
7950
8053
  //# sourceMappingURL=utils.js.map