troubadix 25.6.1__tar.gz → 25.7.1__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.
Files changed (240) hide show
  1. {troubadix-25.6.1 → troubadix-25.7.1}/PKG-INFO +1 -1
  2. {troubadix-25.6.1 → troubadix-25.7.1}/pyproject.toml +2 -1
  3. troubadix-25.7.1/tests/helper/test_if_block_parser.py +216 -0
  4. troubadix-25.7.1/tests/helper/test_remove_comments.py +81 -0
  5. troubadix-25.7.1/tests/helper/test_text_utils.py +168 -0
  6. troubadix-25.7.1/tests/manual_tests/comment_removal_diff.py +62 -0
  7. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_using_display.py +52 -15
  8. troubadix-25.7.1/tests/standalone_plugins/test_changed_creation_date.py +173 -0
  9. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_changed_oid.py +4 -21
  10. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_dependency_graph.py +77 -57
  11. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_file_extensions.py +14 -13
  12. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/__version__.py +1 -1
  13. troubadix-25.7.1/troubadix/helper/if_block_parser.py +200 -0
  14. troubadix-25.7.1/troubadix/helper/remove_comments.py +39 -0
  15. troubadix-25.7.1/troubadix/helper/text_utils.py +80 -0
  16. troubadix-25.7.1/troubadix/plugins/using_display.py +110 -0
  17. troubadix-25.7.1/troubadix/standalone_plugins/changed_creation_date.py +141 -0
  18. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/dependency_graph/dependency_graph.py +12 -14
  19. troubadix-25.7.1/troubadix/standalone_plugins/util.py +27 -0
  20. troubadix-25.6.1/troubadix/plugins/using_display.py +0 -121
  21. {troubadix-25.6.1 → troubadix-25.7.1}/LICENSE +0 -0
  22. {troubadix-25.6.1 → troubadix-25.7.1}/README.md +0 -0
  23. {troubadix-25.6.1 → troubadix-25.7.1}/tests/__init__.py +0 -0
  24. {troubadix-25.6.1 → troubadix-25.7.1}/tests/helper/__init__.py +0 -0
  25. {troubadix-25.6.1 → troubadix-25.7.1}/tests/helper/test_date_format.py +0 -0
  26. {troubadix-25.6.1 → troubadix-25.7.1}/tests/helper/test_linguistic_exception_handler.py +0 -0
  27. {troubadix-25.6.1 → troubadix-25.7.1}/tests/helper/test_patterns.py +0 -0
  28. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/__init__.py +0 -0
  29. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/fail.nasl +0 -0
  30. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/fail2.nasl +0 -0
  31. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test.nasl +0 -0
  32. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_badwords.py +0 -0
  33. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_copyright_text.py +0 -0
  34. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_copyright_year.py +0 -0
  35. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_creation_date.py +0 -0
  36. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_cve_format.py +0 -0
  37. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_cvss_format.py +0 -0
  38. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_dependencies.py +0 -0
  39. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_dependency_category_order.py +0 -0
  40. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_deprecated_dependency.py +0 -0
  41. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_deprecated_functions.py +0 -0
  42. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_double_end_points.py +0 -0
  43. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_duplicate_oid.py +0 -0
  44. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_duplicated_script_tags.py +0 -0
  45. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_encoding.py +0 -0
  46. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/fail_bad_new_line.nasl +0 -0
  47. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/fail_badwords.nasl +0 -0
  48. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/fail_name_and_copyright_newline.nasl +0 -0
  49. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/fail_name_newline.nasl +0 -0
  50. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/fail_permissions.nasl +0 -0
  51. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/fail_spelling.nasl +0 -0
  52. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/fail.nasl +0 -0
  53. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/fail_badwords.nasl +0 -0
  54. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/fail_name_and_copyright_newline.nasl +0 -0
  55. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/fail_name_newline.nasl +0 -0
  56. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/fail_solution_template.nasl +0 -0
  57. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/runner/fail.nasl +0 -0
  58. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/runner/fail2.nasl +0 -0
  59. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/runner/test.nasl +0 -0
  60. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/runner/test_valid_oid.nasl +0 -0
  61. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/test.inc +0 -0
  62. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/21.04/test.nasl +0 -0
  63. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/nasl/warning.nasl +0 -0
  64. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/ok_permissions.nasl +0 -0
  65. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_files/test_oid.nasl +0 -0
  66. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_forking_nasl_functions.py +0 -0
  67. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_get_kb_on_services.py +0 -0
  68. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_grammar.py +0 -0
  69. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_http_links_in_tags.py +0 -0
  70. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_illegal_characters.py +0 -0
  71. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_log_messages.py +0 -0
  72. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_malformed_dependencies.py +0 -0
  73. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_misplaced_compare_in_if.py +0 -0
  74. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_missing_desc_exit.py +0 -0
  75. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_missing_tag_solution.py +0 -0
  76. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_multiple_re_parameters.py +0 -0
  77. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_newlines.py +0 -0
  78. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_overlong_description_lines.py +0 -0
  79. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_overlong_script_tags.py +0 -0
  80. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_prod_svc_detect_in_vulnvt.py +0 -0
  81. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_qod.py +0 -0
  82. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_reporting_consistency.py +0 -0
  83. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_add_preference_type.py +0 -0
  84. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_calls_empty_values.py +0 -0
  85. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_calls_recommended.py +0 -0
  86. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_category.py +0 -0
  87. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_copyright.py +0 -0
  88. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_family.py +0 -0
  89. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_tag_form.py +0 -0
  90. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_tag_whitespaces.py +0 -0
  91. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_tags_mandatory.py +0 -0
  92. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_version_and_last_modification_tags.py +0 -0
  93. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_xref_form.py +0 -0
  94. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_script_xref_url.py +0 -0
  95. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_security_messages.py +0 -0
  96. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_set_get_kb_calls.py +0 -0
  97. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_severity_date.py +0 -0
  98. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_severity_format.py +0 -0
  99. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_severity_origin.py +0 -0
  100. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_solution_text.py +0 -0
  101. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_solution_type.py +0 -0
  102. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_spaces_before_dots.py +0 -0
  103. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_spaces_in_filename.py +0 -0
  104. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_spelling.py +0 -0
  105. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_tabs.py +0 -0
  106. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_todo_tbd.py +0 -0
  107. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_trailing_spaces_tabs.py +0 -0
  108. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_valid_oid.py +0 -0
  109. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_valid_script_tag_names.py +0 -0
  110. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_variable_redefinition_in_foreach.py +0 -0
  111. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_vt_file_permissions.py +0 -0
  112. {troubadix-25.6.1 → troubadix-25.7.1}/tests/plugins/test_vt_placement.py +0 -0
  113. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/__init__.py +0 -0
  114. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/__init__.py +0 -0
  115. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/markers/__init__.py +0 -0
  116. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/markers/test_added_epoch.py +0 -0
  117. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/markers/test_added_release.py +0 -0
  118. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/markers/test_added_udeb.py +0 -0
  119. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/markers/test_changed_update.py +0 -0
  120. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/markers/test_dropped_architecture.py +0 -0
  121. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/test_changed_packages.py +0 -0
  122. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/changed_packages/test_package.py +0 -0
  123. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/nasl/21.04/21_script.nasl +0 -0
  124. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/nasl/22.04/22_script.nasl +0 -0
  125. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/nasl/common/bar.nasl +0 -0
  126. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/nasl/common/foo.nasl +0 -0
  127. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/nasl/common/foobar.nasl +0 -0
  128. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/nasl/common/gsf/enterprise_script.nasl +0 -0
  129. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_changed_cves.py +0 -0
  130. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_deprecate_vts.py +0 -0
  131. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_last_modification.py +0 -0
  132. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_no_solution.py +0 -0
  133. {troubadix-25.6.1 → troubadix-25.7.1}/tests/standalone_plugins/test_version_updated.py +0 -0
  134. {troubadix-25.6.1 → troubadix-25.7.1}/tests/test_argparser.py +0 -0
  135. {troubadix-25.6.1 → troubadix-25.7.1}/tests/test_helper.py +0 -0
  136. {troubadix-25.6.1 → troubadix-25.7.1}/tests/test_naslinter.py +0 -0
  137. {troubadix-25.6.1 → troubadix-25.7.1}/tests/test_reporter.py +0 -0
  138. {troubadix-25.6.1 → troubadix-25.7.1}/tests/test_results.py +0 -0
  139. {troubadix-25.6.1 → troubadix-25.7.1}/tests/test_runner.py +0 -0
  140. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/__init__.py +0 -0
  141. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/argparser.py +0 -0
  142. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/codespell/codespell.additions +0 -0
  143. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/codespell/codespell.exclude +0 -0
  144. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/codespell/codespell.ignore +0 -0
  145. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/helper/__init__.py +0 -0
  146. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/helper/date_format.py +0 -0
  147. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/helper/helper.py +0 -0
  148. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/helper/linguistic_exception_handler.py +0 -0
  149. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/helper/patterns.py +0 -0
  150. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugin.py +0 -0
  151. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/__init__.py +0 -0
  152. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/badwords.py +0 -0
  153. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/copyright_text.py +0 -0
  154. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/copyright_year.py +0 -0
  155. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/creation_date.py +0 -0
  156. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/cve_format.py +0 -0
  157. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/cvss_format.py +0 -0
  158. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/dependencies.py +0 -0
  159. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/dependency_category_order.py +0 -0
  160. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/deprecated_dependency.py +0 -0
  161. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/deprecated_functions.py +0 -0
  162. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/double_end_points.py +0 -0
  163. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/duplicate_oid.py +0 -0
  164. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/duplicated_script_tags.py +0 -0
  165. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/encoding.py +0 -0
  166. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/forking_nasl_functions.py +0 -0
  167. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/get_kb_on_services.py +0 -0
  168. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/grammar.py +0 -0
  169. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/http_links_in_tags.py +0 -0
  170. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/illegal_characters.py +0 -0
  171. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/log_messages.py +0 -0
  172. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/malformed_dependencies.py +0 -0
  173. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/misplaced_compare_in_if.py +0 -0
  174. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/missing_desc_exit.py +0 -0
  175. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/missing_tag_solution.py +0 -0
  176. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/multiple_re_parameters.py +0 -0
  177. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/newlines.py +0 -0
  178. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/overlong_description_lines.py +0 -0
  179. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/overlong_script_tags.py +0 -0
  180. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/prod_svc_detect_in_vulnvt.py +0 -0
  181. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/qod.py +0 -0
  182. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/reporting_consistency.py +0 -0
  183. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_add_preference_type.py +0 -0
  184. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_calls_empty_values.py +0 -0
  185. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_calls_recommended.py +0 -0
  186. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_category.py +0 -0
  187. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_copyright.py +0 -0
  188. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_family.py +0 -0
  189. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_tag_form.py +0 -0
  190. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_tag_whitespaces.py +0 -0
  191. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_tags_mandatory.py +0 -0
  192. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_version_and_last_modification_tags.py +0 -0
  193. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_xref_form.py +0 -0
  194. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/script_xref_url.py +0 -0
  195. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/security_messages.py +0 -0
  196. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/set_get_kb_calls.py +0 -0
  197. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/severity_date.py +0 -0
  198. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/severity_format.py +0 -0
  199. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/severity_origin.py +0 -0
  200. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/solution_text.py +0 -0
  201. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/solution_type.py +0 -0
  202. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/spaces_before_dots.py +0 -0
  203. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/spaces_in_filename.py +0 -0
  204. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/spelling.py +0 -0
  205. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/tabs.py +0 -0
  206. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/todo_tbd.py +0 -0
  207. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/trailing_spaces_tabs.py +0 -0
  208. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/valid_oid.py +0 -0
  209. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/valid_script_tag_names.py +0 -0
  210. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/variable_assigned_in_if.py +0 -0
  211. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/variable_redefinition_in_foreach.py +0 -0
  212. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/vt_file_permissions.py +0 -0
  213. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/plugins/vt_placement.py +0 -0
  214. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/reporter.py +0 -0
  215. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/results.py +0 -0
  216. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/runner.py +0 -0
  217. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/__init__.py +0 -0
  218. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/allowed_rev_diff.py +0 -0
  219. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_cves.py +0 -0
  220. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_oid.py +0 -0
  221. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/changed_packages.py +0 -0
  222. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/__init__.py +0 -0
  223. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/added_epoch.py +0 -0
  224. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/added_release.py +0 -0
  225. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/added_udeb.py +0 -0
  226. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/changed_update.py +0 -0
  227. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/dropped_architecture.py +0 -0
  228. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/marker/marker.py +0 -0
  229. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/changed_packages/package.py +0 -0
  230. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/common.py +0 -0
  231. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/dependency_graph/__init__.py +0 -0
  232. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/dependency_graph/checks.py +0 -0
  233. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/dependency_graph/cli.py +0 -0
  234. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/dependency_graph/models.py +0 -0
  235. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/deprecate_vts.py +0 -0
  236. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/file_extensions.py +0 -0
  237. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/last_modification.py +0 -0
  238. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/no_solution.py +0 -0
  239. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/standalone_plugins/version_updated.py +0 -0
  240. {troubadix-25.6.1 → troubadix-25.7.1}/troubadix/troubadix.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: troubadix
3
- Version: 25.6.1
3
+ Version: 25.7.1
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,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "troubadix"
3
- version = "25.6.1"
3
+ version = "25.7.1"
4
4
  description = "A linting and QA check tool for NASL files"
5
5
  authors = ["Greenbone <info@greenbone.net>"]
6
6
  license = "GPL-3.0-or-later"
@@ -73,6 +73,7 @@ version-module-file = "troubadix/__version__.py"
73
73
 
74
74
  [tool.poetry.scripts]
75
75
  troubadix = 'troubadix.troubadix:main'
76
+ troubadix-changed-creation-date = 'troubadix.standalone_plugins.changed_creation_date:main'
76
77
  troubadix-changed-oid = 'troubadix.standalone_plugins.changed_oid:main'
77
78
  troubadix-last-modification = 'troubadix.standalone_plugins.last_modification:main'
78
79
  troubadix-version-updated = 'troubadix.standalone_plugins.version_updated:main'
@@ -0,0 +1,216 @@
1
+ # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # SPDX-FileCopyrightText: 2025 Greenbone AG
3
+
4
+ import unittest
5
+
6
+ from troubadix.helper.if_block_parser import find_if_statements
7
+
8
+
9
+ class FindIfStatementsTestCase(unittest.TestCase):
10
+ def test_empty_input(self):
11
+ result = find_if_statements("")
12
+ self.assertEqual(len(result), 0)
13
+
14
+ def test_inline_single_expression(self):
15
+ content = 'if(TRUE) display("inline");'
16
+ result = find_if_statements(content)
17
+
18
+ self.assertEqual(1, len(result))
19
+ self.assertEqual("TRUE", result[0].condition)
20
+ self.assertEqual('display("inline")', result[0].statement)
21
+ # Check that position is correct (start at 'if', end at semicolon)
22
+ self.assertEqual(0, result[0].if_start)
23
+ self.assertEqual(len(content), result[0].if_end)
24
+
25
+ def test_single_line_with_newline(self):
26
+ content = 'if(TRUE)\n display("single line");'
27
+ result = find_if_statements(content)
28
+
29
+ self.assertEqual(1, len(result))
30
+ self.assertEqual("TRUE", result[0].condition)
31
+ self.assertEqual('display("single line")', result[0].statement)
32
+
33
+ def test_standard_block(self):
34
+ content = 'if(TRUE) {\n display("block");\n}'
35
+ result = find_if_statements(content)
36
+
37
+ self.assertEqual(1, len(result))
38
+ self.assertEqual("TRUE", result[0].condition)
39
+ self.assertEqual('display("block");', result[0].statement)
40
+ # Check position spans from 'if' to the closing brace
41
+ self.assertEqual(0, result[0].if_start)
42
+ self.assertEqual(len(content), result[0].if_end)
43
+
44
+ def test_block_brace_on_newline(self):
45
+ content = 'if(TRUE)\n{\n display("block");\n}'
46
+ result = find_if_statements(content)
47
+
48
+ self.assertEqual(1, len(result))
49
+ self.assertEqual("TRUE", result[0].condition)
50
+ self.assertEqual('display("block");', result[0].statement)
51
+
52
+ def test_empty_block(self):
53
+ content = "if(TRUE)\n{\n}"
54
+ result = find_if_statements(content)
55
+
56
+ self.assertEqual(1, len(result))
57
+ self.assertEqual("TRUE", result[0].condition)
58
+ self.assertEqual("", result[0].statement.strip())
59
+
60
+ def test_compact_block(self):
61
+ content = "if(TRUE){}"
62
+ result = find_if_statements(content)
63
+
64
+ self.assertEqual(1, len(result))
65
+ self.assertEqual("TRUE", result[0].condition)
66
+ self.assertEqual("", result[0].statement)
67
+
68
+ def test_multiple_if_statements(self):
69
+ content = """
70
+ if(cond1) display("one");
71
+ if(cond2) {
72
+ display("two");
73
+ }
74
+ if(cond3)
75
+ display("three");
76
+ """
77
+ result = find_if_statements(content)
78
+ self.assertEqual(3, len(result))
79
+
80
+ self.assertEqual("cond1", result[0].condition)
81
+ self.assertEqual('display("one")', result[0].statement)
82
+
83
+ self.assertEqual("cond2", result[1].condition)
84
+ self.assertEqual('display("two");', result[1].statement)
85
+
86
+ self.assertEqual("cond3", result[2].condition)
87
+ self.assertEqual('display("three")', result[2].statement)
88
+
89
+ def test_nested_if_statements(self):
90
+ content = """
91
+ if(outer) {
92
+ if(inner1) {
93
+ display("nested block");
94
+ }
95
+ if(inner2) display("nested inline");
96
+ }
97
+ """
98
+ result = find_if_statements(content)
99
+ self.assertEqual(3, len(result))
100
+
101
+ self.assertEqual("outer", result[0].condition)
102
+ self.assertIn("if(inner1)", result[0].statement)
103
+ self.assertIn("if(inner2)", result[0].statement)
104
+
105
+ self.assertEqual("inner1", result[1].condition)
106
+ self.assertIn('display("nested block")', result[1].statement)
107
+
108
+ self.assertEqual("inner2", result[2].condition)
109
+ self.assertEqual('display("nested inline")', result[2].statement)
110
+
111
+ def test_complex_condition(self):
112
+ content = (
113
+ 'if (a == 1 && b > 2 || c != "string") { display("complex"); }'
114
+ )
115
+ result = find_if_statements(content)
116
+
117
+ self.assertEqual(1, len(result))
118
+ self.assertEqual(
119
+ 'a == 1 && b > 2 || c != "string"', result[0].condition
120
+ )
121
+ self.assertEqual('display("complex");', result[0].statement)
122
+
123
+ def test_if_with_problematic_stuff(self):
124
+ # escape single quote and backslash, function call in condition
125
+ content = r"if(some_func('\'\\')) display('\'test\\');"
126
+ result = find_if_statements(content)
127
+
128
+ self.assertEqual(1, len(result))
129
+ self.assertEqual(r"some_func('\'\\')", result[0].condition)
130
+ self.assertEqual(r"display('\'test\\')", result[0].statement)
131
+
132
+ def test_unclosed_parenthesis(self):
133
+ content = "if(unclosed condition\ndisplay();"
134
+ with self.assertRaises(ValueError) as cm:
135
+ find_if_statements(content)
136
+ self.assertEqual(
137
+ "Unclosed parenthesis in if statement at line 1",
138
+ str(cm.exception),
139
+ )
140
+
141
+ def test_no_statement_after_condition(self):
142
+ content = "if(condition)"
143
+ with self.assertRaises(ValueError) as cm:
144
+ find_if_statements(content)
145
+ self.assertEqual(
146
+ "Missing statement after if condition at line 1",
147
+ str(cm.exception),
148
+ )
149
+
150
+ def test_useless_semicolon(self):
151
+ content = "if(condition);"
152
+ with self.assertRaises(ValueError) as cm:
153
+ find_if_statements(content)
154
+ self.assertEqual(
155
+ "Semicolon after if condition at line 1 makes following block always execute."
156
+ " Remove semicolon to fix.",
157
+ str(cm.exception),
158
+ )
159
+
160
+ def test_unclosed_block_brace(self):
161
+ content = "if(condition) {\ndisplay();\n# Missing closing brace"
162
+ with self.assertRaises(ValueError) as cm:
163
+ find_if_statements(content)
164
+ self.assertEqual(
165
+ "Unclosed brace in if statement at line 1",
166
+ str(cm.exception),
167
+ )
168
+
169
+ def test_no_semicolon_in_single_expression(self):
170
+ content = "if(condition) display()" # Missing semicolon
171
+ with self.assertRaises(ValueError) as cm:
172
+ find_if_statements(content)
173
+ self.assertEqual(
174
+ "Missing expression after if condition at line 1",
175
+ str(cm.exception),
176
+ )
177
+
178
+ def test_complex_condition_with_unmatched_brace(self):
179
+ content = "if(func(1, 2) || check(a) { display(); }" # Missing closing ) in condition
180
+ with self.assertRaises(ValueError) as cm:
181
+ find_if_statements(content)
182
+ self.assertEqual(
183
+ "Unclosed parenthesis in if statement at line 1",
184
+ str(cm.exception),
185
+ )
186
+
187
+ def test_position_info_in_error_message(self):
188
+ content = "# Some comment\nif(bad) something" # No semicolon
189
+ with self.assertRaises(ValueError) as cm:
190
+ find_if_statements(content)
191
+ error_msg = str(cm.exception)
192
+ self.assertIn("at line 2", error_msg)
193
+
194
+ def test_condition_and_statement_positions_block(self):
195
+ content = 'if(TRUE) {\n display("block");\n}'
196
+ result = find_if_statements(content)
197
+
198
+ self.assertEqual(1, len(result))
199
+ # Check condition position (inside parentheses)
200
+ self.assertEqual(3, result[0].condition_start)
201
+ self.assertEqual(7, result[0].condition_end)
202
+ # Check statement position (inside braces)
203
+ self.assertEqual(10, result[0].statement_start)
204
+ self.assertEqual(31, result[0].statement_end)
205
+
206
+ def test_condition_and_statement_positions_single(self):
207
+ content = 'if(num > 5) display("inline");'
208
+ result = find_if_statements(content)
209
+
210
+ self.assertEqual(1, len(result))
211
+ # Check condition position (inside parentheses)
212
+ self.assertEqual(3, result[0].condition_start)
213
+ self.assertEqual(10, result[0].condition_end)
214
+ # Check statement position (after parenthesis to semicolon)
215
+ self.assertEqual(12, result[0].statement_start)
216
+ self.assertEqual(29, result[0].statement_end)
@@ -0,0 +1,81 @@
1
+ # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # SPDX-FileCopyrightText: 2025 Greenbone AG
3
+
4
+ import unittest
5
+
6
+ from troubadix.helper.remove_comments import remove_comments
7
+
8
+
9
+ class RemoveCommentsTestCase(unittest.TestCase):
10
+ def test_empty_string(self):
11
+ input_content = ""
12
+ expected_output = ""
13
+ self.assertEqual(remove_comments(input_content), expected_output)
14
+
15
+ def test_no_comments(self):
16
+ input_content = (
17
+ "function detect_archlinux(sock, port, SCRIPT_DESC, is_pfsense) {"
18
+ )
19
+ expected_output = input_content
20
+ self.assertEqual(remove_comments(input_content), expected_output)
21
+
22
+ def test_full_line_comments(self):
23
+ input_content = "# comment\nfunction hello() {\n # Another comment\n return 42;"
24
+ expected_output = "\nfunction hello() {\n\n return 42;"
25
+ self.assertEqual(remove_comments(input_content), expected_output)
26
+
27
+ def test_inline_comments(self):
28
+ input_content = (
29
+ "function hello(){ # A function\n return 42; # The answer"
30
+ )
31
+ expected_output = "function hello(){ \n return 42; "
32
+ self.assertEqual(remove_comments(input_content), expected_output)
33
+
34
+ def test_hash_in_strings(self):
35
+ input_content = "message = 'This # is not a comment';\nurl = \"http://example.com/#anchor\";"
36
+ expected_output = input_content
37
+ self.assertEqual(remove_comments(input_content), expected_output)
38
+
39
+ def test_mixed_quotes_and_comments(self):
40
+ input_content = (
41
+ "display('Hash: #'); # Real comment\n"
42
+ 's = "My string with # character"; # Another comment'
43
+ )
44
+ expected_output = (
45
+ "display('Hash: #'); \ns = \"My string with # character\"; "
46
+ )
47
+ self.assertEqual(remove_comments(input_content), expected_output)
48
+
49
+ def test_complex_scenario(self):
50
+ # ruff does not allow whitespace at end of lines so this looks a bit weird
51
+ input_content = """function hello(){
52
+ # Comment at start
53
+ if (TRUE) {# inline comment
54
+ display('Hello # not a comment');
55
+ # Full comment line
56
+ display("Hash: #");# end comment
57
+ }
58
+ }"""
59
+
60
+ expected_output = """function hello(){
61
+
62
+ if (TRUE) {
63
+ display('Hello # not a comment');
64
+
65
+ display("Hash: #");
66
+ }
67
+ }"""
68
+
69
+ self.assertEqual(remove_comments(input_content), expected_output)
70
+
71
+ def test_indented_comments(self):
72
+ input_content = (
73
+ "function func() {\n # Indented comment\n return 0;\n}"
74
+ )
75
+ expected_output = "function func() {\n\n return 0;\n}"
76
+ self.assertEqual(remove_comments(input_content), expected_output)
77
+
78
+ def test_backslash_double_quotes(self):
79
+ input_content = r'display("\"); # This is a comment'
80
+ expected_output = r'display("\"); '
81
+ self.assertEqual(remove_comments(input_content), expected_output)
@@ -0,0 +1,168 @@
1
+ # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # SPDX-FileCopyrightText: 2025 Greenbone AG
3
+
4
+ import unittest
5
+
6
+ from troubadix.helper.text_utils import (
7
+ StringState,
8
+ index_to_linecol,
9
+ is_position_in_string,
10
+ )
11
+
12
+
13
+ class TestStringState(unittest.TestCase):
14
+ def test_process_normal_char_outside_strings(self):
15
+ state = StringState()
16
+ state.process_next_char("a")
17
+ self.assertFalse(state.escape_next)
18
+ self.assertFalse(state.in_string)
19
+
20
+ def test_enter_double_quotes(self):
21
+ state = StringState()
22
+ state.process_next_char('"')
23
+ self.assertFalse(state.escape_next)
24
+ self.assertTrue(state.in_double_quote)
25
+ self.assertTrue(state.in_string)
26
+
27
+ def test_exit_double_quotes(self):
28
+ state = StringState(in_double_quote=True)
29
+ state.process_next_char('"')
30
+ self.assertFalse(state.escape_next)
31
+ self.assertFalse(state.in_string)
32
+
33
+ def test_enter_single_quotes(self):
34
+ state = StringState()
35
+ state.process_next_char("'")
36
+ self.assertFalse(state.escape_next)
37
+ self.assertTrue(state.in_single_quote)
38
+ self.assertTrue(state.in_string)
39
+
40
+ def test_exit_single_quotes(self):
41
+ state = StringState(in_single_quote=True)
42
+ state.process_next_char("'")
43
+ self.assertFalse(state.escape_next)
44
+ self.assertFalse(state.in_string)
45
+
46
+ def test_escape_in_single_quotes(self):
47
+ state = StringState(in_single_quote=True)
48
+ state.process_next_char("\\")
49
+ self.assertTrue(state.escape_next)
50
+ self.assertTrue(state.in_single_quote)
51
+ self.assertTrue(state.in_string)
52
+
53
+ def test_escaped_single_quote_in_single_quotes(self):
54
+ state = StringState(escape_next=True, in_single_quote=True)
55
+ state.process_next_char("'")
56
+ self.assertFalse(state.escape_next)
57
+ self.assertTrue(state.in_single_quote)
58
+ self.assertTrue(state.in_string)
59
+
60
+ def test_ignore_single_quotes_in_double_quotes(self):
61
+ state = StringState(in_double_quote=True)
62
+ state.process_next_char("'")
63
+ self.assertFalse(state.escape_next)
64
+ self.assertTrue(state.in_double_quote)
65
+ self.assertTrue(state.in_string)
66
+
67
+ def test_ignore_double_quotes_in_single_quotes(self):
68
+ state = StringState(in_single_quote=True)
69
+ state.process_next_char('"')
70
+ self.assertFalse(state.escape_next)
71
+ self.assertTrue(state.in_single_quote)
72
+ self.assertTrue(state.in_string)
73
+
74
+ def test_nasl_backslash_string_sequence(self):
75
+ # Test the sequence "\" in NASL - a valid string where escaping is ignored
76
+ state = StringState()
77
+
78
+ # Enter double quote
79
+ state.process_next_char('"')
80
+ self.assertFalse(state.escape_next)
81
+ self.assertTrue(state.in_double_quote)
82
+
83
+ # Process backslash in double quotes (should not set escape flag)
84
+ state.process_next_char("\\")
85
+ self.assertFalse(state.escape_next)
86
+ self.assertTrue(state.in_double_quote)
87
+
88
+ # Exit double quote
89
+ state.process_next_char('"')
90
+ self.assertFalse(state.escape_next)
91
+ self.assertFalse(state.in_string)
92
+
93
+
94
+ class TestIndexToLinecol(unittest.TestCase):
95
+ def test_start_of_file(self):
96
+ line, col = index_to_linecol("hello\nworld", 0)
97
+ self.assertEqual((line, col), (1, 1))
98
+
99
+ def test_middle_of_first_line(self):
100
+ line, col = index_to_linecol("hello\nworld", 2)
101
+ self.assertEqual((line, col), (1, 3))
102
+
103
+ def test_end_of_first_line(self):
104
+ line, col = index_to_linecol("hello\nworld", 5)
105
+ self.assertEqual((line, col), (1, 6))
106
+
107
+ def test_start_of_second_line(self):
108
+ line, col = index_to_linecol("hello\nworld", 6)
109
+ self.assertEqual((line, col), (2, 1))
110
+
111
+ def test_end_of_file(self):
112
+ line, col = index_to_linecol("hello\nworld", 10)
113
+ self.assertEqual((line, col), (2, 5))
114
+
115
+ def test_multiline_file(self):
116
+ text = "line1\nline2\nline3"
117
+ line, col = index_to_linecol(text, 10)
118
+ self.assertEqual((line, col), (2, 5))
119
+
120
+ def test_empty_file(self):
121
+ self.assertRaises(ValueError, index_to_linecol, "", 0)
122
+
123
+
124
+ class TestIsPositionInString(unittest.TestCase):
125
+ def test_no_strings(self):
126
+ text = "x = 5; y = 10;"
127
+ self.assertFalse(is_position_in_string(text, 0))
128
+ self.assertFalse(is_position_in_string(text, 7))
129
+
130
+ def test_position_before_string(self):
131
+ text = 'x = "hello";'
132
+ self.assertFalse(is_position_in_string(text, 0))
133
+ self.assertFalse(is_position_in_string(text, 3))
134
+
135
+ def test_position_inside_double_quote_string(self):
136
+ text = 'x = "hello";'
137
+ self.assertTrue(is_position_in_string(text, 5)) # inside "hello"
138
+ self.assertTrue(is_position_in_string(text, 9)) # inside "hello"
139
+
140
+ def test_position_inside_single_quote_string(self):
141
+ text = "x = 'world';"
142
+ self.assertTrue(is_position_in_string(text, 5)) # inside 'world'
143
+ self.assertTrue(is_position_in_string(text, 9)) # inside 'world'
144
+
145
+ def test_position_after_string(self):
146
+ text = 'x = "hello";'
147
+ self.assertFalse(is_position_in_string(text, 11)) # after string
148
+
149
+ def test_escaped_quote_in_single_quotes(self):
150
+ text = "x = 'don\\'t';"
151
+ self.assertTrue(is_position_in_string(text, 8)) # inside the string
152
+ self.assertTrue(
153
+ is_position_in_string(text, 10)
154
+ ) # after the escaped quote
155
+
156
+ def test_mixed_quotes(self):
157
+ text = 'a = "it\'s ok"; b = \'say "hi"\';'
158
+ self.assertTrue(is_position_in_string(text, 6)) # inside "it's ok"
159
+ self.assertTrue(is_position_in_string(text, 22)) # inside 'say "hi"'
160
+ self.assertFalse(is_position_in_string(text, 15)) # between strings
161
+
162
+ def test_position_at_quote_characters(self):
163
+ # This checks that the implementation considers only characters before the current index,
164
+ # so the opening quote is not inside the string,
165
+ # but the closing quote is still considered inside.
166
+ text = 'x = "hello";'
167
+ self.assertFalse(is_position_in_string(text, 4)) # at opening quote
168
+ self.assertTrue(is_position_in_string(text, 10)) # at closing quote
@@ -0,0 +1,62 @@
1
+ # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # SPDX-FileCopyrightText: 2025 Greenbone AG
3
+
4
+ import sys
5
+
6
+ from troubadix.helper import CURRENT_ENCODING
7
+ from troubadix.helper.remove_comments import remove_comments
8
+
9
+
10
+ # poetry run python tests/manual_tests/comment_removal_diff.py <path_to_nasl_file>
11
+ def test_comment_removal(input_file):
12
+ """
13
+ Test the remove_comments function and show all lines with their status.
14
+
15
+ Args:
16
+ input_file: Path to the NASL file to test
17
+ """
18
+ try:
19
+ with open(input_file, "r", encoding=CURRENT_ENCODING) as f:
20
+ original_content = f.read()
21
+ except Exception as e:
22
+ print(f"Error reading file: {e}")
23
+ return
24
+
25
+ processed_content = remove_comments(original_content)
26
+
27
+ original_lines = original_content.splitlines()
28
+ processed_lines = processed_content.splitlines()
29
+
30
+ print("\nFull comparison between original and processed file:")
31
+ print("----------------------------------------------------")
32
+
33
+ max_len = max(len(original_lines), len(processed_lines))
34
+
35
+ for i in range(max_len):
36
+ if i < len(original_lines) and i < len(processed_lines):
37
+ if original_lines[i] == processed_lines[i]:
38
+ status = " " # Unchanged
39
+ else:
40
+ status = "! " # Changed
41
+ print(f"{i + 1:4d} {status}{original_lines[i]}")
42
+ if status == "! ":
43
+ print(f" -> {processed_lines[i]}")
44
+
45
+ print("\nSummary:")
46
+ print(f"Original file lines: {len(original_lines)}")
47
+ print(f"Processed file lines: {len(processed_lines)}")
48
+
49
+ comment_lines = 0
50
+ for line in original_lines:
51
+ stripped = line.lstrip()
52
+ if stripped.startswith("#"):
53
+ comment_lines += 1
54
+ print(f"Full-line comments: {comment_lines}")
55
+
56
+
57
+ if __name__ == "__main__":
58
+ if len(sys.argv) != 2:
59
+ print(f"Usage: {sys.argv[0]} <nasl_file>")
60
+ sys.exit(1)
61
+
62
+ test_comment_removal(sys.argv[1])
@@ -38,7 +38,7 @@ class CheckUsingDisplayTestCase(PluginTestCase):
38
38
 
