agentic-stealth-browser 2.5.0__tar.gz → 2.7.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.
Files changed (214) hide show
  1. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/CHANGELOG.md +71 -1
  2. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/PKG-INFO +42 -14
  3. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/README.md +30 -2
  4. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/SECURITY.md +4 -2
  5. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/agentic_stealth_browser.egg-info/PKG-INFO +42 -14
  6. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/agentic_stealth_browser.egg-info/SOURCES.txt +6 -0
  7. agentic_stealth_browser-2.7.0/agentic_stealth_browser.egg-info/requires.txt +13 -0
  8. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/agent_browser.py +6 -1
  9. agentic_stealth_browser-2.7.0/docs/DATA_HANDLING.md +19 -0
  10. agentic_stealth_browser-2.7.0/docs/INCIDENT_RESPONSE.md +22 -0
  11. agentic_stealth_browser-2.7.0/docs/KEY_MANAGEMENT.md +9 -0
  12. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/adapters/__init__.py +3 -0
  13. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/adapters/agentic_stealth_mcp.py +11 -3
  14. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/adapters/base.py +14 -0
  15. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/adapters/cdp_bridge.py +29 -3
  16. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/adapters/playwright_mcp.py +34 -15
  17. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/mcp_server.py +76 -0
  18. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/mcp_session_isolation.py +16 -0
  19. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/pyproject.toml +12 -12
  20. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/recovery/anti_block_orchestrator.py +36 -9
  21. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/advanced_stealth.py +181 -94
  22. agentic_stealth_browser-2.7.0/tests/stealth_harness/__init__.py +0 -0
  23. agentic_stealth_browser-2.7.0/tests/stealth_harness/collect.py +164 -0
  24. agentic_stealth_browser-2.7.0/tests/stealth_harness/test_stealth.py +137 -0
  25. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_adapter_agentic_stealth_mcp.py +28 -0
  26. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_adapter_cdp_bridge.py +25 -0
  27. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_adapter_playwright_mcp.py +48 -13
  28. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_attach_over_cdp.py +5 -0
  29. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_recovery_state_machine.py +22 -0
  30. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_stealth_modules.py +9 -0
  31. agentic_stealth_browser-2.5.0/agentic_stealth_browser.egg-info/requires.txt +0 -13
  32. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/.env.example +0 -0
  33. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/CODE_OF_CONDUCT.md +0 -0
  34. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/CONTRIBUTING.md +0 -0
  35. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/LICENSE +0 -0
  36. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/MANIFEST.in +0 -0
  37. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/agentic_stealth_browser.egg-info/dependency_links.txt +0 -0
  38. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/agentic_stealth_browser.egg-info/entry_points.txt +0 -0
  39. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/agentic_stealth_browser.egg-info/top_level.txt +0 -0
  40. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/ai/__init__.py +0 -0
  41. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/ai/ai_hooks.py +0 -0
  42. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/assets/hn-demo.gif +0 -0
  43. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/audit/__init__.py +0 -0
  44. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/audit/logger.py +0 -0
  45. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/behavior/__init__.py +0 -0
  46. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/behavior/adaptive_tuner.py +0 -0
  47. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/behavior/human_behavior.py +0 -0
  48. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/behavior/orchestration.py +0 -0
  49. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/behavior/persona_rotator.py +0 -0
  50. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/__init__.py +0 -0
  51. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/badge_gen.py +0 -0
  52. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/dashboard_gen.py +0 -0
  53. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/history.py +0 -0
  54. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/py.typed +0 -0
  55. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/readme_gen.py +0 -0
  56. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/runner.py +0 -0
  57. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/score.py +0 -0
  58. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/sites.py +0 -0
  59. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/templates/badge.svg.j2 +0 -0
  60. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/canary/templates/dashboard.html.j2 +0 -0
  61. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/__init__.py +0 -0
  62. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/account_health.py +0 -0
  63. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/account_warming.py +0 -0
  64. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/connection_pool.py +0 -0
  65. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/error_messages.py +0 -0
  66. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/feature_flags.py +0 -0
  67. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/py.typed +0 -0
  68. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/session_checkpoint.py +0 -0
  69. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/core/types.py +0 -0
  70. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/ATTACH_OVER_CDP.md +0 -0
  71. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/README.md +0 -0
  72. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/agentic-stealth-browser-analysis-report.md +0 -0
  73. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/canary/README.md +0 -0
  74. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/canary/badge.svg +0 -0
  75. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/canary/history.jsonl +0 -0
  76. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/canary/index.html +0 -0
  77. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/canary.md +0 -0
  78. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/plans/2026-06-01-v2.4.0-attach-mode-hardening.md +0 -0
  79. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/plans/2026-06-03-v2.5.0-real-backend-adapters.md +0 -0
  80. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/plans/misc/GOAL_MODE_HERMES_BROWSER_DASHBOARD.md +0 -0
  81. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/plans/misc/HN_POST.md +0 -0
  82. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/plans/misc/OPEN_SOURCE_READINESS.md +0 -0
  83. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/docs/plans/misc/RELEASE_AUTONOMOUS_PLAN.md +0 -0
  84. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/examples/recipes/01_cloudflare_bypass.py +0 -0
  85. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/examples/recipes/02_linkedin_search.py +0 -0
  86. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/examples/recipes/03_amazon_product.py +0 -0
  87. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/examples/recipes/README.md +0 -0
  88. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/examples/recipes/linkedin.md +0 -0
  89. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/linkedin/__init__.py +0 -0
  90. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/linkedin/actions.py +0 -0
  91. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/mcp_security.py +0 -0
  92. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/plugins/__init__.py +0 -0
  93. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/plugins/template/__init__.py +0 -0
  94. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/plugins/template/plugin.py +0 -0
  95. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/Dockerfile +0 -0
  96. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/__init__.py +0 -0
  97. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/adapters/_jsonrpc_stdio.py +0 -0
  98. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/approval_gate.py +0 -0
  99. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/audit_enrichment.py +0 -0
  100. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/cli.py +0 -0
  101. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/dashboard_adapter_bridge.py +0 -0
  102. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/deprecations.py +0 -0
  103. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/docker-compose.yml +0 -0
  104. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/docker-healthcheck.py +0 -0
  105. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/hermes_dashboard.py +0 -0
  106. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/mcp_input_validator.py +0 -0
  107. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/metrics.py +0 -0
  108. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/otel_export.py +0 -0
  109. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/policy_engine.py +0 -0
  110. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/profiler.py +0 -0
  111. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/rate_limiter.py +0 -0
  112. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/sdk/__init__.py +0 -0
  113. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/sdk/client.py +0 -0
  114. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/production/workflow_orchestrator.py +0 -0
  115. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/proxy/__init__.py +0 -0
  116. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/proxy/proxy_manager.py +0 -0
  117. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/recovery/__init__.py +0 -0
  118. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/recovery/detectors.py +0 -0
  119. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/recovery/explain_blocked.py +0 -0
  120. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scraping/__init__.py +0 -0
  121. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scraping/scraper.py +0 -0
  122. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/canary_run.py +0 -0
  123. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/evaluate_stealth.py +0 -0
  124. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/generate-demo-gif.py +0 -0
  125. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/health_check.py +0 -0
  126. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/hn-demo.py +0 -0
  127. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/make-gif.py +0 -0
  128. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/migrate_v1_to_v2.py +0 -0
  129. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/perf_benchmark.py +0 -0
  130. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/scripts/setup_rbb.sh +0 -0
  131. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/sessions/__init__.py +0 -0
  132. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/sessions/cookie_manager.py +0 -0
  133. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/sessions/session_manager.py +0 -0
  134. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/setup.cfg +0 -0
  135. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/__init__.py +0 -0
  136. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/cache.py +0 -0
  137. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/firefox_adapter.py +0 -0
  138. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/headers.py +0 -0
  139. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/presets.py +0 -0
  140. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/profiles.py +0 -0
  141. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/tls_fingerprint.py +0 -0
  142. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/stealth/tls_ja3_ja4.py +0 -0
  143. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/debug_nowsecure.py +0 -0
  144. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/detection_check.py +0 -0
  145. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/detection_runner.py +0 -0
  146. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/fingerprint_scorecard.py +0 -0
  147. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/run_detection_tests.py +0 -0
  148. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_account_health.py +0 -0
  149. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_account_warming.py +0 -0
  150. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_adaptive_tuner.py +0 -0
  151. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_backend_adapter_contract.py +0 -0
  152. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_basic.py +0 -0
  153. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_cdp_snapshots.py +0 -0
  154. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_connection_pool.py +0 -0
  155. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_contract_agent_browser.py +0 -0
  156. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_cookie_manager_unit.py +0 -0
  157. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_dashboard_protocol_bridge.py +0 -0
  158. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_detectors.py +0 -0
  159. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_differential.py +0 -0
  160. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_docker_config.py +0 -0
  161. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_e2e_anti_block_recovery.py +0 -0
  162. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_e2e_protected_sites_placeholder.py +0 -0
  163. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_golden_master.py +0 -0
  164. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_hermes_dashboard.py +0 -0
  165. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_human_behavior_fuzz.py +0 -0
  166. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_integration_modules.py +0 -0
  167. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_linkedin_actions.py +0 -0
  168. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_mcp_contract.py +0 -0
  169. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_mcp_server_runtime.py +0 -0
  170. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_mcp_stealth_workflows.py +0 -0
  171. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_mcp_url_safety.py +0 -0
  172. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_metrics_collector_unit.py +0 -0
  173. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_mutation_stealth.py +0 -0
  174. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_persona_rotator.py +0 -0
  175. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_phase7_fixes.py +0 -0
  176. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_player.py +0 -0
  177. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_proxy_config_unit.py +0 -0
  178. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_proxy_manager.py +0 -0
  179. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_rate_limiter_unit.py +0 -0
  180. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_recorder.py +0 -0
  181. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_recovery.py +0 -0
  182. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_recovery_phase1.py +0 -0
  183. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_rehearsal_validation.py +0 -0
  184. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_selector_auto_heal.py +0 -0
  185. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_session_checkpoint.py +0 -0
  186. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_stealth_cache.py +0 -0
  187. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_stealth_coverage.py +0 -0
  188. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_stress_multi_account.py +0 -0
  189. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_tls_ja3_ja4.py +0 -0
  190. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_workflow_orchestrator.py +0 -0
  191. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_workflow_schema.py +0 -0
  192. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_workflow_schema_unit.py +0 -0
  193. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/tests/test_workflow_versioning.py +0 -0
  194. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/__init__.py +0 -0
  195. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/action_interpreter.py +0 -0
  196. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/auto-session-test.yaml +0 -0
  197. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/common/login.yaml +0 -0
  198. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/common/verify-email.yaml +0 -0
  199. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/linkedin/send-connection-request.yaml +0 -0
  200. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/meta-test.yaml +0 -0
  201. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/simple-test.yaml +0 -0
  202. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/teach-test/test-teach.yaml +0 -0
  203. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/upwork/add-portfolio-item.yaml +0 -0
  204. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/upwork/apply.yaml +0 -0
  205. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/upwork/edit-title.yaml +0 -0
  206. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/upwork/submit-proposal.yaml +0 -0
  207. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/library/upwork/update-rate.yaml +0 -0
  208. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/player.py +0 -0
  209. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/recorder.py +0 -0
  210. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/recovery.py +0 -0
  211. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/schema.py +0 -0
  212. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/selector_generator.py +0 -0
  213. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/test-echo.yaml +0 -0
  214. {agentic_stealth_browser-2.5.0 → agentic_stealth_browser-2.7.0}/workflows/variable_resolver.py +0 -0
