tweek 0.3.1__tar.gz → 0.4.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 (204) hide show
  1. {tweek-0.3.1/tweek.egg-info → tweek-0.4.1}/PKG-INFO +8 -7
  2. {tweek-0.3.1 → tweek-0.4.1}/README.md +5 -5
  3. {tweek-0.3.1 → tweek-0.4.1}/pyproject.toml +8 -5
  4. {tweek-0.3.1 → tweek-0.4.1}/tests/test_cli.py +86 -57
  5. tweek-0.4.1/tests/test_cli_configure.py +297 -0
  6. tweek-0.4.1/tests/test_config_templates.py +253 -0
  7. {tweek-0.3.1 → tweek-0.4.1}/tests/test_diagnostics.py +3 -3
  8. {tweek-0.3.1 → tweek-0.4.1}/tests/test_enforcement.py +13 -7
  9. {tweek-0.3.1 → tweek-0.4.1}/tests/test_installer_improvements.py +55 -38
  10. {tweek-0.3.1 → tweek-0.4.1}/tests/test_llm_reviewer.py +133 -24
  11. {tweek-0.3.1 → tweek-0.4.1}/tests/test_local_model.py +89 -31
  12. {tweek-0.3.1 → tweek-0.4.1}/tests/test_mcp_clients.py +3 -3
  13. tweek-0.4.1/tests/test_memory_scoped.py +481 -0
  14. {tweek-0.3.1 → tweek-0.4.1}/tests/test_pattern_families.py +3 -3
  15. tweek-0.4.1/tests/test_pattern_matcher_redos.py +246 -0
  16. {tweek-0.3.1 → tweek-0.4.1}/tests/test_prompt_injection_patterns.py +7 -2
  17. {tweek-0.3.1 → tweek-0.4.1}/tests/test_property_based.py +1 -1
  18. {tweek-0.3.1 → tweek-0.4.1}/tests/test_protect_command.py +15 -2
  19. tweek-0.4.1/tests/test_provenance.py +337 -0
  20. tweek-0.4.1/tests/test_provenance_integration.py +328 -0
  21. tweek-0.4.1/tests/test_skill_context.py +308 -0
  22. tweek-0.4.1/tests/test_tiered_help.py +150 -0
  23. {tweek-0.3.1 → tweek-0.4.1}/tweek/__init__.py +2 -2
  24. {tweek-0.3.1 → tweek-0.4.1}/tweek/audit.py +2 -2
  25. tweek-0.4.1/tweek/cli.py +128 -0
  26. tweek-0.4.1/tweek/cli_config.py +643 -0
  27. tweek-0.4.1/tweek/cli_configure.py +413 -0
  28. tweek-0.4.1/tweek/cli_core.py +718 -0
  29. tweek-0.4.1/tweek/cli_dry_run.py +390 -0
  30. tweek-0.4.1/tweek/cli_helpers.py +509 -0
  31. tweek-0.4.1/tweek/cli_install.py +1666 -0
  32. tweek-0.4.1/tweek/cli_logs.py +301 -0
  33. tweek-0.4.1/tweek/cli_mcp.py +148 -0
  34. tweek-0.4.1/tweek/cli_memory.py +343 -0
  35. tweek-0.4.1/tweek/cli_plugins.py +748 -0
  36. tweek-0.4.1/tweek/cli_protect.py +564 -0
  37. tweek-0.4.1/tweek/cli_proxy.py +405 -0
  38. tweek-0.4.1/tweek/cli_security.py +236 -0
  39. tweek-0.4.1/tweek/cli_skills.py +289 -0
  40. tweek-0.4.1/tweek/cli_uninstall.py +551 -0
  41. tweek-0.4.1/tweek/cli_vault.py +313 -0
  42. tweek-0.4.1/tweek/config/allowed_dirs.yaml +22 -0
  43. {tweek-0.3.1 → tweek-0.4.1}/tweek/config/families.yaml +4 -1
  44. {tweek-0.3.1 → tweek-0.4.1}/tweek/config/manager.py +17 -0
  45. {tweek-0.3.1 → tweek-0.4.1}/tweek/config/patterns.yaml +29 -5
  46. tweek-0.4.1/tweek/config/templates/config.yaml.template +212 -0
  47. tweek-0.4.1/tweek/config/templates/env.template +45 -0
  48. tweek-0.4.1/tweek/config/templates/overrides.yaml.template +121 -0
  49. tweek-0.4.1/tweek/config/templates/tweek.yaml.template +20 -0
  50. tweek-0.4.1/tweek/config/templates.py +136 -0
  51. {tweek-0.3.1 → tweek-0.4.1}/tweek/config/tiers.yaml +5 -4
  52. {tweek-0.3.1 → tweek-0.4.1}/tweek/diagnostics.py +112 -32
  53. {tweek-0.3.1 → tweek-0.4.1}/tweek/hooks/overrides.py +4 -0
  54. {tweek-0.3.1 → tweek-0.4.1}/tweek/hooks/post_tool_use.py +46 -1
  55. {tweek-0.3.1 → tweek-0.4.1}/tweek/hooks/pre_tool_use.py +149 -49
  56. {tweek-0.3.1 → tweek-0.4.1}/tweek/integrations/openclaw.py +84 -0
  57. {tweek-0.3.1 → tweek-0.4.1}/tweek/licensing.py +1 -1
  58. tweek-0.4.1/tweek/mcp/__init__.py +22 -0
  59. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/clients/chatgpt.py +2 -2
  60. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/clients/claude_desktop.py +2 -2
  61. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/clients/gemini.py +2 -2
  62. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/proxy.py +165 -1
  63. tweek-0.4.1/tweek/memory/provenance.py +438 -0
  64. {tweek-0.3.1 → tweek-0.4.1}/tweek/memory/queries.py +2 -0
  65. {tweek-0.3.1 → tweek-0.4.1}/tweek/memory/safety.py +23 -4
  66. {tweek-0.3.1 → tweek-0.4.1}/tweek/memory/schemas.py +1 -0
  67. {tweek-0.3.1 → tweek-0.4.1}/tweek/memory/store.py +101 -71
  68. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/heuristic_scorer.py +1 -1
  69. tweek-0.4.1/tweek/security/integrity.py +77 -0
  70. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/llm_reviewer.py +170 -74
  71. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/local_reviewer.py +44 -2
  72. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/model_registry.py +73 -7
  73. {tweek-0.3.1 → tweek-0.4.1}/tweek/skill_template/overrides-reference.md +1 -1
  74. tweek-0.4.1/tweek/skills/context.py +221 -0
  75. {tweek-0.3.1 → tweek-0.4.1}/tweek/skills/scanner.py +2 -2
  76. {tweek-0.3.1 → tweek-0.4.1/tweek.egg-info}/PKG-INFO +8 -7
  77. {tweek-0.3.1 → tweek-0.4.1}/tweek.egg-info/SOURCES.txt +31 -2
  78. {tweek-0.3.1 → tweek-0.4.1}/tweek.egg-info/requires.txt +1 -0
  79. tweek-0.3.1/tests/test_mcp_server.py +0 -167
  80. tweek-0.3.1/tweek/cli.py +0 -6655
  81. tweek-0.3.1/tweek/cli_helpers.py +0 -193
  82. tweek-0.3.1/tweek/config/allowed_dirs.yaml +0 -23
  83. tweek-0.3.1/tweek/mcp/__init__.py +0 -24
  84. tweek-0.3.1/tweek/mcp/server.py +0 -320
  85. {tweek-0.3.1 → tweek-0.4.1}/LICENSE +0 -0
  86. {tweek-0.3.1 → tweek-0.4.1}/NOTICE +0 -0
  87. {tweek-0.3.1 → tweek-0.4.1}/setup.cfg +0 -0
  88. {tweek-0.3.1 → tweek-0.4.1}/tests/test_approval_queue.py +0 -0
  89. {tweek-0.3.1 → tweek-0.4.1}/tests/test_audit.py +0 -0
  90. {tweek-0.3.1 → tweek-0.4.1}/tests/test_break_glass.py +0 -0
  91. {tweek-0.3.1 → tweek-0.4.1}/tests/test_cli_helpers.py +0 -0
  92. {tweek-0.3.1 → tweek-0.4.1}/tests/test_config_manager.py +0 -0
  93. {tweek-0.3.1 → tweek-0.4.1}/tests/test_config_models.py +0 -0
  94. {tweek-0.3.1 → tweek-0.4.1}/tests/test_credential_scanner.py +0 -0
  95. {tweek-0.3.1 → tweek-0.4.1}/tests/test_feedback.py +0 -0
  96. {tweek-0.3.1 → tweek-0.4.1}/tests/test_heuristic_scorer.py +0 -0
  97. {tweek-0.3.1 → tweek-0.4.1}/tests/test_language_detection.py +0 -0
  98. {tweek-0.3.1 → tweek-0.4.1}/tests/test_licensing.py +0 -0
  99. {tweek-0.3.1 → tweek-0.4.1}/tests/test_llm_local.py +0 -0
  100. {tweek-0.3.1 → tweek-0.4.1}/tests/test_log_bundle.py +0 -0
  101. {tweek-0.3.1 → tweek-0.4.1}/tests/test_logging.py +0 -0
  102. {tweek-0.3.1 → tweek-0.4.1}/tests/test_logging_enhanced.py +0 -0
  103. {tweek-0.3.1 → tweek-0.4.1}/tests/test_mcp_proxy.py +0 -0
  104. {tweek-0.3.1 → tweek-0.4.1}/tests/test_openclaw_integration.py +0 -0
  105. {tweek-0.3.1 → tweek-0.4.1}/tests/test_overrides.py +0 -0
  106. {tweek-0.3.1 → tweek-0.4.1}/tests/test_path_boundary.py +0 -0
  107. {tweek-0.3.1 → tweek-0.4.1}/tests/test_patterns.py +0 -0
  108. {tweek-0.3.1 → tweek-0.4.1}/tests/test_plugin_scoping.py +0 -0
  109. {tweek-0.3.1 → tweek-0.4.1}/tests/test_post_tool_use.py +0 -0
  110. {tweek-0.3.1 → tweek-0.4.1}/tests/test_proxy_detection.py +0 -0
  111. {tweek-0.3.1 → tweek-0.4.1}/tests/test_rate_limiter.py +0 -0
  112. {tweek-0.3.1 → tweek-0.4.1}/tests/test_redaction.py +0 -0
  113. {tweek-0.3.1 → tweek-0.4.1}/tests/test_screening_context.py +0 -0
  114. {tweek-0.3.1 → tweek-0.4.1}/tests/test_session_analyzer.py +0 -0
  115. {tweek-0.3.1 → tweek-0.4.1}/tests/test_vault_cross_platform.py +0 -0
  116. {tweek-0.3.1 → tweek-0.4.1}/tweek/_keygen.py +0 -0
  117. {tweek-0.3.1 → tweek-0.4.1}/tweek/cli_model.py +0 -0
  118. {tweek-0.3.1 → tweek-0.4.1}/tweek/config/__init__.py +0 -0
  119. {tweek-0.3.1 → tweek-0.4.1}/tweek/config/models.py +0 -0
  120. {tweek-0.3.1 → tweek-0.4.1}/tweek/hooks/__init__.py +0 -0
  121. {tweek-0.3.1 → tweek-0.4.1}/tweek/hooks/break_glass.py +0 -0
  122. {tweek-0.3.1 → tweek-0.4.1}/tweek/hooks/feedback.py +0 -0
  123. {tweek-0.3.1 → tweek-0.4.1}/tweek/integrations/__init__.py +0 -0
  124. {tweek-0.3.1 → tweek-0.4.1}/tweek/integrations/openclaw_server.py +0 -0
  125. {tweek-0.3.1 → tweek-0.4.1}/tweek/logging/__init__.py +0 -0
  126. {tweek-0.3.1 → tweek-0.4.1}/tweek/logging/bundle.py +0 -0
  127. {tweek-0.3.1 → tweek-0.4.1}/tweek/logging/json_logger.py +0 -0
  128. {tweek-0.3.1 → tweek-0.4.1}/tweek/logging/security_log.py +0 -0
  129. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/approval.py +0 -0
  130. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/approval_cli.py +0 -0
  131. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/clients/__init__.py +0 -0
  132. {tweek-0.3.1 → tweek-0.4.1}/tweek/mcp/screening.py +0 -0
  133. {tweek-0.3.1 → tweek-0.4.1}/tweek/memory/__init__.py +0 -0
  134. {tweek-0.3.1 → tweek-0.4.1}/tweek/platform/__init__.py +0 -0
  135. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/__init__.py +0 -0
  136. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/base.py +0 -0
  137. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/__init__.py +0 -0
  138. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/gdpr.py +0 -0
  139. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/gov.py +0 -0
  140. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/hipaa.py +0 -0
  141. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/legal.py +0 -0
  142. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/pci.py +0 -0
  143. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/compliance/soc2.py +0 -0
  144. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/detectors/__init__.py +0 -0
  145. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/detectors/continue_dev.py +0 -0
  146. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/detectors/copilot.py +0 -0
  147. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/detectors/cursor.py +0 -0
  148. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/detectors/openclaw.py +0 -0
  149. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/detectors/windsurf.py +0 -0
  150. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/git_discovery.py +0 -0
  151. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/git_installer.py +0 -0
  152. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/git_lockfile.py +0 -0
  153. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/git_registry.py +0 -0
  154. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/git_security.py +0 -0
  155. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/providers/__init__.py +0 -0
  156. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/providers/anthropic.py +0 -0
  157. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/providers/azure_openai.py +0 -0
  158. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/providers/bedrock.py +0 -0
  159. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/providers/google.py +0 -0
  160. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/providers/openai.py +0 -0
  161. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/scope.py +0 -0
  162. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/__init__.py +0 -0
  163. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/llm_reviewer.py +0 -0
  164. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/local_model_reviewer.py +0 -0
  165. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/pattern_matcher.py +0 -0
  166. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/rate_limiter.py +0 -0
  167. {tweek-0.3.1 → tweek-0.4.1}/tweek/plugins/screening/session_analyzer.py +0 -0
  168. {tweek-0.3.1 → tweek-0.4.1}/tweek/proxy/__init__.py +0 -0
  169. {tweek-0.3.1 → tweek-0.4.1}/tweek/proxy/addon.py +0 -0
  170. {tweek-0.3.1 → tweek-0.4.1}/tweek/proxy/interceptor.py +0 -0
  171. {tweek-0.3.1 → tweek-0.4.1}/tweek/proxy/server.py +0 -0
  172. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/__init__.py +0 -0
  173. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/docker_bridge.py +0 -0
  174. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/executor.py +0 -0
  175. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/layers.py +0 -0
  176. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/linux.py +0 -0
  177. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/profile_generator.py +0 -0
  178. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/project.py +0 -0
  179. {tweek-0.3.1 → tweek-0.4.1}/tweek/sandbox/registry.py +0 -0
  180. {tweek-0.3.1 → tweek-0.4.1}/tweek/screening/__init__.py +0 -0
  181. {tweek-0.3.1 → tweek-0.4.1}/tweek/screening/context.py +0 -0
  182. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/__init__.py +0 -0
  183. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/language.py +0 -0
  184. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/local_model.py +0 -0
  185. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/rate_limiter.py +0 -0
  186. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/secret_scanner.py +0 -0
  187. {tweek-0.3.1 → tweek-0.4.1}/tweek/security/session_analyzer.py +0 -0
  188. {tweek-0.3.1 → tweek-0.4.1}/tweek/skill_template/SKILL.md +0 -0
  189. {tweek-0.3.1 → tweek-0.4.1}/tweek/skill_template/__init__.py +0 -0
  190. {tweek-0.3.1 → tweek-0.4.1}/tweek/skill_template/cli-reference.md +0 -0
  191. {tweek-0.3.1 → tweek-0.4.1}/tweek/skill_template/scripts/__init__.py +0 -0
  192. {tweek-0.3.1 → tweek-0.4.1}/tweek/skill_template/scripts/check_installed.py +0 -0
  193. {tweek-0.3.1 → tweek-0.4.1}/tweek/skills/__init__.py +0 -0
  194. {tweek-0.3.1 → tweek-0.4.1}/tweek/skills/config.py +0 -0
  195. {tweek-0.3.1 → tweek-0.4.1}/tweek/skills/fingerprints.py +0 -0
  196. {tweek-0.3.1 → tweek-0.4.1}/tweek/skills/guard.py +0 -0
  197. {tweek-0.3.1 → tweek-0.4.1}/tweek/skills/isolation.py +0 -0
  198. {tweek-0.3.1 → tweek-0.4.1}/tweek/vault/__init__.py +0 -0
  199. {tweek-0.3.1 → tweek-0.4.1}/tweek/vault/cross_platform.py +0 -0
  200. {tweek-0.3.1 → tweek-0.4.1}/tweek/vault/keychain.py +0 -0
  201. {tweek-0.3.1 → tweek-0.4.1}/tweek-openclaw-plugin/node_modules/flatted/python/flatted.py +0 -0
  202. {tweek-0.3.1 → tweek-0.4.1}/tweek.egg-info/dependency_links.txt +0 -0
  203. {tweek-0.3.1 → tweek-0.4.1}/tweek.egg-info/entry_points.txt +0 -0
  204. {tweek-0.3.1 → tweek-0.4.1}/tweek.egg-info/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tweek
