correctover-ccs 1.0.0__py3-none-any.whl

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.
ccs/__init__.py ADDED
@@ -0,0 +1,31 @@
1
+ """
2
+ Correctover Conformance Standard (CCS) v1.0 — Python SDK
3
+
4
+ Synchronous interceptor-based governance for AI Agent frameworks.
5
+ Eliminates architectural fail-open bypasses inherent to observer-pattern hooks.
6
+
7
+ Usage:
8
+ from ccs import govern
9
+
10
+ @govern(policy="default")
11
+ def my_tool(args):
12
+ ...
13
+ """
14
+
15
+ __version__ = "1.0.0"
16
+ __author__ = "Correctover Standards"
17
+
18
+ from ccs.core import govern, GovernanceResult, CCSConfig, CCSPolicy, CCSRuntime, get_runtime
19
+ from ccs.adapters import crewai_adapter, autogen_adapter, langgraph_adapter
20
+
21
+ __all__ = [
22
+ "govern",
23
+ "GovernanceResult",
24
+ "CCSConfig",
25
+ "CCSPolicy",
26
+ "CCSRuntime",
27
+ "get_runtime",
28
+ "crewai_adapter",
29
+ "autogen_adapter",
30
+ "langgraph_adapter",
31
+ ]
ccs/adapters.py ADDED
@@ -0,0 +1,195 @@
1
+ """
2
+ CCS Framework Adapters — Verified interception for CrewAI, AutoGen, LangGraph.
3
+
4
+ Each adapter replaces the framework's observer-pattern hooks with CCS
5
+ synchronous interceptor decorators, eliminating CWE-636 fail-open vulnerabilities.
6
+
7
+ Verified against:
8
+ - CrewAI >= 0.1.0 (BaseTool.run sync interception)
9
+ - AutoGen >= 0.7.0 (FunctionTool.run async interception)
10
+ - LangGraph >= 0.2.0 (LCBaseTool.run sync interception)
11
+
12
+ Reference: CCS v1.0 Standard, Section 3 — Formal Framework
13
+ DOI: 10.5281/zenodo.21271910
14
+ """
15
+
16
+ from typing import Any, Optional
17
+
18
+
19
+ class CrewAIAdapter:
20
+ """
21
+ CCS adapter for CrewAI.
22
+
23
+ Intercepts crewai.tools.base_tool.BaseTool.run() — the single
24
+ entry point for ALL CrewAI tool executions. If CCS governance
25
+ denies or crashes, the tool is NEVER invoked (fail-closed).
26
+
27
+ Usage:
28
+ from ccs.adapters import crewai_adapter
29
+ crewai_adapter.install() # patches BaseTool.run globally
30
+ crewai_adapter.uninstall() # restores original
31
+ """
32
+
33
+ _original_run = None
34
+ _installed = False
35
+
36
+ @staticmethod
37
+ def install(policy: str = "default"):
38
+ """Install CCS governance on CrewAI's BaseTool.run."""
39
+ from crewai.tools.base_tool import BaseTool
40
+ from ccs.core import get_runtime, GovernanceResult
41
+
42
+ if CrewAIAdapter._installed:
43
+ return # Already installed
44
+
45
+ runtime = get_runtime()
46
+ CrewAIAdapter._original_run = BaseTool.run
47
+
48
+ def ccs_governed_run(self, *args, **kwargs):
49
+ tool_input = {"args": args, "kwargs": kwargs}
50
+ result, latency = runtime.evaluate(
51
+ tool_name=getattr(self, "name", type(self).__name__),
52
+ tool_input=tool_input,
53
+ policy_name=policy,
54
+ )
55
+ if result != GovernanceResult.ALLOW:
56
+ raise PermissionError(
57
+ f"CCS DENIED: {getattr(self, 'name', 'unknown')} "
58
+ f"(policy={policy}, latency={latency}µs)"
59
+ )
60
+ return CrewAIAdapter._original_run(self, *args, **kwargs)
61
+
62
+ BaseTool.run = ccs_governed_run
63
+ CrewAIAdapter._installed = True
64
+
65
+ @staticmethod
66
+ def uninstall():
67
+ """Restore original CrewAI BaseTool.run."""
68
+ if not CrewAIAdapter._installed:
69
+ return
70
+ from crewai.tools.base_tool import BaseTool
71
+ BaseTool.run = CrewAIAdapter._original_run
72
+ CrewAIAdapter._installed = False
73
+ CrewAIAdapter._original_run = None
74
+
75
+
76
+ class AutoGenAdapter:
77
+ """
78
+ CCS adapter for Microsoft AutoGen.
79
+
80
+ Intercepts autogen_core.tools.FunctionTool.run() — the async
81
+ entry point for all AutoGen function tool executions.
82
+
83
+ Note: AutoGen 0.7+ uses async run(args, cancellation_token).
84
+ The adapter preserves this async signature.
85
+
86
+ Usage:
87
+ from ccs.adapters import autogen_adapter
88
+ autogen_adapter.install()
89
+ autogen_adapter.uninstall()
90
+ """
91
+
92
+ _original_run = None
93
+ _installed = False
94
+
95
+ @staticmethod
96
+ def install(policy: str = "default"):
97
+ """Install CCS governance on AutoGen's FunctionTool.run."""
98
+ from autogen_core.tools import FunctionTool
99
+ from ccs.core import get_runtime, GovernanceResult
100
+
101
+ if AutoGenAdapter._installed:
102
+ return
103
+
104
+ runtime = get_runtime()
105
+ AutoGenAdapter._original_run = FunctionTool.run
106
+
107
+ async def ccs_governed_run(self, args, cancellation_token):
108
+ tool_input = {"args": str(args), "tool": self.name}
109
+ result, latency = runtime.evaluate(
110
+ tool_name=self.name,
111
+ tool_input=tool_input,
112
+ policy_name=policy,
113
+ )
114
+ if result != GovernanceResult.ALLOW:
115
+ raise PermissionError(
116
+ f"CCS DENIED: {self.name} "
117
+ f"(policy={policy}, latency={latency}µs)"
118
+ )
119
+ return await AutoGenAdapter._original_run(self, args, cancellation_token)
120
+
121
+ FunctionTool.run = ccs_governed_run
122
+ AutoGenAdapter._installed = True
123
+
124
+ @staticmethod
125
+ def uninstall():
126
+ """Restore original AutoGen FunctionTool.run."""
127
+ if not AutoGenAdapter._installed:
128
+ return
129
+ from autogen_core.tools import FunctionTool
130
+ FunctionTool.run = AutoGenAdapter._original_run
131
+ AutoGenAdapter._installed = False
132
+ AutoGenAdapter._original_run = None
133
+
134
+
135
+ class LangGraphAdapter:
136
+ """
137
+ CCS adapter for LangGraph / LangChain.
138
+
139
+ Intercepts langchain_core.tools.BaseTool.run() — the sync
140
+ entry point for all LangChain/LangGraph tool executions.
141
+ Also covers invoke() since it delegates to run().
142
+
143
+ Usage:
144
+ from ccs.adapters import langgraph_adapter
145
+ langgraph_adapter.install()
146
+ langgraph_adapter.uninstall()
147
+ """
148
+
149
+ _original_run = None
150
+ _installed = False
151
+
152
+ @staticmethod
153
+ def install(policy: str = "default"):
154
+ """Install CCS governance on LangChain's BaseTool.run."""
155
+ from langchain_core.tools import BaseTool as LCBaseTool
156
+ from ccs.core import get_runtime, GovernanceResult
157
+
158
+ if LangGraphAdapter._installed:
159
+ return
160
+
161
+ runtime = get_runtime()
162
+ LangGraphAdapter._original_run = LCBaseTool.run
163
+
164
+ def ccs_governed_run(self, tool_input, *args, **kwargs):
165
+ governance_input = {"tool_input": tool_input, "kwargs": kwargs}
166
+ result, latency = runtime.evaluate(
167
+ tool_name=getattr(self, "name", type(self).__name__),
168
+ tool_input=governance_input,
169
+ policy_name=policy,
170
+ )
171
+ if result != GovernanceResult.ALLOW:
172
+ raise PermissionError(
173
+ f"CCS DENIED: {getattr(self, 'name', 'unknown')} "
174
+ f"(policy={policy}, latency={latency}µs)"
175
+ )
176
+ return LangGraphAdapter._original_run(self, tool_input, *args, **kwargs)
177
+
178
+ LCBaseTool.run = ccs_governed_run
179
+ LangGraphAdapter._installed = True
180
+
181
+ @staticmethod
182
+ def uninstall():
183
+ """Restore original LangChain BaseTool.run."""
184
+ if not LangGraphAdapter._installed:
185
+ return
186
+ from langchain_core.tools import BaseTool as LCBaseTool
187
+ LCBaseTool.run = LangGraphAdapter._original_run
188
+ LangGraphAdapter._installed = False
189
+ LangGraphAdapter._original_run = None
190
+
191
+
192
+ # Convenience instances
193
+ crewai_adapter = CrewAIAdapter()
194
+ autogen_adapter = AutoGenAdapter()
195
+ langgraph_adapter = LangGraphAdapter()
ccs/core.py ADDED
@@ -0,0 +1,266 @@
1
+ """
2
+ CCS Core: Synchronous Interceptor Decorator Architecture
3
+
4
+ Unlike observer-pattern hooks that can fail-open, CCS decorators
5
+ OWN the execution control flow. If verification fails or raises,
6
+ the wrapped tool function is NEVER invoked. This provides
7
+ structural fail-closed guarantee.
8
+
9
+ Reference: CCS v1.0 Standard, Section 3 — Formal Framework
10
+ DOI: 10.5281/zenodo.21271910
11
+ """
12
+
13
+ import functools
14
+ import time
15
+ import hashlib
16
+ import json
17
+ from typing import Any, Callable, Dict, List, Optional, Tuple
18
+ from dataclasses import dataclass, field
19
+ from enum import Enum
20
+
21
+
22
+ class GovernanceResult(Enum):
23
+ """Governance evaluation result."""
24
+ ALLOW = "allow"
25
+ DENY = "deny"
26
+ ERROR = "error" # Error in evaluation → ALWAYS DENY (fail-closed)
27
+
28
+
29
+ @dataclass
30
+ class CCSConfig:
31
+ """Configuration for CCS governance."""
32
+ policy_name: str = "default"
33
+ max_tool_input_size: int = 1_000_000 # 1MB max input
34
+ timeout_ms: int = 50 # 50ms timeout for governance evaluation
35
+ fail_mode: str = "closed" # Only "closed" is valid — fail-open is structurally forbidden
36
+ audit_log: bool = True
37
+ # Performance targets (CANON benchmark)
38
+ target_p50_us: float = 22.0
39
+ target_p99_us: float = 99.0
40
+
41
+
42
+ @dataclass
43
+ class GovernanceTrace:
44
+ """Immutable audit trace for a single governance decision."""
45
+ timestamp: float
46
+ tool_name: str
47
+ input_hash: str
48
+ result: GovernanceResult
49
+ latency_us: float
50
+ policy_name: str
51
+ rule_evaluated: str
52
+ detail: str = ""
53
+
54
+
55
+ class CCSPolicy:
56
+ """
57
+ Base class for CCS governance policies.
58
+
59
+ Subclass this to define custom governance rules.
60
+ All evaluation methods MUST return GovernanceResult.
61
+ If evaluation raises → fail-closed (DENY), never ALLOW.
62
+ """
63
+
64
+ def evaluate(self, tool_name: str, tool_input: Dict[str, Any]) -> GovernanceResult:
65
+ """
66
+ Evaluate whether a tool call should be allowed.
67
+
68
+ Args:
69
+ tool_name: Name of the tool being called
70
+ tool_input: Arguments to the tool
71
+
72
+ Returns:
73
+ GovernanceResult.ALLOW or GovernanceResult.DENY
74
+
75
+ Note:
76
+ If this method raises an exception, the decorator will
77
+ catch it and return DENY (fail-closed). This is the
78
+ fundamental guarantee that distinguishes CCS from
79
+ observer-pattern hooks.
80
+ """
81
+ raise NotImplementedError
82
+
83
+
84
+ class DefaultPolicy(CCSPolicy):
85
+ """Default CCS policy: validates input structure and size."""
86
+
87
+ def __init__(self, config: CCSConfig):
88
+ self.config = config
89
+
90
+ def evaluate(self, tool_name: str, tool_input: Dict[str, Any]) -> GovernanceResult:
91
+ # Size check
92
+ try:
93
+ serialized = json.dumps(tool_input, default=str)
94
+ if len(serialized) > self.config.max_tool_input_size:
95
+ return GovernanceResult.DENY
96
+ except (TypeError, ValueError, OverflowError):
97
+ # Non-serializable input → DENY (fail-closed)
98
+ return GovernanceResult.DENY
99
+
100
+ # Type check
101
+ if not isinstance(tool_input, dict):
102
+ return GovernanceResult.DENY
103
+
104
+ return GovernanceResult.ALLOW
105
+
106
+
107
+ class CCSRuntime:
108
+ """
109
+ CCS Governance Runtime — synchronous interceptor engine.
110
+
111
+ This is the core of the CCS architecture. Unlike framework hooks
112
+ that observe events, the runtime INTERCEPTS tool calls and
113
+ controls execution flow. If the runtime fails, the tool is BLOCKED.
114
+ """
115
+
116
+ def __init__(self, config: Optional[CCSConfig] = None):
117
+ self.config = config or CCSConfig()
118
+ self.policies: Dict[str, CCSPolicy] = {}
119
+ self.traces: List[GovernanceTrace] = []
120
+ self._latencies: List[float] = []
121
+
122
+ # Register default policy
123
+ self.policies["default"] = DefaultPolicy(self.config)
124
+
125
+ def register_policy(self, name: str, policy: CCSPolicy):
126
+ """Register a named governance policy."""
127
+ self.policies[name] = policy
128
+
129
+ def evaluate(self, tool_name: str, tool_input: Dict[str, Any],
130
+ policy_name: str = "default") -> Tuple[GovernanceResult, float]:
131
+ """
132
+ Synchronously evaluate a tool call against the named policy.
133
+
134
+ Returns:
135
+ Tuple of (GovernanceResult, latency_microseconds)
136
+
137
+ Guarantee:
138
+ This method NEVER raises. Any exception is caught and
139
+ converted to GovernanceResult.DENY. This is the fail-closed
140
+ guarantee that observer-pattern hooks cannot provide.
141
+ """
142
+ start = time.perf_counter()
143
+
144
+ try:
145
+ policy = self.policies.get(policy_name)
146
+ if policy is None:
147
+ result = GovernanceResult.DENY
148
+ detail = f"Unknown policy: {policy_name}"
149
+ else:
150
+ result = policy.evaluate(tool_name, tool_input)
151
+ detail = f"Policy '{policy_name}' evaluated"
152
+ except Exception as e:
153
+ # FAIL-CLOSED: Any exception → DENY
154
+ # This is the critical difference from observer hooks
155
+ result = GovernanceResult.DENY
156
+ detail = f"Exception caught, fail-closed: {type(e).__name__}: {e}"
157
+
158
+ latency_us = (time.perf_counter() - start) * 1_000_000
159
+ self._latencies.append(latency_us)
160
+
161
+ # Compute input hash for audit trail
162
+ try:
163
+ input_hash = hashlib.sha256(
164
+ json.dumps(tool_input, default=str, sort_keys=True).encode()
165
+ ).hexdigest()[:16]
166
+ except Exception:
167
+ input_hash = "unhashable"
168
+
169
+ if self.config.audit_log:
170
+ trace = GovernanceTrace(
171
+ timestamp=time.time(),
172
+ tool_name=tool_name,
173
+ input_hash=input_hash,
174
+ result=result,
175
+ latency_us=round(latency_us, 2),
176
+ policy_name=policy_name,
177
+ rule_evaluated=policy_name,
178
+ detail=detail,
179
+ )
180
+ self.traces.append(trace)
181
+
182
+ return result, round(latency_us, 2)
183
+
184
+ def get_stats(self) -> Dict[str, Any]:
185
+ """Get runtime performance statistics."""
186
+ if not self._latencies:
187
+ return {"total_evaluations": 0}
188
+
189
+ sorted_lat = sorted(self._latencies)
190
+ n = len(sorted_lat)
191
+ return {
192
+ "total_evaluations": n,
193
+ "total_denied": sum(1 for t in self.traces if t.result == GovernanceResult.DENY),
194
+ "total_allowed": sum(1 for t in self.traces if t.result == GovernanceResult.ALLOW),
195
+ "latency_p50_us": round(sorted_lat[n // 2], 2),
196
+ "latency_p99_us": round(sorted_lat[int(n * 0.99)], 2) if n >= 100 else round(sorted_lat[-1], 2),
197
+ "latency_max_us": round(sorted_lat[-1], 2),
198
+ }
199
+
200
+
201
+ # Global runtime singleton
202
+ _runtime: Optional[CCSRuntime] = None
203
+
204
+
205
+ def get_runtime(config: Optional[CCSConfig] = None) -> CCSRuntime:
206
+ """Get or create the global CCS runtime."""
207
+ global _runtime
208
+ if _runtime is None:
209
+ _runtime = CCSRuntime(config)
210
+ return _runtime
211
+
212
+
213
+ def govern(policy: str = "default", config: Optional[CCSConfig] = None):
214
+ """
215
+ CCS governance decorator — the core of the interceptor pattern.
216
+
217
+ Usage:
218
+ @govern(policy="default")
219
+ def my_tool(args: dict) -> str:
220
+ return "result"
221
+
222
+ Guarantee:
223
+ If governance evaluation raises ANY exception, the decorated
224
+ function is NEVER called. This provides structural fail-closed
225
+ behavior that observer-pattern hooks cannot achieve.
226
+
227
+ Example (CrewAI):
228
+ from ccs import govern
229
+
230
+ @govern(policy="compliance")
231
+ def search_web(query: str):
232
+ # This function will NEVER execute if governance denies
233
+ return search_engine(query)
234
+ """
235
+ def decorator(func: Callable) -> Callable:
236
+ @functools.wraps(func)
237
+ def wrapper(*args, **kwargs):
238
+ runtime = get_runtime(config)
239
+
240
+ # Build tool input for governance evaluation
241
+ tool_input = {"args": args, "kwargs": kwargs}
242
+
243
+ # SYNCHRONOUS INTERCEPTION — not observation
244
+ result, latency_us = runtime.evaluate(
245
+ tool_name=func.__name__,
246
+ tool_input=tool_input,
247
+ policy_name=policy,
248
+ )
249
+
250
+ # FAIL-CLOSED: Only proceed if explicitly ALLOWED
251
+ if result != GovernanceResult.ALLOW:
252
+ raise PermissionError(
253
+ f"CCS governance DENIED tool '{func.__name__}' "
254
+ f"(policy={policy}, latency={latency_us}µs)"
255
+ )
256
+
257
+ # Only reached if governance explicitly ALLOWED
258
+ return func(*args, **kwargs)
259
+
260
+ # Attach CCS metadata
261
+ wrapper.__ccs_governed__ = True
262
+ wrapper.__ccs_policy__ = policy
263
+ wrapper.__ccs_runtime__ = get_runtime(config)
264
+
265
+ return wrapper
266
+ return decorator
@@ -0,0 +1,4 @@
1
+ from ccs.mcp_server.server import mcp
2
+
3
+ if __name__ == "__main__":
4
+ mcp.run()
@@ -0,0 +1,7 @@
1
+ """CCS MCP Server — Model Context Protocol governance for AI Agents."""
2
+ from ccs.mcp_server.server import mcp
3
+
4
+ __all__ = ["mcp"]
5
+
6
+ if __name__ == "__main__":
7
+ mcp.run()
@@ -0,0 +1,196 @@
1
+ """
2
+ CCS MCP Server — Model Context Protocol governance for AI Agents.
3
+
4
+ Exposes CCS governance as an MCP tool, allowing any MCP-compatible
5
+ agent (Claude Desktop, Cursor, Cline, etc.) to validate tool calls
6
+ against CCS policies before execution.
7
+
8
+ Transport: stdio (default for MCP)
9
+
10
+ Usage:
11
+ python -m ccs_sdk.mcp_server.server
12
+
13
+ Or configure in Claude Desktop:
14
+ {
15
+ "mcpServers": {
16
+ "ccs": {
17
+ "command": "python",
18
+ "args": ["-m", "ccs_sdk.mcp_server.server"]
19
+ }
20
+ }
21
+ }
22
+ """
23
+
24
+ from mcp.server.fastmcp import FastMCP
25
+ from ccs.core import (
26
+ CCSConfig, CCSPolicy, GovernanceResult,
27
+ get_runtime,
28
+ )
29
+
30
+ # ============================================================
31
+ # MCP Server
32
+ # ============================================================
33
+ mcp = FastMCP(
34
+ "CCS Governance",
35
+ instructions="Correctover Conformance Standard (CCS) v1.0 — "
36
+ "Synchronous interceptor governance for AI Agent tool calls. "
37
+ "Validates tool invocations against governance policies with "
38
+ "structural fail-closed guarantee (CWE-636). "
39
+ "DOI: 10.5281/zenodo.21271910"
40
+ )
41
+
42
+
43
+ @mcp.tool()
44
+ def ccs_govern(
45
+ tool_name: str,
46
+ tool_input: dict,
47
+ policy_name: str = "default",
48
+ ) -> dict:
49
+ """
50
+ Evaluate a tool call against CCS governance policy.
51
+
52
+ Returns ALLOW or DENY with latency metrics. If the policy engine
53
+ crashes, returns DENY (fail-closed guarantee).
54
+
55
+ Args:
56
+ tool_name: Name of the tool being called (e.g., "search_web")
57
+ tool_input: Arguments dict for the tool (e.g., {"query": "..."})
58
+ policy_name: CCS policy to evaluate against (default: "default")
59
+
60
+ Returns:
61
+ dict with:
62
+ - result: "allow" | "deny" | "error"
63
+ - latency_us: governance evaluation latency in microseconds
64
+ - tool_name: echo of the tool name
65
+ - policy_name: echo of the policy used
66
+ - fail_closed: True if denied due to error (not policy logic)
67
+ """
68
+ runtime = get_runtime()
69
+ result, latency_us = runtime.evaluate(
70
+ tool_name=tool_name,
71
+ tool_input=tool_input,
72
+ policy_name=policy_name,
73
+ )
74
+
75
+ is_error = result == GovernanceResult.ERROR
76
+ return {
77
+ "result": result.value,
78
+ "latency_us": latency_us,
79
+ "tool_name": tool_name,
80
+ "policy_name": policy_name,
81
+ "fail_closed": is_error,
82
+ }
83
+
84
+
85
+ @mcp.tool()
86
+ def ccs_status() -> dict:
87
+ """
88
+ Get CCS governance runtime status and performance metrics.
89
+
90
+ Returns total evaluations, deny/allow counts, and latency
91
+ percentiles (P50, P99, max).
92
+ """
93
+ runtime = get_runtime()
94
+ stats = runtime.get_stats()
95
+
96
+ # Add registered policies info
97
+ stats["registered_policies"] = list(runtime.policies.keys())
98
+ stats["total_traces"] = len(runtime.traces)
99
+ stats["version"] = "1.0.0"
100
+ stats["standard"] = "CCS v1.0"
101
+ stats["doi"] = "10.5281/zenodo.21271910"
102
+
103
+ return stats
104
+
105
+
106
+ @mcp.tool()
107
+ def ccs_register_deny_rule(
108
+ rule_name: str,
109
+ denied_tools: list[str] | None = None,
110
+ denied_patterns: list[str] | None = None,
111
+ ) -> dict:
112
+ """
113
+ Register a custom deny policy. Tools matching the denied list
114
+ or patterns will be blocked; all others pass through.
115
+
116
+ Args:
117
+ rule_name: Name for this policy (e.g., "block_dangerous_tools")
118
+ denied_tools: Exact tool names to deny (e.g., ["rm", "delete_file"])
119
+ denied_patterns: Substring patterns to deny (e.g., ["delete", "destroy"])
120
+
121
+ Returns:
122
+ dict confirming registration with rule details
123
+ """
124
+ denied_tools = denied_tools or []
125
+ denied_patterns = denied_patterns or []
126
+
127
+ class DenyRulePolicy(CCSPolicy):
128
+ def __init__(self, tools, patterns):
129
+ self.tools = set(tools)
130
+ self.patterns = patterns
131
+
132
+ def evaluate(self, tool_name, tool_input):
133
+ # Exact match
134
+ if tool_name in self.tools:
135
+ return GovernanceResult.DENY
136
+ # Pattern match
137
+ for pattern in self.patterns:
138
+ if pattern.lower() in tool_name.lower():
139
+ return GovernanceResult.DENY
140
+ # Also check tool input values
141
+ for v in tool_input.values():
142
+ if isinstance(v, str) and pattern.lower() in v.lower():
143
+ return GovernanceResult.DENY
144
+ return GovernanceResult.ALLOW
145
+
146
+ runtime = get_runtime()
147
+ runtime.register_policy(
148
+ rule_name,
149
+ DenyRulePolicy(denied_tools, denied_patterns)
150
+ )
151
+
152
+ return {
153
+ "status": "registered",
154
+ "rule_name": rule_name,
155
+ "denied_tools": denied_tools,
156
+ "denied_patterns": denied_patterns,
157
+ "available_policies": list(runtime.policies.keys()),
158
+ }
159
+
160
+
161
+ @mcp.tool()
162
+ def ccs_audit_log(limit: int = 20) -> list[dict]:
163
+ """
164
+ Retrieve recent CCS governance audit traces.
165
+
166
+ Each trace includes: timestamp, tool_name, result, latency_us,
167
+ policy_name, input_hash, and detail.
168
+
169
+ Args:
170
+ limit: Maximum number of recent traces to return (default: 20)
171
+
172
+ Returns:
173
+ List of audit trace dicts, most recent first
174
+ """
175
+ runtime = get_runtime()
176
+ traces = runtime.traces[-limit:] if runtime.traces else []
177
+
178
+ return [
179
+ {
180
+ "timestamp": t.timestamp,
181
+ "tool_name": t.tool_name,
182
+ "result": t.result.value,
183
+ "latency_us": t.latency_us,
184
+ "policy_name": t.policy_name,
185
+ "input_hash": t.input_hash,
186
+ "detail": t.detail,
187
+ }
188
+ for t in reversed(traces)
189
+ ]
190
+
191
+
192
+ # ============================================================
193
+ # Entry point
194
+ # ============================================================
195
+ if __name__ == "__main__":
196
+ mcp.run()
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: correctover-ccs
3
+ Version: 1.0.0
4
+ Summary: Correctover Conformance Standard (CCS) v1.0 — Synchronous interceptor governance for AI Agent frameworks
5
+ Author-email: Correctover Standards <wangguigui@correctover.com>
6
+ License: CC BY 4.0
7
+ Project-URL: Homepage, https://correctover.com
8
+ Project-URL: Paper, https://doi.org/10.5281/zenodo.21271910
9
+ Project-URL: Standard, https://github.com/Correctover/standards
10
+ Keywords: ai,agent,governance,security,conformance,mcp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Topic :: Security
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ Provides-Extra: mcp
21
+ Requires-Dist: mcp>=1.0.0; extra == "mcp"
22
+
23
+ # CCS — Correctover Conformance Standard v1.0
24
+
25
+ Synchronous interceptor-based governance for AI Agent frameworks.
26
+
27
+ ## Why CCS?
28
+
29
+ Every major Agent framework (CrewAI AGT, AutoGen, LangGraph) uses **observer-pattern hooks** for governance. These hooks are structurally vulnerable to **fail-open bypass** — when the governance layer throws an exception, the framework defaults to allowing tool execution.
30
+
31
+ **This is not a bug. It's an architectural flaw.** (CWE-636, CVSS 9.1)
32
+
33
+ CCS uses **function decorators** instead of hooks. The decorator owns the execution path — if governance fails, the tool is BLOCKED. Never allowed.
34
+
35
+ ```
36
+ Observer hooks: governance_crash → exception caught → hook_blocked=False → tool EXECUTES ❌
37
+ CCS decorators: governance_crash → exception caught → tool NEVER CALLED ✅
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install ccs
44
+ ```
45
+
46
+ ## Quick Start (3 lines)
47
+
48
+ ```python
49
+ from ccs import govern
50
+
51
+ @govern(policy="default")
52
+ def my_tool(args: dict) -> str:
53
+ return "result"
54
+
55
+ # Governance evaluation happens BEFORE the function runs
56
+ # If denied → PermissionError, function never executes
57
+ ```
58
+
59
+ ## Framework Adapters
60
+
61
+ Adapters intercept at the framework's tool execution entry point.
62
+ Once installed, ALL tool calls go through CCS governance.
63
+
64
+ ### CrewAI
65
+ ```python
66
+ from ccs.adapters import crewai_adapter
67
+ crewai_adapter.install() # patches BaseTool.run globally
68
+ # All CrewAI tool calls now governed by CCS
69
+ crewai_adapter.uninstall() # restore original
70
+ ```
71
+
72
+ ### AutoGen (async)
73
+ ```python
74
+ from ccs.adapters import autogen_adapter
75
+ autogen_adapter.install() # patches FunctionTool.run
76
+ autogen_adapter.uninstall()
77
+ ```
78
+
79
+ ### LangGraph / LangChain
80
+ ```python
81
+ from ccs.adapters import langgraph_adapter
82
+ langgraph_adapter.install() # patches LCBaseTool.run
83
+ langgraph_adapter.uninstall()
84
+ ```
85
+
86
+ ### Verified Against
87
+ | Framework | Version | Interception Point | Pattern |
88
+ |-----------|---------|--------------------|---------|
89
+ | CrewAI | >= 0.1.0 | `BaseTool.run()` | sync |
90
+ | AutoGen | >= 0.7.0 | `FunctionTool.run()` | async |
91
+ | LangGraph | >= 0.2.0 | `LCBaseTool.run()` | sync |
92
+
93
+ ## Custom Policies
94
+
95
+ ```python
96
+ from ccs import CCSPolicy, GovernanceResult, govern
97
+
98
+ class CompliancePolicy(CCSPolicy):
99
+ def evaluate(self, tool_name: str, tool_input: dict) -> GovernanceResult:
100
+ if "delete" in tool_name.lower():
101
+ return GovernanceResult.DENY
102
+ return GovernanceResult.ALLOW
103
+
104
+ from ccs.core import get_runtime
105
+ runtime = get_runtime()
106
+ runtime.register_policy("compliance", CompliancePolicy())
107
+
108
+ @govern(policy="compliance")
109
+ def delete_user(user_id: str):
110
+ ... # This will never execute — policy denies it
111
+ ```
112
+
113
+ ## Fail-Closed Guarantee
114
+
115
+ The fundamental difference from observer-pattern hooks:
116
+
117
+ | | Observer Hooks (AGT) | CCS Decorators |
118
+ |---|---|---|
119
+ | Integration | Framework catches hook exception | Decorator owns execution path |
120
+ | On governance crash | `hook_blocked` stays `False` → tool executes | Exception propagates → tool never called |
121
+ | Fail mode | **FAIL-OPEN** ❌ | **FAIL-CLOSED** ✅ |
122
+ | CWE | CWE-636 (Not Failing Securely) | Structurally immune |
123
+
124
+ ## Performance
125
+
126
+ CANON benchmark (50,000 traces):
127
+ - **P50 latency: 22µs**
128
+ - **P99 latency: 99µs**
129
+
130
+ ## Test Results
131
+
132
+ Verified on 2026-07-09 with real framework installations:
133
+
134
+ ```
135
+ CrewAI Adapter: BaseTool.run intercepted → fail-closed ✅
136
+ AutoGen Adapter: FunctionTool.run intercepted → fail-closed ✅
137
+ LangGraph Adapter: LCBaseTool.run intercepted → fail-closed ✅
138
+ All adapters support install/uninstall lifecycle ✅
139
+ ```
140
+
141
+ Performance (10,000 iterations, decorator + policy evaluation):
142
+ ```
143
+ P50: 6.2µs
144
+ P99: 15.0µs
145
+ P999: 53.0µs
146
+ ```
147
+
148
+ ## MCP Server
149
+
150
+ CCS is available as a [Model Context Protocol](https://modelcontextprotocol.io) server, enabling any MCP-compatible agent (Claude Desktop, Cursor, Cline) to validate tool calls against CCS governance.
151
+
152
+ ```bash
153
+ pip install ccs[mcp]
154
+ python -m ccs.mcp_server
155
+ ```
156
+
157
+ Configure in Claude Desktop:
158
+ ```json
159
+ {
160
+ "mcpServers": {
161
+ "ccs": {
162
+ "command": "python",
163
+ "args": ["-m", "ccs.mcp_server"]
164
+ }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### MCP Tools
170
+ | Tool | Description |
171
+ |------|-------------|
172
+ | `ccs_govern` | Evaluate a tool call against a policy → allow/deny |
173
+ | `ccs_status` | Runtime stats, policies, latency metrics |
174
+ | `ccs_register_deny_rule` | Register custom deny rules by tool name/pattern |
175
+ | `ccs_audit_log` | Recent governance audit traces |
176
+
177
+ ## TypeScript SDK
178
+
179
+ ```bash
180
+ npm install correctover-ccs
181
+ ```
182
+
183
+ ```typescript
184
+ import { govern, GovernanceResult, CCSPolicy } from "correctover-ccs";
185
+
186
+ const governedSearch = govern(searchWeb, { policy: "default" });
187
+ governedSearch({ query: "test" }); // Throws PermissionError if denied
188
+ ```
189
+
190
+ Source: [`ts/`](./ts) | [npm package](https://www.npmjs.com/package/correctover-ccs)
191
+
192
+ ## Go SDK
193
+
194
+ ```bash
195
+ go get github.com/Correctover/ccs-sdk/go
196
+ ```
197
+
198
+ ```go
199
+ rt := ccs.NewRuntime()
200
+ governed := ccs.Govern(searchFn, "default", rt)
201
+ result, err := governed(ccs.ToolInput{"query": "CCS standard"})
202
+ // err = *PermissionError if denied — fn NEVER called
203
+ ```
204
+
205
+ Source: [`go/`](./go)
206
+
207
+ ## Repository Structure
208
+
209
+ ```
210
+ ccs-sdk/
211
+ ├── ccs/ # Python SDK (core + adapters + MCP server)
212
+ │ ├── core.py # Governance runtime
213
+ │ ├── adapters.py # CrewAI/AutoGen/LangGraph adapters
214
+ │ └── mcp_server/ # MCP server (stdio transport)
215
+ ├── ts/ # TypeScript SDK (npm: correctover-ccs)
216
+ │ ├── src/ # Source
217
+ │ └── dist/ # Built output
218
+ ├── go/ # Go SDK
219
+ │ └── ccs/ # Core package
220
+ ├── strict_9test.py # Python 9-test verification suite
221
+ └── pyproject.toml
222
+ ```
223
+
224
+ ## SDK Versions
225
+
226
+ | SDK | Version | Package |
227
+ |-----|---------|---------|
228
+ | Python | 1.0.0 | `pip install ccs` |
229
+ | TypeScript | 1.0.0 | `npm install correctover-ccs` |
230
+ | Go | 1.0.0 | `go get github.com/Correctover/ccs-sdk/go` |
231
+
232
+ ## References
233
+
234
+ - CCS v1.0 Standard: https://doi.org/10.5281/zenodo.21271910
235
+ - CVE Audit (CWE-636 in AGT): https://gist.github.com/Correctover/9cfb97bcf374f79b793fd0bacd4e9d62
236
+ - Correctover: https://correctover.com
@@ -0,0 +1,10 @@
1
+ ccs/__init__.py,sha256=7qmgNN-8jQlB8jjyIKofNaR-ZXL9xNH5L-Xetvu1SFs,745
2
+ ccs/adapters.py,sha256=HB_8PLJ9F6qUZse3Xo05cnXdX4hhRdeYuX2yVSBQ1vo,6724
3
+ ccs/core.py,sha256=qq0j9vkQzLEdjukxM8zHq6N1pWixeniD_5xpKdFn7S4,9126
4
+ ccs/mcp_server/__init__.py,sha256=aiMiPr8qN42olmpuaqE6g451BIg112HtQjfVYqwYQMc,80
5
+ ccs/mcp_server/__main__.py,sha256=x4cZLGJWzuOPB3HjyligYFnU7rPR1q2MILQDQIL7_Y0,173
6
+ ccs/mcp_server/server.py,sha256=amNWHnjrnTG_ncIsPiETDlhuwO6AWEk4sfJmTAENkk0,5822
7
+ correctover_ccs-1.0.0.dist-info/METADATA,sha256=neeJBLOoT5QJRrIgy9SK7rtU9WGPA2JoIIEMNj6WSXc,7092
8
+ correctover_ccs-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
9
+ correctover_ccs-1.0.0.dist-info/top_level.txt,sha256=B_84q_sceurFYPD4eVb3n5al34HIbMKe3LgAXojdC_g,4
10
+ correctover_ccs-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ ccs