troubadix 25.3.3__py3-none-any.whl → 25.3.5__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.3.3"
5
+ __version__ = "25.3.5"
@@ -178,9 +178,7 @@ class StandardPlugins(Plugins):
178
178
  files_plugins = _FILES_PLUGINS
179
179
 
180
180
  if excluded_plugins:
181
- self._check_unknown_plugins(
182
- _FILE_PLUGINS + _FILES_PLUGINS, excluded_plugins
183
- )
181
+ self._check_unknown_plugins(excluded_plugins)
184
182
 
185
183
  file_plugins = self._exclude_plugins(excluded_plugins, file_plugins)
186
184
  files_plugins = self._exclude_plugins(
@@ -188,9 +186,7 @@ class StandardPlugins(Plugins):
188
186
  )
189
187
 
190
188
  if included_plugins:
191
- self._check_unknown_plugins(
192
- _FILE_PLUGINS + _FILES_PLUGINS, included_plugins
193
- )
189
+ self._check_unknown_plugins(included_plugins)
194
190
 
195
191
  file_plugins = self._include_plugins(included_plugins, file_plugins)
196
192
  files_plugins = self._include_plugins(
@@ -220,33 +216,25 @@ class StandardPlugins(Plugins):
220
216
  ]
221
217
 
222
218
  @staticmethod
223
- def _check_unknown_plugins(found_plugins, selected_plugins):
224
- if len(found_plugins) == len(selected_plugins):
225
- return
226
-
219
+ def _check_unknown_plugins(selected_plugins: list[str]):
227
220
  all_plugin_names = {
228
221
  name
229
222
  for plugin in _FILE_PLUGINS + _FILES_PLUGINS
230
223
  for name in (plugin.name, plugin.__name__)
231
224
  }
232
- found_plugin_names = {
233
- name
234
- for plugin in found_plugins
235
- for name in (plugin.name, plugin.__name__)
236
- }
237
225
 
238
- unknown_plugins = set(selected_plugins).difference(found_plugin_names)
226
+ unknown_plugins = set(selected_plugins).difference(all_plugin_names)
239
227
 
240
228
  if not unknown_plugins:
241
229
  return
242
230
 
243
- messages = []
244
- for plugin in sorted(unknown_plugins):
245
- message = f"'{plugin}'"
231
+ def build_message(plugin: str):
246
232
  match = difflib.get_close_matches(plugin, all_plugin_names, n=1)
247
- if match:
248
- message += f" (Did you mean '{match[0]}'?)"
249
-
250
- messages.append(message)
233
+ return (
234
+ f"'{plugin}' (Did you mean '{match[0]}'?)"
235
+ if match
236
+ else f"'{plugin}'"
237
+ )
251
238
 
239
+ messages = [build_message(plugin) for plugin in sorted(unknown_plugins)]
252
240
  raise ValueError(f"Unknown plugins: {', '.join(messages)}")
@@ -17,12 +17,10 @@ def check_duplicates(scripts: list[Script]) -> Result:
17
17
  for script in scripts:
18
18
  counter = Counter(dep.name for dep in script.dependencies)
19
19
  duplicates = [dep for dep, count in counter.items() if count > 1]
20
-
21
20
  if duplicates:
22
- msg = f"Duplicate dependencies in {script.name}: {', '.join(duplicates)}"
23
- warnings.append(msg)
21
+ warnings.append(f"in {script.name}: {', '.join(duplicates)}")
24
22
 
25
- return Result(name="check_duplicates", warnings=warnings)
23
+ return Result(name="duplicate dependency", warnings=warnings)
26
24
 
27
25
 