@@ -9,6 +9,75 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [2.7.0] — Enterprise Hardening (2026-07-18)
13
+
14
+ Auditability, supply-chain, and business-facing hardening from a full enterprise
15
+ audit. No breaking changes; no runtime behavior change on existing flows.
16
+
17
+ ### Added
18
+ - **Acceptable Use Policy** (`ACCEPTABLE_USE.md`) + a `## Legal & Acceptable Use`
19
+ section in the README — authorized-use scope, prohibited uses (ToS/robots/CFAA/
20
+ GDPR-CCPA), operator responsibility, and rate-limit good-citizenship, for an
21
+ anti-bot tool that enterprise/legal review can pass through procurement.
22
+ - **Compliance docs** (`docs/`): `INCIDENT_RESPONSE.md` (credential/key-compromise
23
+ playbook, triage severities, post-incident), `KEY_MANAGEMENT.md` (secret
24
+ inventory + env sourcing + rotation), `DATA_HANDLING.md` (what is persisted,
25
+ data-controller statement, retention + deletion posture).
26
+ - **Navigation success/failure metrics** (`core/agent_browser.py`): `safe_goto`
27
+ now emits `requests_success` / `requests_failed` counters and calls
28
+ `metrics.record_error("navigation", …)` on failure, so `MetricsCollector`'s
29
+ `success_rate` reflects real traffic instead of being permanently 100%.
30
+
31
+ ### Changed
32
+ - **Dependency lower bounds** (`pyproject.toml`): the seven previously-unpinned
33
+ runtime deps and the four dev deps now carry `>=` floors set to
34
+ CVE-safe/current releases (e.g. `aiohttp>=3.10.11`, `cryptography>=43.0.1`,
35
+ `jinja2>=3.1.5`), so a fresh install can no longer resolve a known-vulnerable
36
+ release. No upper caps — existing installs are unaffected.
37
+ - **README claims hedged** for an enterprise audience: the tagline and the
38
+ "zero-flag" line are now framed as a point-in-time canary snapshot, not a
39
+ guarantee.
40
+ - `pyproject.toml` version 2.6.0 → 2.7.0; MCP `clientInfo.version` handshake
41
+ strings in the two stdio adapters aligned to 2.7.0.
42
+
43
+ ### Security
44
+ - **Release-metadata gate** (`.github/workflows/publish.yml`): the build job now
45
+ runs `twine check --strict dist/*` before upload, so malformed metadata can no
46
+ longer burn an immutable PyPI version.
47
+ - **SECURITY.md supported-versions table** corrected from a stale `0.8.x` to
48
+ `2.7.x` (`< 2.7` unsupported), with a note that the table is updated every
49
+ release.
50
+
51
+ ### Testing
52
+ - The five live-Chromium attach tests in `tests/test_attach_over_cdp.py` are now
53
+ marked `@pytest.mark.e2e`, so the default (non-e2e) CI run no longer errors when
54
+ a browser is unavailable and the deterministic subset stays green.
55
+
56
+ ## [2.6.0] — Stealth & MCP Hardening (2026-07-12)
57
+
58
+ ### Added
59
+ - **`attach_mode` param** (`stealth/advanced_stealth.py`): `get_stealth_script(..., attach_mode=True)` skips `navigator.platform` / WebGL vendor-renderer / screen-DPR overrides when attaching to a real browser, so the injected fingerprint no longer contradicts the real OS/GPU. `core/agent_browser.py`'s `attach_over_cdp()` now passes `attach_mode=True`.
60
+ - **`AdapterToolError`** (`production/adapters/`): raised when an MCP tool result carries `isError: true` — previously a failed `navigate`/`click`/`fill` call reported silent success.
61
+ - **Canonical `connected` field** on adapter `status()` (`production/adapters/`), with a `running` back-compat alias.
62
+ - **CDP bridge profile resolution** (`production/adapters/cdp_bridge.py`): `launch(profile)` now accepts either a raw `ws/wss/http(s)` endpoint or a profile name resolved via `CDP_ENDPOINT_<PROFILE>` / `CDP_ENDPOINT` env, aligning its signature with the `BackendAdapter` protocol and sibling adapters.
63
+ - Adapter, stealth, and recovery unit tests covering the above (`tests/test_adapter_*.py`, `tests/test_stealth_modules.py`, `tests/test_recovery_state_machine.py`).
64
+ - `CLAUDE.md`: contributor guidance (setup, test commands mirroring CI, architecture map, conventions).
65
+
66
+ ### Fixed
67
+ - **Per-patch isolation** (`stealth/advanced_stealth.py`): each stealth patch now runs in its own try/catch, so one API mismatch no longer aborts every patch queued after it.
68
+ - **Rotation failure correctness** (`recovery/anti_block_orchestrator.py`): a failed `ROTATE_*` action now returns `False` and records `_update_recovery_history(success=False)` instead of silently succeeding; per-attempt session/proxy names get a uuid suffix to avoid collisions; a redundant tentative history update was removed.
69
+ - **playwright-mcp pin** (`production/adapters/playwright_mcp.py`): pinned to `@playwright/mcp@0.0.78` with corrected `browser_navigate`/`browser_click`/`browser_type` schema (`element`/`target`/`text`).
70
+
71
+ ### Security
72
+ - **WebRTC leak fix** (`stealth/advanced_stealth.py`): `onicecandidate` is now rebound per-instance instead of on the shared prototype (no cross-instance/global leak); `addEventListener('icecandidate', ...)` listeners are now filtered too; `createDataChannel` restored to a real passthrough.
73
+ - **PolicyEngine + ApprovalGate wiring** (`production/mcp_server.py`): both now sit in the `tools/call` dispatch path and workflow replay. Fail-open by default — no policy files means allow-all and auto-approve, so existing flows are unchanged — operators opt into enforcement via `STEALTH_MCP_POLICY` env or an approval callback.
74
+ - **Honesty docstring** (`production/mcp_session_isolation.py`): documents that `SessionEnforcer` is defined and tested but NOT wired into the dispatch path — inert until a multi-client transport exists (single-client stdio has no per-context token).
75
+
76
+ ### Changed
77
+ - `core/agent_browser.py`: `attach_over_cdp()` passes `attach_mode=True` through to the stealth script generator (see Added).
78
+
79
+ ---
80
+
12
81
  ## [2.5.0] — Real Dashboard Backend Adapters (#444) (2026-06-07)
