coreason-manifest 0.4.0__tar.gz → 0.5.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.
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/PKG-INFO +5 -3
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/README.md +1 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/pyproject.toml +7 -6
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/loader.py +116 -3
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/models.py +11 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/schemas/agent.schema.json +14 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/LICENSE +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/NOTICE +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/__init__.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/engine.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/errors.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/integrity.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/main.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/policies/compliance.rego +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/policies/tbom.json +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/policy.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/schemas/__init__.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/server.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/utils/__init__.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/utils/logger.py +0 -0
- {coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/validator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coreason_manifest
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
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
5
|
License: # The Prosperity Public License 3.0.0
|
|
6
6
|
|
|
@@ -68,9 +68,10 @@ Classifier: License :: Other/Proprietary License
|
|
|
68
68
|
Classifier: Programming Language :: Python :: 3.12
|
|
69
69
|
Classifier: Operating System :: OS Independent
|
|
70
70
|
Requires-Dist: aiofiles (>=23.2.1,<24.0.0)
|
|
71
|
-
Requires-Dist: anyio (>=4.
|
|
71
|
+
Requires-Dist: anyio (>=4.12.1,<5.0.0)
|
|
72
|
+
Requires-Dist: coreason-identity (>=0.1.0,<0.2.0)
|
|
72
73
|
Requires-Dist: fastapi (>=0.111.0,<0.112.0)
|
|
73
|
-
Requires-Dist: httpx (>=0.
|
|
74
|
+
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
74
75
|
Requires-Dist: jsonschema (>=4.25.1,<5.0.0)
|
|
75
76
|
Requires-Dist: loguru (>=0.7.2,<0.8.0)
|
|
76
77
|
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
@@ -99,6 +100,7 @@ The definitive source of truth for CoReason-AI Asset definitions. "The Blueprint
|
|
|
99
100
|
* **Open Agent Specification (OAS) Validation:** Parses and validates agent definitions against a strict schema.
|
|
100
101
|
* **Compliance Enforcement:** Uses Open Policy Agent (OPA) / Rego to enforce complex business rules and allowlists.
|
|
101
102
|
* **Integrity Verification:** Calculates and verifies SHA256 hashes of the agent's source code to prevent tampering.
|
|
103
|
+
* **Automatic Schema Generation:** Inspects Python functions to generate Agent Interfaces, automatically handling `UserContext` injection.
|
|
102
104
|
* **Dependency Pinning:** Enforces strict version pinning for all library dependencies.
|
|
103
105
|
* **Trusted Bill of Materials (TBOM):** Validates libraries against an approved list.
|
|
104
106
|
* **Compliance Microservice:** Can be run as a standalone API server (Service C) for centralized validation.
|
|
@@ -16,6 +16,7 @@ The definitive source of truth for CoReason-AI Asset definitions. "The Blueprint
|
|
|
16
16
|
* **Open Agent Specification (OAS) Validation:** Parses and validates agent definitions against a strict schema.
|
|
17
17
|
* **Compliance Enforcement:** Uses Open Policy Agent (OPA) / Rego to enforce complex business rules and allowlists.
|
|
18
18
|
* **Integrity Verification:** Calculates and verifies SHA256 hashes of the agent's source code to prevent tampering.
|
|
19
|
+
* **Automatic Schema Generation:** Inspects Python functions to generate Agent Interfaces, automatically handling `UserContext` injection.
|
|
19
20
|
* **Dependency Pinning:** Enforces strict version pinning for all library dependencies.
|
|
20
21
|
* **Trusted Bill of Materials (TBOM):** Validates libraries against an approved list.
|
|
21
22
|
* **Compliance Microservice:** Can be run as a standalone API server (Service C) for centralized validation.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "coreason_manifest"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "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
5
|
authors = ["Gowtham A Rao <gowtham.rao@coreason.ai>"]
|
|
6
6
|
license = "Prosperity-3.0"
|
|
@@ -13,15 +13,16 @@ loguru = "^0.7.2"
|
|
|
13
13
|
pydantic = "^2.12.5"
|
|
14
14
|
jsonschema = "^4.25.1"
|
|
15
15
|
pyyaml = "^6.0.3"
|
|
16
|
-
anyio = "^4.
|
|
17
|
-
|
|
16
|
+
anyio = "^4.12.1"
|
|
17
|
+
coreason-identity = "^0.1.0"
|
|
18
|
+
httpx = "^0.28.1"
|
|
18
19
|
aiofiles = "^23.2.1"
|
|
19
20
|
fastapi = "^0.111.0"
|
|
20
21
|
uvicorn = "^0.30.1"
|
|
21
22
|
|
|
22
23
|
[tool.poetry.group.dev.dependencies]
|
|
23
24
|
pytest = "^8.2.2"
|
|
24
|
-
ruff = "^0.
|
|
25
|
+
ruff = "^0.5.0"
|
|
25
26
|
pre-commit = "^3.7.1"
|
|
26
27
|
pytest-cov = "^5.0.0"
|
|
27
28
|
mkdocs = "^1.6.0"
|
|
@@ -29,7 +30,7 @@ mkdocs-material = "^9.5.26"
|
|
|
29
30
|
pydantic = "^2.12.5"
|
|
30
31
|
mypy = "^1.19.1"
|
|
31
32
|
types-aiofiles = "^23.2.0"
|
|
32
|
-
pytest-asyncio = "^0.23.
|
|
33
|
+
pytest-asyncio = "^0.23.7"
|
|
33
34
|
|
|
34
35
|
[build-system]
|
|
35
36
|
requires = ["poetry-core"]
|
|
@@ -37,7 +38,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
37
38
|
|
|
38
39
|
[project]
|
|
39
40
|
name = "coreason_manifest"
|
|
40
|
-
version = "0.
|
|
41
|
+
version = "0.5.0"
|
|
41
42
|
description = "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."
|
|
42
43
|
readme = "README.md"
|
|
43
44
|
requires-python = ">=3.11"
|
|
@@ -7,15 +7,23 @@ dictionaries, normalizing the data, and converting it into Pydantic models.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
import inspect
|
|
10
11
|
from pathlib import Path
|
|
11
|
-
from typing import Any, Union
|
|
12
|
+
from typing import Any, Callable, Dict, List, Union, get_type_hints
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from typing import get_args, get_origin
|
|
16
|
+
except ImportError: # pragma: no cover
|
|
17
|
+
# For Python < 3.8, though project requires 3.12+
|
|
18
|
+
from typing_extensions import get_args, get_origin # type: ignore
|
|
12
19
|
|
|
13
20
|
import aiofiles
|
|
14
21
|
import yaml
|
|
15
|
-
from
|
|
22
|
+
from coreason_identity import UserContext
|
|
23
|
+
from pydantic import ValidationError, create_model
|
|
16
24
|
|
|
17
25
|
from coreason_manifest.errors import ManifestSyntaxError
|
|
18
|
-
from coreason_manifest.models import AgentDefinition
|
|
26
|
+
from coreason_manifest.models import AgentDefinition, AgentInterface
|
|
19
27
|
|
|
20
28
|
|
|
21
29
|
class ManifestLoader:
|
|
@@ -156,3 +164,108 @@ class ManifestLoader:
|
|
|
156
164
|
while version and version[0] in ("v", "V"):
|
|
157
165
|
version = version[1:]
|
|
158
166
|
data["metadata"]["version"] = version
|
|
167
|
+
|
|
168
|
+
@staticmethod
|
|
169
|
+
def inspect_function(func: Callable[..., Any]) -> AgentInterface:
|
|
170
|
+
"""Generates an AgentInterface from a Python function.
|
|
171
|
+
|
|
172
|
+
Scans the function signature. If `user_context` (by name) or UserContext (by type)
|
|
173
|
+
is found, it is marked as injected and excluded from the public schema.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
func: The function to inspect.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
AgentInterface: The generated interface definition.
|
|
180
|
+
|
|
181
|
+
Raises:
|
|
182
|
+
ManifestSyntaxError: If forbidden arguments are found.
|
|
183
|
+
"""
|
|
184
|
+
sig = inspect.signature(func)
|
|
185
|
+
try:
|
|
186
|
+
type_hints = get_type_hints(func)
|
|
187
|
+
except Exception:
|
|
188
|
+
# Fallback if get_type_hints fails (e.g. forward refs issues)
|
|
189
|
+
type_hints = {}
|
|
190
|
+
|
|
191
|
+
field_definitions: Dict[str, Any] = {}
|
|
192
|
+
injected: List[str] = []
|
|
193
|
+
|
|
194
|
+
for param_name, param in sig.parameters.items():
|
|
195
|
+
if param_name in ("self", "cls"):
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
# Determine type annotation
|
|
199
|
+
annotation = type_hints.get(param_name, param.annotation)
|
|
200
|
+
if annotation is inspect.Parameter.empty:
|
|
201
|
+
annotation = Any
|
|
202
|
+
|
|
203
|
+
# Check for forbidden arguments
|
|
204
|
+
if param_name in ("api_key", "token"):
|
|
205
|
+
raise ManifestSyntaxError(f"Function argument '{param_name}' is forbidden. Use UserContext for auth.")
|
|
206
|
+
|
|
207
|
+
# Check for injection
|
|
208
|
+
is_injected = False
|
|
209
|
+
if param_name == "user_context":
|
|
210
|
+
is_injected = True
|
|
211
|
+
else:
|
|
212
|
+
# Check direct type
|
|
213
|
+
if annotation is UserContext:
|
|
214
|
+
is_injected = True
|
|
215
|
+
else:
|
|
216
|
+
# Check for Optional[UserContext], Annotated[UserContext, ...], Union[UserContext, ...]
|
|
217
|
+
origin = get_origin(annotation)
|
|
218
|
+
args = get_args(annotation)
|
|
219
|
+
if origin is not None:
|
|
220
|
+
# Recursively check if UserContext is in args (handles Optional/Union)
|
|
221
|
+
# or if this is Annotated (UserContext might be the first arg)
|
|
222
|
+
# We do a shallow check on args.
|
|
223
|
+
for arg in args:
|
|
224
|
+
if arg is UserContext:
|
|
225
|
+
is_injected = True
|
|
226
|
+
break
|
|
227
|
+
|
|
228
|
+
if is_injected:
|
|
229
|
+
if "user_context" not in injected:
|
|
230
|
+
injected.append("user_context")
|
|
231
|
+
continue
|
|
232
|
+
|
|
233
|
+
# Prepare for Pydantic model creation
|
|
234
|
+
default = param.default
|
|
235
|
+
if default is inspect.Parameter.empty:
|
|
236
|
+
default = ...
|
|
237
|
+
|
|
238
|
+
field_definitions[param_name] = (annotation, default)
|
|
239
|
+
|
|
240
|
+
# Create dynamic model to generate JSON Schema for inputs
|
|
241
|
+
# We assume strict mode or similar is handled by the consumer, here we just describe it.
|
|
242
|
+
try:
|
|
243
|
+
InputsModel = create_model("Inputs", **field_definitions)
|
|
244
|
+
inputs_schema = InputsModel.model_json_schema()
|
|
245
|
+
except Exception as e:
|
|
246
|
+
raise ManifestSyntaxError(f"Failed to generate schema from function signature: {e}") from e
|
|
247
|
+
|
|
248
|
+
# Handle return type for outputs
|
|
249
|
+
return_annotation = type_hints.get("return", sig.return_annotation)
|
|
250
|
+
outputs_schema = {}
|
|
251
|
+
if (
|
|
252
|
+
return_annotation is not inspect.Parameter.empty
|
|
253
|
+
and return_annotation is not None
|
|
254
|
+
and return_annotation is not type(None)
|
|
255
|
+
):
|
|
256
|
+
try:
|
|
257
|
+
# If return annotation is a Pydantic model, use its schema
|
|
258
|
+
if hasattr(return_annotation, "model_json_schema"):
|
|
259
|
+
outputs_schema = return_annotation.model_json_schema()
|
|
260
|
+
else:
|
|
261
|
+
# Wrap in a model
|
|
262
|
+
OutputsModel = create_model("Outputs", result=(return_annotation, ...))
|
|
263
|
+
outputs_schema = OutputsModel.model_json_schema()
|
|
264
|
+
except Exception:
|
|
265
|
+
pass
|
|
266
|
+
|
|
267
|
+
return AgentInterface(
|
|
268
|
+
inputs=inputs_schema,
|
|
269
|
+
outputs=outputs_schema,
|
|
270
|
+
injected_params=injected,
|
|
271
|
+
)
|
|
@@ -20,6 +20,7 @@ from pydantic import (
|
|
|
20
20
|
Field,
|
|
21
21
|
PlainSerializer,
|
|
22
22
|
field_validator,
|
|
23
|
+
model_validator,
|
|
23
24
|
)
|
|
24
25
|
from typing_extensions import Annotated
|
|
25
26
|
|
|
@@ -86,6 +87,7 @@ class AgentMetadata(BaseModel):
|
|
|
86
87
|
name: str = Field(..., min_length=1, description="Name of the Agent.")
|
|
87
88
|
author: str = Field(..., min_length=1, description="Author of the Agent.")
|
|
88
89
|
created_at: datetime = Field(..., description="Creation timestamp (ISO 8601).")
|
|
90
|
+
requires_auth: bool = Field(default=False, description="Whether the agent requires user authentication.")
|
|
89
91
|
|
|
90
92
|
|
|
91
93
|
class AgentInterface(BaseModel):
|
|
@@ -100,6 +102,7 @@ class AgentInterface(BaseModel):
|
|
|
100
102
|
|
|
101
103
|
inputs: ImmutableDict = Field(..., description="Typed arguments the agent accepts (JSON Schema).")
|
|
102
104
|
outputs: ImmutableDict = Field(..., description="Typed structure of the result.")
|
|
105
|
+
injected_params: List[str] = Field(default_factory=list, description="List of parameters injected by the system.")
|
|
103
106
|
|
|
104
107
|
|
|
105
108
|
class Step(BaseModel):
|
|
@@ -218,3 +221,11 @@ class AgentDefinition(BaseModel):
|
|
|
218
221
|
pattern=r"^[a-fA-F0-9]{64}$",
|
|
219
222
|
description="SHA256 hash of the source code.",
|
|
220
223
|
)
|
|
224
|
+
|
|
225
|
+
@model_validator(mode="after")
|
|
226
|
+
def validate_auth_requirements(self) -> AgentDefinition:
|
|
227
|
+
"""Validate that agents requiring auth have user_context injected."""
|
|
228
|
+
if self.metadata.requires_auth:
|
|
229
|
+
if "user_context" not in self.interface.injected_params:
|
|
230
|
+
raise ValueError("Agent requires authentication but 'user_context' is not an injected parameter.")
|
|
231
|
+
return self
|
{coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/schemas/agent.schema.json
RENAMED
|
@@ -41,6 +41,14 @@
|
|
|
41
41
|
"description": "Typed structure of the result.",
|
|
42
42
|
"title": "Outputs",
|
|
43
43
|
"type": "object"
|
|
44
|
+
},
|
|
45
|
+
"injected_params": {
|
|
46
|
+
"description": "List of parameters injected by the system.",
|
|
47
|
+
"items": {
|
|
48
|
+
"type": "string"
|
|
49
|
+
},
|
|
50
|
+
"title": "Injected Params",
|
|
51
|
+
"type": "array"
|
|
44
52
|
}
|
|
45
53
|
},
|
|
46
54
|
"required": [
|
|
@@ -83,6 +91,12 @@
|
|
|
83
91
|
"format": "date-time",
|
|
84
92
|
"title": "Created At",
|
|
85
93
|
"type": "string"
|
|
94
|
+
},
|
|
95
|
+
"requires_auth": {
|
|
96
|
+
"default": false,
|
|
97
|
+
"description": "Whether the agent requires user authentication.",
|
|
98
|
+
"title": "Requires Auth",
|
|
99
|
+
"type": "boolean"
|
|
86
100
|
}
|
|
87
101
|
},
|
|
88
102
|
"required": [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/policies/compliance.rego
RENAMED
|
File without changes
|
{coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/policies/tbom.json
RENAMED
|
File without changes
|
|
File without changes
|
{coreason_manifest-0.4.0 → coreason_manifest-0.5.0}/src/coreason_manifest/schemas/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|