obvyr-cli 2.3.1__tar.gz → 2.4.0__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,23 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: obvyr-cli
3
- Version: 2.3.1
3
+ Version: 2.4.0
4
4
  Summary: Command-line wrapper to allow Obvyr to capture evidence from any machine.
5
5
  License: Proprietary
6
6
  Author: Wyrd Technology Ltd
7
- Requires-Python: >=3.12,<4.0
7
+ Requires-Python: >=3.14.3,<4.0.0
8
8
  Classifier: License :: Other/Proprietary License
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.12
11
- Classifier: Programming Language :: Python :: 3.13
12
- Classifier: Programming Language :: Python :: 3.14
13
- Requires-Dist: boto3 (>=1.42.47,<2.0.0)
10
+ Requires-Dist: boto3 (>=1.42.64,<2.0.0)
14
11
  Requires-Dist: click (>=8.3.1,<9.0.0)
15
12
  Requires-Dist: httpx (>=0.28.1,<0.29.0)
16
13
  Requires-Dist: orjson (>=3.11.7,<4.0.0)
17
- Requires-Dist: pydantic (>=2.10.1,<3.0.0)
18
- Requires-Dist: pydantic-settings (>=2.6.1,<2.13)
19
- Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
20
- Requires-Dist: tenacity (>=9.0.0,<10.0.0)
14
+ Requires-Dist: pydantic (>=2.12.5,<3.0.0)
15
+ Requires-Dist: pydantic-settings (>=2.13.1,<3.0.0)
16
+ Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
17
+ Requires-Dist: tenacity (>=9.1.4,<10.0.0)
21
18
  Requires-Dist: toml (>=0.10.2,<0.11.0)
22
19
  Requires-Dist: zstandard (>=0.25.0,<0.26.0)
23
20
  Project-URL: Homepage, https://wyrd-technology.com
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "obvyr-cli"
7
- version = "2.3.1"
7
+ version = "2.4.0"
8
8
  description = "Command-line wrapper to allow Obvyr to capture evidence from any machine."
9
9
  authors = ["Wyrd Technology Ltd"]
10
10
  license = "Proprietary"
@@ -27,28 +27,28 @@ from = "src"
27
27
  include = "obvyr_cli"
28
28
 
29
29
  [tool.poetry.dependencies]
30
- python = "^3.12"
31
- python-dotenv = "^1.0.1"
30
+ python = "^3.14.3"
31
+ python-dotenv = "^1.2.2"
32
32
  click = "^8.3.1"
33
- boto3 = "^1.42.47"
34
- pydantic = "^2.10.1"
35
- pydantic-settings = ">=2.6.1,<2.13"
33
+ boto3 = "^1.42.64"
34
+ pydantic = "^2.12.5"
35
+ pydantic-settings = "^2.13.1"
36
36
  httpx = "^0.28.1"
37
- tenacity = "^9.0.0"
37
+ tenacity = "^9.1.4"
38
38
  toml = "^0.10.2"
39
39
  orjson = "^3.11.7"
40
40
  zstandard = "^0.25.0"
41
41
 
42
42
  [tool.poetry.group.dev.dependencies]
43
- ruff = "^0.15.0"
43
+ ruff = "^0.15.5"
44
44
  mypy = "^1.19.1"
45
45
  pytest = "^9.0.2"
46
46
  pytest-cov = "^7.0.0"
47
- black = "^26.0.0"
48
- pyproject-fmt = "^2.15.3"
47
+ black = "^26.3.0"
48
+ pyproject-fmt = "^2.18.1"
49
49
  pytest-subprocess = "^1.5.3"
50
50
  types-toml = "^0.10.8.20240310"
51
- poethepoet = "^0.41.0"
51
+ poethepoet = "^0.42.1"
52
52
 
53
53
  [tool.poetry.scripts]
54
54
  obvyr = "obvyr_cli.cli:cli_run_process"
@@ -1,3 +1,4 @@
1
+ import glob
1
2
  import pathlib
2
3
  import time
3
4
  from typing import List
@@ -82,6 +83,25 @@ def is_attachment_fresh(
82
83
  return file_age_seconds < max_age_seconds
83
84
 
84
85
 
86
+ def resolve_attachment_globs(pattern_strings: list[str]) -> list[pathlib.Path]:
87
+ """Expand glob patterns in attachment path strings to concrete file paths.
88
+
89
+ Patterns are resolved relative to the current working directory.
90
+ Warns (does not error) if a pattern matches no files.
91
+ Deduplicates the result preserving order.
92
+ """
93
+ resolved: list[pathlib.Path] = []
94
+ for pattern_str in pattern_strings:
95
+ matches = glob.glob(pattern_str, recursive=True)
96
+ if not matches:
97
+ logger.warning(
98
+ f"No files matched attachment pattern '{pattern_str}' — "
99
+ "check your ATTACHMENT_PATHS configuration."
100
+ )
101
+ resolved.extend(pathlib.Path(m) for m in matches)
102
+ return list(dict.fromkeys(resolved))
103
+
104
+
85
105
  def list_available_profiles(settings: Settings) -> None:
86
106
  """
87
107
  Lists all available profiles.
@@ -188,9 +208,11 @@ def send_to_api(
188
208
  # Create archive from command execution data
189
209
  attachment_paths = None
190
210
  if active_profile.ATTACHMENT_PATHS:
211
+ resolved_paths = resolve_attachment_globs(
212
+ active_profile.ATTACHMENT_PATHS
213
+ )
191
214
  fresh_paths = []
192
- for path_str in active_profile.ATTACHMENT_PATHS:
193
- path = pathlib.Path(path_str)
215
+ for path in resolved_paths:
194
216
  if is_attachment_fresh(
195
217
  path, active_profile.ATTACHMENT_MAX_AGE_SECONDS
196
218
  ):
@@ -77,6 +77,7 @@ class Settings(BaseSettings):
77
77
  env_ignore_empty=True,
78
78
  extra="ignore",
79
79
  populate_by_name=True,
80
+ enable_decoding=False,
80
81
  )
81
82
 
82
83
  SECRET_KEY: str = secrets.token_urlsafe(32)
File without changes