13
82
 
14
83
  ### Added
@@ -405,7 +474,8 @@ See the full v0.9.0 milestone and the stacked PRs #383/#384/#385 for implementat
405
474
 
406
475
  ---
407
476
 
408
- [unreleased]: https://github.com/shanewas/agentic-stealth-browser/compare/v2.3.0...HEAD
477
+ [unreleased]: https://github.com/shanewas/agentic-stealth-browser/compare/v2.6.0...HEAD
478
+ [2.6.0]: https://github.com/shanewas/agentic-stealth-browser/releases/tag/v2.6.0
409
479
  [2.3.0]: https://github.com/shanewas/agentic-stealth-browser/releases/tag/v2.3.0
410
480
  [2.1.1]: https://github.com/shanewas/agentic-stealth-browser/releases/tag/v2.1.1
411
481
  [2.1.0]: https://github.com/shanewas/agentic-stealth-browser/releases/tag/v2.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-stealth-browser
3
- Version: 2.5.0
3
+ Version: 2.7.0
4
4
  Summary: Production-grade, human-mimicking browser automation framework for autonomous agents. Survives modern anti-bot systems.
5
5
  Author-email: Shane W <shanewas@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -23,23 +23,23 @@ Classifier: Framework :: AsyncIO
23
23
  Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Requires-Dist: playwright
