scythe-ttp 0.17.0__tar.gz → 0.17.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 (59) hide show
  1. {scythe_ttp-0.17.0/scythe_ttp.egg-info → scythe_ttp-0.17.1}/PKG-INFO +1 -1
  2. scythe_ttp-0.17.1/VERSION +1 -0
  3. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/cli/main.py +13 -0
  4. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/core/executor.py +18 -0
  5. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/journeys/executor.py +6 -0
  6. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1/scythe_ttp.egg-info}/PKG-INFO +1 -1
  7. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_expected_results.py +57 -0
  8. scythe_ttp-0.17.0/VERSION +0 -1
  9. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/LICENSE +0 -0
  10. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/MANIFEST.in +0 -0
  11. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/README.md +0 -0
  12. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/pyproject.toml +0 -0
  13. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/requirements.txt +0 -0
  14. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/__init__.py +0 -0
  15. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/auth/__init__.py +0 -0
  16. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/auth/base.py +0 -0
  17. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/auth/basic.py +0 -0
  18. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/auth/bearer.py +0 -0
  19. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/auth/cookie_jwt.py +0 -0
  20. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/behaviors/__init__.py +0 -0
  21. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/behaviors/base.py +0 -0
  22. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/behaviors/default.py +0 -0
  23. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/behaviors/human.py +0 -0
  24. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/behaviors/machine.py +0 -0
  25. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/behaviors/stealth.py +0 -0
  26. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/cli/__init__.py +0 -0
  27. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/core/__init__.py +0 -0
  28. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/core/headers.py +0 -0
  29. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/core/ttp.py +0 -0
  30. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/journeys/__init__.py +0 -0
  31. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/journeys/actions.py +0 -0
  32. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/journeys/base.py +0 -0
  33. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/orchestrators/__init__.py +0 -0
  34. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/orchestrators/base.py +0 -0
  35. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/orchestrators/batch.py +0 -0
  36. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/orchestrators/distributed.py +0 -0
  37. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/orchestrators/scale.py +0 -0
  38. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/payloads/__init__.py +0 -0
  39. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/payloads/generators.py +0 -0
  40. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/ttps/__init__.py +0 -0
  41. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/ttps/web/__init__.py +0 -0
  42. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/ttps/web/login_bruteforce.py +0 -0
  43. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/ttps/web/sql_injection.py +0 -0
  44. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe/ttps/web/uuid_guessing.py +0 -0
  45. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe_ttp.egg-info/SOURCES.txt +0 -0
  46. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe_ttp.egg-info/dependency_links.txt +0 -0
  47. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe_ttp.egg-info/entry_points.txt +0 -0
  48. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe_ttp.egg-info/requires.txt +0 -0
  49. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/scythe_ttp.egg-info/top_level.txt +0 -0
  50. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/setup.cfg +0 -0
  51. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_api_models.py +0 -0
  52. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_authentication.py +0 -0
  53. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_behaviors.py +0 -0
  54. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_cli.py +0 -0
  55. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_cookie_jwt_auth.py +0 -0
  56. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_feature_completeness.py +0 -0
  57. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_header_extraction.py +0 -0
  58. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_journeys.py +0 -0
  59. {scythe_ttp-0.17.0 → scythe_ttp-0.17.1}/tests/test_orchestrators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scythe-ttp
3
- Version: 0.17.0
3
+ Version: 0.17.1
4
4
  Summary: An extensible framework for emulating attacker TTPs with Selenium.
5
5
  Author-email: EpykLab <cyber@epyklab.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -0,0 +1 @@
1
+ 0.17.1
@@ -68,6 +68,19 @@ def check_version_in_response_header(args) -> bool:
68
68
  def scythe_test_definition(args) -> bool:
69
69
  # TODO: implement your test using Scythe primitives.
70
70
  # Example placeholder that simply passes.
71
+
72
+ # Example usage with TTPExecutor:
73
+ # from scythe.core.executor import TTPExecutor
74
+ # executor = TTPExecutor(ttp=my_ttp, target_url=args.url)
75
+ # executor.run()
76
+ # return executor.was_successful() # Returns True if all results matched expectations
77
+
78
+ # Example usage with JourneyExecutor:
79
+ # from scythe.journeys.executor import JourneyExecutor
80
+ # executor = JourneyExecutor(journey=my_journey, target_url=args.url)
81
+ # executor.run()
82
+ # return executor.was_successful() # Returns True if journey succeeded as expected
83
+
71
84
  return True
72
85
 
73
86
 
@@ -40,6 +40,7 @@ class TTPExecutor:
40
40
  self.driver = None
41
41
  self.results = []
42
42
  self.header_extractor = HeaderExtractor()
43
+ self.has_test_failures = False # Track if any test had unexpected results
43
44
 
44
45
  def _setup_driver(self):
45
46
  """Initializes the WebDriver."""
@@ -134,10 +135,12 @@ class TTPExecutor:
134
135
  else:
135
136
  version_info = f" | Version: {target_version}" if target_version else ""
136
137
  self.logger.warning(f"UNEXPECTED SUCCESS: '{payload}' (expected to fail){version_info}")
138
+ self.has_test_failures = True # Mark as failure when result differs from expected
137
139
  else:
138
140
  consecutive_failures += 1
139
141
  if self.ttp.expected_result:
140
142
  self.logger.info(f"EXPECTED FAILURE: '{payload}' (security control working)")
143
+ self.has_test_failures = True # Mark as failure when result differs from expected
141
144
  else:
142
145
  self.logger.info(f"EXPECTED FAILURE: '{payload}'")
143
146
 
@@ -212,3 +215,18 @@ class TTPExecutor:
212
215
  self.logger.info("No successes detected (expected to find vulnerabilities).")
213
216
  else:
214
217
  self.logger.info("No successes detected (security controls working as expected).")
218
+
219
+ # Log overall test status
220
+ if self.has_test_failures:
221
+ self.logger.error("\n✗ TEST FAILED: One or more test results differed from expected")
222
+ else:
223
+ self.logger.info("\n✓ TEST PASSED: All test results matched expectations")
224
+
225
+ def was_successful(self) -> bool:
226
+ """
227
+ Check if all test results matched expectations.
228
+
229
+ Returns:
230
+ True if all test results matched expectations, False otherwise
231
+ """
232
+ return not self.has_test_failures
@@ -406,6 +406,12 @@ class JourneyExecutor:
406
406
  else:
407
407
  self.logger.info("\nNo X-SCYTHE-TARGET-VERSION headers detected in responses.")
408
408
 
409
+ # Log overall test status (similar to TTPExecutor)
410
+ if self.was_successful():
411
+ self.logger.info("\n✓ TEST PASSED: Journey results matched expectations")
412
+ else:
413
+ self.logger.error("\n✗ TEST FAILED: Journey results differed from expected")
414
+
409
415
  self.logger.info("="*60)
410
416
 
411
417
  def get_results(self) -> Optional[Dict[str, Any]]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scythe-ttp
3
- Version: 0.17.0
3
+ Version: 0.17.1
4
4
  Summary: An extensible framework for emulating attacker TTPs with Selenium.
5
5
  Author-email: EpykLab <cyber@epyklab.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -296,6 +296,63 @@ class TestExpectedResults(unittest.TestCase):
296
296
 
297
297
  self.assertTrue(ttp_pass.expected_result)
298
298
  self.assertFalse(ttp_fail.expected_result)
299
+
300
+ @patch('scythe.core.executor.webdriver.Chrome')
301
+ def test_was_successful_with_expected_results(self, mock_webdriver):
302
+ """Test was_successful() returns True when all results match expectations."""
303
+ mock_webdriver.return_value = self.mock_driver
304
+
305
+ # Test with expected successes
306
+ ttp = MockTTP(
307
+ name="Test TTP",
308
+ description="Test description",
309
+ expected_result=True,
310
+ success_results=[True, True]
311
+ )
312
+
313
+ executor = TTPExecutor(ttp=ttp, target_url="http://test.com", headless=True)
314
+ executor.run()
315
+
316
+ # Should return True since results matched expectations
317
+ self.assertTrue(executor.was_successful())
318
+
319
+ @patch('scythe.core.executor.webdriver.Chrome')
320
+ def test_was_successful_with_unexpected_results(self, mock_webdriver):
321
+ """Test was_successful() returns False when results don't match expectations."""
322
+ mock_webdriver.return_value = self.mock_driver
323
+
324
+ # Test with unexpected successes (expected to fail but succeeded)
325
+ ttp = MockTTP(
326
+ name="Test TTP",
327
+ description="Test description",
328
+ expected_result=False,
329
+ success_results=[True]
330
+ )
331
+
332
+ executor = TTPExecutor(ttp=ttp, target_url="http://test.com", headless=True)
333
+ executor.run()
334
+
335
+ # Should return False since we got unexpected success
336
+ self.assertFalse(executor.was_successful())
337
+
338
+ @patch('scythe.core.executor.webdriver.Chrome')
339
+ def test_was_successful_with_unexpected_failures(self, mock_webdriver):
340
+ """Test was_successful() returns False when expected success but got failure."""
341
+ mock_webdriver.return_value = self.mock_driver
342
+
343
+ # Test expecting success but getting failure
344
+ ttp = MockTTP(
345
+ name="Test TTP",
346
+ description="Test description",
347
+ expected_result=True,
348
+ success_results=[False, False]
349
+ )
350
+
351
+ executor = TTPExecutor(ttp=ttp, target_url="http://test.com", headless=True)
352
+ executor.run()
353
+
354
+ # Should return False since we expected success but got failures
355
+ self.assertFalse(executor.was_successful())
299
356
 
300
357
 
301
358
  if __name__ == '__main__':
scythe_ttp-0.17.0/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.17.0
File without changes
File without changes
File without changes
File without changes
File without changes