troubadix 25.10.9__py3-none-any.whl → 25.11.0__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.9"
5
+ __version__ = "25.11.0"
@@ -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);
@@ -78,3 +78,29 @@ def is_position_in_string(text: str, position: int) -> bool:
78
78
  string_state.process_next_char(char)
79
79
 
80
80
  return string_state.in_string
81
+
82
+
83
+ def find_matching_brace(
84
+ text: str, opening_pos: int, braces: tuple[str, str] = ("(", ")")
85
+ ) -> int | None:
86
+ """
87
+ Return the index of the matching closing brace for the brace at opening_pos.
88
+ """
89
+ opening, closing = braces
90
+ depth = 1
91
+ string_state = StringState()
92
+
93
+ for pos in range(opening_pos + 1, len(text)):
94
+ char = text[pos]
95
+ string_state.process_next_char(char)
96
+
97
+ if string_state.in_string:
98
+ continue
99
+
100
+ if char == opening:
101
+ depth += 1
102
+ elif char == closing:
103
+ depth -= 1
104
+ if depth == 0:
105
+ return pos
106
+ return None
@@ -53,6 +53,7 @@ from .overlong_script_tags import CheckOverlongScriptTags
53
53
  from .prod_svc_detect_in_vulnvt import CheckProdSvcDetectInVulnvt
54
54
  from .qod import CheckQod
55
55
  from .reporting_consistency import CheckReportingConsistency
56
+ from .script_add_preference_id import CheckScriptAddPreferenceId
56
57
  from .script_add_preference_type import CheckScriptAddPreferenceType
57
58
  from .script_calls_empty_values import CheckScriptCallsEmptyValues
58
59
  from .script_calls_recommended import CheckScriptCallsRecommended
@@ -151,6 +152,7 @@ _FILE_PLUGINS = [
151
152
  CheckWrongSetGetKBCalls,
152
153
  CheckSpacesBeforeDots,
153
154
  CheckIfStatementSyntax,
155
+ CheckScriptAddPreferenceId,
154
156
  ]
155
157
 
156
158
  # plugins checking all files
@@ -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(
@@ -0,0 +1,53 @@
1
+ # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # SPDX-FileCopyrightText: 2025 Greenbone AG
3
+
4
+ import re
5
+ from collections.abc import Iterator
6
+ from pathlib import Path
7
+
8
+ from troubadix.helper.text_utils import find_matching_brace
9
+ from troubadix.plugin import FileContentPlugin, LinterError, LinterResult
10
+
11
+ SCRIPT_CALL_PATTERN = re.compile(r"script_add_preference\s*\(")
12
+ ID_PATTERN = re.compile(r"id\s*:\s*(?P<id>\d+)")
13
+
14
+
15
+ def iter_script_add_preference_values(
16
+ source: str,
17
+ ) -> Iterator[str]:
18
+ for match in SCRIPT_CALL_PATTERN.finditer(source):
19
+ opening_paren = match.end() - 1
20
+ closing_paren = find_matching_brace(source, opening_paren, ("(", ")"))
21
+ if closing_paren is None:
22
+ continue
23
+ yield source[opening_paren + 1 : closing_paren]
24
+
25
+
26
+ class CheckScriptAddPreferenceId(FileContentPlugin):
27
+ name = "check_script_add_preference_id"
28
+
29
+ def check_content(
30
+ self, nasl_file: Path, file_content: str
31
+ ) -> Iterator[LinterResult]:
32
+ if (
33
+ nasl_file.suffix == ".inc"
34
+ or "script_add_preference" not in file_content
35
+ ):
36
+ return
37
+
38
+ seen_ids: set[int] = set()
39
+
40
+ for index, value in enumerate(
41
+ iter_script_add_preference_values(file_content), 1
42
+ ):
43
+ id_match = ID_PATTERN.search(value)
44
+ pref_id = int(id_match.group("id")) if id_match else index
45
+
46
+ if pref_id in seen_ids:
47
+ yield LinterError(
48
+ f"script_add_preference id {pref_id} is used multiple times",
49
+ file=nasl_file,
50
+ plugin=self.name,
51
+ )
52
+
53
+ seen_ids.add(pref_id)
@@ -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.9
3
+ Version: 25.11.0
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=5vWilWzDGYBXmf8qR5PG3cr7jcf2aD3Xeu9CIBn01Ms,104
2
+ troubadix/__version__.py,sha256=9t47mYdr93-yy77T-BAoI9lMqA4XEmi1aMSqoDHycO8,104
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
@@ -11,9 +11,9 @@ troubadix/helper/if_block_parser.py,sha256=_51UlsYrELt4GwWzJIU7qc7HIZPdpmExLG8WM
11
11
  troubadix/helper/linguistic_exception_handler.py,sha256=Bq7ULjDdWTKUpFNTUX6XMPdD4s4v8eIjZPyqBe8VLws,6811
12
12
  troubadix/helper/patterns.py,sha256=qhiAtNQs89Hk6-yRGrjjRO4DdVIMhYLd8IEQ48REpu4,9752
13
13
  troubadix/helper/remove_comments.py,sha256=zjhXPQXgKaEOparAdu4aBXcJlEul8LbNaP3uLCYGwHw,1244
14
- troubadix/helper/text_utils.py,sha256=gBX0box9VtgA0CMfE0u2Vvi1IuOopxUfCQFYn_1wVjE,2543
14
+ troubadix/helper/text_utils.py,sha256=YM0qaiBDsWJSUkQoRPFjVGEvQsLVDxN90GwNb240Lb8,3184
15
15
  troubadix/plugin.py,sha256=3fQPj3Qe_hgwHerlYE4hbdzYMzRU557NxJ-UwtE9mOI,3525
16
- troubadix/plugins/__init__.py,sha256=7NqTzddmptQZJ_s1yxpamVo0Y8zohAWlEQU2lf103_Y,8745
16
+ troubadix/plugins/__init__.py,sha256=C6ym0txssNcF7a4MiSl6uhDOeWYL3b-GcTa03pm5Edk,8842
17
17
  troubadix/plugins/badwords.py,sha256=ppTJT7yl6kPo51PT-mHxpbmuKMJpBgEKzLDU0sLktig,5014
18
18
  troubadix/plugins/copyright_text.py,sha256=jYsLWmTbT_A78XQQxQFK-5kMMHkh3xdvlh7mEF2dZGU,3583
19
19
  troubadix/plugins/copyright_year.py,sha256=XzM9MHVzOXwNLwHpfuaWj8PUOmswr56SBVOLBdvxjd4,5478
@@ -31,7 +31,7 @@ troubadix/plugins/encoding.py,sha256=Ow_ZpyjtL2_nqhbukY_3EUhiR0agfSxMxJ4IcMSGsT4
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
@@ -46,6 +46,7 @@ troubadix/plugins/overlong_script_tags.py,sha256=LKJQxX9s2fkExkM0MOIqYZGOKbEe9et
46
46
  troubadix/plugins/prod_svc_detect_in_vulnvt.py,sha256=AnHF5jPNz4wEr-etZ2fkJNqqMH2he-9ofOdzWJyPeK4,4292
47
47
  troubadix/plugins/qod.py,sha256=OMEjZR3fbimLX4F3LsMZZn4IZi32j4soMYp1uQFv5Sc,4164
48
48
  troubadix/plugins/reporting_consistency.py,sha256=yp4FQ8T6gVPzLDF5334mGG5m8n9x8c2I_ApfHzZpVRA,4024
49
+ troubadix/plugins/script_add_preference_id.py,sha256=LcmvhMLnYNqEp3S1j9HdMZ1w-cUWdmMTlts8Pru0aR8,1669
49
50
  troubadix/plugins/script_add_preference_type.py,sha256=PHySUVWqI8dG51xI0CIzaB2a83GicCryPtbcugE8jgE,3643
50
51
  troubadix/plugins/script_calls_empty_values.py,sha256=XdtqTGWI3k_3eId-XAgxwXLxucENqC5CIQJG8Ncn1_M,2512
51
52
  troubadix/plugins/script_calls_recommended.py,sha256=GHnfCKBlmutfCXrkvvujvDR7TJDxr2Dx2KZDMa1z_TU,3180
@@ -101,15 +102,15 @@ troubadix/standalone_plugins/dependency_graph/checks.py,sha256=O4KyiVKpKxrgdmADX
101
102
  troubadix/standalone_plugins/dependency_graph/cli.py,sha256=RIyGeSm83XJ88N7Ati6z417hXkMajzzAtqdxnOg-urI,1305
102
103
  troubadix/standalone_plugins/dependency_graph/dependency_graph.py,sha256=_4x_btU9GTdh5MZw56R7hfUwpdejNa2iXXxRRIPiEGU,5536
103
104
  troubadix/standalone_plugins/dependency_graph/models.py,sha256=7kLrjFRdyReTRTgxte6-3KCBve4evg91AcqkX4I8VJU,1002
104
- troubadix/standalone_plugins/deprecate_vts.py,sha256=mLt2DV9Y1YAEuh6c4nFweZYIOprsBzO7115dihEn4lA,7602
105
+ troubadix/standalone_plugins/deprecate_vts.py,sha256=2Lk7aPVsD8iUWSglSr46bcibnxG1KsWsKB9CA1TsmwQ,9528
105
106
  troubadix/standalone_plugins/file_extensions.py,sha256=fqswrhCcQqygIszcnobS9hFQmSpv3gDkvlufoaTckBg,2355
106
107
  troubadix/standalone_plugins/last_modification.py,sha256=ROzwVzzYilXJ0llVt4Lv0w8b9BJKoahl6YxPDiub614,4338
107
108
  troubadix/standalone_plugins/no_solution.py,sha256=p_-az9Igl4GH6HnhLLYbYlWIiEP64OTQLpX-z3JAshs,8760
108
109
  troubadix/standalone_plugins/util.py,sha256=JTXGmi-_BJouTNe6QzEosLlXUt9jKW-3fz4db05RJJw,696
109
110
  troubadix/standalone_plugins/version_updated.py,sha256=6YHF0OjL5NWszQdsSh7XzlSji1e6Uaqwu_Y6m3R0mvI,4203
110
111
  troubadix/troubadix.py,sha256=5__Jz3bYSrya4aG6RCBWxqnsDepXfwXZ3v0bjCzEFi0,6039
111
- troubadix-25.10.9.dist-info/METADATA,sha256=vqH-RyAUMdTGfE_TiQ1WAsxQrsyXNm5LSD4xuf7l7G8,4536
112
- troubadix-25.10.9.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
113
- troubadix-25.10.9.dist-info/entry_points.txt,sha256=ETEPBi4fKv3o7hzkzceX4838G6g5_5wRdEddYot8N6A,920
114
- troubadix-25.10.9.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
115
- troubadix-25.10.9.dist-info/RECORD,,
112
+ troubadix-25.11.0.dist-info/METADATA,sha256=LviylbQXVt8_Zb2I1pXzOEbyUYXjzbTfGN5XYlxGyGg,4536
113
+ troubadix-25.11.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
114
+ troubadix-25.11.0.dist-info/entry_points.txt,sha256=ETEPBi4fKv3o7hzkzceX4838G6g5_5wRdEddYot8N6A,920
115
+ troubadix-25.11.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
116
+ troubadix-25.11.0.dist-info/RECORD,,