3
- Version: 0.3.1
3
+ Version: 0.4.1
4
4
  Summary: Defense-in-depth security for AI coding assistants - protect credentials, code, and system from prompt injection attacks
5
5
  Author: Tommy Mancino
6
6
  License-Expression: Apache-2.0
7
7
  Project-URL: Homepage, https://gettweek.com
8
8
  Project-URL: Repository, https://github.com/gettweek/tweek
9
9
  Project-URL: Issues, https://github.com/gettweek/tweek/issues
10
- Keywords: claude,security,sandbox,ai,llm,tweek,claude-code,prompt-injection,mcp,credential-theft
10
+ Keywords: claude,security,dry-run,ai,llm,tweek,claude-code,prompt-injection,mcp,credential-theft
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Operating System :: MacOS :: MacOS X
@@ -45,6 +45,7 @@ Provides-Extra: dev
45
45
  Requires-Dist: pytest>=7.0; extra == "dev"
46
46
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
47
47
  Requires-Dist: pytest-xdist>=3.5.0; extra == "dev"
48
+ Requires-Dist: pytest-timeout>=2.2.0; extra == "dev"
48
49
  Requires-Dist: hypothesis>=6.98.0; extra == "dev"
49
50
  Requires-Dist: black>=23.0; extra == "dev"
