aisbom-cli 0.4.1__tar.gz → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aisbom-cli
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: An AI Supply Chain security tool that that detects Pickle bombs and generates CycloneDX SBOMs for Machine Learning models.
5
5
  License-File: LICENSE
6
6
  Author: Ajoy L
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.13
13
13
  Classifier: Programming Language :: Python :: 3.14
14
14
  Requires-Dist: click (<8.2.0)
15
15
  Requires-Dist: cyclonedx-python-lib (>=8.5.0,<9.0.0)
16
+ Requires-Dist: packaging (>=24.0,<25.0)
16
17
  Requires-Dist: pip-requirements-parser (>=32.0.1,<33.0.0)
17
18
  Requires-Dist: requests (>=2.32.3,<3.0.0)
18
19
  Requires-Dist: rich (>=13.7.1,<15.0.0)
@@ -17,9 +17,40 @@ import importlib.metadata
17
17
  from .scanner import DeepScanner
18
18
  from .diff import SBOMDiff
19
19
 
20
+ import threading
21
+ from .version_check import check_latest_version
22
+
20
23
  app = typer.Typer()
21
24
  console = Console()
22
25
 
26
+ # Thread-safe storage for update checks
27
+ update_result = {"version": None}
28
+
29
+ def run_version_check_wrapper():
30
+ """Wrapper to run version check and store result."""
31
+ update_result["version"] = check_latest_version()
32
+
33
+ def _check_update_status():
34
+ """Checks if update thread finished and prints message if needed."""
35
+ # We join with a tiny timeout to see if it's done without blocking
36
+ # Since we call this at the END of the command, the network request likely finished.
37
+ # If it's still hung, we skip showing the message to avoid delay.
38
+ # Note: Threads in Python are daemon by default? No, we need to set daemon=True
39
+ # so it doesn't block exit if network hangs. But here we just want to check results.
40
+ if update_result["version"]:
41
+ ver = update_result["version"]
42
+ try:
43
+ curr = importlib.metadata.version("aisbom-cli")
44
+ except:
45
+ curr = "unknown"
46
+
47
+ console.print(Panel(
48
+ f"💡 [bold yellow]Update Available:[/bold yellow] You are on v{curr}. v{ver} is available.\n"
49
+ f"Run [bold white]pip install --upgrade aisbom-cli[/bold white] to update.",
50
+ border_style="yellow",
51
+ expand=False
52
+ ))
53
+
23
54
  class OutputFormat(str, Enum):
24
55
  JSON = "json"
25
56
  MARKDOWN = "markdown"
@@ -71,6 +102,10 @@ def scan(
71
102
  """
72
103
  Deep Introspection Scan: Analyzes binary headers and dependency manifests.
73
104
  """
105
+ # Start background check
106
+ t = threading.Thread(target=run_version_check_wrapper, daemon=True)
107
+ t.start()
108
+
74
109
  console.print(Panel.fit(f"🚀 [bold cyan]AIsbom[/bold cyan] Scanning: [underline]{target}[/underline]"))
75
110
 
76
111
  # 1. Run the Logic
@@ -220,6 +255,9 @@ def scan(
220
255
  elif exit_code == 1:
221
256
  console.print("[bold yellow]Errors encountered during scan.[/bold yellow] Exiting with code 1.")
222
257
 
258
+ # Check update status before exiting
259
+ _check_update_status()
260
+
223
261
  # Non-zero exit codes for CI/CD when high risk or errors are present
224
262
  raise typer.Exit(code=exit_code)
225
263
 
@@ -293,6 +331,10 @@ def diff(
293
331
  """
294
332
  Compare two SBOM files (CycloneDX JSON) and detect drift in risks, licenses, dependencies, or model hashes.
295
333
  """
334
+ # Start background check
335
+ t = threading.Thread(target=run_version_check_wrapper, daemon=True)
336
+ t.start()
337
+
296
338
  path_old = Path(old_file)
297
339
  path_new = Path(new_file)
298
340
 
@@ -388,6 +430,8 @@ def diff(
388
430
  raise typer.Exit(code=1)
389
431
 
390
432
  console.print("\n[bold green]Success: No critical regression detected.[/bold green]")
433
+
434
+ _check_update_status()
391
435
 
392
436
  if __name__ == "__main__":
393
437
  app()
@@ -0,0 +1,50 @@
1
+ import os
2
+ import platform
3
+ import importlib.metadata
4
+ import requests
5
+ from packaging.version import parse as parse_version
6
+
7
+ API_URL = "https://api.aisbom.io/v1/version"
8
+
9
+ def check_latest_version() -> str | None:
10
+ """
11
+ Checks for the latest version of aisbom-cli.
12
+ Returns the latest version string if an update is available, otherwise None.
13
+ Respects AISBOM_NO_TELEMETRY env var.
14
+ """
15
+ # 1. Privacy Check
16
+ if os.getenv("AISBOM_NO_TELEMETRY"):
17
+ return None
18
+
19
+ try:
20
+ # 2. Get Current Version & Context
21
+ current_version = importlib.metadata.version("aisbom-cli")
22
+ system = platform.system()
23
+ py_ver = platform.python_version()
24
+ is_ci = "true" if (os.getenv("GITHUB_ACTIONS") or os.getenv("CI")) else "false"
25
+
26
+ user_agent = f"aisbom-cli/{current_version} ({system}; python {py_ver}; ci={is_ci})"
27
+
28
+ # 3. Request
29
+ response = requests.get(
30
+ API_URL,
31
+ headers={"User-Agent": user_agent},
32
+ timeout=1.0 # Strict timeout
33
+ )
34
+ response.raise_for_status()
35
+
36
+ data = response.json()
37
+ latest_version = data.get("latest")
38
+
39
+ if not latest_version:
40
+ return None
41
+
42
+ # 4. Compare
43
+ if parse_version(latest_version) > parse_version(current_version):
44
+ return latest_version
45
+
46
+ except Exception:
47
+ # Fail silently for any network/parsing issue
48
+ return None
49
+
50
+ return None
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "aisbom-cli"
3
- version = "0.4.1"
3
+ version = "0.4.2"
4
4
  description = "An AI Supply Chain security tool that that detects Pickle bombs and generates CycloneDX SBOMs for Machine Learning models."
5
5
  authors = ["Ajoy L <lab700xdev@gmail.com>"]
6
6
  readme = "README.md"
@@ -15,6 +15,7 @@ cyclonedx-python-lib = "^8.5.0"
15
15
  pip-requirements-parser = "^32.0.1"
16
16
  click = "<8.2.0"
17
17
  spdx-tools = "^0.8.3"
18
+ packaging = "^24.0"
18
19
 
19
20
  [tool.poetry.dependencies.requests]
20
21
  version = "^2.32.3"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes