tweek 0.3.0__tar.gz → 0.4.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.
- {tweek-0.3.0/tweek.egg-info → tweek-0.4.0}/PKG-INFO +9 -7
- {tweek-0.3.0 → tweek-0.4.0}/README.md +5 -5
- {tweek-0.3.0 → tweek-0.4.0}/pyproject.toml +9 -5
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_cli.py +86 -57
- tweek-0.4.0/tests/test_cli_configure.py +297 -0
- tweek-0.4.0/tests/test_config_models.py +1000 -0
- tweek-0.4.0/tests/test_config_templates.py +253 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_diagnostics.py +3 -3
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_enforcement.py +13 -7
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_installer_improvements.py +55 -38
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_llm_reviewer.py +133 -24
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_local_model.py +89 -31
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_mcp_clients.py +3 -3
- tweek-0.4.0/tests/test_memory_scoped.py +481 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_pattern_families.py +3 -3
- tweek-0.4.0/tests/test_pattern_matcher_redos.py +246 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_prompt_injection_patterns.py +7 -2
- tweek-0.4.0/tests/test_property_based.py +823 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_protect_command.py +15 -2
- tweek-0.4.0/tests/test_provenance.py +337 -0
- tweek-0.4.0/tests/test_provenance_integration.py +328 -0
- tweek-0.4.0/tests/test_skill_context.py +308 -0
- tweek-0.4.0/tests/test_tiered_help.py +150 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/__init__.py +2 -2
- {tweek-0.3.0 → tweek-0.4.0}/tweek/audit.py +2 -2
- tweek-0.4.0/tweek/cli.py +128 -0
- tweek-0.4.0/tweek/cli_config.py +643 -0
- tweek-0.4.0/tweek/cli_configure.py +413 -0
- tweek-0.4.0/tweek/cli_core.py +718 -0
- tweek-0.4.0/tweek/cli_dry_run.py +390 -0
- tweek-0.4.0/tweek/cli_helpers.py +509 -0
- tweek-0.4.0/tweek/cli_install.py +1666 -0
- tweek-0.4.0/tweek/cli_logs.py +301 -0
- tweek-0.4.0/tweek/cli_mcp.py +148 -0
- tweek-0.4.0/tweek/cli_memory.py +343 -0
- tweek-0.4.0/tweek/cli_plugins.py +748 -0
- tweek-0.4.0/tweek/cli_protect.py +564 -0
- tweek-0.4.0/tweek/cli_proxy.py +405 -0
- tweek-0.4.0/tweek/cli_security.py +236 -0
- tweek-0.4.0/tweek/cli_skills.py +289 -0
- tweek-0.4.0/tweek/cli_uninstall.py +551 -0
- tweek-0.4.0/tweek/cli_vault.py +313 -0
- tweek-0.4.0/tweek/config/__init__.py +21 -0
- tweek-0.4.0/tweek/config/allowed_dirs.yaml +22 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/config/families.yaml +4 -1
- {tweek-0.3.0 → tweek-0.4.0}/tweek/config/manager.py +49 -0
- tweek-0.4.0/tweek/config/models.py +307 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/config/patterns.yaml +29 -5
- tweek-0.4.0/tweek/config/templates/config.yaml.template +212 -0
- tweek-0.4.0/tweek/config/templates/env.template +45 -0
- tweek-0.4.0/tweek/config/templates/overrides.yaml.template +121 -0
- tweek-0.4.0/tweek/config/templates/tweek.yaml.template +20 -0
- tweek-0.4.0/tweek/config/templates.py +136 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/config/tiers.yaml +5 -4
- {tweek-0.3.0 → tweek-0.4.0}/tweek/diagnostics.py +112 -32
- {tweek-0.3.0 → tweek-0.4.0}/tweek/hooks/overrides.py +4 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/hooks/post_tool_use.py +46 -1
- {tweek-0.3.0 → tweek-0.4.0}/tweek/hooks/pre_tool_use.py +149 -49
- {tweek-0.3.0 → tweek-0.4.0}/tweek/integrations/openclaw.py +84 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/licensing.py +1 -1
- tweek-0.4.0/tweek/mcp/__init__.py +22 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/clients/chatgpt.py +2 -2
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/clients/claude_desktop.py +2 -2
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/clients/gemini.py +2 -2
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/proxy.py +165 -1
- tweek-0.4.0/tweek/memory/provenance.py +438 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/memory/queries.py +2 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/memory/safety.py +23 -4
- {tweek-0.3.0 → tweek-0.4.0}/tweek/memory/schemas.py +1 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/memory/store.py +101 -71
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/heuristic_scorer.py +1 -1
- tweek-0.4.0/tweek/security/integrity.py +77 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/llm_reviewer.py +162 -68
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/local_reviewer.py +44 -2
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/model_registry.py +73 -7
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skill_template/overrides-reference.md +1 -1
- tweek-0.4.0/tweek/skills/context.py +221 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skills/scanner.py +2 -2
- {tweek-0.3.0 → tweek-0.4.0/tweek.egg-info}/PKG-INFO +9 -7
- {tweek-0.3.0 → tweek-0.4.0}/tweek.egg-info/SOURCES.txt +34 -2
- {tweek-0.3.0 → tweek-0.4.0}/tweek.egg-info/requires.txt +2 -0
- tweek-0.3.0/tests/test_mcp_server.py +0 -167
- tweek-0.3.0/tweek/cli.py +0 -6609
- tweek-0.3.0/tweek/cli_helpers.py +0 -193
- tweek-0.3.0/tweek/config/__init__.py +0 -13
- tweek-0.3.0/tweek/config/allowed_dirs.yaml +0 -23
- tweek-0.3.0/tweek/mcp/__init__.py +0 -24
- tweek-0.3.0/tweek/mcp/server.py +0 -320
- {tweek-0.3.0 → tweek-0.4.0}/LICENSE +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/NOTICE +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/setup.cfg +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_approval_queue.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_audit.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_break_glass.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_cli_helpers.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_config_manager.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_credential_scanner.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_feedback.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_heuristic_scorer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_language_detection.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_licensing.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_llm_local.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_log_bundle.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_logging.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_logging_enhanced.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_mcp_proxy.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_openclaw_integration.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_overrides.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_path_boundary.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_patterns.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_plugin_scoping.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_post_tool_use.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_proxy_detection.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_rate_limiter.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_redaction.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_screening_context.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_session_analyzer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tests/test_vault_cross_platform.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/_keygen.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/cli_model.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/hooks/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/hooks/break_glass.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/hooks/feedback.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/integrations/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/integrations/openclaw_server.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/logging/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/logging/bundle.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/logging/json_logger.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/logging/security_log.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/approval.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/approval_cli.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/clients/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/mcp/screening.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/memory/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/platform/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/base.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/gdpr.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/gov.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/hipaa.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/legal.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/pci.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/compliance/soc2.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/detectors/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/detectors/continue_dev.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/detectors/copilot.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/detectors/cursor.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/detectors/openclaw.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/detectors/windsurf.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/git_discovery.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/git_installer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/git_lockfile.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/git_registry.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/git_security.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/providers/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/providers/anthropic.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/providers/azure_openai.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/providers/bedrock.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/providers/google.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/providers/openai.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/scope.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/llm_reviewer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/local_model_reviewer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/pattern_matcher.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/rate_limiter.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/plugins/screening/session_analyzer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/proxy/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/proxy/addon.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/proxy/interceptor.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/proxy/server.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/docker_bridge.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/executor.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/layers.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/linux.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/profile_generator.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/project.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/sandbox/registry.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/screening/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/screening/context.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/language.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/local_model.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/rate_limiter.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/secret_scanner.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/security/session_analyzer.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skill_template/SKILL.md +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skill_template/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skill_template/cli-reference.md +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skill_template/scripts/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skill_template/scripts/check_installed.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skills/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skills/config.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skills/fingerprints.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skills/guard.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/skills/isolation.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/vault/__init__.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/vault/cross_platform.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek/vault/keychain.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek-openclaw-plugin/node_modules/flatted/python/flatted.py +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek.egg-info/dependency_links.txt +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/tweek.egg-info/entry_points.txt +0 -0
- {tweek-0.3.0 → tweek-0.4.0}/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
|
+
Version: 0.4.0
|
|
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,
|
|
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,8 @@ 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"
|
|
49
|
+
Requires-Dist: hypothesis>=6.98.0; extra == "dev"
|
|
48
50
|
Requires-Dist: black>=23.0; extra == "dev"
|
|
49
51
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
50
52
|
Requires-Dist: twine>=4.0; extra == "dev"
|
|
@@ -123,7 +125,7 @@ tweek proxy setup # Cursor, Windsurf, Continue.dev (HTTP p
|
|
|
123
125
|
tweek doctor
|
|
124
126
|
```
|
|
125
127
|
|
|
126
|
-
That's it. Tweek auto-detects your tools, applies all
|
|
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.
|
|
127
129
|
|
|
128
130
|
---
|
|
129
131
|
|
|
@@ -165,7 +167,7 @@ Turn 3: cat ~/.ssh/id_rsa → BLOCKED: path_escalation anomaly
|
|
|
165
167
|
|
|
166
168
|
**Response injection** — Malicious instructions hidden in tool responses are caught at ingestion.
|
|
167
169
|
|
|
168
|
-
See the full [Attack Patterns Reference](docs/ATTACK_PATTERNS.md) for all
|
|
170
|
+
See the full [Attack Patterns Reference](docs/ATTACK_PATTERNS.md) for all 262 patterns across 11 categories.
|
|
169
171
|
|
|
170
172
|
---
|
|
171
173
|
|
|
@@ -216,7 +218,7 @@ Every tool call passes through six independent screening layers. An attacker wou
|
|
|
216
218
|
|
|
217
219
|
| Layer | What It Does |
|
|
218
220
|
|-------|-------------|
|
|
219
|
-
| **1. Pattern Matching** |
|
|
221
|
+
| **1. Pattern Matching** | 262 regex signatures catch known credential theft, exfiltration, and injection attacks instantly |
|
|
220
222
|
| **2. Rate Limiting** | Detects burst attacks, automated probing, and resource theft sequences |
|
|
221
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. |
|
|
222
224
|
| **4. Session Tracking** | Behavioral analysis across turns detects multi-step attacks that look innocent individually |
|
|
@@ -234,7 +236,7 @@ See [Defense Layers](docs/DEFENSE_LAYERS.md) for the deep dive and [Architecture
|
|
|
234
236
|
| [Full Feature List](docs/FEATURES.md) | Complete feature inventory |
|
|
235
237
|
| [Architecture](docs/ARCHITECTURE.md) | System design and interception layers |
|
|
236
238
|
| [Defense Layers](docs/DEFENSE_LAYERS.md) | Screening pipeline deep dive |
|
|
237
|
-
| [Attack Patterns](docs/ATTACK_PATTERNS.md) | Full
|
|
239
|
+
| [Attack Patterns](docs/ATTACK_PATTERNS.md) | Full 262-pattern library reference |
|
|
238
240
|
| [Configuration](docs/CONFIGURATION.md) | Config files, tiers, and presets |
|
|
239
241
|
| [CLI Reference](docs/CLI_REFERENCE.md) | All commands, flags, and examples |
|
|
240
242
|
| [MCP Integration](docs/MCP_INTEGRATION.md) | MCP proxy and gateway setup |
|
|
@@ -243,7 +245,7 @@ See [Defense Layers](docs/DEFENSE_LAYERS.md) for the deep dive and [Architecture
|
|
|
243
245
|
| [Credential Vault](docs/VAULT.md) | Vault setup and migration |
|
|
244
246
|
| [Plugins](docs/PLUGINS.md) | Plugin development and registry |
|
|
245
247
|
| [Logging](docs/LOGGING.md) | Event logging and audit trail |
|
|
246
|
-
| [
|
|
248
|
+
| [Dry-Run](docs/DRY_RUN.md) | Dry-run preview configuration |
|
|
247
249
|
| [Tweek vs. Claude Code](docs/COMPARISON.md) | Feature comparison with native security |
|
|
248
250
|
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Common issues and fixes |
|
|
249
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
|
|
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
|
|
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** |
|
|
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
|
|
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
|
-
| [
|
|
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.
|
|
7
|
+
version = "0.4.0"
|
|
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", "
|
|
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,8 @@ 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",
|
|
61
|
+
"hypothesis>=6.98.0",
|
|
60
62
|
"black>=23.0",
|
|
61
63
|
"ruff>=0.1.0",
|
|
62
64
|
"twine>=4.0",
|
|
@@ -114,6 +116,7 @@ exclude = ["website*", "tests*", "scripts*", "test-environment*", "docs*"]
|
|
|
114
116
|
tweek = [
|
|
115
117
|
"config/*.yaml",
|
|
116
118
|
"config/_integrity.json",
|
|
119
|
+
"config/templates/*",
|
|
117
120
|
"skill_template/*.md",
|
|
118
121
|
"skill_template/scripts/*.py",
|
|
119
122
|
]
|
|
@@ -121,13 +124,13 @@ tweek = [
|
|
|
121
124
|
[tool.pytest.ini_options]
|
|
122
125
|
testpaths = ["tests"]
|
|
123
126
|
python_files = ["test_*.py"]
|
|
124
|
-
addopts = "-v --cov=tweek --cov-report=term-missing --cov-fail-under=
|
|
127
|
+
addopts = "-v --cov=tweek --cov-report=term-missing --cov-fail-under=60 -m 'not integration'"
|
|
125
128
|
markers = [
|
|
126
129
|
"patterns: Regex pattern matching and prompt injection detection (slow, ~37s)",
|
|
127
130
|
"hooks: Pre/post tool use hook pipeline and path boundary escalation",
|
|
128
131
|
"cli: CLI commands (install, uninstall, protect, config, license, logs, update)",
|
|
129
132
|
"plugins: Plugin system (git registry, lockfile, compliance, discovery, security)",
|
|
130
|
-
"sandbox:
|
|
133
|
+
"sandbox: Dry-run execution, project isolation, and Docker bridge",
|
|
131
134
|
"skills: Skill scanning, isolation, fingerprints, and guard",
|
|
132
135
|
"mcp: MCP proxy, server, and desktop client integration",
|
|
133
136
|
"security: Credential scanning, redaction, break-glass, enforcement, overrides",
|
|
@@ -136,6 +139,7 @@ markers = [
|
|
|
136
139
|
"memory: Memory store, safety, and query system",
|
|
137
140
|
"core: Approval queue, audit, diagnostics, feedback, rate limiting, sessions",
|
|
138
141
|
"local_model: Local ONNX model inference, registry, and CLI commands",
|
|
142
|
+
"integration: End-to-end integration tests with isolated venv install (slow)",
|
|
139
143
|
]
|
|
140
144
|
|
|
141
145
|
[tool.black]
|
|
@@ -182,7 +186,7 @@ omit = [
|
|
|
182
186
|
]
|
|
183
187
|
|
|
184
188
|
[tool.coverage.report]
|
|
185
|
-
fail_under =
|
|
189
|
+
fail_under = 60
|
|
186
190
|
show_missing = true
|
|
187
191
|
exclude_lines = [
|
|
188
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.
|
|
54
|
-
with patch('
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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.
|
|
111
|
-
with patch('
|
|
112
|
-
with patch('tweek.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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.
|
|
133
|
-
with patch('
|
|
134
|
-
with patch('tweek.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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.
|
|
155
|
-
with patch('
|
|
156
|
-
with patch('tweek.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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.
|
|
178
|
-
with patch('
|
|
179
|
-
with patch('tweek.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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.
|
|
205
|
-
with patch('
|
|
206
|
-
with patch('tweek.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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.
|
|
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.
|
|
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
|