50
51
  Requires-Dist: ruff>=0.1.0; extra == "dev"
@@ -124,7 +125,7 @@ tweek proxy setup # Cursor, Windsurf, Continue.dev (HTTP p
124
125
  tweek doctor
125
126
  ```
126
127
 
127
- That's it. Tweek auto-detects your tools, applies all 259 attack patterns across 6 defense layers, and runs 100% locally. Your code never leaves your machine.
128
+ That's it. Tweek auto-detects your tools, applies all 262 attack patterns across 6 defense layers, and runs 100% locally. Your code never leaves your machine.
128
129
 
129
130
  ---
130
131
 
@@ -166,7 +167,7 @@ Turn 3: cat ~/.ssh/id_rsa → BLOCKED: path_escalation anomaly
166
167
 
167
168
  **Response injection** — Malicious instructions hidden in tool responses are caught at ingestion.
168
169
 
169
- See the full [Attack Patterns Reference](docs/ATTACK_PATTERNS.md) for all 259 patterns across 11 categories.
170
+ See the full [Attack Patterns Reference](docs/ATTACK_PATTERNS.md) for all 262 patterns across 11 categories.
170
171
 
171
172
  ---
172
173
 
@@ -217,7 +218,7 @@ Every tool call passes through six independent screening layers. An attacker wou
217
218
 
218
219
  | Layer | What It Does |
219
220
  |-------|-------------|
220
- | **1. Pattern Matching** | 259 regex signatures catch known credential theft, exfiltration, and injection attacks instantly |
221
+ | **1. Pattern Matching** | 262 regex signatures catch known credential theft, exfiltration, and injection attacks instantly |
221
222
  | **2. Rate Limiting** | Detects burst attacks, automated probing, and resource theft sequences |
222
223
  | **3. Local Prompt Injection AI** | Custom-trained AI models built specifically to classify and detect prompt injection. Run 100% on your machine — no API calls, no cloud, no latency. Small enough to be fast, accurate enough to catch what regex can't. |
223
224
  | **4. Session Tracking** | Behavioral analysis across turns detects multi-step attacks that look innocent individually |
@@ -235,7 +236,7 @@ See [Defense Layers](docs/DEFENSE_LAYERS.md) for the deep dive and [Architecture
235
236
  | [Full Feature List](docs/FEATURES.md) | Complete feature inventory |
236
237
  | [Architecture](docs/ARCHITECTURE.md) | System design and interception layers |
237
238
  | [Defense Layers](docs/DEFENSE_LAYERS.md) | Screening pipeline deep dive |
238
- | [Attack Patterns](docs/ATTACK_PATTERNS.md) | Full 259-pattern library reference |
239
+ | [Attack Patterns](docs/ATTACK_PATTERNS.md) | Full 262-pattern library reference |
239
240
  | [Configuration](docs/CONFIGURATION.md) | Config files, tiers, and presets |
240
241
  | [CLI Reference](docs/CLI_REFERENCE.md) | All commands, flags, and examples |
241
242
  | [MCP Integration](docs/MCP_INTEGRATION.md) | MCP proxy and gateway setup |
@@ -244,7 +245,7 @@ See [Defense Layers](docs/DEFENSE_LAYERS.md) for the deep dive and [Architecture
244
245
  | [Credential Vault](docs/VAULT.md) | Vault setup and migration |
245
246
  | [Plugins](docs/PLUGINS.md) | Plugin development and registry |
246
247
  | [Logging](docs/LOGGING.md) | Event logging and audit trail |
247
- | [Sandbox](docs/SANDBOX.md) | Sandbox preview configuration |
248
+ | [Dry-Run](docs/DRY_RUN.md) | Dry-run preview configuration |
248
249
  | [Tweek vs. Claude Code](docs/COMPARISON.md) | Feature comparison with native security |
249
250
  | [Troubleshooting](docs/TROUBLESHOOTING.md) | Common issues and fixes |
250
251
 
@@ -68,7 +68,7 @@ tweek proxy setup # Cursor, Windsurf, Continue.dev (HTTP p
68
68
  tweek doctor
69
69
  ```
