correctover 2.1.0__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. correctover-2.2.0/PKG-INFO +12 -0
  2. correctover-2.2.0/pyproject.toml +21 -0
  3. {correctover-2.1.0 → correctover-2.2.0}/setup.cfg +4 -4
  4. correctover-2.2.0/src/correctover/__init__.py +22 -0
  5. correctover-2.2.0/src/correctover/guardrail.py +211 -0
  6. correctover-2.2.0/src/correctover/validator.py +37 -0
  7. correctover-2.2.0/src/correctover.egg-info/PKG-INFO +12 -0
  8. correctover-2.2.0/src/correctover.egg-info/SOURCES.txt +9 -0
  9. correctover-2.2.0/src/correctover.egg-info/requires.txt +1 -0
  10. correctover-2.1.0/LICENSE +0 -7
  11. correctover-2.1.0/MANIFEST.in +0 -2
  12. correctover-2.1.0/PKG-INFO +0 -49
  13. correctover-2.1.0/README.md +0 -21
  14. correctover-2.1.0/correctover/__init__.py +0 -310
  15. correctover-2.1.0/correctover/__pycache__/__init__.cpython-312.pyc +0 -0
  16. correctover-2.1.0/correctover/__pycache__/_checkup.cpython-312.pyc +0 -0
  17. correctover-2.1.0/correctover/__pycache__/_engine.cpython-312.pyc +0 -0
  18. correctover-2.1.0/correctover/__pycache__/_fixes.cpython-312.pyc +0 -0
  19. correctover-2.1.0/correctover/__pycache__/_fixes2.cpython-312.pyc +0 -0
  20. correctover-2.1.0/correctover/__pycache__/_guard.cpython-312.pyc +0 -0
  21. correctover-2.1.0/correctover/__pycache__/_ping.cpython-312.pyc +0 -0
  22. correctover-2.1.0/correctover/__pycache__/_security.cpython-312.pyc +0 -0
  23. correctover-2.1.0/correctover/__pycache__/_types.cpython-312.pyc +0 -0
  24. correctover-2.1.0/correctover/__pycache__/_version.cpython-312.pyc +0 -0
  25. correctover-2.1.0/correctover/__pycache__/bounty_rules.cpython-312.pyc +0 -0
  26. correctover-2.1.0/correctover/__pycache__/ccs_scanner.cpython-312.pyc +0 -0
  27. correctover-2.1.0/correctover/__pycache__/chain.cpython-312.pyc +0 -0
  28. correctover-2.1.0/correctover/__pycache__/cli.cpython-312.pyc +0 -0
  29. correctover-2.1.0/correctover/__pycache__/cloudkill.cpython-312.pyc +0 -0
  30. correctover-2.1.0/correctover/__pycache__/license.cpython-312.pyc +0 -0
  31. correctover-2.1.0/correctover/__pycache__/mcs_scanner.cpython-312.pyc +0 -0
  32. correctover-2.1.0/correctover/_checkup.py +0 -335
  33. correctover-2.1.0/correctover/_core.py +0 -1557
  34. correctover-2.1.0/correctover/_device.py +0 -294
  35. correctover-2.1.0/correctover/_engine.py +0 -2779
  36. correctover-2.1.0/correctover/_fixes.py +0 -209
  37. correctover-2.1.0/correctover/_fixes2.py +0 -178
  38. correctover-2.1.0/correctover/_guard.py +0 -169
  39. correctover-2.1.0/correctover/_ping.py +0 -296
  40. correctover-2.1.0/correctover/_security.py +0 -127
  41. correctover-2.1.0/correctover/_sentry.py +0 -360
  42. correctover-2.1.0/correctover/_stats.py +0 -519
  43. correctover-2.1.0/correctover/_tracker.py +0 -191
  44. correctover-2.1.0/correctover/_types.py +0 -64
  45. correctover-2.1.0/correctover/_version.py +0 -5
  46. correctover-2.1.0/correctover/benchmark/__init__.py +0 -6
  47. correctover-2.1.0/correctover/benchmark/fault_injector.py +0 -129
  48. correctover-2.1.0/correctover/benchmark/metrics_collector.py +0 -222
  49. correctover-2.1.0/correctover/benchmark/run_benchmark.py +0 -211
  50. correctover-2.1.0/correctover/benchmark/scenarios.py +0 -123
  51. correctover-2.1.0/correctover/bounty_rules.py +0 -806
  52. correctover-2.1.0/correctover/carbon.py +0 -454
  53. correctover-2.1.0/correctover/ccs_scanner.py +0 -653
  54. correctover-2.1.0/correctover/chain.py +0 -951
  55. correctover-2.1.0/correctover/checkpoint.py +0 -805
  56. correctover-2.1.0/correctover/classifier.py +0 -212
  57. correctover-2.1.0/correctover/cli.py +0 -1048
  58. correctover-2.1.0/correctover/client.py +0 -400
  59. correctover-2.1.0/correctover/cloudkill.py +0 -446
  60. correctover-2.1.0/correctover/cost_tracker.py +0 -62
  61. correctover-2.1.0/correctover/dashboard.py +0 -1157
  62. correctover-2.1.0/correctover/demo.py +0 -466
  63. correctover-2.1.0/correctover/diagnoser.py +0 -34
  64. correctover-2.1.0/correctover/drift.py +0 -262
  65. correctover-2.1.0/correctover/free_provider.py +0 -186
  66. correctover-2.1.0/correctover/gateway.py +0 -732
  67. correctover-2.1.0/correctover/health_scorer.py +0 -54
  68. correctover-2.1.0/correctover/integrity.py +0 -56
  69. correctover-2.1.0/correctover/license.py +0 -861
  70. correctover-2.1.0/correctover/logging_config.py +0 -84
  71. correctover-2.1.0/correctover/mcs_scanner.py +0 -561
  72. correctover-2.1.0/correctover/router.py +0 -279
  73. correctover-2.1.0/correctover/run.py +0 -139
  74. correctover-2.1.0/correctover/shield.py +0 -366
  75. correctover-2.1.0/correctover/smart_router.py +0 -13
  76. correctover-2.1.0/correctover/state_machine.py +0 -84
  77. correctover-2.1.0/correctover/status.py +0 -514
  78. correctover-2.1.0/correctover/telemetry.py +0 -308
  79. correctover-2.1.0/correctover/tracing.py +0 -89
  80. correctover-2.1.0/correctover.egg-info/PKG-INFO +0 -49
  81. correctover-2.1.0/correctover.egg-info/SOURCES.txt +0 -77
  82. correctover-2.1.0/correctover.egg-info/entry_points.txt +0 -5
  83. correctover-2.1.0/correctover.egg-info/requires.txt +0 -2
  84. correctover-2.1.0/pyproject.toml +0 -43
  85. correctover-2.1.0/setup.py +0 -40
  86. {correctover-2.1.0 → correctover-2.2.0/src}/correctover.egg-info/dependency_links.txt +0 -0
  87. {correctover-2.1.0 → correctover-2.2.0/src}/correctover.egg-info/top_level.txt +0 -0
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: correctover
3
+ Version: 2.2.0
4
+ Summary: Correctover - AI Agent Runtime Assurance. CCS standard + GuardrailProvider + MCP Security Scanner.
5
+ Author-email: Guigui Wang <wangguigui@correctover.com>
6
+ License: Proprietary Commercial License
7
+ Project-URL: Homepage, https://correctover.com
8
+ Project-URL: CCS Standard, https://correctover.com/ccs
9
+ Project-URL: GitHub, https://github.com/Correctover
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: pydantic>=1.10
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "correctover"
7
+ version = "2.2.0"
8
+ authors = [{name="Guigui Wang", email="wangguigui@correctover.com"}]
9
+ description = "Correctover - AI Agent Runtime Assurance. CCS standard + GuardrailProvider + MCP Security Scanner."
10
+ readme = "README.md"
11
+ license = {text = "Proprietary Commercial License"}
12
+ requires-python = ">=3.8"
13
+ dependencies = ["pydantic>=1.10"]
14
+
15
+ [project.urls]
16
+ Homepage = "https://correctover.com"
17
+ "CCS Standard" = "https://correctover.com/ccs"
18
+ GitHub = "https://github.com/Correctover"
19
+
20
+ [tool.setuptools.packages.find]
21
+ where = ["src"]
@@ -1,4 +1,4 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,22 @@
1
+ """Correctover v2.2.0 - AI Agent Runtime Assurance"""
2
+ __version__ = "2.2.0"
3
+ __author__ = "Guigui Wang"
4
+ __email__ = "wangguigui@correctover.com"
5
+ from .validator import CCSValidator, ValidationResult
6
+ from .guardrail import (
7
+ GuardrailDecisionV1, ActionEnvelopeV1, ToolCallContext,
8
+ GuardrailProvider, AllowAllGuardrailProvider, DenyAllGuardrailProvider,
9
+ ToolListGuardrailProvider, CKGGuardrailProvider, EnvProtectionProvider,
10
+ CompositeGuardrailProvider, AuditTrail, GuardrailContext,
11
+ make_guardrail_hook, detect_missing_guardrail, compute_decision_id,
12
+ canonical_json, MCPSecurityValidator,
13
+ )
14
+ __all__ = [
15
+ "CCSValidator","ValidationResult",
16
+ "GuardrailDecisionV1","ActionEnvelopeV1","ToolCallContext",
17
+ "GuardrailProvider","AllowAllGuardrailProvider","DenyAllGuardrailProvider",
18
+ "ToolListGuardrailProvider","CKGGuardrailProvider","EnvProtectionProvider",
19
+ "CompositeGuardrailProvider","AuditTrail","GuardrailContext",
20
+ "make_guardrail_hook","detect_missing_guardrail","compute_decision_id",
21
+ "canonical_json","MCPSecurityValidator",
22
+ ]
@@ -0,0 +1,211 @@
1
+ """
2
+ correctover.guardrail - Framework-agnostic runtime security guardrail system.
3
+ CCS reference implementation.
4
+ """
5
+ import hashlib, json, time
6
+ from abc import ABC, abstractmethod
7
+ from dataclasses import dataclass, field
8
+ from typing import Any, Callable, Dict, List, Optional, Set
9
+
10
+ def canonical_json(obj):
11
+ return json.dumps(obj, sort_keys=True, separators=(",",":"), default=str)
12
+
13
+ def compute_decision_id(claims, expires_at=None):
14
+ preimage = claims.copy()
15
+ if expires_at is not None:
16
+ preimage["_expires_at"] = expires_at
17
+ return hashlib.sha256(canonical_json(preimage).encode("utf-8")).hexdigest()
18
+
19
+ @dataclass(frozen=True)
20
+ class GuardrailDecisionV1:
21
+ decision_id: str
22
+ authorized: bool
23
+ claims: Dict[str, Any]
24
+ expires_at: Optional[float] = None
25
+ def is_expired(self):
26
+ if self.expires_at is None: return False
27
+ return time.time() > self.expires_at
28
+ def verify_integrity(self):
29
+ return self.decision_id == compute_decision_id(self.claims, self.expires_at)
30
+ def to_dict(self):
31
+ return {"decision_id":self.decision_id,"authorized":self.authorized,"claims":self.claims,"expires_at":self.expires_at}
32
+
33
+ @dataclass(frozen=True)
34
+ class ActionEnvelopeV1:
35
+ decision_id: str
36
+ tool_result_digest: str
37
+ executed_at: float
38
+ duration_ms: float
39
+ @staticmethod
40
+ def digest_result(result):
41
+ raw = canonical_json(result) if result is not None else ""
42
+ return hashlib.sha256(raw.encode("utf-8")).hexdigest()
43
+ def to_dict(self):
44
+ return {"decision_id":self.decision_id,"tool_result_digest":self.tool_result_digest,"executed_at":self.executed_at,"duration_ms":self.duration_ms}
45
+
46
+ @dataclass
47
+ class ToolCallContext:
48
+ tool_name: str
49
+ tool_args: Dict[str, Any] = field(default_factory=dict)
50
+ agent_id: str = "unknown"
51
+ metadata: Dict[str, Any] = field(default_factory=dict)
52
+
53
+ class GuardrailProvider(ABC):
54
+ @abstractmethod
55
+ def authorize(self, context: ToolCallContext) -> GuardrailDecisionV1: ...
56
+
57
+ class AllowAllGuardrailProvider(GuardrailProvider):
58
+ def authorize(self, context):
59
+ claims = {"provider":"AllowAllGuardrailProvider","tool_name":context.tool_name,"agent_id":context.agent_id}
60
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=True, claims=claims)
61
+
62
+ class DenyAllGuardrailProvider(GuardrailProvider):
63
+ def authorize(self, context):
64
+ claims = {"provider":"DenyAllGuardrailProvider","tool_name":context.tool_name,"reason":"deny-all safety lock active"}
65
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=False, claims=claims)
66
+
67
+ class ToolListGuardrailProvider(GuardrailProvider):
68
+ def __init__(self, allowed_tools=None, denied_tools=None):
69
+ self.allowed_tools = allowed_tools
70
+ self.denied_tools = denied_tools or set()
71
+ def authorize(self, context):
72
+ claims = {"provider":"ToolListGuardrailProvider","tool_name":context.tool_name,"agent_id":context.agent_id}
73
+ if self.allowed_tools is not None:
74
+ authorized = context.tool_name in self.allowed_tools
75
+ claims["policy"] = "allowlist"
76
+ claims["allowed_tools"] = sorted(self.allowed_tools)
77
+ elif context.tool_name in self.denied_tools:
78
+ authorized = False
79
+ claims["policy"] = "denylist"
80
+ claims["denied_tools"] = sorted(self.denied_tools)
81
+ else:
82
+ authorized = True
83
+ claims["policy"] = "default-allow"
84
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=authorized, claims=claims)
85
+
86
+ class CKGGuardrailProvider(GuardrailProvider):
87
+ def __init__(self):
88
+ self._constraints = []
89
+ def add_constraint(self, predicate, **kwargs):
90
+ self._constraints.append({"predicate":predicate, **kwargs})
91
+ return self
92
+ def authorize(self, context):
93
+ claims = {"provider":"CKGGuardrailProvider","tool_name":context.tool_name,"agent_id":context.agent_id}
94
+ satisfied, failed_predicate = True, None
95
+ for c in self._constraints:
96
+ p = c["predicate"]
97
+ if p=="tool_name_in" and context.tool_name not in c["tools"]: satisfied,failed_predicate=False,p
98
+ elif p=="tool_name_not_in" and context.tool_name in c["tools"]: satisfied,failed_predicate=False,p
99
+ elif p=="agent_id_in" and context.agent_id not in c["agents"]: satisfied,failed_predicate=False,p
100
+ elif p=="param_matches" and context.tool_args.get(c["name"])!=c["value"]: satisfied,failed_predicate=False,p
101
+ elif p=="has_param" and c["name"] not in context.tool_args: satisfied,failed_predicate=False,p
102
+ elif p=="no_param" and c["name"] in context.tool_args: satisfied,failed_predicate=False,p
103
+ if not satisfied: claims["failed_predicate"]=failed_predicate
104
+ claims["constraints_count"]=len(self._constraints)
105
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=satisfied, claims=claims)
106
+
107
+ class EnvProtectionProvider(GuardrailProvider):
108
+ DANGEROUS_PATTERNS = {
109
+ "env_vars":["API_KEY","API_SECRET","SECRET_KEY","PRIVATE_KEY","ACCESS_TOKEN","AUTH_TOKEN","DB_PASSWORD","DATABASE_URL","AWS_SECRET","AWS_ACCESS_KEY","GITHUB_TOKEN","OPENAI_API_KEY","ANTHROPIC_API_KEY"],
110
+ "env_commands":["os.environ","process.env","getenv","env ","printenv","echo $","${"],
111
+ "file_paths":[".env",".env.local",".env.production","credentials.json","service-account.json"],
112
+ }
113
+ def __init__(self, extra_patterns=None):
114
+ self.extra_patterns = extra_patterns or []
115
+ def authorize(self, context):
116
+ claims = {"provider":"EnvProtectionProvider","tool_name":context.tool_name,"agent_id":context.agent_id}
117
+ args_str = canonical_json(context.tool_args).lower()
118
+ matched = [f"{cat}:{p}" for cat,pats in self.DANGEROUS_PATTERNS.items() for p in pats if p.lower() in args_str]
119
+ matched += [f"custom:{p}" for p in self.extra_patterns if p.lower() in args_str]
120
+ if matched:
121
+ claims["matched_patterns"]=matched
122
+ claims["reason"]="Environment variable access attempt detected"
123
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=False, claims=claims)
124
+ claims["reason"]="No environment variable access detected"
125
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=True, claims=claims)
126
+
127
+ class CompositeGuardrailProvider(GuardrailProvider):
128
+ def __init__(self, providers, mode="AND"):
129
+ if mode not in ("AND","OR"): raise ValueError(f"mode must be AND or OR, got {mode}")
130
+ self.providers = providers
131
+ self.mode = mode
132
+ def authorize(self, context):
133
+ results = [p.authorize(context) for p in self.providers]
134
+ authorized = all(d.authorized for d in results) if self.mode=="AND" else any(d.authorized for d in results)
135
+ claims = {"provider":"CompositeGuardrailProvider","mode":self.mode,"tool_name":context.tool_name,"agent_id":context.agent_id,"sub_decisions":[d.decision_id for d in results],"sub_providers":[d.claims.get("provider","unknown") for d in results]}
136
+ return GuardrailDecisionV1(decision_id=compute_decision_id(claims), authorized=authorized, claims=claims)
137
+
138
+ class AuditTrail:
139
+ def __init__(self):
140
+ self._decisions = {}
141
+ self._envelopes = {}
142
+ def record_decision(self, decision): self._decisions[decision.decision_id] = decision
143
+ def record_envelope(self, envelope): self._envelopes[envelope.decision_id] = envelope
144
+ def get_decision(self, did): return self._decisions.get(did)
145
+ def get_envelope(self, did): return self._envelopes.get(did)
146
+ def get_all_decisions(self): return list(self._decisions.values())
147
+ def get_all_envelopes(self): return list(self._envelopes.values())
148
+ def clear(self): self._decisions.clear(); self._envelopes.clear()
149
+ @property
150
+ def decision_count(self): return len(self._decisions)
151
+ @property
152
+ def envelope_count(self): return len(self._envelopes)
153
+ def verify_all(self): return all(d.verify_integrity() for d in self._decisions.values())
154
+ def export(self): return {"decisions":[d.to_dict() for d in self._decisions.values()],"envelopes":[e.to_dict() for e in self._envelopes.values()],"verified":self.verify_all()}
155
+
156
+ class GuardrailContext:
157
+ def __init__(self, provider, trail=None, on_deny=None):
158
+ self.provider = provider; self.trail = trail or AuditTrail(); self.on_deny = on_deny
159
+ def authorize(self, context):
160
+ decision = self.provider.authorize(context)
161
+ self.trail.record_decision(decision)
162
+ if not decision.authorized and self.on_deny: self.on_deny(decision)
163
+ return decision
164
+ def after_tool_call(self, decision, result, start_time):
165
+ duration_ms = (time.time()-start_time)*1000
166
+ envelope = ActionEnvelopeV1(decision_id=decision.decision_id, tool_result_digest=ActionEnvelopeV1.digest_result(result), executed_at=time.time(), duration_ms=duration_ms)
167
+ self.trail.record_envelope(envelope)
168
+ return envelope
169
+
170
+ def make_guardrail_hook(provider, trail=None, on_deny=None):
171
+ ctx = GuardrailContext(provider=provider, trail=trail, on_deny=on_deny)
172
+ def _hook(tool_name, tool_args=None, agent_id="unknown", **kwargs):
173
+ context = ToolCallContext(tool_name=tool_name, tool_args=tool_args or {}, agent_id=agent_id, metadata=kwargs)
174
+ decision = ctx.authorize(context)
175
+ if not decision.authorized: return False
176
+ return None
177
+ _hook._guardrail_context = ctx
178
+ return _hook
179
+
180
+ def detect_missing_guardrail(agents):
181
+ findings = []
182
+ for agent in agents:
183
+ agent_name = getattr(agent,"role",getattr(agent,"name",getattr(agent,"id","unknown")))
184
+ has_hooks = getattr(agent,"_before_tool_call_hooks",None) or getattr(agent,"before_tool_call",None) or getattr(agent,"_guardrails",None) or getattr(agent,"guardrail_provider",None)
185
+ if not has_hooks:
186
+ findings.append({"severity":"CRITICAL","pattern":"AS-GUARDRAIL-MISS-001","agent":agent_name,"message":f"Agent '{agent_name}' has no registered GuardrailProvider","remediation":"Register a GuardrailProvider via make_guardrail_hook()","ccs_ref":"https://correctover.com/ccs"})
187
+ return findings
188
+
189
+ class MCPSecurityValidator:
190
+ DANGEROUS_COMMANDS = ["rm -rf","curl | sh","wget | bash","eval(","exec(","os.system","subprocess.call"]
191
+ SENSITIVE_ENV_PATTERNS = ["API_KEY","SECRET","TOKEN","PASSWORD","PRIVATE_KEY","CREDENTIALS","AUTH"]
192
+ @staticmethod
193
+ def validate_tool_definition(tool_def):
194
+ issues = []
195
+ impl = str(tool_def.get("implementation",""))
196
+ for cmd in MCPSecurityValidator.DANGEROUS_COMMANDS:
197
+ if cmd in impl: issues.append({"severity":"CRITICAL","type":"command_injection","pattern":cmd,"cve_ref":"CVE-2026-42271"})
198
+ env_section = str(tool_def.get("env",{}))
199
+ for pattern in MCPSecurityValidator.SENSITIVE_ENV_PATTERNS:
200
+ if pattern.upper() in env_section.upper(): issues.append({"severity":"HIGH","type":"env_exposure","pattern":pattern,"cve_ref":"CVE-2026-12957"})
201
+ return {"safe":len(issues)==0,"issues":issues,"tool_name":tool_def.get("name","unknown")}
202
+ @staticmethod
203
+ def validate_mcp_config(config):
204
+ issues = []
205
+ transport = config.get("transport","stdio")
206
+ if transport == "stdio":
207
+ env = config.get("env",{})
208
+ if env: issues.append({"severity":"HIGH","type":"stdio_env_exposure","message":"stdio transport with env variables","cve_ref":"CVE-2026-12957","remediation":"Use env_isolation or switch to sse/http transport"})
209
+ for tool in config.get("tools",[]):
210
+ issues.extend(MCPSecurityValidator.validate_tool_definition(tool)["issues"])
211
+ return {"safe":len(issues)==0,"issues":issues,"config_name":config.get("name","unknown")}
@@ -0,0 +1,37 @@
1
+ from typing import Dict, List, Any, Optional
2
+ from pydantic import BaseModel, Field
3
+ from datetime import datetime
4
+ import hashlib, hmac, json
5
+
6
+ class ValidationResult(BaseModel):
7
+ is_valid: bool
8
+ errors: List[str] = Field(default_factory=list)
9
+ warnings: List[str] = Field(default_factory=list)
10
+ validated_at: str = Field(default_factory=lambda: datetime.utcnow().isoformat())
11
+ trace_id: Optional[str] = None
12
+
13
+ class CCSValidator:
14
+ def __init__(self, required_fields=None, supported_fields=None, forbidden_fields=None, enable_integrity=False, integrity_key=None):
15
+ self.required_fields = set(required_fields or [])
16
+ self.supported_fields = set(supported_fields or [])
17
+ self.forbidden_fields = set(forbidden_fields or [])
18
+ self.enable_integrity = enable_integrity
19
+ self.integrity_key = integrity_key or "default-key"
20
+ def validate(self, output, trace_id=None):
21
+ errors, warnings = [], []
22
+ for f in self.required_fields:
23
+ if f not in output: errors.append(f"Missing required field: {f}")
24
+ for f in self.forbidden_fields:
25
+ if f in output: errors.append(f"Forbidden field present: {f}")
26
+ unexpected = set(output.keys()) - self.required_fields - self.supported_fields - self.forbidden_fields
27
+ for f in unexpected: warnings.append(f"Unexpected field: {f}")
28
+ if self.enable_integrity:
29
+ stored_hash = output.get("integrity_hash")
30
+ computed = self._compute_integrity(output)
31
+ if stored_hash is None: warnings.append("No integrity hash in output")
32
+ elif stored_hash != computed: errors.append("Integrity hash mismatch")
33
+ return ValidationResult(is_valid=len(errors)==0, errors=errors, warnings=warnings, trace_id=trace_id)
34
+ def _compute_integrity(self, output):
35
+ data = {k:v for k,v in output.items() if k != "integrity_hash"}
36
+ canonical = json.dumps(data, sort_keys=True, separators=(",",":"))
37
+ return hmac.new(self.integrity_key.encode(), canonical.encode(), hashlib.sha256).hexdigest()
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: correctover
3
+ Version: 2.2.0
4
+ Summary: Correctover - AI Agent Runtime Assurance. CCS standard + GuardrailProvider + MCP Security Scanner.
5
+ Author-email: Guigui Wang <wangguigui@correctover.com>
6
+ License: Proprietary Commercial License
7
+ Project-URL: Homepage, https://correctover.com
8
+ Project-URL: CCS Standard, https://correctover.com/ccs
9
+ Project-URL: GitHub, https://github.com/Correctover
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: pydantic>=1.10
@@ -0,0 +1,9 @@
1
+ pyproject.toml
2
+ src/correctover/__init__.py
3
+ src/correctover/guardrail.py
4
+ src/correctover/validator.py
5
+ src/correctover.egg-info/PKG-INFO
6
+ src/correctover.egg-info/SOURCES.txt
7
+ src/correctover.egg-info/dependency_links.txt
8
+ src/correctover.egg-info/requires.txt
9
+ src/correctover.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ pydantic>=1.10
correctover-2.1.0/LICENSE DELETED
@@ -1,7 +0,0 @@
1
- CORRECTOVER SDK — PROPRIETARY COMMERCIAL LICENSE
2
- Copyright (c) 2024-2026 Correctover Team. All rights reserved.
3
-
4
- This software is NOT open source. It is distributed as compiled
5
- bytecode only. Redistribution requires a valid commercial license.
6
-
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
@@ -1,2 +0,0 @@
1
- recursive-include correctover *.pyc
2
- recursive-include correctover/benchmark *.pyc
@@ -1,49 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: correctover
3
- Version: 2.1.0
4
- Summary: Correctover — Failure is not fatal. Protocol-level contract validation with automatic verified failover for LLM APIs.
5
- Home-page: https://correctover.com
6
- Author: Correctover Team
7
- Author-email: Correctover Team <team@correctover.com>
8
- Maintainer-email: Correctover Team <team@correctover.com>
9
- License: Proprietary Commercial License — see LICENSE
10
- Project-URL: Homepage, https://correctover.com
11
- Project-URL: Documentation, https://correctover.com/docs
12
- Project-URL: Changelog, https://correctover.com/docs/changelog
13
- Project-URL: Bug Tracker, https://correctover.com/support
14
- Keywords: llm,self-healing,failover,circuit-breaker,api-resilience,openai,anthropic,deepseek,contract-validation,correctover,ai-gateway,semantic-verification
15
- Classifier: Development Status :: 5 - Production/Stable
16
- Classifier: Intended Audience :: Developers
17
- Classifier: License :: Other/Proprietary License
18
- Classifier: Operating System :: OS Independent
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
- Requires-Python: >=3.12
24
- Description-Content-Type: text/markdown
25
- License-File: LICENSE
26
- Requires-Dist: httpx>=0.24.0
27
- Requires-Dist: aiohttp>=3.8.0
28
-
29
- # Correctover SDK
30
-
31
- **Failure is not fatal.** Protocol-level contract validation with automatic verified failover for LLM APIs.
32
-
33
- ## Install
34
-
35
- ```bash
36
- pip install correctover
37
- ```
38
-
39
- ## Quick Start
40
-
41
- ```python
42
- import correctover
43
- result = correctover.run("Hello!")
44
- print(result)
45
- ```
46
-
47
- ## License
48
-
49
- Proprietary Commercial License. See LICENSE file.
@@ -1,21 +0,0 @@
1
- # Correctover SDK
2
-
3
- **Failure is not fatal.** Protocol-level contract validation with automatic verified failover for LLM APIs.
4
-
5
- ## Install
6
-
7
- ```bash
8
- pip install correctover
9
- ```
10
-
11
- ## Quick Start
12
-
13
- ```python
14
- import correctover
15
- result = correctover.run("Hello!")
16
- print(result)
17
- ```
18
-
19
- ## License
20
-
21
- Proprietary Commercial License. See LICENSE file.