clawmoat 0.7.0 → 1.0.0
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.
- package/.dockerignore +9 -0
- package/CHANGELOG.md +18 -0
- package/CONTRIBUTING.md +4 -2
- package/DEMO.md +87 -0
- package/Dockerfile +5 -18
- package/README.md +294 -8
- package/SECURITY.md +58 -10
- package/THREAT_MODEL.md +129 -0
- package/agent/README.md +131 -0
- package/agent/index.js +471 -0
- package/agent/install-service.sh +94 -0
- package/agent/openclaw-hook.js +453 -0
- package/agent/provider-setup.js +649 -0
- package/agent/setup.js +274 -0
- package/assets/BADGE-USAGE.md +20 -0
- package/assets/clawmoat-badge.svg +21 -0
- package/bin/clawmoat.js +468 -111
- package/docs/affiliates/dashboard.html +124 -0
- package/docs/affiliates/index.html +236 -0
- package/docs/agent-install.html +183 -0
- package/docs/ai-agent-security-scanner.html +10 -6
- package/docs/badge/index.html +149 -0
- package/docs/badge/scanning.svg +23 -0
- package/docs/blog/386-malicious-skills.html +262 -0
- package/docs/blog/40000-exposed-openclaw-instances.html +201 -0
- package/docs/blog/agent-trust-protocol.html +198 -0
- package/docs/blog/ai-agent-earns-commissions.html +230 -0
- package/docs/blog/bugmageddon-agent-firewall.html +174 -0
- package/docs/blog/calculator-math.html +180 -0
- package/docs/blog/clawmoat-vs-llamafirewall-nemo-guardrails.html +229 -0
- package/docs/blog/host-guardian-launch.html +18 -8
- package/docs/blog/ibm-experts-agent-runtime-protection.html +247 -0
- package/docs/blog/index.html +211 -9
- package/docs/blog/langchain-security-tutorial.html +18 -8
- package/docs/blog/mcp-30-cves-security-crisis.html +286 -0
- package/docs/blog/meta-researcher-rogue-agent.html +201 -0
- package/docs/blog/microsoft-openclaw-workstation-security.html +235 -0
- package/docs/blog/nist-ai-agent-standards-clawmoat.html +377 -0
- package/docs/blog/oasis-websocket-hijack.html +212 -0
- package/docs/blog/ollama-openclaw-security.html +160 -0
- package/docs/blog/openclaw-enterprise-readiness-claw10.html +199 -0
- package/docs/blog/openclaw-security-reckoning-2026.html +368 -0
- package/docs/blog/owasp-agentic-ai-top10.html +18 -8
- package/docs/blog/securing-ai-agents.html +18 -8
- package/docs/blog/supply-chain-agents.html +18 -8
- package/docs/business/index.html +525 -0
- package/docs/business/install.html +261 -0
- package/docs/checklist.html +174 -0
- package/docs/compare/index.html +122 -0
- package/docs/compare/lakera/index.html +62 -0
- package/docs/compare/llm-guard/index.html +49 -0
- package/docs/compare/snyk-agent-scan/index.html +63 -0
- package/docs/compare.html +10 -6
- package/docs/dashboard/index.html +520 -0
- package/docs/finance/index.html +220 -0
- package/docs/guides/business-deployment.html +770 -0
- package/docs/hall-of-fame.html +174 -0
- package/docs/index.html +447 -154
- package/docs/install.sh +557 -0
- package/docs/integrations/langchain.html +14 -6
- package/docs/integrations/openai.html +14 -6
- package/docs/integrations/openclaw.html +55 -7
- package/docs/plans/2026-03-26-threat-intel-api.md +255 -0
- package/docs/plans/2026-04-14-bugmageddon-marketing-pack.md +329 -0
- package/docs/plans/2026-04-14-clawmoat-v1-bugmageddon.md +248 -0
- package/docs/plans/2026-04-14-v1-release-update.md +91 -0
- package/docs/plans/2026-04-19-supabase-audit.md +68 -0
- package/docs/plans/2026-05-12-sales-push.md +303 -0
- package/docs/playground/index.html +893 -0
- package/docs/playground.html +4 -7
- package/docs/privacy-policy/index.html +122 -0
- package/docs/rfcs/defense-in-depth.md +467 -0
- package/docs/scan/index.html +358 -0
- package/docs/services/case-study.html +255 -0
- package/docs/services/downloads/install-openclaw.bat +45 -0
- package/docs/services/downloads/install-openclaw.command +38 -0
- package/docs/services/downloads/install-openclaw.sh +38 -0
- package/docs/services/get-started.html +165 -0
- package/docs/services/index.html +598 -0
- package/docs/services/multi-agent-security.html +284 -0
- package/docs/services/one-pager.html +99 -0
- package/docs/services/pitch-deck.html +229 -0
- package/docs/services/roi-calculator.html +258 -0
- package/docs/sitemap.xml +192 -2
- package/docs/support/index.html +135 -0
- package/docs/templates/customer-service/HEARTBEAT.md +61 -0
- package/docs/templates/customer-service/MEMORY.md +89 -0
- package/docs/templates/customer-service/SOUL.md +41 -0
- package/docs/templates/customer-service/USER.md +56 -0
- package/docs/templates/executive/HEARTBEAT.md +86 -0
- package/docs/templates/executive/MEMORY.md +92 -0
- package/docs/templates/executive/SOUL.md +44 -0
- package/docs/templates/executive/USER.md +62 -0
- package/docs/templates/finance/HEARTBEAT.md +58 -0
- package/docs/templates/finance/MEMORY.md +87 -0
- package/docs/templates/finance/SOUL.md +38 -0
- package/docs/templates/finance/USER.md +53 -0
- package/docs/templates/index.html +115 -0
- package/docs/templates/operations/HEARTBEAT.md +63 -0
- package/docs/templates/operations/MEMORY.md +68 -0
- package/docs/templates/operations/SOUL.md +38 -0
- package/docs/templates/operations/USER.md +49 -0
- package/docs/templates/sales/HEARTBEAT.md +55 -0
- package/docs/templates/sales/MEMORY.md +89 -0
- package/docs/templates/sales/SOUL.md +34 -0
- package/docs/templates/sales/USER.md +54 -0
- package/docs/terms-of-service/index.html +122 -0
- package/eslint.config.js +32 -0
- package/evals/README.md +29 -0
- package/evals/cases.json +390 -0
- package/evals/results.md +68 -0
- package/evals/run.js +180 -0
- package/examples/basic-usage.js +38 -0
- package/examples/demo-attack/demo.js +186 -0
- package/examples/python-quickstart/README.md +54 -0
- package/examples/python-quickstart/clawmoat_client.py +167 -0
- package/examples/video-demo/README.md +14 -0
- package/examples/video-demo/scene-a-normal.js +29 -0
- package/examples/video-demo/scene-b-attack-arrives.js +31 -0
- package/examples/video-demo/scene-c-hijack.js +44 -0
- package/examples/video-demo/scene-d-clawmoat.js +46 -0
- package/integrations/crewai/README.md +32 -0
- package/integrations/crewai/clawmoat_crewai/__init__.py +17 -0
- package/integrations/crewai/clawmoat_crewai/guard.py +103 -0
- package/integrations/crewai/pyproject.toml +21 -0
- package/integrations/langchain/README.md +91 -0
- package/integrations/langchain/clawmoat_langchain/__init__.py +17 -0
- package/integrations/langchain/clawmoat_langchain/callback.py +489 -0
- package/integrations/langchain/pyproject.toml +32 -0
- package/integrations/litellm/README.md +324 -0
- package/integrations/litellm/clawmoat_litellm/__init__.py +21 -0
- package/integrations/litellm/clawmoat_litellm/callback.py +329 -0
- package/integrations/litellm/clawmoat_litellm/proxy_middleware.py +224 -0
- package/integrations/litellm/pyproject.toml +74 -0
- package/integrations/openai-agents/README.md +392 -0
- package/integrations/openai-agents/clawmoat_openai_agents/__init__.py +20 -0
- package/integrations/openai-agents/clawmoat_openai_agents/guardrail.py +431 -0
- package/integrations/openai-agents/clawmoat_openai_agents/middleware.py +311 -0
- package/integrations/openai-agents/pyproject.toml +76 -0
- package/package.json +6 -5
- package/plugins/openclaw-adapter/PHASE1.md +439 -0
- package/plugins/openclaw-adapter/README.md +103 -0
- package/plugins/openclaw-adapter/SPEC.md +1644 -0
- package/plugins/openclaw-adapter/package.json +31 -0
- package/plugins/openclaw-adapter/src/index.test.ts +226 -0
- package/plugins/openclaw-adapter/src/index.ts +140 -0
- package/plugins/openclaw-adapter/tsconfig.json +14 -0
- package/server/data/threats.json +290 -0
- package/server/index.js +224 -10
- package/src/adapters/express.js +161 -0
- package/src/adapters/index.js +92 -0
- package/src/adapters/langchain.js +185 -0
- package/src/approval/index.js +456 -0
- package/src/ban-scanner.js +200 -0
- package/src/boundary-scanner.js +296 -0
- package/src/ci-scanner.js +279 -0
- package/src/code-scanner.js +245 -0
- package/src/enforce.js +166 -0
- package/src/finance/index.js +585 -0
- package/src/finance/mcp-firewall.js +486 -0
- package/src/formatters/json.js +80 -0
- package/src/formatters/sarif.js +388 -0
- package/src/guardian/alerts.js +34 -3
- package/src/guardian/gateway-monitor.js +590 -0
- package/src/guardian/index.js +41 -2
- package/src/index.js +105 -0
- package/src/integrations/agentmesh.js +501 -0
- package/src/language-detector.js +201 -0
- package/src/mcp-scanner.js +253 -0
- package/src/multimodal/index.js +579 -0
- package/src/obfuscation-scanner.js +457 -0
- package/src/policy-engine.js +402 -0
- package/src/scanners/dependency-attacks.js +128 -0
- package/src/scanners/prompt-injection.js +18 -0
- package/src/scanners/supply-chain.js +14 -0
- package/src/templates/default-config.yml +90 -0
- package/src/vuln-ops/exploitability.js +46 -0
- package/src/watch/live-monitor.js +720 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""OpenAI Agents SDK middleware for ClawMoat security scanning."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any, List, Optional, AsyncGenerator, Union
|
|
4
|
+
import json
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ClawMoatAgentMiddleware:
|
|
9
|
+
"""Middleware for OpenAI Agents SDK to add comprehensive ClawMoat security.
|
|
10
|
+
|
|
11
|
+
This provides a higher-level integration that can wrap entire agents
|
|
12
|
+
or conversation flows with security scanning and policy enforcement.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
guardrail_config: Optional[Dict[str, Any]] = None,
|
|
18
|
+
enable_conversation_tracking: bool = True,
|
|
19
|
+
max_conversation_length: int = 50,
|
|
20
|
+
audit_all_interactions: bool = True
|
|
21
|
+
):
|
|
22
|
+
"""Initialize ClawMoat agent middleware.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
guardrail_config: Configuration for ClawMoat guardrails
|
|
26
|
+
enable_conversation_tracking: Track conversation history for context
|
|
27
|
+
max_conversation_length: Maximum turns to keep in conversation history
|
|
28
|
+
audit_all_interactions: Whether to audit all agent interactions
|
|
29
|
+
"""
|
|
30
|
+
self.guardrail_config = guardrail_config or {}
|
|
31
|
+
self.enable_conversation_tracking = enable_conversation_tracking
|
|
32
|
+
self.max_conversation_length = max_conversation_length
|
|
33
|
+
self.audit_all_interactions = audit_all_interactions
|
|
34
|
+
|
|
35
|
+
# Initialize guardrails
|
|
36
|
+
try:
|
|
37
|
+
from .guardrail import ClawMoatGuardrail
|
|
38
|
+
self.input_guardrail = ClawMoatGuardrail(
|
|
39
|
+
scan_input=True,
|
|
40
|
+
scan_output=False,
|
|
41
|
+
**self.guardrail_config
|
|
42
|
+
)
|
|
43
|
+
self.output_guardrail = ClawMoatGuardrail(
|
|
44
|
+
scan_input=False,
|
|
45
|
+
scan_output=True,
|
|
46
|
+
**self.guardrail_config
|
|
47
|
+
)
|
|
48
|
+
except ImportError as e:
|
|
49
|
+
print(f"Warning: Could not initialize ClawMoat guardrails: {e}")
|
|
50
|
+
self.input_guardrail = None
|
|
51
|
+
self.output_guardrail = None
|
|
52
|
+
|
|
53
|
+
# State tracking
|
|
54
|
+
self.conversation_history = []
|
|
55
|
+
self.interaction_log = []
|
|
56
|
+
self.security_summary = {
|
|
57
|
+
"total_interactions": 0,
|
|
58
|
+
"blocked_inputs": 0,
|
|
59
|
+
"blocked_outputs": 0,
|
|
60
|
+
"threats_detected": 0,
|
|
61
|
+
"last_threat": None
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
def wrap_agent(self, agent):
|
|
65
|
+
"""Wrap an OpenAI agent with ClawMoat security middleware.
|
|
66
|
+
|
|
67
|
+
Returns a new agent instance with security guardrails attached.
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
# Add ClawMoat guardrails to the agent
|
|
71
|
+
if hasattr(agent, 'input_guardrails') and self.input_guardrail:
|
|
72
|
+
if not agent.input_guardrails:
|
|
73
|
+
agent.input_guardrails = []
|
|
74
|
+
agent.input_guardrails.append(self.input_guardrail)
|
|
75
|
+
|
|
76
|
+
if hasattr(agent, 'output_guardrails') and self.output_guardrail:
|
|
77
|
+
if not agent.output_guardrails:
|
|
78
|
+
agent.output_guardrails = []
|
|
79
|
+
agent.output_guardrails.append(self.output_guardrail)
|
|
80
|
+
|
|
81
|
+
# Wrap key methods for additional tracking
|
|
82
|
+
original_run = agent.run if hasattr(agent, 'run') else None
|
|
83
|
+
if original_run:
|
|
84
|
+
agent.run = self._wrap_run_method(original_run)
|
|
85
|
+
|
|
86
|
+
return agent
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
print(f"Warning: Could not fully wrap agent with ClawMoat: {e}")
|
|
90
|
+
return agent
|
|
91
|
+
|
|
92
|
+
def _wrap_run_method(self, original_run):
|
|
93
|
+
"""Wrap the agent's run method to add security tracking."""
|
|
94
|
+
def wrapped_run(*args, **kwargs):
|
|
95
|
+
interaction_id = f"interaction_{int(time.time() * 1000)}"
|
|
96
|
+
start_time = time.time()
|
|
97
|
+
|
|
98
|
+
# Pre-run security check
|
|
99
|
+
try:
|
|
100
|
+
self.security_summary["total_interactions"] += 1
|
|
101
|
+
|
|
102
|
+
# Log interaction start
|
|
103
|
+
if self.audit_all_interactions:
|
|
104
|
+
self.interaction_log.append({
|
|
105
|
+
"id": interaction_id,
|
|
106
|
+
"timestamp": start_time,
|
|
107
|
+
"type": "agent_run_start",
|
|
108
|
+
"args_count": len(args),
|
|
109
|
+
"kwargs_keys": list(kwargs.keys()) if kwargs else []
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
# Call original run method
|
|
113
|
+
result = original_run(*args, **kwargs)
|
|
114
|
+
|
|
115
|
+
# Post-run processing
|
|
116
|
+
end_time = time.time()
|
|
117
|
+
duration = end_time - start_time
|
|
118
|
+
|
|
119
|
+
if self.audit_all_interactions:
|
|
120
|
+
self.interaction_log.append({
|
|
121
|
+
"id": interaction_id,
|
|
122
|
+
"timestamp": end_time,
|
|
123
|
+
"type": "agent_run_complete",
|
|
124
|
+
"duration": duration,
|
|
125
|
+
"success": True
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
# Update conversation tracking
|
|
129
|
+
if self.enable_conversation_tracking:
|
|
130
|
+
self._update_conversation_tracking(args, kwargs, result)
|
|
131
|
+
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
except Exception as e:
|
|
135
|
+
# Handle errors
|
|
136
|
+
end_time = time.time()
|
|
137
|
+
duration = end_time - start_time
|
|
138
|
+
|
|
139
|
+
if self.audit_all_interactions:
|
|
140
|
+
self.interaction_log.append({
|
|
141
|
+
"id": interaction_id,
|
|
142
|
+
"timestamp": end_time,
|
|
143
|
+
"type": "agent_run_error",
|
|
144
|
+
"duration": duration,
|
|
145
|
+
"error": str(e),
|
|
146
|
+
"success": False
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
# Check if this was a security block
|
|
150
|
+
if "ClawMoat" in str(e) or "blocked" in str(e).lower():
|
|
151
|
+
self.security_summary["blocked_inputs"] += 1
|
|
152
|
+
self.security_summary["last_threat"] = {
|
|
153
|
+
"timestamp": end_time,
|
|
154
|
+
"type": "input_blocked",
|
|
155
|
+
"error": str(e)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# Re-raise the original exception
|
|
159
|
+
raise
|
|
160
|
+
|
|
161
|
+
return wrapped_run
|
|
162
|
+
|
|
163
|
+
def _update_conversation_tracking(self, args, kwargs, result):
|
|
164
|
+
"""Update conversation history tracking."""
|
|
165
|
+
try:
|
|
166
|
+
# Extract conversation turn from args/kwargs
|
|
167
|
+
turn_data = {
|
|
168
|
+
"timestamp": time.time(),
|
|
169
|
+
"input": self._extract_input_content(args, kwargs),
|
|
170
|
+
"output": self._extract_output_content(result),
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Add to conversation history
|
|
174
|
+
self.conversation_history.append(turn_data)
|
|
175
|
+
|
|
176
|
+
# Trim history if too long
|
|
177
|
+
if len(self.conversation_history) > self.max_conversation_length:
|
|
178
|
+
self.conversation_history = self.conversation_history[-self.max_conversation_length:]
|
|
179
|
+
|
|
180
|
+
except Exception as e:
|
|
181
|
+
# Don't fail the main operation if tracking fails
|
|
182
|
+
if self.guardrail_config.get("verbose", False):
|
|
183
|
+
print(f"Conversation tracking error: {e}")
|
|
184
|
+
|
|
185
|
+
def _extract_input_content(self, args, kwargs) -> str:
|
|
186
|
+
"""Extract input content for conversation tracking."""
|
|
187
|
+
content_parts = []
|
|
188
|
+
|
|
189
|
+
# Extract from args
|
|
190
|
+
for arg in args:
|
|
191
|
+
if isinstance(arg, str):
|
|
192
|
+
content_parts.append(arg)
|
|
193
|
+
elif hasattr(arg, 'content'):
|
|
194
|
+
content_parts.append(str(arg.content))
|
|
195
|
+
elif isinstance(arg, dict):
|
|
196
|
+
if 'content' in arg:
|
|
197
|
+
content_parts.append(str(arg['content']))
|
|
198
|
+
elif 'message' in arg:
|
|
199
|
+
content_parts.append(str(arg['message']))
|
|
200
|
+
|
|
201
|
+
# Extract from kwargs
|
|
202
|
+
for key, value in kwargs.items():
|
|
203
|
+
if key in ['message', 'prompt', 'input', 'content']:
|
|
204
|
+
content_parts.append(str(value))
|
|
205
|
+
|
|
206
|
+
return " ".join(content_parts)
|
|
207
|
+
|
|
208
|
+
def _extract_output_content(self, result) -> str:
|
|
209
|
+
"""Extract output content for conversation tracking."""
|
|
210
|
+
try:
|
|
211
|
+
if isinstance(result, str):
|
|
212
|
+
return result
|
|
213
|
+
elif hasattr(result, 'content'):
|
|
214
|
+
return str(result.content)
|
|
215
|
+
elif hasattr(result, 'message'):
|
|
216
|
+
return str(result.message)
|
|
217
|
+
elif isinstance(result, dict):
|
|
218
|
+
if 'content' in result:
|
|
219
|
+
return str(result['content'])
|
|
220
|
+
elif 'message' in result:
|
|
221
|
+
return str(result['message'])
|
|
222
|
+
elif 'response' in result:
|
|
223
|
+
return str(result['response'])
|
|
224
|
+
return str(result)
|
|
225
|
+
except Exception:
|
|
226
|
+
return "[Unable to extract content]"
|
|
227
|
+
|
|
228
|
+
def get_security_summary(self) -> Dict[str, Any]:
|
|
229
|
+
"""Get comprehensive security summary."""
|
|
230
|
+
summary = {
|
|
231
|
+
**self.security_summary,
|
|
232
|
+
"conversation_length": len(self.conversation_history),
|
|
233
|
+
"total_interactions_logged": len(self.interaction_log),
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
# Add guardrail stats if available
|
|
237
|
+
if self.input_guardrail:
|
|
238
|
+
summary["input_stats"] = self.input_guardrail.get_stats()
|
|
239
|
+
if self.output_guardrail:
|
|
240
|
+
summary["output_stats"] = self.output_guardrail.get_stats()
|
|
241
|
+
|
|
242
|
+
return summary
|
|
243
|
+
|
|
244
|
+
def get_conversation_history(self, limit: int = 10) -> List[Dict[str, Any]]:
|
|
245
|
+
"""Get recent conversation history."""
|
|
246
|
+
return self.conversation_history[-limit:] if self.conversation_history else []
|
|
247
|
+
|
|
248
|
+
def get_recent_interactions(self, limit: int = 20) -> List[Dict[str, Any]]:
|
|
249
|
+
"""Get recent interaction logs."""
|
|
250
|
+
return self.interaction_log[-limit:] if self.interaction_log else []
|
|
251
|
+
|
|
252
|
+
def get_threat_summary(self) -> Dict[str, Any]:
|
|
253
|
+
"""Get summary of detected threats."""
|
|
254
|
+
all_findings = []
|
|
255
|
+
|
|
256
|
+
if self.input_guardrail:
|
|
257
|
+
all_findings.extend(self.input_guardrail.findings)
|
|
258
|
+
if self.output_guardrail:
|
|
259
|
+
all_findings.extend(self.output_guardrail.findings)
|
|
260
|
+
|
|
261
|
+
# Group by threat type
|
|
262
|
+
threat_counts = {}
|
|
263
|
+
for finding in all_findings:
|
|
264
|
+
threat_type = finding.get("type", "unknown")
|
|
265
|
+
severity = finding.get("severity", "unknown")
|
|
266
|
+
key = f"{threat_type}_{severity}"
|
|
267
|
+
threat_counts[key] = threat_counts.get(key, 0) + 1
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
"total_threats": len(all_findings),
|
|
271
|
+
"threat_breakdown": threat_counts,
|
|
272
|
+
"recent_threats": all_findings[-5:] if all_findings else [],
|
|
273
|
+
"last_threat_time": self.security_summary.get("last_threat", {}).get("timestamp")
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
def export_audit_log(self, format: str = "json") -> str:
|
|
277
|
+
"""Export complete audit log for compliance."""
|
|
278
|
+
audit_data = {
|
|
279
|
+
"metadata": {
|
|
280
|
+
"export_timestamp": time.time(),
|
|
281
|
+
"total_interactions": len(self.interaction_log),
|
|
282
|
+
"conversation_turns": len(self.conversation_history),
|
|
283
|
+
"security_summary": self.security_summary
|
|
284
|
+
},
|
|
285
|
+
"interactions": self.interaction_log,
|
|
286
|
+
"conversation_history": self.conversation_history if self.enable_conversation_tracking else [],
|
|
287
|
+
"threat_summary": self.get_threat_summary(),
|
|
288
|
+
"security_stats": self.get_security_summary()
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if format.lower() == "json":
|
|
292
|
+
return json.dumps(audit_data, indent=2, default=str)
|
|
293
|
+
else:
|
|
294
|
+
raise ValueError(f"Unsupported export format: {format}")
|
|
295
|
+
|
|
296
|
+
def reset_tracking(self) -> None:
|
|
297
|
+
"""Reset all tracking data (for testing or cleanup)."""
|
|
298
|
+
self.conversation_history.clear()
|
|
299
|
+
self.interaction_log.clear()
|
|
300
|
+
self.security_summary = {
|
|
301
|
+
"total_interactions": 0,
|
|
302
|
+
"blocked_inputs": 0,
|
|
303
|
+
"blocked_outputs": 0,
|
|
304
|
+
"threats_detected": 0,
|
|
305
|
+
"last_threat": None
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if self.input_guardrail:
|
|
309
|
+
self.input_guardrail.reset_stats()
|
|
310
|
+
if self.output_guardrail:
|
|
311
|
+
self.output_guardrail.reset_stats()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "clawmoat-openai-agents"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "ClawMoat security integration for OpenAI Agents SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
keywords = ["ai", "security", "openai", "agents", "guardrails", "prompt-injection"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "ClawMoat Team", email = "security@clawmoat.com" },
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.8",
|
|
23
|
+
"Programming Language :: Python :: 3.9",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Topic :: Security",
|
|
28
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"requests>=2.25.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
openai-agents = [
|
|
36
|
+
"openai-agents-sdk>=1.0.0",
|
|
37
|
+
]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=6.0",
|
|
40
|
+
"pytest-asyncio",
|
|
41
|
+
"black",
|
|
42
|
+
"isort",
|
|
43
|
+
"flake8",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Documentation = "https://github.com/darfaz/clawmoat/tree/main/integrations/openai-agents"
|
|
48
|
+
Issues = "https://github.com/darfaz/clawmoat/issues"
|
|
49
|
+
Source = "https://github.com/darfaz/clawmoat/tree/main/integrations/openai-agents"
|
|
50
|
+
Homepage = "https://github.com/darfaz/clawmoat"
|
|
51
|
+
|
|
52
|
+
[tool.hatch.version]
|
|
53
|
+
path = "clawmoat_openai_agents/__init__.py"
|
|
54
|
+
|
|
55
|
+
[tool.hatch.build.targets.sdist]
|
|
56
|
+
include = [
|
|
57
|
+
"/clawmoat_openai_agents",
|
|
58
|
+
"/README.md",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.wheel]
|
|
62
|
+
packages = ["clawmoat_openai_agents"]
|
|
63
|
+
|
|
64
|
+
[tool.black]
|
|
65
|
+
line-length = 120
|
|
66
|
+
target-version = ['py38']
|
|
67
|
+
|
|
68
|
+
[tool.isort]
|
|
69
|
+
profile = "black"
|
|
70
|
+
line_length = 120
|
|
71
|
+
|
|
72
|
+
[tool.pytest.ini_options]
|
|
73
|
+
testpaths = ["tests"]
|
|
74
|
+
python_files = "test_*.py"
|
|
75
|
+
python_classes = "Test*"
|
|
76
|
+
python_functions = "test_*"
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawmoat",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The open-source agent firewall. Prevent AI agents from leaking data, using dangerous tools, and importing poisoned dependencies.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"clawmoat": "bin/clawmoat.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node src/server.js",
|
|
11
|
-
"test": "node --test test
|
|
11
|
+
"test": "node --test test/*.test.js",
|
|
12
12
|
"lint": "eslint src/"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=18"
|
|
32
32
|
},
|
|
33
|
-
"
|
|
34
|
-
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"eslint": "^10.3.0"
|
|
35
|
+
}
|
|
35
36
|
}
|