70
70
 
71
- That's it. Tweek auto-detects your tools, applies all 259 attack patterns across 6 defense layers, and runs 100% locally. Your code never leaves your machine.
71
+ That's it. Tweek auto-detects your tools, applies all 262 attack patterns across 6 defense layers, and runs 100% locally. Your code never leaves your machine.
72
72
 
73
73
  ---
74
74
 
@@ -110,7 +110,7 @@ Turn 3: cat ~/.ssh/id_rsa → BLOCKED: path_escalation anomaly
110
110
 
111
111
  **Response injection** — Malicious instructions hidden in tool responses are caught at ingestion.
112
112
 
113
- See the full [Attack Patterns Reference](docs/ATTACK_PATTERNS.md) for all 259 patterns across 11 categories.
113
+ See the full [Attack Patterns Reference](docs/ATTACK_PATTERNS.md) for all 262 patterns across 11 categories.
114
114
 
115
115
  ---
116
116
 
@@ -161,7 +161,7 @@ Every tool call passes through six independent screening layers. An attacker wou
161
161
 
162
162
  | Layer | What It Does |
163
163
  |-------|-------------|
164
- | **1. Pattern Matching** | 259 regex signatures catch known credential theft, exfiltration, and injection attacks instantly |
164
+ | **1. Pattern Matching** | 262 regex signatures catch known credential theft, exfiltration, and injection attacks instantly |
165
165
  | **2. Rate Limiting** | Detects burst attacks, automated probing, and resource theft sequences |
