sandbox-cli 0.3.0__tar.gz → 0.3.2__tar.gz

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 (53) hide show
  1. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/PKG-INFO +5 -5
  2. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/pyproject.toml +4 -4
  3. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/__init__.py +52 -53
  4. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/config.py +1 -1
  5. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/compiler/ssh.py +1 -1
  6. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/downloader.py +2 -1
  7. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/advanced.py +28 -5
  8. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/basic.py +23 -4
  9. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/rescan.py +11 -2
  10. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/.gitignore +0 -0
  11. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/LICENSE +0 -0
  12. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/NOTICE +0 -0
  13. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/README.md +0 -0
  14. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/__main__.py +0 -0
  15. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/_converters.py +0 -0
  16. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/browser.py +0 -0
  17. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/download/__init__.py +0 -0
  18. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/download/artifacts.py +0 -0
  19. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/download/email.py +0 -0
  20. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/images.py +0 -0
  21. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/report.py +0 -0
  22. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/rules/__init__.py +0 -0
  23. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/rules/compile.py +0 -0
  24. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/rules/test.py +0 -0
  25. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/scanner/__init__.py +0 -0
  26. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/scanner/re_scan.py +0 -0
  27. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/scanner/scan.py +0 -0
  28. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/scanner/scan_new.py +0 -0
  29. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/cli/unpack.py +0 -0
  30. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/console.py +0 -0
  31. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/__init__.py +0 -0
  32. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/browser.py +0 -0
  33. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/exceptions.py +0 -0
  34. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/progress.py +0 -0
  35. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/sandbox.py +0 -0
  36. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/core/scan.py +0 -0
  37. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/__init__.py +0 -0
  38. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/compiler/__init__.py +0 -0
  39. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/compiler/abc.py +0 -0
  40. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/compiler/docker.py +0 -0
  41. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/report.py +0 -0
  42. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/__init__.py +0 -0
  43. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/compile.py +0 -0
  44. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/hooks.py +0 -0
  45. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/images.py +0 -0
  46. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/tasks.py +0 -0
  47. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/uploads.py +0 -0
  48. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/scanner/utils.py +0 -0
  49. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/unpack/__init__.py +0 -0
  50. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/unpack/plugins/__init__.py +0 -0
  51. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/unpack/plugins/abc.py +0 -0
  52. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/unpack/plugins/correlation.py +0 -0
  53. {sandbox_cli-0.3.0 → sandbox_cli-0.3.2}/sandbox_cli/services/unpack/plugins/sort_by_plugins.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: sandbox-cli
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Command line tool for interaction with sandboxes
5
5
  Project-URL: Homepage, https://github.com/Security-Experts-Community/sandbox-cli
6
6
  Project-URL: Documentation, https://security-experts-community.github.io/sandbox-cli
@@ -14,10 +14,10 @@ Requires-Python: >=3.11
14
14
  Requires-Dist: aiofiles>=25.1.0
15
15
  Requires-Dist: asyncssh>=2.24.0
16
16
  Requires-Dist: colorama>=0.4.6
17
- Requires-Dist: cryptography>=49.0.0
18
- Requires-Dist: cyclopts>=4.20.0
17
+ Requires-Dist: cryptography>=50.0.0
18
+ Requires-Dist: cyclopts>=4.23.3
19
19
  Requires-Dist: docker>=7.2.0
20
- Requires-Dist: ptsandbox>=5.1.0
20
+ Requires-Dist: ptsandbox>=5.1.5
21
21
  Requires-Dist: rich>=15.0.0
22
22
  Requires-Dist: zstandard>=0.25.0
23
23
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sandbox-cli"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  description = "Command line tool for interaction with sandboxes"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -11,10 +11,10 @@ dependencies = [
11
11
  "aiofiles>=25.1.0",
12
12
  "asyncssh>=2.24.0",
13
13
  "colorama>=0.4.6",
14
- "cryptography>=49.0.0",
15
- "cyclopts>=4.20.0",
14
+ "cryptography>=50.0.0",
15
+ "cyclopts>=4.23.3",
16
16
  "docker>=7.2.0",
17
- "ptsandbox>=5.1.0",
17
+ "ptsandbox>=5.1.5",
18
18
  "rich>=15.0.0",
19
19
  "zstandard>=0.25.0",
20
20
  ]