39
39
  results = list(plugin.run())
40
40
 
41
- self.assertEqual(len(results), 0)
41
+ self.assertEqual(0, len(results))
42
42
 
43
43
  def test_using_display(self):
44
44
  path = Path("some/file.nasl")
@@ -55,10 +55,10 @@ class CheckUsingDisplayTestCase(PluginTestCase):
55
55
 
56
56
  results = list(plugin.run())
57
57
 
58
- self.assertEqual(len(results), 1)
58
+ self.assertEqual(1, len(results))
59
59
  self.assertIsInstance(results[0], LinterError)
60
60
  self.assertEqual(
61
- 'VT/Include is using a display() function at: display("FOO");',
61
+ 'VT is using a display() without any if statement at line 3: display("FOO");',
62
62
  results[0].message,
63
63
  )
64
64
 
@@ -77,14 +77,13 @@ class CheckUsingDisplayTestCase(PluginTestCase):
77
77
 
78
78
  results = list(plugin.run())
79
79
 
80
- self.assertEqual(len(results), 1)
80
+ self.assertEqual(1, len(results))
81
81
  self.assertIsInstance(results[0], LinterWarning)
82
- self.assertEqual(
83
- "VT is using a display() function which is "
84
- "protected by a comment or an if statement at: "
85
- 'if (0) display("FOO");.',
82
+ self.assertIn(
83
+ "VT is using a display() inside an if statement but without debug check",
86
84
  results[0].message,
87
85
  )
86
+ self.assertIn('if (0) display("FOO");', results[0].message)
88
87
 
89
88
  def test_using_comment_display(self):
90
89
  path = Path("some/file.nasl")
@@ -101,11 +100,49 @@ class CheckUsingDisplayTestCase(PluginTestCase):
101
100
 
102
101
  results = list(plugin.run())
103
102
 
104
- self.assertEqual(len(results), 1)
105
- self.assertIsInstance(results[0], LinterWarning)
106
- self.assertEqual(
107
- "VT is using a display() function which is "
108
- "protected by a comment or an if statement at: "
109
- '# display("FOO");.',
110
- results[0].message,
103
+ # Comments are removed, so display() won't be found
104
+ self.assertEqual(0, len(results))
105
+
106
+ def test_using_debug_if_display(self):
107
+ """Test that display() inside a debug if statement is allowed"""
108
+ path = Path("some/file.nasl")
109
+ content = (
110
+ ' script_tag(name:"cvss_base", value:"4.0");\n'
111
+ 'if (debug) display("FOO");\n'
111
112
  )
113
+ fake_context = self.create_file_plugin_context(
114
+ nasl_file=path, file_content=content
115
+ )
116
+ plugin = CheckUsingDisplay(fake_context)
117
+
118
+ results = list(plugin.run())
119
+
120
+ # Should be OK because it's in a debug if
121
+ self.assertEqual(0, len(results))
122
+
123
+ def test_display_in_string_ignored(self):
124
+ path = Path("some/file.nasl")
125
+ content = "str = 'display(\"FOO\")';\n"
126
+ fake_context = self.create_file_plugin_context(
127
+ nasl_file=path, file_content=content
128
+ )
129
+ plugin = CheckUsingDisplay(fake_context)
130
+
131
+ results = list(plugin.run())
132
+
133
+ self.assertEqual(0, len(results))
134
+
135
+ def test_propagate_if_parser_error(self):
136
+ path = Path("some/file.nasl")
137
+ content = "if (Foo);\ndisplay('Foo');"
138
+ fake_context = self.create_file_plugin_context(
139
+ nasl_file=path, file_content=content
140
+ )
141
+ plugin = CheckUsingDisplay(fake_context)
142
+
143
+ results = list(plugin.run())
144
+
145
+ # only one result for if parser error,
146
+ # display call not part of result due to early exit of entire run.
147
+ self.assertEqual(1, len(results))
148
+ self.assertIn("Semicolon after if condition", results[0].message)