166
166
  | **3. Local Prompt Injection AI** | Custom-trained AI models built specifically to classify and detect prompt injection. Run 100% on your machine — no API calls, no cloud, no latency. Small enough to be fast, accurate enough to catch what regex can't. |
167
167
  | **4. Session Tracking** | Behavioral analysis across turns detects multi-step attacks that look innocent individually |
@@ -179,7 +179,7 @@ See [Defense Layers](docs/DEFENSE_LAYERS.md) for the deep dive and [Architecture
179
179
  | [Full Feature List](docs/FEATURES.md) | Complete feature inventory |
180
180
  | [Architecture](docs/ARCHITECTURE.md) | System design and interception layers |
181
181
  | [Defense Layers](docs/DEFENSE_LAYERS.md) | Screening pipeline deep dive |
182
- | [Attack Patterns](docs/ATTACK_PATTERNS.md) | Full 259-pattern library reference |
182
+ | [Attack Patterns](docs/ATTACK_PATTERNS.md) | Full 262-pattern library reference |
183
183
  | [Configuration](docs/CONFIGURATION.md) | Config files, tiers, and presets |
184
184
  | [CLI Reference](docs/CLI_REFERENCE.md) | All commands, flags, and examples |
185
185
  | [MCP Integration](docs/MCP_INTEGRATION.md) | MCP proxy and gateway setup |
@@ -188,7 +188,7 @@ See [Defense Layers](docs/DEFENSE_LAYERS.md) for the deep dive and [Architecture
188
188
  | [Credential Vault](docs/VAULT.md) | Vault setup and migration |
189
189
  | [Plugins](docs/PLUGINS.md) | Plugin development and registry |
190
190
  | [Logging](docs/LOGGING.md) | Event logging and audit trail |
191
- | [Sandbox](docs/SANDBOX.md) | Sandbox preview configuration |
191
+ | [Dry-Run](docs/DRY_RUN.md) | Dry-run preview configuration |
192
192
  | [Tweek vs. Claude Code](docs/COMPARISON.md) | Feature comparison with native security |
193
193
  | [Troubleshooting](docs/TROUBLESHOOTING.md) | Common issues and fixes |
194
194
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tweek"
7
- version = "0.3.1"
7
+ version = "0.4.1"
8
8
  description = "Defense-in-depth security for AI coding assistants - protect credentials, code, and system from prompt injection attacks"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -12,7 +12,7 @@ license = "Apache-2.0"
12
12
  authors = [
13
13
  {name = "Tommy Mancino"}
14
14
  ]
15
- keywords = ["claude", "security", "sandbox", "ai", "llm", "tweek", "claude-code", "prompt-injection", "mcp", "credential-theft"]
15
+ keywords = ["claude", "security", "dry-run", "ai", "llm", "tweek", "claude-code", "prompt-injection", "mcp", "credential-theft"]
16
16
  classifiers = [
17
17
  "Development Status :: 4 - Beta",
18
18
  "Intended Audience :: Developers",
@@ -57,6 +57,7 @@ dev = [
57
57
  "pytest>=7.0",
58
58
  "pytest-cov>=4.0",
59
59
  "pytest-xdist>=3.5.0",
60
+ "pytest-timeout>=2.2.0",
60
61
  "hypothesis>=6.98.0",
61
62
  "black>=23.0",
62
63
  "ruff>=0.1.0",
@@ -115,6 +116,7 @@ exclude = ["website*", "tests*", "scripts*", "test-environment*", "docs*"]
115
116
  tweek = [
116
117
  "config/*.yaml",
117
118
  "config/_integrity.json",
119
+ "config/templates/*",
118
120
  "skill_template/*.md",
119
121
  "skill_template/scripts/*.py",
120
122
  ]
@@ -122,13 +124,13 @@ tweek = [
122
124
  [tool.pytest.ini_options]
123
125
  testpaths = ["tests"]
124
126
  python_files = ["test_*.py"]
125
- addopts = "-v --cov=tweek --cov-report=term-missing --cov-fail-under=65"
127
+ addopts = "-v --cov=tweek --cov-report=term-missing --cov-fail-under=60 -m 'not integration'"
126
128
  markers = [
127
129
  "patterns: Regex pattern matching and prompt injection detection (slow, ~37s)",
128
130
  "hooks: Pre/post tool use hook pipeline and path boundary escalation",
129
131
  "cli: CLI commands (install, uninstall, protect, config, license, logs, update)",
130
132
  "plugins: Plugin system (git registry, lockfile, compliance, discovery, security)",
131
- "sandbox: Sandbox execution, project isolation, and Docker bridge",
133
+ "sandbox: Dry-run execution, project isolation, and Docker bridge",
132
134
  "skills: Skill scanning, isolation, fingerprints, and guard",
133
135
  "mcp: MCP proxy, server, and desktop client integration",
134
136
  "security: Credential scanning, redaction, break-glass, enforcement, overrides",
@@ -137,6 +139,7 @@ markers = [
137
139
  "memory: Memory store, safety, and query system",
138
140
  "core: Approval queue, audit, diagnostics, feedback, rate limiting, sessions",
139
141
  "local_model: Local ONNX model inference, registry, and CLI commands",
142
+ "integration: End-to-end integration tests with isolated venv install (slow)",
140
143
  ]
141
144
 
142
145
  [tool.black]
@@ -183,7 +186,7 @@ omit = [
183
186
  ]
184
187
 
185
188
  [tool.coverage.report]
186
- fail_under = 65
189
+ fail_under = 60
187
190
  show_missing = true
188
191
  exclude_lines = [
189
192
  "pragma: no cover",
@@ -12,11 +12,13 @@ Tests coverage of:
12
12
  """
13
13
 
14
14
  import json
15
+ import os
15
16
  import pytest
16
17
  from pathlib import Path
17
18
  from unittest.mock import patch, MagicMock
18
19
  from click.testing import CliRunner
19
20
  import sys
21
+ import shutil
20
22
 
21
23
  sys.path.insert(0, str(Path(__file__).parent.parent))
22
24
 
@@ -43,6 +45,18 @@ def temp_home(tmp_path):
43
45
  return tmp_path
44
46
 
45
47
 
48
+ @pytest.fixture(autouse=True)
49
+ def mock_claude_on_path():
50
+ """Mock Claude Code binary as available (not installed in CI)."""
51
+ _original = shutil.which
52
+ def _which(cmd):
53
+ if cmd == "claude":
54
+ return "/usr/local/bin/claude"
55
+ return _original(cmd)
56
+ with patch('tweek.cli_install.shutil.which', new=_which):
57
+ yield
58
+
59
+
46
60
  class TestInstallCommand:
47
61
  """Tests for the protect claude-code command (formerly install)."""
48
62
 
@@ -50,13 +64,14 @@ class TestInstallCommand:
50
64
  """Test global protect claude-code creates settings.json."""
51
65
  claude_dir = tmp_path / ".claude"
52
66
 
53
- with patch.object(Path, 'home', return_value=tmp_path):
54
- with patch('tweek.cli.Path.home', return_value=tmp_path):
55
- result = runner.invoke(
56
- main,
57
- ['protect', 'claude-code', '--skip-env-scan'],
58
- catch_exceptions=False
59
- )
67
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
68
+ with patch.object(Path, 'home', return_value=tmp_path):
69
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
70
+ result = runner.invoke(
71
+ main,
72
+ ['protect', 'claude-code', '--skip-env-scan'],
73
+ catch_exceptions=False
74
+ )
60
75
 
61
76
  # Should complete successfully
62
77
  assert result.exit_code == 0 or "Installation complete" in result.output
@@ -77,21 +92,25 @@ class TestInstallCommand:
77
92
 
78
93
  def test_install_with_preset(self, runner, tmp_path):
79
94
  """Test protect claude-code with security preset."""
80
- with patch.object(Path, 'home', return_value=tmp_path):
81
- result = runner.invoke(
82
- main,
83
- ['protect', 'claude-code', '--preset', 'paranoid', '--skip-env-scan']
84
- )
95
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
96
+ with patch.object(Path, 'home', return_value=tmp_path):
97
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
98
+ result = runner.invoke(
99
+ main,
100
+ ['protect', 'claude-code', '--preset', 'paranoid', '--skip-env-scan']
101
+ )
85
102
 
86
103
  assert "paranoid" in result.output.lower() or result.exit_code == 0
87
104
 
88
105
  def test_install_skip_proxy_check(self, runner, tmp_path):
89
106
  """Test protect claude-code with --skip-proxy-check skips openclaw detection."""
90
- with patch.object(Path, 'home', return_value=tmp_path):
91
- result = runner.invoke(
92
- main,
93
- ['protect', 'claude-code', '--skip-env-scan', '--skip-proxy-check']
94
- )
107
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
108
+ with patch.object(Path, 'home', return_value=tmp_path):
109
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
110
+ result = runner.invoke(
111
+ main,
112
+ ['protect', 'claude-code', '--skip-env-scan', '--skip-proxy-check']
113
+ )
95
114
 
96
115
  # Should not mention openclaw
97
116
  assert "openclaw" not in result.output.lower()
@@ -107,14 +126,16 @@ class TestInstallCommand:
107
126
  "config_path": str(tmp_path / ".openclaw"),
108
127
  }
109
128
 
110
- with patch.object(Path, 'home', return_value=tmp_path):
111
- with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
112
- with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
113
- result = runner.invoke(
114
- main,
115
- ['protect', 'claude-code', '--skip-env-scan'],
116
- input='n\n' # Answer 'no' to proxy override prompt
117
- )
129
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
130
+ with patch.object(Path, 'home', return_value=tmp_path):
131
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
132
+ with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
133
+ with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
134
+ result = runner.invoke(
135
+ main,
136
+ ['protect', 'claude-code', '--skip-env-scan'],
137
+ input='n\n' # Answer 'no' to proxy override prompt
138
+ )
118
139
 
119
140
  # Should mention openclaw was detected
120
141
  assert "openclaw" in result.output.lower() or result.exit_code == 0
@@ -129,14 +150,16 @@ class TestInstallCommand:
129
150
  "config_path": str(tmp_path / ".openclaw"),
130
151
  }
131
152
 
132
- with patch.object(Path, 'home', return_value=tmp_path):
133
- with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
134
- with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
135
- result = runner.invoke(
136
- main,
137
- ['protect', 'claude-code', '--skip-env-scan'],
138
- input='n\n' # Answer 'no' to proxy override prompt
139
- )
153
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
154
+ with patch.object(Path, 'home', return_value=tmp_path):
155
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
156
+ with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
157
+ with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
158
+ result = runner.invoke(
159
+ main,
160
+ ['protect', 'claude-code', '--skip-env-scan'],
161
+ input='n\n' # Answer 'no' to proxy override prompt
162
+ )
140
163
 
141
164
  # Should mention gateway is running
142
165
  assert "gateway" in result.output.lower() or "running" in result.output.lower() or result.exit_code == 0
@@ -151,13 +174,15 @@ class TestInstallCommand:
151
174
  "config_path": None,
152
175
  }
153
176
 
154
- with patch.object(Path, 'home', return_value=tmp_path):
155
- with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
156
- with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
157
- result = runner.invoke(
158
- main,
159
- ['protect', 'claude-code', '--skip-env-scan', '--force-proxy']
160
- )
177
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
178
+ with patch.object(Path, 'home', return_value=tmp_path):
179
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
180
+ with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
181
+ with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
182
+ result = runner.invoke(
183
+ main,
184
+ ['protect', 'claude-code', '--skip-env-scan', '--force-proxy']
185
+ )
161
186
 
162
187
  # Should mention force/override
163
188
  assert "override" in result.output.lower() or "proxy" in result.output.lower() or result.exit_code == 0
@@ -174,13 +199,15 @@ class TestInstallCommand:
174
199
 
175
200
  tweek_dir = tmp_path / ".tweek"
176
201
 
177
- with patch.object(Path, 'home', return_value=tmp_path):
178
- with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
179
- with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
180
- result = runner.invoke(
181
- main,
182
- ['protect', 'claude-code', '--skip-env-scan', '--force-proxy']
183
- )
202
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
203
+ with patch.object(Path, 'home', return_value=tmp_path):
204
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
205
+ with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
206
+ with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
207
+ result = runner.invoke(
208
+ main,
209
+ ['protect', 'claude-code', '--skip-env-scan', '--force-proxy']
210
+ )
184
211
 
185
212
  # Check config file was created
186
213
  config_file = tweek_dir / "config.yaml"
@@ -201,14 +228,16 @@ class TestInstallCommand:
201
228
  "config_path": None,
202
229
  }
203
230
 
204
- with patch.object(Path, 'home', return_value=tmp_path):
205
- with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
206
- with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
207
- result = runner.invoke(
208
- main,
209
- ['protect', 'claude-code', '--skip-env-scan'],
210
- input='y\n' # Answer 'yes' to proxy override prompt
211
- )
231
+ with patch.dict(os.environ, {'HOME': str(tmp_path)}):
232
+ with patch.object(Path, 'home', return_value=tmp_path):
233
+ with patch('tweek.cli_install.Path.home', return_value=tmp_path):
234
+ with patch('tweek.proxy.get_openclaw_status', return_value=openclaw_status):
235
+ with patch('tweek.proxy.detect_proxy_conflicts', return_value=[]):
236
+ result = runner.invoke(
237
+ main,
238
+ ['protect', 'claude-code', '--skip-env-scan'],
239
+ input='y\n' # Answer 'yes' to proxy override prompt
240
+ )
212
241
 
213
242
  # Should confirm proxy override
214
243
  assert "proxy" in result.output.lower() or result.exit_code == 0
@@ -217,7 +246,7 @@ class TestInstallCommand:
217
246
  class TestUninstallCommand:
218
247
  """Tests for the unprotect command (formerly uninstall)."""
219
248
 
220
- @patch('tweek.cli.sys')
249
+ @patch('tweek.cli_protect.sys')
221
250
  def test_uninstall_not_installed(self, mock_sys, runner, tmp_path):
222
251
  """Test unprotect when not installed (project scope, empty directory)."""
223
252
  mock_sys.stdin.isatty.return_value = True
@@ -227,7 +256,7 @@ class TestUninstallCommand:
227
256
 
228
257
  assert "No Tweek installation" in result.output or result.exit_code == 0
229
258
 
230
- @patch('tweek.cli.sys')
259
+ @patch('tweek.cli_protect.sys')
231
260
  def test_uninstall_removes_hooks(self, mock_sys, runner, tmp_path):
232
261
  """Test unprotect removes Tweek hooks."""
233
262
  mock_sys.stdin.isatty.return_value = True