scythe-ttp 0.15.10__tar.gz → 0.16.0__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.

Potentially problematic release.


This version of scythe-ttp might be problematic. Click here for more details.

Files changed (59) hide show
  1. {scythe_ttp-0.15.10/scythe_ttp.egg-info → scythe_ttp-0.16.0}/PKG-INFO +1 -1
  2. scythe_ttp-0.16.0/VERSION +1 -0
  3. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/journeys/actions.py +29 -7
  4. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0/scythe_ttp.egg-info}/PKG-INFO +1 -1
  5. scythe_ttp-0.15.10/VERSION +0 -1
  6. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/LICENSE +0 -0
  7. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/MANIFEST.in +0 -0
  8. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/README.md +0 -0
  9. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/pyproject.toml +0 -0
  10. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/requirements.txt +0 -0
  11. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/__init__.py +0 -0
  12. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/auth/__init__.py +0 -0
  13. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/auth/base.py +0 -0
  14. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/auth/basic.py +0 -0
  15. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/auth/bearer.py +0 -0
  16. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/auth/cookie_jwt.py +0 -0
  17. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/behaviors/__init__.py +0 -0
  18. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/behaviors/base.py +0 -0
  19. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/behaviors/default.py +0 -0
  20. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/behaviors/human.py +0 -0
  21. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/behaviors/machine.py +0 -0
  22. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/behaviors/stealth.py +0 -0
  23. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/cli/__init__.py +0 -0
  24. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/cli/main.py +0 -0
  25. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/core/__init__.py +0 -0
  26. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/core/executor.py +0 -0
  27. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/core/headers.py +0 -0
  28. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/core/ttp.py +0 -0
  29. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/journeys/__init__.py +0 -0
  30. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/journeys/base.py +0 -0
  31. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/journeys/executor.py +0 -0
  32. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/orchestrators/__init__.py +0 -0
  33. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/orchestrators/base.py +0 -0
  34. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/orchestrators/batch.py +0 -0
  35. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/orchestrators/distributed.py +0 -0
  36. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/orchestrators/scale.py +0 -0
  37. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/payloads/__init__.py +0 -0
  38. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/payloads/generators.py +0 -0
  39. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/ttps/__init__.py +0 -0
  40. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/ttps/web/__init__.py +0 -0
  41. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/ttps/web/login_bruteforce.py +0 -0
  42. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/ttps/web/sql_injection.py +0 -0
  43. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe/ttps/web/uuid_guessing.py +0 -0
  44. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe_ttp.egg-info/SOURCES.txt +0 -0
  45. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe_ttp.egg-info/dependency_links.txt +0 -0
  46. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe_ttp.egg-info/entry_points.txt +0 -0
  47. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe_ttp.egg-info/requires.txt +0 -0
  48. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/scythe_ttp.egg-info/top_level.txt +0 -0
  49. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/setup.cfg +0 -0
  50. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_api_models.py +0 -0
  51. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_authentication.py +0 -0
  52. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_behaviors.py +0 -0
  53. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_cli.py +0 -0
  54. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_cookie_jwt_auth.py +0 -0
  55. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_expected_results.py +0 -0
  56. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_feature_completeness.py +0 -0
  57. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_header_extraction.py +0 -0
  58. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_journeys.py +0 -0
  59. {scythe_ttp-0.15.10 → scythe_ttp-0.16.0}/tests/test_orchestrators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scythe-ttp
3
- Version: 0.15.10
3
+ Version: 0.16.0
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.16.0
@@ -659,6 +659,7 @@ class ApiRequestAction(Action):
659
659
  def __init__(self,
660
660
  method: str,
661
661
  url: str,
662
+ flush: bool = False,
662
663
  params: Optional[Dict[str, Any]] = None,
663
664
  body_json: Optional[Dict[str, Any]] = None,
664
665
  data: Optional[Dict[str, Any]] = None,
@@ -673,6 +674,7 @@ class ApiRequestAction(Action):
673
674
  fail_on_validation_error: bool = False):
674
675
  self.method = method.upper()