@@ -58,7 +58,7 @@ def completion(
58
58
  path = app.install_completion(shell=shell)
59
59
  console.info(f"Completion installed to {path}")
60
60
  else:
61
- console.print(app.generate_completion(shell=shell), end="")
61
+ print(app.generate_completion(shell=shell))
62
62
 
63
63
 
64
64
  app.command(name="completion")(completion)
@@ -81,55 +81,54 @@ app.command(
81
81
  help="Open sandbox link in the default browser.",
82
82
  )
83
83
 
84
- if len(settings.sandbox_keys) > 0:
85
- scanner_app = App(name="scanner", help="Scan with the sandbox.", help_format="markdown", console=console)
86
- scanner_app.command(
87
- "sandbox_cli.cli.scanner.scan:scan",
88
- name="scan",
89
- help="Send files to scan with the sandbox.",
90
- )
91
- scanner_app.command(
92
- "sandbox_cli.cli.scanner.scan_new:scan_new",
93
- name="scan-new",
94
- help="Send files to scan with the sandbox (advanced scan).",
95
- )
96
- scanner_app.command(
97
- "sandbox_cli.cli.scanner.re_scan:re_scan",
98
- name="re-scan",
99
- help="Send traces to re-scan.",
100
- )
101
- app.command(scanner_app)
102
-
103
- rules_app = App(
104
- name="rules",
105
- help="Working with raw sandbox rules.",
106
- help_format="markdown",
107
- console=console,
108
- )
109
- rules_app.command(
110
- "sandbox_cli.cli.rules.compile:compile_rules",
111
- name="compile",
112
- help="Get compiled rules for working with third-party services.",
113
- )
114
- rules_app.command(
115
- "sandbox_cli.cli.rules.test:test_rules",
116
- name="test",
117
- help="Testing written rules.",
118
- )
119
- app.command(rules_app)
120
-
121
- app.command(
122
- "sandbox_cli.cli.images:get_images",
123
- name="images",
124
- help="Get available images in the sandbox.",
125
- )
126
- app.command(
127
- "sandbox_cli.cli.download:download_command",
128
- name="download",
129
- help="Download any artifact from the sandbox.",
130
- )
131
- app.command(
132
- "sandbox_cli.cli.download:download_email",
133
- name="email",
134
- help="Upload an email and get its headers.",
135
- )
84
+ scanner_app = App(name="scanner", help="Scan with the sandbox.", help_format="markdown", console=console)
85
+ scanner_app.command(
86
+ "sandbox_cli.cli.scanner.scan:scan",
87
+ name="scan",
88
+ help="Send files to scan with the sandbox.",
89
+ )
90
+ scanner_app.command(
91
+ "sandbox_cli.cli.scanner.scan_new:scan_new",
92
+ name="scan-new",
93
+ help="Send files to scan with the sandbox (advanced scan).",
94
+ )
95
+ scanner_app.command(
96
+ "sandbox_cli.cli.scanner.re_scan:re_scan",
97
+ name="re-scan",
98
+ help="Send traces to re-scan.",
99
+ )
100
+ app.command(scanner_app)
101
+
102
+ rules_app = App(
103
+ name="rules",
104
+ help="Working with raw sandbox rules.",
105
+ help_format="markdown",
106
+ console=console,
107
+ )
108
+ rules_app.command(
109
+ "sandbox_cli.cli.rules.compile:compile_rules",
110
+ name="compile",
111
+ help="Get compiled rules for working with third-party services.",
112
+ )
113
+ rules_app.command(
114
+ "sandbox_cli.cli.rules.test:test_rules",
115
+ name="test",
116
+ help="Testing written rules.",
117
+ )
118
+ app.command(rules_app)
119
+
120
+ app.command(
121
+ "sandbox_cli.cli.images:get_images",
122
+ name="images",
123
+ help="Get available images in the sandbox.",
124
+ )
125
+ app.command(
126
+ "sandbox_cli.cli.download:download_command",
127
+ name="download",
128
+ help="Download any artifact from the sandbox.",
129
+ )
130
+ app.command(
131
+ "sandbox_cli.cli.download:download_email",
132
+ name="email",
133
+ help="Upload an email and get its headers.",
134
+ )
@@ -92,7 +92,7 @@ class Platform(str, Enum):
92
92
 
93
93
 
94
94
  class SSHConfig(BaseModel):
95
- login: str = ""
95
+ username: str = ""
96
96
  password: str = ""
97
97
 
98
98
 
@@ -45,7 +45,7 @@ class RemoteCompiler(AbstractCompiler):
45
45
  def __init__(self) -> None:
46
46
  sandbox = settings.sandbox[0]
47
47
  self._host: str = sandbox.host
48
- self._username: str = sandbox.ssh.login
48
+ self._username: str = sandbox.ssh.username
49
49
  self._password: str = sandbox.ssh.password
50
50
  self._client: SSHClientConnection | None = None
51
51
  self._tmp_directory: PurePosixPath | None = None
@@ -321,11 +321,12 @@ async def download(
321
321
  full_report: SandboxBaseTaskResponse | None = None,
322
322
  concurrency: int = DEFAULT_CONCURRENCY,
323
323
  read_timeout: int = DEFAULT_READ_TIMEOUT,
324
+ semaphore: asyncio.Semaphore | None = None,
324
325
  ) -> None:
325
326
  tasks: list[Coroutine[Any, Any, None]] = []
326
327
  saved_report_dirs: set[Path] = set()
327
328
  claimed: set[Path] = set()
328
- semaphore = asyncio.Semaphore(value=concurrency)
329
+ semaphore = semaphore or asyncio.Semaphore(value=concurrency)
329
330
 
330
331
  def add_task(out_dir: Path, name: str, file_uri: str, decompress: bool = False, overwrite: bool = False) -> None:
331
332
  tasks.append(
@@ -28,12 +28,28 @@ from sandbox_cli.core.scan import (
28
28
  save_report,
29
29
  save_scan_arguments,
30
30
  )
31
- from sandbox_cli.services.downloader import DownloadOptions, download
31
+ from sandbox_cli.services.downloader import DEFAULT_CONCURRENCY as DEFAULT_DOWNLOAD_CONCURRENCY
32
+ from sandbox_cli.services.downloader import (
33
+ DownloadOptions,
34
+ download,
35
+ )
32
36
  from sandbox_cli.services.scanner.compile import compile_rules
33
- from sandbox_cli.services.scanner.images import fetch_available_images, resolve_scan_images
37
+ from sandbox_cli.services.scanner.images import (
38
+ fetch_available_images,
39
+ resolve_scan_images,
40
+ )
34
41
  from sandbox_cli.services.scanner.tasks import build_scan_tasks
35
- from sandbox_cli.services.scanner.uploads import gather_uploads, upload_dll_hooks, upload_file, upload_rules
36
- from sandbox_cli.services.scanner.utils import compute_wait_time, get_elapsed_time, shorten_name
42
+ from sandbox_cli.services.scanner.uploads import (
43
+ gather_uploads,
44
+ upload_dll_hooks,
45
+ upload_file,
46
+ upload_rules,
47
+ )
48
+ from sandbox_cli.services.scanner.utils import (
49
+ compute_wait_time,
50
+ get_elapsed_time,
51
+ shorten_name,
52
+ )
37
53
  from sandbox_cli.services.unpack import Unpack
38
54
 
39
55
  if TYPE_CHECKING:
@@ -210,6 +226,7 @@ async def scan_internal_advanced(
210
226
  ) -> None:
211
227
  key = get_key_by_name(key_name)
212
228
  sandbox_sem = asyncio.Semaphore(value=key.max_workers)
229
+ download_sem = asyncio.Semaphore(value=DEFAULT_DOWNLOAD_CONCURRENCY)
213
230
  progress = make_scan_progress(with_image=True, disable=True)
214
231
 
215
232
  async def process_file(
@@ -308,6 +325,7 @@ async def scan_internal_advanced(
308
325
  idx=idx,
309
326
  image=formatted_image,
310
327
  link=formatted_link,
328
+ semaphore=download_sem,
311
329
  )
312
330
  except aiohttp.SocketTimeoutError:
313
331
  console.error(f"{final_output} • got timeout while downloading results • {get_elapsed_time(task)}")
@@ -333,7 +351,12 @@ async def scan_internal_advanced(
333
351
  sandbox_options=sandbox_options,
334
352
  )
335
353
  save_scan_arguments(out_dir, sandbox_arguments)
336
- await process_file(sandbox_options, file_path, out_dir, idx)
354
+
355
+ image_string = rf"\[{sandbox_options.image_id}]"
356
+ try:
357
+ await process_file(sandbox_options, file_path, out_dir, idx)
358
+ except Exception as e:
359
+ console.error(f"{image_string} • [yellow]{shorten_name(file_path.name)}[/] • unexpected error • {e}")
337
360
 
338
361
  console.info(f"Using key: name={key.name} max_workers={key.max_workers}")
339
362
 
@@ -24,11 +24,23 @@ from sandbox_cli.core.scan import (
24
24
  save_report,
25
25
  save_scan_arguments,
26
26
  )
27
- from sandbox_cli.services.downloader import DownloadOptions, download
27
+ from sandbox_cli.services.downloader import DEFAULT_CONCURRENCY as DEFAULT_DOWNLOAD_CONCURRENCY
28
+ from sandbox_cli.services.downloader import (
29
+ DownloadOptions,
30
+ download,
31
+ )
28
32
  from sandbox_cli.services.scanner.compile import compile_rules
29
- from sandbox_cli.services.scanner.images import fetch_available_images, resolve_scan_images
33
+ from sandbox_cli.services.scanner.images import (
34
+ fetch_available_images,
35
+ resolve_scan_images,
36
+ )
30
37
  from sandbox_cli.services.scanner.tasks import build_scan_tasks
31
- from sandbox_cli.services.scanner.uploads import gather_uploads, upload_dll_hooks, upload_file, upload_rules
38
+ from sandbox_cli.services.scanner.uploads import (
39
+ gather_uploads,
40
+ upload_dll_hooks,
41
+ upload_file,
42
+ upload_rules,
43
+ )
32
44
  from sandbox_cli.services.scanner.utils import compute_wait_time, shorten_name
33
45
  from sandbox_cli.services.unpack import Unpack
34
46
 
@@ -107,6 +119,7 @@ async def scan_internal(
107
119
  ) -> None:
108
120
  key = get_key_by_name(key_name)
109
121
  sandbox_sem = asyncio.Semaphore(value=key.max_workers)
122
+ download_sem = asyncio.Semaphore(value=DEFAULT_DOWNLOAD_CONCURRENCY)
110
123
 
111
124
  async def process_file(
112
125
  sandbox_options: SandboxBaseScanTaskRequest.Options,
@@ -174,6 +187,7 @@ async def scan_internal(
174
187
  sandbox,
175
188
  out_dir,
176
189
  replace(download_options, video=True, logs=True),
190
+ semaphore=download_sem,
177
191
  )
178
192
  console.info(
179
193
  rf"\[[magenta]{sandbox_options.sandbox.image_id}[/magenta]] Scan [yellow]{shorten_name(file_path.name)}[/] completed. {link}"
@@ -194,7 +208,12 @@ async def scan_internal(
194
208
  sandbox_options=sandbox_options.sandbox,
195
209
  )
196
210
  save_scan_arguments(out_dir, sandbox_arguments)
197
- await process_file(sandbox_options, file_path, out_dir, idx)
211
+
212
+ image_string = f"[{sandbox_options.sandbox.image_id}]"
213
+ try:
214
+ await process_file(sandbox_options, file_path, out_dir, idx)
215
+ except Exception as e:
216
+ console.error(f"{idx} [{image_string}] [yellow]{shorten_name(file_path.name)}[/] • unexpected error • {e}")
198
217
 
199
218
  console.info(f"Using key: name={key.name} max_workers={key.max_workers}")
200
219
 
@@ -28,7 +28,11 @@ from sandbox_cli.core.scan import (
28
28
  save_report,
29
29
  save_scan_arguments,
30
30
  )
31
- from sandbox_cli.services.downloader import DownloadOptions, download
31
+ from sandbox_cli.services.downloader import DEFAULT_CONCURRENCY as DEFAULT_DOWNLOAD_CONCURRENCY
32
+ from sandbox_cli.services.downloader import (
33
+ DownloadOptions,
34
+ download,
35
+ )
32
36
  from sandbox_cli.services.scanner.compile import compile_rules
33
37
  from sandbox_cli.services.scanner.utils import shorten_name
34
38
  from sandbox_cli.services.unpack import Unpack
@@ -122,6 +126,7 @@ async def rescan_internal(
122
126
  ) -> None:
123
127
  key = get_key_by_name(key_name)
124
128
  sandbox_sem = asyncio.Semaphore(value=key.max_workers)
129
+ download_sem = asyncio.Semaphore(value=DEFAULT_DOWNLOAD_CONCURRENCY)
125
130
 
126
131
  progress = make_scan_progress(with_image=False, disable=True)
127
132
 
@@ -202,6 +207,7 @@ async def rescan_internal(
202
207
  sandbox,
203
208
  out_dir,
204
209
  replace(download_options, logs=True),
210
+ semaphore=download_sem,
205
211
  )
206
212
 
207
213
  console.done(final_output)
@@ -217,7 +223,10 @@ async def rescan_internal(
217
223
  console.error(str(e))
218
224
  return
219
225
 
220
- await process_trace(drakvuf_trace, tcpdump_pcap, trace, out_dir, idx)
226
+ try:
227
+ await process_trace(drakvuf_trace, tcpdump_pcap, trace, out_dir, idx)
228
+ except Exception as e:
229
+ console.error(f"[yellow]{shorten_name(trace.name)}[/] • unexpected error • {e}")
221
230
 
222
231
  console.info(f"Using key: name={key.name} max_workers={key.max_workers}")
223
232
 
File without changes
File without changes
File without changes
File without changes