coreason-manifest 0.1.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.
- coreason_manifest/__init__.py +41 -0
- coreason_manifest/engine.py +117 -0
- coreason_manifest/errors.py +28 -0
- coreason_manifest/integrity.py +136 -0
- coreason_manifest/loader.py +125 -0
- coreason_manifest/main.py +16 -0
- coreason_manifest/models.py +156 -0
- coreason_manifest/policies/compliance.rego +81 -0
- coreason_manifest/policies/tbom.json +14 -0
- coreason_manifest/policy.py +132 -0
- coreason_manifest/schemas/__init__.py +1 -0
- coreason_manifest/schemas/agent.schema.json +209 -0
- coreason_manifest/utils/__init__.py +13 -0
- coreason_manifest/utils/logger.py +48 -0
- coreason_manifest/validator.py +56 -0
- coreason_manifest-0.1.0.dist-info/METADATA +114 -0
- coreason_manifest-0.1.0.dist-info/RECORD +20 -0
- coreason_manifest-0.1.0.dist-info/WHEEL +4 -0
- coreason_manifest-0.1.0.dist-info/licenses/LICENSE +57 -0
- coreason_manifest-0.1.0.dist-info/licenses/NOTICE +8 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package coreason.compliance
|
|
2
|
+
|
|
3
|
+
import rego.v1
|
|
4
|
+
|
|
5
|
+
# Do not import data.tbom to avoid namespace confusion, access via data.tbom directly if needed or via helper.
|
|
6
|
+
|
|
7
|
+
default allow := false
|
|
8
|
+
|
|
9
|
+
# Deny if 'pickle' is in libraries (matches "pickle", "pickle==1.0", "pickle>=2.0")
|
|
10
|
+
deny contains msg if {
|
|
11
|
+
some i
|
|
12
|
+
lib_str := input.dependencies.libraries[i]
|
|
13
|
+
# Check if the library name starts with 'pickle' followed by end of string or version specifier
|
|
14
|
+
regex.match("^pickle([<>=!@\\[].*)?$", lib_str)
|
|
15
|
+
msg := "Security Risk: 'pickle' library is strictly forbidden."
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Deny if 'os' is in libraries
|
|
19
|
+
deny contains msg if {
|
|
20
|
+
some i
|
|
21
|
+
lib_str := input.dependencies.libraries[i]
|
|
22
|
+
regex.match("^os([<>=!@\\[].*)?$", lib_str)
|
|
23
|
+
msg := "Security Risk: 'os' library is strictly forbidden."
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Deny if description is too short (Business Rule example)
|
|
27
|
+
# Iterates over ALL steps to ensure compliance.
|
|
28
|
+
deny contains msg if {
|
|
29
|
+
some step in input.topology.steps
|
|
30
|
+
count(step.description) < 5
|
|
31
|
+
msg := "Step description is too short."
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Rule 1 (Dependency Pinning): All library dependencies must have explicit version pins.
|
|
35
|
+
# Strictly enforces "name==version" (with optional extras).
|
|
36
|
+
# Rejects "name>=version", "name==version,>=other", etc.
|
|
37
|
+
deny contains msg if {
|
|
38
|
+
some i
|
|
39
|
+
lib := input.dependencies.libraries[i]
|
|
40
|
+
|
|
41
|
+
# Regex Explanation:
|
|
42
|
+
# ^ Start
|
|
43
|
+
# [a-zA-Z0-9_\-\.]+ Package name (alphanum, _, -, .)
|
|
44
|
+
# (\[[a-zA-Z0-9_\-\.,]+\])? Optional extras in brackets (e.g. [security,fast])
|
|
45
|
+
# == Must be strictly '=='
|
|
46
|
+
# [a-zA-Z0-9_\-\.\+]+ Version string (alphanum, _, -, ., + for metadata)
|
|
47
|
+
# $ End (No trailing constraints like ,>=2.0)
|
|
48
|
+
|
|
49
|
+
not regex.match("^[a-zA-Z0-9_\\-\\.]+(\\[[a-zA-Z0-9_\\-\\.,]+\\])?==[a-zA-Z0-9_\\-\\.\\+]+$", lib)
|
|
50
|
+
msg := sprintf("Compliance Violation: Library '%v' must be strictly pinned with '==' (e.g., 'pandas==2.0.1').", [lib])
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Rule 2 (Allowlist Enforcement): Libraries must be in TBOM
|
|
54
|
+
deny contains msg if {
|
|
55
|
+
some i
|
|
56
|
+
lib_str := input.dependencies.libraries[i]
|
|
57
|
+
|
|
58
|
+
# Extract library name using regex
|
|
59
|
+
# Pattern must support dots (for namespace packages) and stop before extras brackets or version specifiers.
|
|
60
|
+
parts := regex.find_all_string_submatch_n("^[a-zA-Z0-9_\\-\\.]+", lib_str, 1)
|
|
61
|
+
count(parts) > 0
|
|
62
|
+
lib_name := parts[0][0]
|
|
63
|
+
|
|
64
|
+
# Check if lib_name is in tbom (case-insensitive)
|
|
65
|
+
not is_in_tbom(lib_name)
|
|
66
|
+
|
|
67
|
+
msg := sprintf("Compliance Violation: Library '%v' is not in the Trusted Bill of Materials (TBOM).", [lib_name])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Helper to safely check if lib is in TBOM
|
|
71
|
+
# Returns true if data.tbom exists AND contains the lib (case-insensitive)
|
|
72
|
+
is_in_tbom(lib) if {
|
|
73
|
+
# Lowercase the input library name
|
|
74
|
+
lower_lib := lower(lib)
|
|
75
|
+
|
|
76
|
+
# Check against TBOM
|
|
77
|
+
# If data.tbom is undefined, this rule body is undefined (false).
|
|
78
|
+
# Iterate through TBOM and compare lowercased versions
|
|
79
|
+
some tbom_lib in data.tbom
|
|
80
|
+
lower(tbom_lib) == lower_lib
|
|
81
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Prosperity-3.0
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, List, Optional
|
|
9
|
+
|
|
10
|
+
from coreason_manifest.errors import PolicyViolationError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PolicyEnforcer:
|
|
14
|
+
"""
|
|
15
|
+
Component C: PolicyEnforcer (The Compliance Officer).
|
|
16
|
+
|
|
17
|
+
Responsibility:
|
|
18
|
+
- Evaluate the agent against the compliance.rego policy file using OPA.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
policy_path: str | Path,
|
|
24
|
+
opa_path: str = "opa",
|
|
25
|
+
data_paths: Optional[List[str | Path]] = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Initialize the PolicyEnforcer.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
policy_path: Path to the Rego policy file.
|
|
32
|
+
opa_path: Path to the OPA executable. Defaults to "opa" (expected in PATH).
|
|
33
|
+
data_paths: List of paths to data files (e.g. JSON/YAML) to be loaded by OPA.
|
|
34
|
+
"""
|
|
35
|
+
self.policy_path = Path(policy_path)
|
|
36
|
+
self.data_paths = [Path(p) for p in data_paths] if data_paths else []
|
|
37
|
+
|
|
38
|
+
# Validate OPA executable
|
|
39
|
+
# If opa_path is a simple name (like "opa"), use shutil.which to find it
|
|
40
|
+
if "/" not in str(opa_path) and "\\" not in str(opa_path):
|
|
41
|
+
resolved_opa = shutil.which(opa_path)
|
|
42
|
+
if not resolved_opa:
|
|
43
|
+
raise FileNotFoundError(f"OPA executable not found in PATH: {opa_path}")
|
|
44
|
+
self.opa_path = resolved_opa
|
|
45
|
+
else:
|
|
46
|
+
# If it's a path, check existence
|
|
47
|
+
if not Path(opa_path).exists():
|
|
48
|
+
raise FileNotFoundError(f"OPA executable not found at: {opa_path}")
|
|
49
|
+
self.opa_path = opa_path
|
|
50
|
+
|
|
51
|
+
if not self.policy_path.exists():
|
|
52
|
+
raise FileNotFoundError(f"Policy file not found: {self.policy_path}")
|
|
53
|
+
|
|
54
|
+
for path in self.data_paths:
|
|
55
|
+
if not path.exists():
|
|
56
|
+
raise FileNotFoundError(f"Data file not found: {path}")
|
|
57
|
+
|
|
58
|
+
def evaluate(self, agent_data: dict[str, Any]) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Evaluates the agent data against the policy.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
agent_data: The dictionary representation of the AgentDefinition.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
PolicyViolationError: If there are any policy violations.
|
|
67
|
+
RuntimeError: If OPA execution fails.
|
|
68
|
+
"""
|
|
69
|
+
# Prepare input for OPA
|
|
70
|
+
# We invoke OPA via subprocess: opa eval -d <policy> -d <data> ... -I <input> "data.coreason.compliance.deny"
|
|
71
|
+
# We pass input via stdin to avoid temp files
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
# We use 'data.coreason.compliance.deny' as the query
|
|
75
|
+
query = "data.coreason.compliance.deny"
|
|
76
|
+
|
|
77
|
+
# Serialize input to JSON
|
|
78
|
+
input_json = json.dumps(agent_data)
|
|
79
|
+
|
|
80
|
+
cmd = [
|
|
81
|
+
self.opa_path,
|
|
82
|
+
"eval",
|
|
83
|
+
"-d",
|
|
84
|
+
str(self.policy_path),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
# Add data paths
|
|
88
|
+
for data_path in self.data_paths:
|
|
89
|
+
cmd.extend(["-d", str(data_path)])
|
|
90
|
+
|
|
91
|
+
cmd.extend(
|
|
92
|
+
[
|
|
93
|
+
"-I", # Read input from stdin
|
|
94
|
+
query,
|
|
95
|
+
"--format",
|
|
96
|
+
"json",
|
|
97
|
+
]
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
process = subprocess.run(
|
|
101
|
+
cmd,
|
|
102
|
+
input=input_json,
|
|
103
|
+
capture_output=True,
|
|
104
|
+
text=True,
|
|
105
|
+
check=False, # We handle return code manually
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if process.returncode != 0:
|
|
109
|
+
# Include stdout in error message if stderr is empty or insufficient
|
|
110
|
+
error_msg = process.stderr.strip()
|
|
111
|
+
if not error_msg:
|
|
112
|
+
error_msg = process.stdout.strip() or "Unknown error (empty stdout/stderr)"
|
|
113
|
+
raise RuntimeError(f"OPA execution failed: {error_msg}")
|
|
114
|
+
|
|
115
|
+
# Parse OPA output
|
|
116
|
+
# Format: {"result": [{"expressions": [{"value": ["violation1", "violation2"]}]}]}
|
|
117
|
+
result = json.loads(process.stdout)
|
|
118
|
+
|
|
119
|
+
violations: List[str] = []
|
|
120
|
+
if "result" in result and len(result["result"]) > 0:
|
|
121
|
+
# Assuming the query returns a set/list of strings
|
|
122
|
+
expressions = result["result"][0].get("expressions", [])
|
|
123
|
+
if expressions:
|
|
124
|
+
violations = expressions[0].get("value", [])
|
|
125
|
+
|
|
126
|
+
if violations:
|
|
127
|
+
raise PolicyViolationError("Policy violations found.", violations=violations)
|
|
128
|
+
|
|
129
|
+
except FileNotFoundError as e:
|
|
130
|
+
raise RuntimeError(f"OPA executable not found at: {self.opa_path}") from e
|
|
131
|
+
except json.JSONDecodeError as e:
|
|
132
|
+
raise RuntimeError(f"Failed to parse OPA output: {e}") from e
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Prosperity-3.0
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$defs": {
|
|
3
|
+
"AgentDependencies": {
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"description": "External dependencies for the Agent.",
|
|
6
|
+
"properties": {
|
|
7
|
+
"tools": {
|
|
8
|
+
"description": "List of MCP capability URIs required.",
|
|
9
|
+
"items": {
|
|
10
|
+
"format": "uri",
|
|
11
|
+
"minLength": 1,
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
"title": "Tools",
|
|
15
|
+
"type": "array"
|
|
16
|
+
},
|
|
17
|
+
"libraries": {
|
|
18
|
+
"description": "List of Python packages required (if code execution is allowed).",
|
|
19
|
+
"items": {
|
|
20
|
+
"type": "string"
|
|
21
|
+
},
|
|
22
|
+
"title": "Libraries",
|
|
23
|
+
"type": "array"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"title": "AgentDependencies",
|
|
27
|
+
"type": "object"
|
|
28
|
+
},
|
|
29
|
+
"AgentInterface": {
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"description": "Interface definition for the Agent.",
|
|
32
|
+
"properties": {
|
|
33
|
+
"inputs": {
|
|
34
|
+
"additionalProperties": true,
|
|
35
|
+
"description": "Typed arguments the agent accepts (JSON Schema).",
|
|
36
|
+
"title": "Inputs",
|
|
37
|
+
"type": "object"
|
|
38
|
+
},
|
|
39
|
+
"outputs": {
|
|
40
|
+
"additionalProperties": true,
|
|
41
|
+
"description": "Typed structure of the result.",
|
|
42
|
+
"title": "Outputs",
|
|
43
|
+
"type": "object"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"required": [
|
|
47
|
+
"inputs",
|
|
48
|
+
"outputs"
|
|
49
|
+
],
|
|
50
|
+
"title": "AgentInterface",
|
|
51
|
+
"type": "object"
|
|
52
|
+
},
|
|
53
|
+
"AgentMetadata": {
|
|
54
|
+
"additionalProperties": false,
|
|
55
|
+
"description": "Metadata for the Agent.",
|
|
56
|
+
"properties": {
|
|
57
|
+
"id": {
|
|
58
|
+
"description": "Unique Identifier for the Agent (UUID).",
|
|
59
|
+
"format": "uuid",
|
|
60
|
+
"title": "Id",
|
|
61
|
+
"type": "string"
|
|
62
|
+
},
|
|
63
|
+
"version": {
|
|
64
|
+
"description": "Semantic Version of the Agent.",
|
|
65
|
+
"pattern": "^[vV]*(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$",
|
|
66
|
+
"title": "Version",
|
|
67
|
+
"type": "string"
|
|
68
|
+
},
|
|
69
|
+
"name": {
|
|
70
|
+
"description": "Name of the Agent.",
|
|
71
|
+
"minLength": 1,
|
|
72
|
+
"title": "Name",
|
|
73
|
+
"type": "string"
|
|
74
|
+
},
|
|
75
|
+
"author": {
|
|
76
|
+
"description": "Author of the Agent.",
|
|
77
|
+
"minLength": 1,
|
|
78
|
+
"title": "Author",
|
|
79
|
+
"type": "string"
|
|
80
|
+
},
|
|
81
|
+
"created_at": {
|
|
82
|
+
"description": "Creation timestamp (ISO 8601).",
|
|
83
|
+
"format": "date-time",
|
|
84
|
+
"title": "Created At",
|
|
85
|
+
"type": "string"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"required": [
|
|
89
|
+
"id",
|
|
90
|
+
"version",
|
|
91
|
+
"name",
|
|
92
|
+
"author",
|
|
93
|
+
"created_at"
|
|
94
|
+
],
|
|
95
|
+
"title": "AgentMetadata",
|
|
96
|
+
"type": "object"
|
|
97
|
+
},
|
|
98
|
+
"AgentTopology": {
|
|
99
|
+
"additionalProperties": false,
|
|
100
|
+
"description": "Topology of the Agent execution.",
|
|
101
|
+
"properties": {
|
|
102
|
+
"steps": {
|
|
103
|
+
"description": "A directed acyclic graph (DAG) of execution steps.",
|
|
104
|
+
"items": {
|
|
105
|
+
"$ref": "#/$defs/Step"
|
|
106
|
+
},
|
|
107
|
+
"title": "Steps",
|
|
108
|
+
"type": "array"
|
|
109
|
+
},
|
|
110
|
+
"model_config": {
|
|
111
|
+
"$ref": "#/$defs/ModelConfig",
|
|
112
|
+
"description": "Specific LLM parameters."
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"required": [
|
|
116
|
+
"steps",
|
|
117
|
+
"model_config"
|
|
118
|
+
],
|
|
119
|
+
"title": "AgentTopology",
|
|
120
|
+
"type": "object"
|
|
121
|
+
},
|
|
122
|
+
"ModelConfig": {
|
|
123
|
+
"additionalProperties": false,
|
|
124
|
+
"description": "LLM Configuration parameters.",
|
|
125
|
+
"properties": {
|
|
126
|
+
"model": {
|
|
127
|
+
"description": "The LLM model identifier.",
|
|
128
|
+
"title": "Model",
|
|
129
|
+
"type": "string"
|
|
130
|
+
},
|
|
131
|
+
"temperature": {
|
|
132
|
+
"description": "Temperature for generation.",
|
|
133
|
+
"maximum": 2.0,
|
|
134
|
+
"minimum": 0.0,
|
|
135
|
+
"title": "Temperature",
|
|
136
|
+
"type": "number"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"required": [
|
|
140
|
+
"model",
|
|
141
|
+
"temperature"
|
|
142
|
+
],
|
|
143
|
+
"title": "ModelConfig",
|
|
144
|
+
"type": "object"
|
|
145
|
+
},
|
|
146
|
+
"Step": {
|
|
147
|
+
"additionalProperties": false,
|
|
148
|
+
"description": "A single step in the execution graph.",
|
|
149
|
+
"properties": {
|
|
150
|
+
"id": {
|
|
151
|
+
"description": "Unique identifier for the step.",
|
|
152
|
+
"minLength": 1,
|
|
153
|
+
"title": "Id",
|
|
154
|
+
"type": "string"
|
|
155
|
+
},
|
|
156
|
+
"description": {
|
|
157
|
+
"anyOf": [
|
|
158
|
+
{
|
|
159
|
+
"type": "string"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"type": "null"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"default": null,
|
|
166
|
+
"description": "Description of the step.",
|
|
167
|
+
"title": "Description"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"required": [
|
|
171
|
+
"id"
|
|
172
|
+
],
|
|
173
|
+
"title": "Step",
|
|
174
|
+
"type": "object"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"$id": "https://coreason.ai/schemas/agent.schema.json",
|
|
178
|
+
"additionalProperties": false,
|
|
179
|
+
"description": "The definitive source of truth for CoReason Agent definitions.",
|
|
180
|
+
"properties": {
|
|
181
|
+
"metadata": {
|
|
182
|
+
"$ref": "#/$defs/AgentMetadata"
|
|
183
|
+
},
|
|
184
|
+
"interface": {
|
|
185
|
+
"$ref": "#/$defs/AgentInterface"
|
|
186
|
+
},
|
|
187
|
+
"topology": {
|
|
188
|
+
"$ref": "#/$defs/AgentTopology"
|
|
189
|
+
},
|
|
190
|
+
"dependencies": {
|
|
191
|
+
"$ref": "#/$defs/AgentDependencies"
|
|
192
|
+
},
|
|
193
|
+
"integrity_hash": {
|
|
194
|
+
"description": "SHA256 hash of the source code.",
|
|
195
|
+
"pattern": "^[a-fA-F0-9]{64}$",
|
|
196
|
+
"title": "Integrity Hash",
|
|
197
|
+
"type": "string"
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"required": [
|
|
201
|
+
"metadata",
|
|
202
|
+
"interface",
|
|
203
|
+
"topology",
|
|
204
|
+
"dependencies",
|
|
205
|
+
"integrity_hash"
|
|
206
|
+
],
|
|
207
|
+
"title": "CoReason Agent Manifest",
|
|
208
|
+
"type": "object"
|
|
209
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright (c) 2025 CoReason, Inc.
|
|
2
|
+
#
|
|
3
|
+
# This software is proprietary and dual-licensed.
|
|
4
|
+
# Licensed under the Prosperity Public License 3.0 (the "License").
|
|
5
|
+
# A copy of the license is available at https://prosperitylicense.com/versions/3.0.0
|
|
6
|
+
# For details, see the LICENSE file.
|
|
7
|
+
# Commercial use beyond a 30-day trial requires a separate license.
|
|
8
|
+
#
|
|
9
|
+
# Source Code: https://github.com/CoReason-AI/coreason_manifest
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
Utils module.
|
|
13
|
+
"""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Copyright (c) 2025 CoReason, Inc.
|
|
2
|
+
#
|
|
3
|
+
# This software is proprietary and dual-licensed.
|
|
4
|
+
# Licensed under the Prosperity Public License 3.0 (the "License").
|
|
5
|
+
# A copy of the license is available at https://prosperitylicense.com/versions/3.0.0
|
|
6
|
+
# For details, see the LICENSE file.
|
|
7
|
+
# Commercial use beyond a 30-day trial requires a separate license.
|
|
8
|
+
#
|
|
9
|
+
# Source Code: https://github.com/CoReason-AI/coreason_manifest
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from loguru import logger
|
|
16
|
+
|
|
17
|
+
__all__ = ["logger"]
|
|
18
|
+
|
|
19
|
+
# Remove default handler
|
|
20
|
+
logger.remove()
|
|
21
|
+
|
|
22
|
+
# Sink 1: Stdout (Human-readable)
|
|
23
|
+
logger.add(
|
|
24
|
+
sys.stderr,
|
|
25
|
+
level="INFO",
|
|
26
|
+
format=(
|
|
27
|
+
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
|
|
28
|
+
"<level>{level: <8}</level> | "
|
|
29
|
+
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
|
|
30
|
+
"<level>{message}</level>"
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Ensure logs directory exists
|
|
35
|
+
log_dir = os.getenv("COREASON_LOG_DIR", "logs")
|
|
36
|
+
log_path = Path(log_dir)
|
|
37
|
+
if not log_path.exists():
|
|
38
|
+
log_path.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
|
|
40
|
+
# Sink 2: File (JSON, Rotation, Retention)
|
|
41
|
+
logger.add(
|
|
42
|
+
f"{log_dir}/app.log",
|
|
43
|
+
rotation="500 MB",
|
|
44
|
+
retention="10 days",
|
|
45
|
+
serialize=True,
|
|
46
|
+
enqueue=True,
|
|
47
|
+
level="INFO",
|
|
48
|
+
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Prosperity-3.0
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from importlib.resources import files
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from jsonschema import FormatChecker, ValidationError, validate
|
|
9
|
+
|
|
10
|
+
from coreason_manifest.errors import ManifestSyntaxError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SchemaValidator:
|
|
14
|
+
"""
|
|
15
|
+
Component B: SchemaValidator (The Structural Engineer).
|
|
16
|
+
|
|
17
|
+
Responsibility:
|
|
18
|
+
- Validate the dictionary against the Master JSON Schema.
|
|
19
|
+
- Check required fields, data types, and format constraints.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
"""Initialize the validator by loading the schema."""
|
|
24
|
+
self.schema = self._load_schema()
|
|
25
|
+
|
|
26
|
+
def _load_schema(self) -> dict[str, Any]:
|
|
27
|
+
"""Loads the JSON schema from the package resources."""
|
|
28
|
+
try:
|
|
29
|
+
schema_path = files("coreason_manifest.schemas").joinpath("agent.schema.json")
|
|
30
|
+
with schema_path.open("r", encoding="utf-8") as f:
|
|
31
|
+
schema = json.load(f)
|
|
32
|
+
if not isinstance(schema, dict):
|
|
33
|
+
raise ManifestSyntaxError("Schema file is not a valid JSON object.")
|
|
34
|
+
return schema
|
|
35
|
+
except (IOError, json.JSONDecodeError) as e:
|
|
36
|
+
raise ManifestSyntaxError(f"Failed to load agent schema: {e}") from e
|
|
37
|
+
|
|
38
|
+
def validate(self, data: dict[str, Any]) -> bool:
|
|
39
|
+
"""
|
|
40
|
+
Validates the given dictionary against the agent schema.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
data: The raw dictionary to validate.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
bool: True if validation passes.
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
ManifestSyntaxError: If validation fails.
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
validate(instance=data, schema=self.schema, format_checker=FormatChecker())
|
|
53
|
+
return True
|
|
54
|
+
except ValidationError as e:
|
|
55
|
+
# We treat schema validation errors as syntax errors in the manifest
|
|
56
|
+
raise ManifestSyntaxError(f"Schema validation failed: {e.message}") from e
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coreason_manifest
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: This package is the definitive source of truth. If it isn't in the manifest, it doesn't exist. If it violates the manifest, it doesn't run.
|
|
5
|
+
License: # The Prosperity Public License 3.0.0
|
|
6
|
+
|
|
7
|
+
Contributor: CoReason, Inc.
|
|
8
|
+
|
|
9
|
+
Source Code: https://github.com/CoReason-AI/coreason_manifest
|
|
10
|
+
|
|
11
|
+
## Purpose
|
|
12
|
+
|
|
13
|
+
This license allows you to use and share this software for noncommercial purposes for free and to try this software for commercial purposes for thirty days.
|
|
14
|
+
|
|
15
|
+
## Agreement
|
|
16
|
+
|
|
17
|
+
In order to receive this license, you have to agree to its rules. Those rules are both obligations under that agreement and conditions to your license. Don't do anything with this software that triggers a rule you can't or won't follow.
|
|
18
|
+
|
|
19
|
+
## Notices
|
|
20
|
+
|
|
21
|
+
Make sure everyone who gets a copy of any part of this software from you, with or without changes, also gets the text of this license and the contributor and source code lines above.
|
|
22
|
+
|
|
23
|
+
## Commercial Trial
|
|
24
|
+
|
|
25
|
+
Limit your use of this software for commercial purposes to a thirty-day trial period. If you use this software for work, your company gets one trial period for all personnel, not one trial per person.
|
|
26
|
+
|
|
27
|
+
## Contributions Back
|
|
28
|
+
|
|
29
|
+
Developing feedback, changes, or additions that you contribute back to the contributor on the terms of a standardized public software license such as [the Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0), [the Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html), [the MIT license](https://spdx.org/licenses/MIT.html), or [the two-clause BSD license](https://spdx.org/licenses/BSD-2-Clause.html) doesn't count as use for a commercial purpose.
|
|
30
|
+
|
|
31
|
+
## Personal Uses
|
|
32
|
+
|
|
33
|
+
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, doesn't count as use for a commercial purpose.
|
|
34
|
+
|
|
35
|
+
## Noncommercial Organizations
|
|
36
|
+
|
|
37
|
+
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution doesn't count as use for a commercial purpose regardless of the source of funding or obligations resulting from the funding.
|
|
38
|
+
|
|
39
|
+
## Defense
|
|
40
|
+
|
|
41
|
+
Don't make any legal claim against anyone accusing this software, with or without changes, alone or with other technology, of infringing any patent.
|
|
42
|
+
|
|
43
|
+
## Copyright
|
|
44
|
+
|
|
45
|
+
The contributor licenses you to do everything with this software that would otherwise infringe their copyright in it.
|
|
46
|
+
|
|
47
|
+
## Patent
|
|
48
|
+
|
|
49
|
+
The contributor licenses you to do everything with this software that would otherwise infringe any patents they can license or become able to license.
|
|
50
|
+
|
|
51
|
+
## Reliability
|
|
52
|
+
|
|
53
|
+
The contributor can't revoke this license.
|
|
54
|
+
|
|
55
|
+
## Excuse
|
|
56
|
+
|
|
57
|
+
You're excused for unknowingly breaking [Notices](#notices) if you take all practical steps to comply within thirty days of learning you broke the rule.
|
|
58
|
+
|
|
59
|
+
## No Liability
|
|
60
|
+
|
|
61
|
+
***As far as the law allows, this software comes as is, without any warranty or condition, and the contributor won't be liable to anyone for any damages related to this software or this license, under any kind of legal claim.***
|
|
62
|
+
License-File: LICENSE
|
|
63
|
+
License-File: NOTICE
|
|
64
|
+
Author: Gowtham A Rao
|
|
65
|
+
Author-email: gowtham.rao@coreason.ai
|
|
66
|
+
Requires-Python: >=3.11
|
|
67
|
+
Classifier: License :: Other/Proprietary License
|
|
68
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
69
|
+
Classifier: Operating System :: OS Independent
|
|
70
|
+
Requires-Dist: jsonschema (>=4.25.1,<5.0.0)
|
|
71
|
+
Requires-Dist: loguru (>=0.7.2,<0.8.0)
|
|
72
|
+
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
73
|
+
Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
|
|
74
|
+
Project-URL: Documentation, https://github.com/CoReason-AI/coreason_manifest
|
|
75
|
+
Project-URL: Homepage, https://github.com/CoReason-AI/coreason_manifest
|
|
76
|
+
Project-URL: Repository, https://github.com/CoReason-AI/coreason_manifest
|
|
77
|
+
Description-Content-Type: text/markdown
|
|
78
|
+
|
|
79
|
+
# coreason-manifest
|
|
80
|
+
|
|
81
|
+
This package is the definitive source of truth. If it isn't in the manifest, it doesn't exist. If it violates the manifest, it doesn't run.
|
|
82
|
+
|
|
83
|
+
[](https://github.com/CoReason-AI/coreason_manifest/actions/workflows/ci.yml)
|
|
84
|
+
|
|
85
|
+
## Getting Started
|
|
86
|
+
|
|
87
|
+
### Prerequisites
|
|
88
|
+
|
|
89
|
+
- Python 3.12+
|
|
90
|
+
- Poetry
|
|
91
|
+
|
|
92
|
+
### Installation
|
|
93
|
+
|
|
94
|
+
1. Clone the repository:
|
|
95
|
+
```sh
|
|
96
|
+
git clone https://github.com/example/example.git
|
|
97
|
+
cd my_python_project
|
|
98
|
+
```
|
|
99
|
+
2. Install dependencies:
|
|
100
|
+
```sh
|
|
101
|
+
poetry install
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Usage
|
|
105
|
+
|
|
106
|
+
- Run the linter:
|
|
107
|
+
```sh
|
|
108
|
+
poetry run pre-commit run --all-files
|
|
109
|
+
```
|
|
110
|
+
- Run the tests:
|
|
111
|
+
```sh
|
|
112
|
+
poetry run pytest
|
|
113
|
+
```
|
|
114
|
+
|