675
676
  self.url = url
677
+ self.flush = flush
676
678
  self.params = params or {}
677
679
  self.body_json = body_json
678
680
  self.data = data
@@ -692,15 +694,15 @@ class ApiRequestAction(Action):
692
694
  if session is None:
693
695
  session = requests.Session()
694
696
  context['requests_session'] = session
695
-
696
- # Build headers: auth headers from context + action headers (action overrides)
697
+
698
+ # Build headers: auth headers from context and action headers (action overrides)
697
699
  final_headers = {}
698
700
  auth_headers = context.get('auth_headers', {}) or {}
699
701
  if auth_headers:
700
702
  final_headers.update(auth_headers)
701
703
  if self.headers:
702
704
  final_headers.update(self.headers)
703
-
705
+
704
706
  # Simple masking for sensitive headers
705
707
  def _mask_headers(headers: Dict[str, Any]) -> Dict[str, Any]:
706
708
  masked = {}
@@ -713,7 +715,7 @@ class ApiRequestAction(Action):
713
715
  else:
714
716
  masked[k] = v
715
717
  return masked
716
-
718
+
717
719
  # Resolve URL: absolute or join with target_url from context
718
720
  from urllib.parse import urljoin
719
721
  from ..core.headers import HeaderExtractor
@@ -725,7 +727,7 @@ class ApiRequestAction(Action):
725
727
  resolved_url = self.url
726
728
  else:
727
729
  resolved_url = urljoin(base_url, self.url)
728
-
730
+
729
731
  # Store request details early
730
732
  self.store_result('request_method', self.method)
731
733
  self.store_result('url', resolved_url)
@@ -736,7 +738,7 @@ class ApiRequestAction(Action):
736
738
  if self.data is not None:
737
739
  self.store_result('request_data', self.data)
738
740
  self.store_result('request_headers', _mask_headers(final_headers))
739
-
741
+
740
742
  logger = logging.getLogger("Journey.ApiRequestAction")
741
743
  # Honor any pending rate-limit resume time set by previous actions/steps
742
744
  try:
@@ -861,14 +863,25 @@ class ApiRequestAction(Action):
861
863
 
862
864
  # Determine success (status-based by default)
863
865
  if self.expected_status is not None:
864
- http_ok = (getattr(response, 'status_code', None) == self.expected_status)
866
+ http_ok = (status_code == self.expected_status)
867
+ if not http_ok:
868
+ self.store_result('status_mismatch', f"Expected status {self.expected_status}, got {status_code}")
869
+ logger.warning(f"API request status mismatch: expected {self.expected_status}, got {status_code}")
865
870
  else:
866
871
  http_ok = bool(getattr(response, 'ok', False))
867
872
 
873
+ # Store the final status check result
874
+ self.store_result('http_status_ok', http_ok)
875
+
868
876
  # Optionally fail on validation error
869
877
  if self.response_model is not None and self.fail_on_validation_error and self.get_result('response_validation_error'):
870
878
  return False
871
879
 
880
+ if self.flush:
881
+ clear_requests_session(context)
882
+
883
+ # Return False if status doesn't match expected, regardless of expected_result
884
+ # The framework will then compare this with expected_result to determine test outcome
872
885
  return http_ok
873
886
  except Exception as e:
874
887
  last_exception = e
@@ -878,3 +891,12 @@ class ApiRequestAction(Action):
878
891
 
879
892
  # If we got here and had an exception or no return, fail
880
893
  return False
894
+
895
+ def clear_requests_session(context: Dict[str, Any]):
896
+ """Clear the request session from the context."""
897
+ logger = logging.getLogger("Journey.ApiRequestAction")
898
+ session = context.get('requests_session')
899
+ if session is not None:
900
+ session.close()
901
+ context['requests_session'] = None
902
+ logger.info("Cleared requests session from context")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scythe-ttp
3
- Version: 0.15.10
3
+ Version: 0.16.0
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
@@ -1 +0,0 @@
1
- 0.15.10
File without changes
File without changes
File without changes
File without changes
File without changes