27
- Requires-Dist: aiohttp
28
- Requires-Dist: cryptography
29
- Requires-Dist: pyyaml
30
- Requires-Dist: fastapi
31
- Requires-Dist: jinja2
32
- Requires-Dist: uvicorn
26
+ Requires-Dist: playwright>=1.45
27
+ Requires-Dist: aiohttp>=3.10.11
28
+ Requires-Dist: cryptography>=43.0.1
29
+ Requires-Dist: pyyaml>=6.0.2
30
+ Requires-Dist: fastapi>=0.115.0
31
+ Requires-Dist: jinja2>=3.1.5
32
+ Requires-Dist: uvicorn>=0.32.0
33
33
  Provides-Extra: dev
34
- Requires-Dist: pytest; extra == "dev"
35
- Requires-Dist: pytest-asyncio; extra == "dev"
36
- Requires-Dist: pytest-cov; extra == "dev"
37
- Requires-Dist: httpx; extra == "dev"
34
+ Requires-Dist: pytest>=8.0; extra == "dev"
35
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
36
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
37
+ Requires-Dist: httpx>=0.27; extra == "dev"
38
38
  Dynamic: license-file
39
39
 
40
40
  # Agentic Stealth Browser
41
41
 
42
- **Playwright gets detected. This doesn't.**
42
+ **Playwright gets detected. This is much harder to detect.**
43
43
 
