troubadix 25.10.8__py3-none-any.whl → 25.10.10__py3-none-any.whl

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.
troubadix/__version__.py CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  # THIS IS AN AUTOGENERATED FILE. DO NOT TOUCH!
4
4
 
5
- __version__ = "25.10.8"
5
+ __version__ = "25.10.10"
@@ -273,6 +273,7 @@ CPE = "cpe:/a:mapp:webtrekk:";
273
273
  CPE = "cpe:/a:netsparker:wass";
274
274
  CPE = "cpe:/a:tawk:tawk.to_live_chat";
275
275
  CPE: cpe:/a:tawk:tawk.to_live_chat:0.8.0
276
+ cpe =~ "^cpe:/o:fujifilm:apeos_2150_(n|nd|nda)_firmware") {
276
277
  cpe =~ "^cpe:/o:hp:laserjet_pro_420[1-3](cdn|dn|dw|dne|dwe)_firmware") {
277
278
  CPU' could have occured because a retry loop continually finds the same
278
279
  crafted IFF ILBM file. NOTE: some of these details are obtained from
@@ -398,7 +399,9 @@ drbd: Avoid Clang warning about pointless switch statment (bsc#1051510).
398
399
  eliptic curve parameters were not sufficiently validated during
399
400
  } else if( banner =~ "^220 (RICOH|LANIER|SAVIN|Gestetner|NRG) (Aficio |Pro)?([A-Z]+)? [^ ]+ (\([^)]+\) )?FTP server" ) {
400
401
  } else if("diese Vorgabe muss manuell ueberprueft werden" >< tolower(status)) {
402
+ } else if (prod =~ "^BMX\s*NOE\s*0100$") {
401
403
  else if (prod =~ "^BMX\s*NOE\s*0100$" || prod =~ "^BMX\s*NOE\s*0100H$") {
404
+ } else if (prod =~ "^BMX\s*NOE\s*0110$") {
402
405
  else if (prod =~ "^BMX\s*NOE\s*0110$" || prod =~ "^BMX\s*NOE\s*0110H$") {
403
406
  else if( svc == "agobot.fo" )
404
407
  Enable log information of starting/stoping services. (bsc#1144923,
@@ -415,6 +418,7 @@ examined with fuzzing by Tim Blazytko, Cornelius Aschermann, Sergej
415
418
  execute arbitrary code via a crafted Upack PE file.
416
419
  executuon (bsc#966437).
417
420
  EXP=CustomIE.dll
421
+ expected_value = '1. The output should contain "iif "lo" accept" and contain "iif != "lo" ip saddr 127.0.0.0/8 drop" and contain "iif != "lo" ip6 saddr ::1 drop"
418
422
  EXP=expext.dll
419
423
  expressions that are not properly handled by a stap script that
420
424
  * extended EAP-SIM/AKA fast re-authentication to allow use with FILS
@@ -442,6 +446,7 @@ files. If a user were tricked into opening a specially-crafted CAF file, a
442
446
  files packed with UPack.
443
447
  files to potentially execute code and it is tracked by the Mitre CVE
444
448
  file_xml = '\t\t<file_item' + status + ' xmlns="http://oval.mitre.org/XMLSchema/' +
449
+ firebird:x:109:117:Firebird Database Administator,,,:/var/lib/firebird:/usr/sbin/nologin
445
450
  Fixed a bug where Podman could not run containers usin... [Please see the references for more information on the vulnerabilities]");
446
451
  Fixed an issue with version missmatch (bsc#1162224).
447
452
  Fixed a regression in regards to the 'edge' comand line flag
@@ -582,6 +587,7 @@ if (prod =~ "^BMX\s*NOE\s*0110$" || prod =~ "^BMX\s*NOE\s*0110H$") {
582
587
  if (prod =~ "^BMX\s*NOE\s*0110" && version_is_less(version: version, test_version: "6.5")) {
583
588
  if (prod =~ "^BMX\s*NOE\s*0110" && version_is_less(version: version, test_version: "6.70")) {
584
589
  if (prod =~ "^BMX\s*NOE\s*0200") {
590
+ if (!prod || (prod !~ "^BMX\s*P34" && prod !~ "^BMX\s*(NOC\s*0401|NGD\s*0100|NOR\s*0200H|NOE\s*01[01]0)"))
585
591
  if (!prod || (prod !~ "^BMX\s*P34" && prod !~ "^BMX\s*NOE\s*01[01]0"))
586
592
  if (!prod || (prod !~ "^BMX\s*P34" && prod !~ "^BMX\s*NOE\s*0(1[01]|20)0"))
587
593
  if (!prod || (prod !~ "^BMX\s*P34" && prod !~ "^BMX\s*NOR\s*0200H" && prod !~ "^BMX\s*NOE\s*0100" &&
@@ -752,6 +758,7 @@ ML^Q8<TQ^+LTL*)6UG-,[V6-;N*W*79^&[ND/.DM''*U8D?Q:.'+%RB;S$!.'
752
758
  MM]7>[YM~GC^@?_WK0@W/F>UDL^Q8<TQ^+LTL*)6UG-,[V6-;N*W*79^&[ND/
753
759
  MN*W*79^&[ND/.DM''*U8D?Q:.'+%RB;S$!.'6['*(;8>~A:>&GO>&&M7/36X
754
760
  model = "TE Unknown Model";
761
+ mod = eregmatch(pattern: "([-A-Za-z0-9]+) -?\s*.*([Cc]ard|[Cc]ontroller) \[v", string: recv);
755
762
  mod = eregmatch(pattern: "Huawei (TE[0-9]0)", string: banner);
756
763
  mod = eregmatch(pattern: "(RICOH|LANIER|SAVIN|Gestetner|NRG) ((Aficio |Pro)?([A-Z]+)? [^ ]+)", string: banner);
757
764
  mod = eregmatch(pattern: "^(RICOH|LANIER|SAVIN|Gestetner|NRG) ((Aficio )?[^ ]+ [^ :]*)(:[^:]+:Ver.([.0-9]+))?", string: banner);
@@ -1,62 +1,78 @@
1
1
  # Copyright (C) 2022 Greenbone AG
2
- #
3
2
  # SPDX-License-Identifier: GPL-3.0-or-later
4
- #
5
- # This program is free software: you can redistribute it and/or modify
6
- # it under the terms of the GNU General Public License as published by
7
- # the Free Software Foundation, either version 3 of the License, or
8
- # (at your option) any later version.
9
- #
10
- # This program is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- # GNU General Public License for more details.
14
- #
15
- # You should have received a copy of the GNU General Public License
16
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
3
 
18
- import re
19
- from pathlib import Path
20
- from typing import Iterable, Iterator
4
+ from typing import Iterator
21
5
 
22
- import charset_normalizer
6
+ import magic
23
7
 
24
- from troubadix.plugin import LineContentPlugin, LinterError, LinterResult
8
+ from troubadix.plugin import (
9
+ FilePlugin,
10
+ LinterError,
11
+ LinterResult,
12
+ )
25
13
 
26
- # Only the ASCII and extended ASCII for now... # https://www.ascii-code.com/
27
- # CHAR_SET = r"[^\x00-\xFF]"
28
- # Temporary only check for chars in between 7f-9f, like in the old Feed-QA...
29
- INVALID_CHAR_PATTERN = re.compile(r"[\x7F-\x9F]")
14
+ # OpenVAS decodes NASL files using ISO-8859-1 (Latin-1).
15
+ # Files saved in other encodings (like UTF-8)
16
+ # will be misinterpreted and cause errors or garbled text.
17
+ # US-ASCII is also allowed since it's a subset of ISO-8859-1.
18
+ ALLOWED_ENCODINGS = ["iso-8859-1", "us-ascii"]
30
19
 
31
- ALLOWED_ENCODINGS = ["ascii", "latin_1"]
32
20
 
21
+ class CheckEncoding(FilePlugin):
22
+ """
23
+ Check if the encoding of the NASL file is ISO-8859-1 (Latin-1) encoded.
24
+ Finds UTF-8 multibyte sequences that are composed of individually valid Latin-1 bytes,
25
+ but result in garbled text.
26
+ """
33
27
 
34
- class CheckEncoding(LineContentPlugin):
35
28
  name = "check_encoding"
36
29
 
37
- def check_lines(
38
- self,
39
- nasl_file: Path,
40
- lines: Iterable[str],
41
- ) -> Iterator[LinterResult]:
42
- match = charset_normalizer.from_path(
43
- nasl_file, threshold=0.4, cp_isolation=ALLOWED_ENCODINGS
44
- ).best()
30
+ def run(self) -> Iterator[LinterResult]:
31
+ with open(self.context.nasl_file, "rb") as f:
32
+ raw = f.read()
45
33
 
46
- if not match:
34
+ # Use magic to detect encoding
35
+ detected_encoding = magic.Magic(mime_encoding=True).from_buffer(raw)
36
+
37
+ if detected_encoding not in ALLOWED_ENCODINGS:
47
38
  yield LinterError(
48
- f"VT uses a wrong encoding. "
49
- f"Allowed encodings are {', '.join(ALLOWED_ENCODINGS)}.",
50
- file=nasl_file,
39
+ f"Detected encoding '{detected_encoding.upper()}' is not Latin-1 compatible.",
40
+ file=self.context.nasl_file,
51
41
  plugin=self.name,
52
42
  )
53
43
 
54
- for index, line in enumerate(lines, 1):
55
- encoding = INVALID_CHAR_PATTERN.search(line)
56
- if encoding:
44
+ def has_utf8_multibyte(data: bytes) -> bool:
45
+ """
46
+ Function to detect UTF-8 multibyte sequences by checking the first two bytes.
47
+ UTF-8 multibyte sequences start with a lead byte followed by continuation bytes.
48
+
49
+ Lead byte ranges:
50
+ - 2-byte: 0xC2–0xDF (110xxxxx, excluding 0xC0–0xC1 to avoid overlongs)
51
+ - 3-byte: 0xE0–0xEF (1110xxxx)
52
+ - 4-byte: 0xF0–0xF4 (11110xxx)
53
+ These ranges are continuous, so we can check 0xC2–0xF4 as a single range.
54
+ 11000010 C2 -- F4 11110111
55
+
56
+ Continuation bytes: 0x80–0xBF (10yyyyyy)
57
+ 10000000 80 -- BF 10111111
58
+
59
+ Lead and continuation byte values are either not valid Latin-1 or special symbols
60
+ that are unlikely to be following each other in normal use.
61
+ """
62
+
63
+ for i in range(len(data) - 1):
64
+ first = data[i]
65
+ second = data[i + 1]
66
+ if 0xC2 <= first <= 0xF4 and 0x80 <= second <= 0xBF:
67
+ return True
68
+ return False
69
+
70
+ lines = raw.split(b"\n")
71
+ for i, line_bytes in enumerate(lines, start=1):
72
+ if has_utf8_multibyte(line_bytes):
57
73
  yield LinterError(
58
- f"Found invalid character in line: {index}",
59
- file=nasl_file,
74
+ f"Likely UTF-8 multibyte sequence found in line {i}",
75
+ file=self.context.nasl_file,
60
76
  plugin=self.name,
61
- line=index,
77
+ line=i,
62
78
  )
@@ -172,6 +172,10 @@ class CheckHttpLinksInTags(FilePlugin):
172
172
  # e.g.:
173
173
  # sun.net.www.protocol.jar.JarURLConnection
174
174
  "sun.net.www.",
175
+ # e.g.:
176
+ # For example: 'http://[::1]/'.
177
+ "http://[::1]/",
178
+ "https://[::1]/",
175
179
  ]
176
180
 
177
181
  return any(
@@ -1,12 +1,14 @@
1
1
  # SPDX-License-Identifier: GPL-3.0-or-later
2
2
  # SPDX-FileCopyrightText: 2024 Greenbone AG
3
3
 
4
+ import importlib.util
5
+ import logging
4
6
  import re
5
7
  from argparse import ArgumentParser, Namespace
6
8
  from dataclasses import dataclass
7
9
  from enum import Enum
8
10
  from pathlib import Path
9
- from typing import Iterable, Optional
11
+ from typing import Iterable
10
12
 
11
13
  from pontos.terminal.terminal import ConsoleTerminal
12
14
 
@@ -19,6 +21,8 @@ from troubadix.helper.patterns import (
19
21
  )
20
22
  from troubadix.troubadix import from_file
21
23
 
24
+ logger = logging.getLogger(__name__)
25
+
22
26
 
23
27
  class Deprecations(Enum):
24
28
  NOTUS = "and replaced by a Notus scanner based one."
@@ -37,7 +41,21 @@ class DeprecatedFile:
37
41
  KB_ITEMS_PATTERN = re.compile(r"set_kb_item\(.+\);")
38
42
 
39
43
 
40
- def update_summary(file: DeprecatedFile, deprecation_reason: str) -> str:
44
+ def load_transition_oid_mapping(transition_file: Path) -> dict[str, str]:
45
+ spec = importlib.util.spec_from_file_location(
46
+ "transition_layer", transition_file
47
+ )
48
+ transition_layer = importlib.util.module_from_spec(spec)
49
+ spec.loader.exec_module(transition_layer)
50
+
51
+ return transition_layer.mapping
52
+
53
+
54
+ def update_summary(
55
+ file: DeprecatedFile,
56
+ deprecation_reason: str,
57
+ replacement_oid: str | None = None,
58
+ ) -> str:
41
59
  """Update the summary of the nasl script by adding the information
42
60
  that the script has been deprecated, and if possible, the oid of
43
61
  the new notus script replacing it.
@@ -46,21 +64,22 @@ def update_summary(file: DeprecatedFile, deprecation_reason: str) -> str:
46
64
  file: DeprecatedFile object containing the content of the VT
47
65
  deprecation_reason: The reason this VT is being deprecated,
48
66
  from a list of options.
67
+ replacement_oid: The OID of the script that replaces this deprecated one.
49
68
 
50
69
  Returns:
51
70
  The updated content of the file
52
71
  """
53
72
  old_summary = _get_summary(file.content)
54
73
  if not old_summary:
55
- print(f"No summary in: {file.name}")
74
+ logger.warning(f"No summary in: {file.name}")
56
75
  return file.content
57
76
 
58
- deprecate_text = (
59
- f"Note: This VT has been deprecated "
60
- f"{Deprecations[deprecation_reason].value}"
61
- )
77
+ deprecate_text = f"Note: This VT has been deprecated {Deprecations[deprecation_reason].value}"
78
+
79
+ if replacement_oid:
80
+ deprecate_text += f" The replacement VT has OID {replacement_oid}."
62
81
 
63
- new_summary = old_summary + "\n" + deprecate_text
82
+ new_summary = old_summary + "\n\n " + deprecate_text
64
83
  file.content = file.content.replace(old_summary, new_summary)
65
84
 
66
85
  return file.content
@@ -71,8 +90,7 @@ def _finalize_content(content: str) -> str:
71
90
  deprecated tag and removing the extra content."""
72
91
  content_to_keep = content.split("exit(0);")[0]
73
92
  return content_to_keep + (
74
- 'script_tag(name:"deprecated", value:TRUE);'
75
- "\n\n exit(0);\n}\n\nexit(66);\n"
93
+ 'script_tag(name:"deprecated", value:TRUE);\n\n exit(0);\n}\n\nexit(66);\n'
76
94
  )
77
95
 
78
96
 
@@ -111,7 +129,7 @@ def parse_files(files: list) -> list[DeprecatedFile]:
111
129
  return to_deprecate
112
130
 
113
131
 
114
- def _get_summary(content: str) -> Optional[str]:
132
+ def _get_summary(content: str) -> str | None:
115
133
  """Extract the summary from the nasl script"""
116
134
  pattern = get_script_tag_pattern(ScriptTag.SUMMARY)
117
135
  if match_summary := re.search(pattern, content):
@@ -120,10 +138,34 @@ def _get_summary(content: str) -> Optional[str]:
120
138
  return None
121
139
 
122
140
 
141
+ def find_replacement_oid(
142
+ file: DeprecatedFile,
143
+ oid_mapping: dict[str, str] | None = None,
144
+ ) -> str | None:
145
+ # Get replacement OID if available
146
+ if not oid_mapping:
147
+ return None
148
+
149
+ oid_match = re.search(
150
+ get_special_script_tag_pattern(SpecialScriptTag.OID),
151
+ file.content,
152
+ )
153
+ if not oid_match:
154
+ raise ValueError(
155
+ f"No OID found in {file.name}. Cannot map to replacement OID."
156
+ )
157
+ oid = oid_match.group("value")
158
+ replacement_oid = oid_mapping.get(oid)
159
+ if not replacement_oid:
160
+ raise ValueError(f"No replacement OID found for {oid} in {file.name}.")
161
+ return replacement_oid
162
+
163
+
123
164
  def deprecate(
124
165
  output_path: Path,
125
166
  to_deprecate: list[DeprecatedFile],
126
167
  deprecation_reason: str,
168
+ oid_mapping: dict[str, str] | None = None,
127
169
  ) -> None:
128
170
  """Deprecate the selected VTs by removing unnecessary keys, updating the
129
171
  summary, and adding the deprecated tag.
@@ -134,16 +176,19 @@ def deprecate(
134
176
  to_deprecate: the list of files to be deprecated
135
177
  deprecation_reason: The reason this VT is being deprecated,
136
178
  from a list of options.
179
+ oid_mapping: Optional mapping of file paths to replacement OIDs
137
180
  """
138
181
  output_path.mkdir(parents=True, exist_ok=True)
139
182
  for file in to_deprecate:
140
183
  if re.findall(KB_ITEMS_PATTERN, file.content):
141
- print(
142
- f"Unable to deprecate {file.name}. There are still KB keys "
143
- f"remaining."
184
+ logger.warning(
185
+ f"Unable to deprecate {file.name}. There are still KB keys remaining."
144
186
  )
145
187
  continue
146
- file.content = update_summary(file, deprecation_reason)
188
+
189
+ replacement_oid = find_replacement_oid(file, oid_mapping)
190
+
191
+ file.content = update_summary(file, deprecation_reason, replacement_oid)
147
192
  file.content = _finalize_content(file.content)
148
193
 
149
194
  # Drop any unnecessary script tags like script_dependencies(),
@@ -229,6 +274,17 @@ def parse_args(args: Iterable[str] = None) -> Namespace:
229
274
  "to be deprecated, separated by new lines."
230
275
  ),
231
276
  )
277
+
278
+ parser.add_argument(
279
+ "--transition-file",
280
+ metavar="<transition_file>",
281
+ default=None,
282
+ type=file_type_existing,
283
+ help=(
284
+ "Path to a file containing a list of oid mappings."
285
+ "Found in notus/generator/nasl/transition_layer."
286
+ ),
287
+ )
232
288
  return parser.parse_args(args)
233
289
 
234
290
 
@@ -245,8 +301,17 @@ def main():
245
301
  elif args.file:
246
302
  files = args.file
247
303
 
248
- to_be_deprecated = parse_files(files)
249
- deprecate(args.output_path, to_be_deprecated, args.deprecation_reason)
304
+ # Load OID mapping if provided
305
+ oid_mapping = None
306
+ if args.transition_file:
307
+ oid_mapping = load_transition_oid_mapping(args.transition_file)
308
+
309
+ deprecate(
310
+ args.output_path,
311
+ parse_files(files),
312
+ args.deprecation_reason,
313
+ oid_mapping,
314
+ )
250
315
 
251
316
 
252
317
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: troubadix
3
- Version: 25.10.8
3
+ Version: 25.10.10
4
4
  Summary: A linting and QA check tool for NASL files
5
5
  License: GPL-3.0-or-later
6
6
  License-File: LICENSE
@@ -1,8 +1,8 @@
1
1
  troubadix/__init__.py,sha256=K7sIXXDrC7YRb7BvIpdQ6ZfG_QkT0qUH_wAlHROVRfM,716
2
- troubadix/__version__.py,sha256=LKatNjYY1ZbozzFtR7raG-8gEu33IfSl6DX4jDIsg5I,104
2
+ troubadix/__version__.py,sha256=tM6XBs928mas3m_SEaK-UlVtWoA2w4UXHge5R3tqxRc,105
3
3
  troubadix/argparser.py,sha256=-H07Jhqh68_M4Mbjq9qJjTr3MShy_N2pxl2qHA6cfRU,7481
4
4
  troubadix/codespell/codespell.additions,sha256=SJPlIo8vEKEOTftY6ZBSXzcfyv6y9aFAXl9FdpcMxD0,561
5
- troubadix/codespell/codespell.exclude,sha256=W1dHEbKuXZbiLMRLhUPIzhCV1ptHqPLuaB6VsJLxn64,147965
5
+ troubadix/codespell/codespell.exclude,sha256=1zLTC45y7o1pVWUju35IFRNFG1Tj-r5HbgJwtCb8FRk,148569
6
6
  troubadix/codespell/codespell.ignore,sha256=2CP8u6O2VENcDpt2FfEDNmfa1Eh3D80yeYHT54GM1X4,1512
7
7
  troubadix/helper/__init__.py,sha256=tp2fPLzwGEA_2eiJbvuePiY6rjYSFxx7VUsCV4fSwvw,1110
8
8
  troubadix/helper/date_format.py,sha256=2m8EWZPmTQ1kxgv4i5hrPoPlAA8usjz28aRff352zNU,2488
@@ -27,11 +27,11 @@ troubadix/plugins/deprecated_functions.py,sha256=6e46woXd-3hUBnnuIXLlaqlcP6F7c99
27
27
  troubadix/plugins/double_end_points.py,sha256=1TLVc8HFYEKS870zaIoKmsAjBsRU9WZpaMKReRDUoLo,2509
28
28
  troubadix/plugins/duplicate_oid.py,sha256=lemYl3CUoOMFtRTLnlfjwPptnN51sQby3D9YjFtOv2Q,2652
29
29
  troubadix/plugins/duplicated_script_tags.py,sha256=UPBR2jbU15JLKJlVk1e2GFREH5Wj5Ax2yDFrmRKq74Y,3123
30
- troubadix/plugins/encoding.py,sha256=zNzqNpP39TUwOklnc8OJ3OIUelAN_hvnuBYoa3Pz764,2104
30
+ troubadix/plugins/encoding.py,sha256=Ow_ZpyjtL2_nqhbukY_3EUhiR0agfSxMxJ4IcMSGsT4,2768
31
31
  troubadix/plugins/forking_nasl_functions.py,sha256=IUtCrTK_sGDx79jAPS8lF_aN8zSG2AkzfC6duTMvJOw,6069
32
32
  troubadix/plugins/get_kb_on_services.py,sha256=oFmcjiF7ZD3x5tEbJEoZNn80y1qUzNgeSZNsogSqaZ0,3401
33
33
  troubadix/plugins/grammar.py,sha256=-53McZsKFuEavIS8-8CG7fUbW8VO3FuZv0PXenD42Bk,10239
34
- troubadix/plugins/http_links_in_tags.py,sha256=F4fm74M3CbmWOJoCyDdEO-bKQahFsHL6vs4ZynhHEkc,7325
34
+ troubadix/plugins/http_links_in_tags.py,sha256=DOAsN16av2UdMJUvK3nDi44ertBIi9EauK821GwGLKY,7448
35
35
  troubadix/plugins/if_statement_syntax.py,sha256=5BRJwCCghvZn1AfvYzmk8l9S7aRqbVaLHhSKod_Q9zw,1429
36
36
  troubadix/plugins/illegal_characters.py,sha256=B6q_RU85AxCjLry56Oc-RhMSpnJU8mTrxclRzi1FVFU,4406
37
37
  troubadix/plugins/log_messages.py,sha256=COrnp3bXMG8PRIAD2x5Ka9hk-jI16We9ifXj6JBZI0c,2960
@@ -101,15 +101,15 @@ troubadix/standalone_plugins/dependency_graph/checks.py,sha256=O4KyiVKpKxrgdmADX
101
101
  troubadix/standalone_plugins/dependency_graph/cli.py,sha256=RIyGeSm83XJ88N7Ati6z417hXkMajzzAtqdxnOg-urI,1305
102
102
  troubadix/standalone_plugins/dependency_graph/dependency_graph.py,sha256=_4x_btU9GTdh5MZw56R7hfUwpdejNa2iXXxRRIPiEGU,5536
103
103
  troubadix/standalone_plugins/dependency_graph/models.py,sha256=7kLrjFRdyReTRTgxte6-3KCBve4evg91AcqkX4I8VJU,1002
104
- troubadix/standalone_plugins/deprecate_vts.py,sha256=mLt2DV9Y1YAEuh6c4nFweZYIOprsBzO7115dihEn4lA,7602
104
+ troubadix/standalone_plugins/deprecate_vts.py,sha256=2Lk7aPVsD8iUWSglSr46bcibnxG1KsWsKB9CA1TsmwQ,9528
105
105
  troubadix/standalone_plugins/file_extensions.py,sha256=fqswrhCcQqygIszcnobS9hFQmSpv3gDkvlufoaTckBg,2355
106
106
  troubadix/standalone_plugins/last_modification.py,sha256=ROzwVzzYilXJ0llVt4Lv0w8b9BJKoahl6YxPDiub614,4338
107
107
  troubadix/standalone_plugins/no_solution.py,sha256=p_-az9Igl4GH6HnhLLYbYlWIiEP64OTQLpX-z3JAshs,8760
108
108
  troubadix/standalone_plugins/util.py,sha256=JTXGmi-_BJouTNe6QzEosLlXUt9jKW-3fz4db05RJJw,696
109
109
  troubadix/standalone_plugins/version_updated.py,sha256=6YHF0OjL5NWszQdsSh7XzlSji1e6Uaqwu_Y6m3R0mvI,4203
110
110
  troubadix/troubadix.py,sha256=5__Jz3bYSrya4aG6RCBWxqnsDepXfwXZ3v0bjCzEFi0,6039
111
- troubadix-25.10.8.dist-info/METADATA,sha256=kigEySlJSqyETojN33KHA3-ydy1FluxCt23Yxo2UqJA,4536
112
- troubadix-25.10.8.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
113
- troubadix-25.10.8.dist-info/entry_points.txt,sha256=ETEPBi4fKv3o7hzkzceX4838G6g5_5wRdEddYot8N6A,920
114
- troubadix-25.10.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
115
- troubadix-25.10.8.dist-info/RECORD,,
111
+ troubadix-25.10.10.dist-info/METADATA,sha256=leca1P8z5zmMk5RnLALX8jqEqKMPY1ilL3ii1eH4aLo,4537
112
+ troubadix-25.10.10.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
113
+ troubadix-25.10.10.dist-info/entry_points.txt,sha256=ETEPBi4fKv3o7hzkzceX4838G6g5_5wRdEddYot8N6A,920
114
+ troubadix-25.10.10.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
115
+ troubadix-25.10.10.dist-info/RECORD,,