28
26
  def check_missing_dependencies(
@@ -34,20 +32,22 @@ def check_missing_dependencies(
34
32
  logs the scripts dependending on the missing script
35
33
  """
36
34
  errors = []
37
- dependencies = {
35
+ dependency_names = {
38
36
  dep.name for script in scripts for dep in script.dependencies
39
37
  }
40
38
  script_names = {script.name for script in scripts}
41
- missing_dependencies = dependencies - script_names
39
+ missing_dependencies = dependency_names - script_names
42
40
 
43
41
  for missing in missing_dependencies:
44
42
  depending_scripts = graph.predecessors(missing)
45
- msg = f"missing dependency file: {missing}:"
46
- for script in depending_scripts:
47
- msg += f"\n - used by: {script}"
48
- errors.append(msg)
43
+ errors.append(
44
+ f"{missing}:"
45
+ + "".join(
46
+ f"\n - used by: {script}" for script in depending_scripts
47
+ )
48
+ )
49
49
 
50
- return Result(name="missing_dependencies", errors=errors)
50
+ return Result(name="missing dependency", errors=errors)
51
51
 
52
52
 
53
53
  def check_cycles(graph) -> Result:
@@ -59,8 +59,8 @@ def check_cycles(graph) -> Result:
59
59
 
60
60
  cycles = nx.simple_cycles(graph)
61
61
 
62
- errors = [f"cyclic dependency: {cycle}" for cycle in cycles]
63
- return Result(name="check_cycles", errors=errors)
62
+ errors = [str(cycle) for cycle in cycles]
63
+ return Result(name="cyclic dependency", errors=errors)
64
64
 
65
65
 
66
66
  def cross_feed_dependencies(
@@ -86,22 +86,19 @@ def check_cross_feed_dependencies(graph) -> Result:
86
86
  and if they are correctly contained within a is_enterprise_feed check.
87
87
  """
88
88
  gated_cfd = cross_feed_dependencies(graph, is_enterprise_checked=True)
89
- warnings = [
90
- f"cross-feed-dependency: {dependent}(community feed) "
91
- f"depends on {dependency}(enterprise feed)"
89
+ infos = [
90
+ f"{dependent}(community feed) depends on {dependency}(enterprise feed)"
92
91
  for dependent, dependency in gated_cfd
93
92
  ]
94
93
 
95
94
  ungated_cfd = cross_feed_dependencies(graph, is_enterprise_checked=False)
96
95
  errors = [
97
- f"unchecked cross-feed-dependency: {dependent}(community feed) "
98
- f"depends on {dependency}(enterprise feed), but the current feed is not properly checked"
96
+ f"incorrect feed check in {dependent}(community feed) "
97
+ f"which depends on {dependency}(enterprise feed)"
99
98
  for dependent, dependency in ungated_cfd
100
99
  ]
101
100
 
102
- return Result(
103
- name="check_cross_feed_dependencies", warnings=warnings, errors=errors
104
- )
101
+ return Result(name="cross-feed dependency", infos=infos, errors=errors)
105
102
 
106
103
 
107
104
  def check_category_order(graph) -> Result:
@@ -116,7 +113,7 @@ def check_category_order(graph) -> Result:
116
113
  f"{dependent} depends on {dependency} which has a lower category order"
117
114
  for dependent, dependency in problematic_edges
118
115
  ]
119
- return Result(name="check_category_order", errors=errors)
116
+ return Result(name="category order", errors=errors)
120
117
 
121
118
 
122
119
  def check_deprecated_dependencies(graph) -> Result:
@@ -125,4 +122,4 @@ def check_deprecated_dependencies(graph) -> Result:
125
122
  for dependent, dependency in graph.edges()
126
123
  if graph.nodes[dependency].get("deprecated", False)
127
124
  ]
128
- return Result(name="check_deprecated_dependencies", errors=errors)
125
+ return Result(name="deprecated dependency", errors=errors)
@@ -3,7 +3,7 @@
3
3
 
4
4
 
5
5
  import os
6
- from argparse import ArgumentParser, ArgumentTypeError, Namespace
6
+ from argparse import ArgumentParser, Namespace
7
7
  from pathlib import Path
8
8
 
9
9
  from troubadix.argparser import directory_type_existing
@@ -11,13 +11,6 @@ from troubadix.argparser import directory_type_existing
11
11
  from .models import Feed
12
12
 
13
13
 
14
- def feed_type(value: str) -> Feed:
15
- try:
16
- return Feed[value.upper()]
17
- except KeyError:
18
- raise ArgumentTypeError(f"Invalid Feed value: '{value}'")
19
-
20
-
21
14
  def parse_args() -> Namespace:
22
15
  parser = ArgumentParser(
23
16
  description="Tool for analysing the dependencies in the NASL repository.",
@@ -31,18 +24,18 @@ def parse_args() -> Namespace:
31
24
  parser.add_argument(
32
25
  "-f",
33
26
  "--feed",
34
- type=feed_type,
27
+ type=Feed,
35
28
  choices=Feed,
36
- nargs="+",
37
- default=[Feed.FULL],
38
- help="feed",
29
+ default=Feed.COMMON,
30
+ help="Feed selection",
39
31
  )
40
32
  parser.add_argument(
41
33
  "--log",
34
+ type=str.upper,
42
35
  default="WARNING",
43
- help="Set the logging level (INFO, WARNING, ERROR)",
36
+ choices=["INFO", "WARNING", "ERROR"],
37
+ help="Set the logging level (default: WARNING)",
44
38
  )
45
- parser.add_argument("-v", "--verbose", action="count", default=0)
46
39
 
47
40
  args = parser.parse_args()
48
41
 
@@ -5,7 +5,6 @@
5
5
  import logging
6
6
  import re
7
7
  import sys
8
- from functools import reduce
9
8
  from pathlib import Path
10
9
 
11
10
  import networkx as nx
@@ -47,46 +46,23 @@ ENTERPRISE_FEED_CHECK_PATTERN = re.compile(
47
46
 
48
47
 
49
48
  class Reporter:
50
- def __init__(self, verbosity) -> None:
51
- self.verbosity = verbosity
49
+ def __init__(self) -> None:
50
+ self.logger = logging.getLogger(__name__)
52
51
 
53
52
  def report(self, results: list[Result]):
54
53
  for result in results:
55
- if self.verbosity >= 2:
56
- self.print_statistic(result)
57
- self.print_divider()
58
- if self.verbosity >= 1:
59
- self.print_warnings(result)
60
- self.print_errors(result)
61
- if self.verbosity >= 2:
62
- self.print_divider("=")
63
-
64
- def print_divider(self, char="-", length=40):
65
- print(char * length)
66
-
67
- def print_statistic(self, result: Result):
68
- print(
69
- f"{result.name} - warnings: {len(result.warnings)}, errors: {len(result.errors)}"
70
- )
71
-
72
- def print_warnings(self, result: Result):
73
- for warning in result.warnings:
74
- print(f"warning: {warning}")
54
+ for error in result.errors:
55
+ self.logger.error(f"{result.name}: {error}")
56
+ for warning in result.warnings:
57
+ self.logger.warning(f"{result.name}: {warning}")
58
+ for info in result.infos:
59
+ self.logger.info(f"{result.name}: {info}")
75
60
 
76
- def print_errors(self, result: Result):
77
- for error in result.errors:
78
- print(f"error: {error}")
79
61
 
80
-
81
- def get_feed(root, feeds: list[Feed]) -> list[Script]:
82
- feed = reduce((lambda x, y: x | y), feeds)
83
- scripts = []
84
- if feed & Feed.COMMON:
85
- scripts.extend(get_scripts(root / "common"))
86
- if feed & Feed.FEED_21_04:
87
- scripts.extend(get_scripts(root / "21.04"))
88
- if feed & Feed.FEED_22_04:
89
- scripts.extend(get_scripts(root / "22.04"))
62
+ def get_feed(root: Path, feed: Feed) -> list[Script]:
63
+ scripts = get_scripts(root / "common") # Always include common
64
+ if feed != Feed.COMMON: # Add version-specific scripts if not just common
65
+ scripts.extend(get_scripts(root / feed.value))
90
66
 
91
67
  return scripts
92
68
 
@@ -197,7 +173,7 @@ def main():
197
173
  check_category_order(graph),
198
174
  check_deprecated_dependencies(graph),
199
175
  ]
200
- reporter = Reporter(args.verbose)
176
+ reporter = Reporter()
201
177
  reporter.report(results)
202
178
 
203
179
  if any(result.errors for result in results):
@@ -2,18 +2,19 @@
2
2
  # SPDX-FileCopyrightText: 2025 Greenbone AG
3
3
 
4
4
  from dataclasses import dataclass, field
5
- from enum import Flag, auto
5
+ from enum import Enum
6
6
 
7
7
 
8
- class Feed(Flag):
9
- COMMON = auto()
10
- FEED_21_04 = auto()
11
- FEED_22_04 = auto()
12
- FULL = COMMON | FEED_21_04 | FEED_22_04
8
+ class Feed(str, Enum):
9
+ COMMON = "common"
10
+ FEED_21_04 = "21.04"
11
+ FEED_22_04 = "22.04"
13
12
 
14
- def __str__(self):
15
- # Make enum values user-friendly for argparse help
16
- return self.name.lower()
13
+
14
+ class OutputLevel(Enum):
15
+ ERROR = 1
16
+ WARNING = 2
17
+ INFO = 3
17
18
 
18
19
 
19
20
  @dataclass
@@ -35,6 +36,11 @@ class Script:
35
36
 
36
37
  @dataclass
37
38
  class Result:
39
+ """Holds the results of a single check.
40
+ A check can report a combination of errors, warnings and infos
41
+ """
42
+
38
43
  name: str
39
44
  warnings: list[str] = field(default_factory=list)
40
45
  errors: list[str] = field(default_factory=list)
46
+ infos: list[str] = field(default_factory=list)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: troubadix
3
- Version: 25.3.3
3
+ Version: 25.3.5
4
4
  Summary: A linting and QA check tool for NASL files
5
5
  License: GPL-3.0-or-later
6
6
  Author: Greenbone
@@ -1,5 +1,5 @@
1
1
  troubadix/__init__.py,sha256=K7sIXXDrC7YRb7BvIpdQ6ZfG_QkT0qUH_wAlHROVRfM,716
2
- troubadix/__version__.py,sha256=q5kWKpRVFYVkKWYs2N4F77Md7amqbRNf6_bct4WFtMA,103
2
+ troubadix/__version__.py,sha256=7WX-neef-Lza94lX2gc3qmODm6ncbJ_M8Dmn9cEJfgg,103
3
3
  troubadix/argparser.py,sha256=-H07Jhqh68_M4Mbjq9qJjTr3MShy_N2pxl2qHA6cfRU,7481
4
4
  troubadix/codespell/codespell.additions,sha256=NAYnQF79kdk4YhU_h8fpjAVVkqBm778aPHPPP7FEkZY,504
5
5
  troubadix/codespell/codespell.exclude,sha256=RS0PH7Px2NRg40UpreuXfnInaC4veaeeDxP1FNac4ms,147431
@@ -9,7 +9,7 @@ troubadix/helper/helper.py,sha256=GXapYLii2rLKwkX2ok31YoAdUSizBnyPjWz-aPP6HM8,31
9
9
  troubadix/helper/linguistic_exception_handler.py,sha256=Bq7ULjDdWTKUpFNTUX6XMPdD4s4v8eIjZPyqBe8VLws,6811
10
10
  troubadix/helper/patterns.py,sha256=_ifRnwHsPee9B0yRYSCsyFms4StWVWJq7I9YnQwToa8,9174
11
11
  troubadix/plugin.py,sha256=3fQPj3Qe_hgwHerlYE4hbdzYMzRU557NxJ-UwtE9mOI,3525
12
- troubadix/plugins/__init__.py,sha256=SqunGwbE9ReOyhRLgoSAo6zxvKWhQdvWVWlnS8kKys4,8754
12
+ troubadix/plugins/__init__.py,sha256=v328Yxgd8dU8g69Jpe4li-HM0iaqoT9_bOxfA7hP8jU,8445
13
13
  troubadix/plugins/badwords.py,sha256=k1A1d2pdXzie87FGGXrykP2BgdZbY5QtmQItupHtNyw,4701
14
14
  troubadix/plugins/copyright_text.py,sha256=jYsLWmTbT_A78XQQxQFK-5kMMHkh3xdvlh7mEF2dZGU,3583
15
15
  troubadix/plugins/copyright_year.py,sha256=XzM9MHVzOXwNLwHpfuaWj8PUOmswr56SBVOLBdvxjd4,5478
@@ -88,18 +88,18 @@ troubadix/standalone_plugins/changed_packages/marker/marker.py,sha256=7uZXR2Ds_8
88
88
  troubadix/standalone_plugins/changed_packages/package.py,sha256=Pcr2tcwiPTzD3jB0iteqA7-TajL-dl5Onh1dvC_H9xk,2743
89
89
  troubadix/standalone_plugins/common.py,sha256=PkScV-lisNY4WyrzwjV3dK1DF26hJv5JXTcREblJ0v0,1028
90
90
  troubadix/standalone_plugins/dependency_graph/__init__.py,sha256=SQSaQXWmpq5-5ozpqMgvnvoYTK8oj64A5kie1m_5bWQ,88
91
- troubadix/standalone_plugins/dependency_graph/checks.py,sha256=nrpY2cyQlRb-A6gbVq-1bQEYlanNdOJwfX4liwjiN6Q,4249
92
- troubadix/standalone_plugins/dependency_graph/cli.py,sha256=osTVMWknVo_jWmlaYtRM-qcE88c_YVcT1my-jnFdxiM,1510
93
- troubadix/standalone_plugins/dependency_graph/dependency_graph.py,sha256=TB54FTBFlt2iNDqLrlYj9AO04ntS7DN44ASMwfbJWy8,6257
94
- troubadix/standalone_plugins/dependency_graph/models.py,sha256=bEvj71inolH-_NLv1fEHMYF8tH9ck-T0jIlThR91uPM,918
91
+ troubadix/standalone_plugins/dependency_graph/checks.py,sha256=O4KyiVKpKxrgdmADXiduKY794nZndyy7epilbbY7JLo,4074
92
+ troubadix/standalone_plugins/dependency_graph/cli.py,sha256=RIyGeSm83XJ88N7Ati6z417hXkMajzzAtqdxnOg-urI,1305
93
+ troubadix/standalone_plugins/dependency_graph/dependency_graph.py,sha256=G_Ilm_EENpVHTw8wItknbfytVPRuTnVN1OoZEYvlTaU,5613
94
+ troubadix/standalone_plugins/dependency_graph/models.py,sha256=7kLrjFRdyReTRTgxte6-3KCBve4evg91AcqkX4I8VJU,1002
95
95
  troubadix/standalone_plugins/deprecate_vts.py,sha256=mLt2DV9Y1YAEuh6c4nFweZYIOprsBzO7115dihEn4lA,7602
96
96
  troubadix/standalone_plugins/file_extensions.py,sha256=fqswrhCcQqygIszcnobS9hFQmSpv3gDkvlufoaTckBg,2355
97
97
  troubadix/standalone_plugins/last_modification.py,sha256=ROzwVzzYilXJ0llVt4Lv0w8b9BJKoahl6YxPDiub614,4338
98
98
  troubadix/standalone_plugins/no_solution.py,sha256=p_-az9Igl4GH6HnhLLYbYlWIiEP64OTQLpX-z3JAshs,8760
99
99
  troubadix/standalone_plugins/version_updated.py,sha256=6YHF0OjL5NWszQdsSh7XzlSji1e6Uaqwu_Y6m3R0mvI,4203
100
100
  troubadix/troubadix.py,sha256=5__Jz3bYSrya4aG6RCBWxqnsDepXfwXZ3v0bjCzEFi0,6039
101
- troubadix-25.3.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
102
- troubadix-25.3.3.dist-info/METADATA,sha256=6WS3yLPwR9a83b4Xc4RNhqISrOWddfYAB4px3jUsDw8,4462
103
- troubadix-25.3.3.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
104
- troubadix-25.3.3.dist-info/entry_points.txt,sha256=SnhEUe4W76P-ADmO9J355gRztTyHU_PTxRewKy3-e5o,832
105
- troubadix-25.3.3.dist-info/RECORD,,
101
+ troubadix-25.3.5.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
102
+ troubadix-25.3.5.dist-info/METADATA,sha256=bs9tbGZf3ZCQ7DNhvHsiW_5T20XwH0d56zD4Y4DGKKs,4462
103
+ troubadix-25.3.5.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
104
+ troubadix-25.3.5.dist-info/entry_points.txt,sha256=SnhEUe4W76P-ADmO9J355gRztTyHU_PTxRewKy3-e5o,832
105
+ troubadix-25.3.5.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.1
2
+ Generator: poetry-core 2.1.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any