44
44
  [![CI](https://github.com/shanewas/agentic-stealth-browser/actions/workflows/ci.yml/badge.svg)](https://github.com/shanewas/agentic-stealth-browser/actions/workflows/ci.yml)
45
45
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
@@ -51,6 +51,10 @@ Dynamic: license-file
51
51
  <img src="assets/hn-demo.gif" alt="Agentic Stealth Browser Demo" width="90%">
52
52
  </p>
53
53
 
54
+ ## Legal & Acceptable Use
55
+
56
+ This is an anti-bot-evasion tool. Read the [Acceptable Use Policy](ACCEPTABLE_USE.md) before use — you are responsible for using it lawfully and within the target site's Terms of Service.
57
+
54
58
  ## What is this
55
59
 
56
60
  A production-grade stealth browser automation library for Python, built on Playwright.
@@ -95,7 +99,8 @@ Sites don't just check your User-Agent anymore. They check *everything*:
95
99
  | **Account warming** | Nothing | 14-day graduated ramp-up per account |
96
100
 
97
101
  Result: **passes bot.sannysoft.com, pixelscan.net, and CreepJS** with zero flags in
98
- headless mode (detection canaries run every 4 hours via `docs/canary.md`).
102
+ headless mode as of the latest 4-hourly canary run (detection canaries run every 4 hours
103
+ via `docs/canary.md`).
99
104
 
100
105
  ---
101
106
 
@@ -224,6 +229,29 @@ live E2E (`RUN_E2E_ANTI_BLOCK=1` to enable).
224
229
 
225
230
  ---
226
231
 
232
+ ## New in v2.6.0
233
+
234
+ - **Stealth patch isolation** — per-patch try/catch in `advanced_stealth.py`; one
235
+ API mismatch no longer aborts every patch queued after it
236
+ - **Attach-mode fingerprint coherence** — new `attach_mode` skips
237
+ navigator.platform / WebGL vendor-renderer / screen-DPR overrides that would
238
+ otherwise contradict a real attached browser's OS/GPU
239
+ - **WebRTC leak hardening** — per-instance `onicecandidate` rebind (no
240
+ prototype-global leak); the `addEventListener('icecandidate')` variant is
241
+ now filtered too
242
+ - **MCP policy/approval gates** — `PolicyEngine` + `ApprovalGate` wired into
243
+ the dispatch path, fail-open by default (opt-in enforcement via
244
+ `STEALTH_MCP_POLICY` env)
245
+ - **Adapter `isError` surfacing** — failed MCP tool calls now raise
246
+ `AdapterToolError` instead of reporting silent success; playwright-mcp
247
+ pinned to 0.0.78 with the corrected tool schema
248
+ - **Recovery rotation-failure correctness** — failed rotations now propagate
249
+ and record history instead of silently succeeding
250
+
251
+ See [CHANGELOG.md](CHANGELOG.md) for the full release history.
252
+
253
+ ---
254
+
227
255
  ## New in v2.5.0
228
256
 
229
257
  - **BackendAdapter protocol** — pluggable execution backends (M0–M4 shipped)
@@ -1,6 +1,6 @@
1
1
  # Agentic Stealth Browser
2
2
 
3
- **Playwright gets detected. This doesn't.**
3
+ **Playwright gets detected. This is much harder to detect.**
4
4
 
5
5
  [![CI](https://github.com/shanewas/agentic-stealth-browser/actions/workflows/ci.yml/badge.svg)](https://github.com/shanewas/agentic-stealth-browser/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
@@ -12,6 +12,10 @@
12
12
  <img src="assets/hn-demo.gif" alt="Agentic Stealth Browser Demo" width="90%">
13
13
  </p>
14
14
 
15
+ ## Legal & Acceptable Use
16
+
17
+ This is an anti-bot-evasion tool. Read the [Acceptable Use Policy](ACCEPTABLE_USE.md) before use — you are responsible for using it lawfully and within the target site's Terms of Service.
18
+
15
19
  ## What is this
16
20
 
17
21
  A production-grade stealth browser automation library for Python, built on Playwright.
@@ -56,7 +60,8 @@ Sites don't just check your User-Agent anymore. They check *everything*:
56
60
  | **Account warming** | Nothing | 14-day graduated ramp-up per account |
57
61
 
58
62
  Result: **passes bot.sannysoft.com, pixelscan.net, and CreepJS** with zero flags in
59
- headless mode (detection canaries run every 4 hours via `docs/canary.md`).
63
+ headless mode as of the latest 4-hourly canary run (detection canaries run every 4 hours
64
+ via `docs/canary.md`).
60
65
 
61
66
  ---
62
67
 
@@ -185,6 +190,29 @@ live E2E (`RUN_E2E_ANTI_BLOCK=1` to enable).
185
190
 
186
191
  ---
187
192
 
193
+ ## New in v2.6.0
194
+
195
+ - **Stealth patch isolation** — per-patch try/catch in `advanced_stealth.py`; one
196
+ API mismatch no longer aborts every patch queued after it
197
+ - **Attach-mode fingerprint coherence** — new `attach_mode` skips
198
+ navigator.platform / WebGL vendor-renderer / screen-DPR overrides that would
199
+ otherwise contradict a real attached browser's OS/GPU
200
+ - **WebRTC leak hardening** — per-instance `onicecandidate` rebind (no
201
+ prototype-global leak); the `addEventListener('icecandidate')` variant is
202
+ now filtered too
203
+ - **MCP policy/approval gates** — `PolicyEngine` + `ApprovalGate` wired into
204
+ the dispatch path, fail-open by default (opt-in enforcement via
205
+ `STEALTH_MCP_POLICY` env)
206
+ - **Adapter `isError` surfacing** — failed MCP tool calls now raise
207
+ `AdapterToolError` instead of reporting silent success; playwright-mcp
208
+ pinned to 0.0.78 with the corrected tool schema
209
+ - **Recovery rotation-failure correctness** — failed rotations now propagate
210
+ and record history instead of silently succeeding
211
+
212
+ See [CHANGELOG.md](CHANGELOG.md) for the full release history.
213
+
214
+ ---
215
+
188
216
  ## New in v2.5.0
189
217
 
190
218
  - **BackendAdapter protocol** — pluggable execution backends (M0–M4 shipped)
@@ -4,8 +4,10 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | ------- | ------------------ |
7
- | 0.8.x | :white_check_mark: |
8
- | < 0.8 | :x: |
7
+ | 2.7.x | :white_check_mark: |
8
+ | < 2.7 | :x: |
9
+
10
+ This table is updated as part of every release; a release is not complete until the current minor version appears here.
9
11
 
10
12
  ## Reporting a Vulnerability
11
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-stealth-browser
3
- Version: 2.5.0
3
+ Version: 2.7.0
4
4
  Summary: Production-grade, human-mimicking browser automation framework for autonomous agents. Survives modern anti-bot systems.
5
5
  Author-email: Shane W <shanewas@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -23,23 +23,23 @@ Classifier: Framework :: AsyncIO
23
23
  Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Requires-Dist: playwright
27
- Requires-Dist: aiohttp
28
- Requires-Dist: cryptography
29
- Requires-Dist: pyyaml
30
- Requires-Dist: fastapi
31
- Requires-Dist: jinja2
32
- Requires-Dist: uvicorn
26
+ Requires-Dist: playwright>=1.45
27
+ Requires-Dist: aiohttp>=3.10.11
28
+ Requires-Dist: cryptography>=43.0.1
29
+ Requires-Dist: pyyaml>=6.0.2
30
+ Requires-Dist: fastapi>=0.115.0
31
+ Requires-Dist: jinja2>=3.1.5
32
+ Requires-Dist: uvicorn>=0.32.0
33
33
  Provides-Extra: dev
34
- Requires-Dist: pytest; extra == "dev"
35
- Requires-Dist: pytest-asyncio; extra == "dev"
36
- Requires-Dist: pytest-cov; extra == "dev"
37
- Requires-Dist: httpx; extra == "dev"
34
+ Requires-Dist: pytest>=8.0; extra == "dev"
35
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
36
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
37
+ Requires-Dist: httpx>=0.27; extra == "dev"
38
38
  Dynamic: license-file
39
39
 
40
40
  # Agentic Stealth Browser
41
41
 
42
- **Playwright gets detected. This doesn't.**
42
+ **Playwright gets detected. This is much harder to detect.**
43
43
 
44
44
  [![CI](https://github.com/shanewas/agentic-stealth-browser/actions/workflows/ci.yml/badge.svg)](https://github.com/shanewas/agentic-stealth-browser/actions/workflows/ci.yml)
45
45
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
@@ -51,6 +51,10 @@ Dynamic: license-file
51
51
  <img src="assets/hn-demo.gif" alt="Agentic Stealth Browser Demo" width="90%">
52
52
  </p>
53
53
 
54
+ ## Legal & Acceptable Use
55
+
56
+ This is an anti-bot-evasion tool. Read the [Acceptable Use Policy](ACCEPTABLE_USE.md) before use — you are responsible for using it lawfully and within the target site's Terms of Service.
57
+
54
58
  ## What is this
55
59
 
56
60
  A production-grade stealth browser automation library for Python, built on Playwright.
@@ -95,7 +99,8 @@ Sites don't just check your User-Agent anymore. They check *everything*:
95
99
  | **Account warming** | Nothing | 14-day graduated ramp-up per account |
96
100
 
97
101
  Result: **passes bot.sannysoft.com, pixelscan.net, and CreepJS** with zero flags in
98
- headless mode (detection canaries run every 4 hours via `docs/canary.md`).
102
+ headless mode as of the latest 4-hourly canary run (detection canaries run every 4 hours
103
+ via `docs/canary.md`).
99
104
 
100
105
  ---
101
106
 
@@ -224,6 +229,29 @@ live E2E (`RUN_E2E_ANTI_BLOCK=1` to enable).
224
229
 
225
230
  ---
226
231
 
232
+ ## New in v2.6.0
233
+
234
+ - **Stealth patch isolation** — per-patch try/catch in `advanced_stealth.py`; one
235
+ API mismatch no longer aborts every patch queued after it
236
+ - **Attach-mode fingerprint coherence** — new `attach_mode` skips
237
+ navigator.platform / WebGL vendor-renderer / screen-DPR overrides that would
238
+ otherwise contradict a real attached browser's OS/GPU
239
+ - **WebRTC leak hardening** — per-instance `onicecandidate` rebind (no
240
+ prototype-global leak); the `addEventListener('icecandidate')` variant is
241
+ now filtered too
242
+ - **MCP policy/approval gates** — `PolicyEngine` + `ApprovalGate` wired into
243
+ the dispatch path, fail-open by default (opt-in enforcement via
244
+ `STEALTH_MCP_POLICY` env)
245
+ - **Adapter `isError` surfacing** — failed MCP tool calls now raise
246
+ `AdapterToolError` instead of reporting silent success; playwright-mcp
247
+ pinned to 0.0.78 with the corrected tool schema
248
+ - **Recovery rotation-failure correctness** — failed rotations now propagate
249
+ and record history instead of silently succeeding
250
+
251
+ See [CHANGELOG.md](CHANGELOG.md) for the full release history.
252
+
253
+ ---
254
+
227
255
  ## New in v2.5.0
228
256
 
229
257
  - **BackendAdapter protocol** — pluggable execution backends (M0–M4 shipped)
@@ -46,6 +46,9 @@ core/py.typed
46
46
  core/session_checkpoint.py
47
47
  core/types.py
48
48
  docs/ATTACH_OVER_CDP.md
49
+ docs/DATA_HANDLING.md
50
+ docs/INCIDENT_RESPONSE.md
51
+ docs/KEY_MANAGEMENT.md
49
52
  docs/README.md
50
53
  docs/agentic-stealth-browser-analysis-report.md
51
54
  docs/canary.md
@@ -182,6 +185,9 @@ tests/test_workflow_orchestrator.py
182
185
  tests/test_workflow_schema.py
183
186
  tests/test_workflow_schema_unit.py
184
187
  tests/test_workflow_versioning.py
188
+ tests/stealth_harness/__init__.py
189
+ tests/stealth_harness/collect.py
190
+ tests/stealth_harness/test_stealth.py
185
191
  workflows/__init__.py
186
192
  workflows/action_interpreter.py
187
193
  workflows/player.py
@@ -0,0 +1,13 @@
1
+ playwright>=1.45
2
+ aiohttp>=3.10.11
3
+ cryptography>=43.0.1
4
+ pyyaml>=6.0.2
5
+ fastapi>=0.115.0
6
+ jinja2>=3.1.5
7
+ uvicorn>=0.32.0
8
+
9
+ [dev]
10
+ pytest>=8.0
11
+ pytest-asyncio>=0.23
12
+ pytest-cov>=5.0
13
+ httpx>=0.27
@@ -1272,6 +1272,7 @@ class AgentBrowser:
1272
1272
  self.account_warming.record_page_visit(url)
1273
1273
  self.connection_pool.release_context(domain)
1274
1274
  self.adaptive_tuner.record_feedback(blocked=False, platform=platform)
1275
+ self.metrics.increment("requests_success")
1275
1276
  return True
1276
1277
  except Exception as e:
1277
1278
  # P3: Record failure to all tracking systems
@@ -1284,6 +1285,8 @@ class AgentBrowser:
1284
1285
  self.logger.log_error(
1285
1286
  "safe_goto_failed", str(e), {"url": url, "platform": platform}
1286
1287
  )
1288
+ self.metrics.increment("requests_failed")
1289
+ self.metrics.record_error("navigation", str(e))
1287
1290
  return False
1288
1291
 
1289
1292
  async def load_cookies(self, cookies_path: str):
@@ -2274,7 +2277,9 @@ class AgentBrowser:
2274
2277
  if apply_stealth:
2275
2278
  session_name = (self.session or {}).get("name", "default-session")
2276
2279
  fp_seed = f"agentic-{session_name}-canvas-v4"
2277
- stealth_script = get_stealth_script(fingerprint_seed=fp_seed)
2280
+ stealth_script = get_stealth_script(
2281
+ fingerprint_seed=fp_seed, attach_mode=True
2282
+ )
2278
2283
  try:
2279
2284
  await ctx.add_init_script(stealth_script)
2280
2285
  stealth_installed = True
@@ -0,0 +1,19 @@
1
+ # Data Handling & Retention
2
+
3
+ ## What the tool persists
4
+
5
+ - Scraped results (wherever the operator's workflow writes them)
6
+ - Cookies under `sessions/`
7
+ - Screenshots under `checkpoints/`
8
+
9
+ ## Data controller
10
+
11
+ The operator running this tool is the data controller for any data it collects or persists. The maintainers are not.
12
+
13
+ ## Retention recommendation
14
+
15
+ By default, retain persisted files no longer than necessary for the operator's task — 30 days is a reasonable starting point unless the operator's own policy or applicable law requires otherwise.
16
+
17
+ ## Deletion
18
+
19
+ Deletion is the operator's responsibility. Documented deletion means removing the relevant files under `sessions/` and `checkpoints/`.
@@ -0,0 +1,22 @@
1
+ # Security Incident Response
2
+
3
+ ## Reporting
4
+
5
+ See [SECURITY.md](../SECURITY.md) for how to report a vulnerability.
6
+
7
+ ## Credential / Key Compromise
8
+
9
+ 1. Rotate the leaked secret.
10
+ 2. Invalidate live dashboard sessions by rotating `DashboardSettings.secret_key`.
11
+ 3. Delete affected session cookie files under `sessions/`.
12
+ 4. Force re-login for all operators.
13
+
14
+ ## Triage Severity
15
+
16
+ - **SEV1** — key/credential leak
17
+ - **SEV2** — data exposure
18
+ - **SEV3** — availability
19
+
20
+ ## Post-Incident
21
+
22
+ Record the incident in the CHANGELOG Security section.
@@ -0,0 +1,9 @@
1
+ # Key Management
2
+
3
+ | Secret | Source | Rotation procedure |
4
+ |---|---|---|
5
+ | Cookie encryption key | env var | Generate a new key, re-encrypt or discard existing session cookie files under `sessions/`, force re-login. |
6
+ | Dashboard `secret_key` (`DashboardSettings.secret_key`) | env var | Set a new value, restart the dashboard process — this invalidates all live dashboard sessions. |
7
+ | HMAC / audit keys | env var | Generate a new key, redeploy, allow a short overlap window if signed artifacts must remain verifiable during rotation. |
8
+
9
+ Keys must come from environment variables and must never be committed to the repository. Rotation should be performed immediately on suspected compromise (see [docs/INCIDENT_RESPONSE.md](INCIDENT_RESPONSE.md)) and periodically as routine hygiene.
@@ -9,6 +9,7 @@ Public surface:
9
9
  Capability - the feature enum
10
10
  AdapterLaunchError - cannot start (runtime)
11
11
  AdapterCapabilityError - cannot perform a requested action
12
+ AdapterToolError - MCP tool call reported isError: true
12
13
  AdapterNotFoundError - get_adapter() was called with an unknown name
13
14
  BACKEND_REGISTRY - mutable dict[name -> Adapter class]
14
15
  get_adapter(name) - registry lookup with friendly error
@@ -21,6 +22,7 @@ from production.adapters.base import (
21
22
  AdapterCapabilityError,
22
23
  AdapterLaunchError,
23
24
  AdapterNotFoundError,
25
+ AdapterToolError,
24
26
  BackendAdapter,
25
27
  Capability,
26
28
  )
@@ -103,6 +105,7 @@ __all__ = [
103
105
  "AdapterCapabilityError",
104
106
  "AdapterLaunchError",
105
107
  "AdapterNotFoundError",
108
+ "AdapterToolError",
106
109
  "BACKEND_REGISTRY",
107
110
  "BackendAdapter",
108
111
  "Capability",
@@ -24,6 +24,7 @@ from production.adapters._jsonrpc_stdio import JsonRpcStdioClient
24
24
  from production.adapters.base import (
25
25
  AdapterCapabilityError,
26
26
  AdapterLaunchError,
27
+ AdapterToolError,
27
28
  Capability,
28
29
  )
29
30
 
@@ -118,7 +119,7 @@ class AgenticStealthMCPAdapter:
118
119
  "protocolVersion": "2024-11-05",
119
120
  "clientInfo": {
120
121
  "name": "agentic-stealth-browser-dashboard",
121
- "version": "2.5.0",
122
+ "version": "2.7.0",
122
123
  },
123
124
  "capabilities": {},
124
125
  },
@@ -199,9 +200,11 @@ class AgenticStealthMCPAdapter:
199
200
  return str(path)
200
201
 
201
202
  async def status(self) -> dict[str, Any]:
203
+ alive = self._proc is not None and self._proc.returncode is None
202
204
  return {
203
205
  "backend": self.name,
204
- "running": self._proc is not None and self._proc.returncode is None,
206
+ "connected": alive,
207
+ "running": alive, # back-compat alias; "connected" is canonical
205
208
  "headless": self._headless,
206
209
  "profile": self._profile,
207
210
  }
@@ -215,7 +218,12 @@ class AgenticStealthMCPAdapter:
215
218
  response = await self._client.request(
216
219
  "tools/call", {"name": name, "arguments": arguments}
217
220
  )
218
- return response.get("result", {})
221
+ result = response.get("result", {})
222
+ if result.get("isError"):
223
+ raise AdapterToolError(
224
+ f"MCP tool {name!r} failed: {result.get('content')!r}"
225
+ )
226
+ return result
219
227
 
220
228
  def _require_capability(self, cap: Capability) -> None:
221
229
  """Raise AdapterCapabilityError when the active adapter does not
@@ -46,6 +46,20 @@ class AdapterCapabilityError(RuntimeError):
46
46
  """
47
47
 
48
48
 
49
+ class AdapterToolError(RuntimeError):
50
+ """Raised when an MCP tool call completes as a valid JSON-RPC response
51
+ but reports a tool-level failure (``result["isError"] is True``).
52
+
53
+ MCP servers report a failed tool execution (bad selector, navigation
54
+ timeout, etc.) as a *successful* JSON-RPC call whose result carries
55
+ ``isError: true`` — not as a JSON-RPC protocol-level error. Without this
56
+ exception, adapters would silently treat a failed navigate/click/fill/
57
+ screenshot as success. Distinct from AdapterLaunchError (process/handshake
58
+ failures) and the plain RuntimeError raised by JsonRpcStdioClient for
59
+ JSON-RPC protocol errors (e.g. unknown method).
60
+ """
61
+
62
+
49
63
  class AdapterNotFoundError(LookupError):
50
64
  """Raised by get_adapter() when the requested name is not in
51
65
  BACKEND_REGISTRY. Inherits from LookupError (the natural superclass for
@@ -14,6 +14,7 @@ running and reachable at the CDP endpoint.
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import os
17
18
  from typing import Any, Optional
18
19
 
19
20
  from playwright.async_api import (
@@ -72,17 +73,24 @@ class CDPBridgeAdapter:
72
73
  return capability in self.capabilities()
73
74
 
74
75
  # ------------------------------------------------------------------ launch
75
- async def launch(self, endpoint: str, headless: bool = True) -> None:
76
+ async def launch(self, profile: str, headless: bool = True) -> None:
76
77
  """Connect to an existing CDP endpoint. Does NOT spawn a new browser.
77
78
 
78
79
  Args:
79
- endpoint: ws:// or wss:// URL of the Chrome DevTools Protocol server.
80
+ profile: either a raw ws:// / wss:// / http(s):// CDP endpoint URL
81
+ (back-compat with direct callers of this adapter), or a
82
+ profile name — consistent with the base.py contract and the
83
+ M2/M3 adapters — resolved to an endpoint via the
84
+ ``CDP_ENDPOINT_<PROFILE>`` (or generic ``CDP_ENDPOINT``)
85
+ environment variable.
80
86
  headless: cosmetic flag, passed to spec but the remote browser's
81
87
  display state is determined by its own launch args.
82
88
 
83
89
  Raises:
84
- AdapterLaunchError: if the connection cannot be established.
90
+ AdapterLaunchError: if the connection cannot be established, or
91
+ (for a profile name) if no endpoint is configured for it.
85
92
  """
93
+ endpoint = self._resolve_endpoint(profile)
86
94
  self._endpoint = endpoint
87
95
  self._playwright = await async_playwright().start()
88
96
  try:
@@ -103,6 +111,23 @@ class CDPBridgeAdapter:
103
111
  self._context = await self._browser.new_context()
104
112
  self._owns_page = True
105
113
 
114
+ # ponytail: profile -> endpoint resolution is a flat env-var lookup, not
115
+ # a real profile registry. Fine while operators set one CDP target per
116
+ # profile by hand; upgrade to a config-file-backed mapping if/when the
117
+ # dashboard needs to drive many named CDP profiles at once.
118
+ @staticmethod
119
+ def _resolve_endpoint(profile: str) -> str:
120
+ if profile.startswith(("ws://", "wss://", "http://", "https://")):
121
+ return profile
122
+ env_key = f"CDP_ENDPOINT_{profile.upper().replace('-', '_')}"
123
+ endpoint = os.environ.get(env_key) or os.environ.get("CDP_ENDPOINT")
124
+ if not endpoint:
125
+ raise AdapterLaunchError(
126
+ f"No CDP endpoint configured for profile {profile!r}; "
127
+ f"set {env_key} or CDP_ENDPOINT to a ws:// CDP URL"
128
+ )
129
+ return endpoint
130
+
106
131
  # ------------------------------------------------------------------ close
107
132
  async def close(self) -> None:
108
133
  """Tear down. Honors the v2.4.1 attach contract: only closes owned pages.
@@ -180,6 +205,7 @@ class CDPBridgeAdapter:
180
205
  return {
181
206
  "backend": self.name,
182
207
  "connected": connected,
208
+ "running": connected, # back-compat alias; "connected" is canonical
183
209
  "endpoint": self._endpoint,
184
210
  "owns_page": self._owns_page,
185
211
  }