safentic 1.0.5__tar.gz → 1.0.6__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 (56) hide show
  1. {safentic-1.0.5/safentic → safentic-1.0.6}/LICENSE.txt +36 -36
  2. safentic-1.0.6/MANIFEST.in +15 -0
  3. safentic-1.0.6/PKG-INFO +193 -0
  4. safentic-1.0.6/README.md +160 -0
  5. safentic-1.0.6/pyproject.toml +55 -0
  6. safentic-1.0.6/requirements/constraints.txt +16 -0
  7. safentic-1.0.6/requirements/requirements-dev.txt +21 -0
  8. {safentic-1.0.5 → safentic-1.0.6/requirements}/requirements.txt +9 -10
  9. safentic-1.0.6/safentic/__init__.py +5 -0
  10. safentic-1.0.6/safentic/_internal/errors.py +26 -0
  11. safentic-1.0.6/safentic/adapters/mcp_adapter.py +46 -0
  12. safentic-1.0.6/safentic/cli/__init__.py +3 -0
  13. safentic-1.0.6/safentic/cli/commands/check_tool.py +47 -0
  14. safentic-1.0.6/safentic/cli/commands/logs.py +66 -0
  15. safentic-1.0.6/safentic/cli/commands/validate_policy.py +59 -0
  16. safentic-1.0.6/safentic/cli/main.py +153 -0
  17. safentic-1.0.6/safentic/cli/utils.py +169 -0
  18. {safentic-1.0.5 → safentic-1.0.6}/safentic/config.py +2 -2
  19. safentic-1.0.6/safentic/decorators.py +49 -0
  20. safentic-1.0.6/safentic/helper/helper.py +212 -0
  21. safentic-1.0.6/safentic/layer.py +96 -0
  22. safentic-1.0.6/safentic/logger/audit.py +181 -0
  23. safentic-1.0.6/safentic/policy_enforcer.py +116 -0
  24. safentic-1.0.6/safentic/policy_engine.py +141 -0
  25. safentic-1.0.6/safentic/verifiers/llm_verifier.py +238 -0
  26. safentic-1.0.6/safentic.egg-info/PKG-INFO +193 -0
  27. safentic-1.0.6/safentic.egg-info/SOURCES.txt +36 -0
  28. safentic-1.0.6/safentic.egg-info/entry_points.txt +2 -0
  29. safentic-1.0.6/safentic.egg-info/requires.txt +20 -0
  30. safentic-1.0.6/safentic.egg-info/top_level.txt +2 -0
  31. safentic-1.0.6/safentic_poc/backend/api/__init__.py +0 -0
  32. safentic-1.0.6/safentic_poc/backend/api/main.py +164 -0
  33. {safentic-1.0.5 → safentic-1.0.6}/setup.cfg +4 -4
  34. safentic-1.0.5/MANIFEST.in +0 -18
  35. safentic-1.0.5/PKG-INFO +0 -60
  36. safentic-1.0.5/README.md +0 -33
  37. safentic-1.0.5/safentic/__init__.py +0 -8
  38. safentic-1.0.5/safentic/engine.py +0 -92
  39. safentic-1.0.5/safentic/helper/auth.py +0 -12
  40. safentic-1.0.5/safentic/layer.py +0 -69
  41. safentic-1.0.5/safentic/logger/audit.py +0 -83
  42. safentic-1.0.5/safentic/policies/__init__.py +0 -3
  43. safentic-1.0.5/safentic/policies/example_policy.txt +0 -33
  44. safentic-1.0.5/safentic/policies/policy.yaml +0 -49
  45. safentic-1.0.5/safentic/policy.py +0 -102
  46. safentic-1.0.5/safentic/verifiers/sentence_verifier.py +0 -69
  47. safentic-1.0.5/safentic.egg-info/PKG-INFO +0 -60
  48. safentic-1.0.5/safentic.egg-info/SOURCES.txt +0 -25
  49. safentic-1.0.5/safentic.egg-info/requires.txt +0 -5
  50. safentic-1.0.5/safentic.egg-info/top_level.txt +0 -2
  51. safentic-1.0.5/setup.py +0 -27
  52. {safentic-1.0.5 → safentic-1.0.6}/safentic/helper/__init__.py +0 -0
  53. {safentic-1.0.5 → safentic-1.0.6}/safentic/logger/__init__.py +0 -0
  54. {safentic-1.0.5 → safentic-1.0.6}/safentic/verifiers/__init__.py +0 -0
  55. {safentic-1.0.5 → safentic-1.0.6}/safentic.egg-info/dependency_links.txt +0 -0
  56. /safentic-1.0.5/safentic/policies/.gitkeep → /safentic-1.0.6/safentic_poc/backend/__init__.py +0 -0
@@ -1,36 +1,36 @@
1
- Safentic SDK Commercial License Agreement
2
- =========================================
3
-
4
- IMPORTANT – READ CAREFULLY:
5
-
6
- This license governs the use of the Safentic SDK (“Software”) developed and owned by Safentic. By installing or using this Software, you (“Licensee”) agree to the following terms and conditions:
7
-
8
- 1. GRANT OF LICENSE
9
- Licensor grants Licensee a non-exclusive, non-transferable, non-sublicensable license to use the Software solely for internal business purposes and only in accordance with the terms of the commercial agreement executed between the parties. This license may include limited evaluation rights, subject to expiration or usage restrictions.
10
-
11
- 2. RESTRICTIONS
12
- Licensee shall NOT:
13
- - Use the Software without a valid, active license key or subscription.
14
- - Reverse engineer, decompile, or disassemble the Software.
15
- - Modify, copy, or create derivative works based on the Software.
16
- - Distribute, sublicense, lease, or otherwise make the Software available to any third party.
17
- - Circumvent or attempt to disable any license verification, telemetry, or access control mechanisms.
18
-
19
- 3. OWNERSHIP
20
- The Software is licensed, not sold. Safentic retains all rights, title, and interest in and to the Software, including all intellectual property rights.
21
-
22
- 4. TERMINATION
23
- This license is effective until terminated. It will terminate automatically without notice if Licensee breaches any term of this agreement. Upon termination, Licensee must cease all use and destroy all copies of the Software.
24
-
25
- 5. NO WARRANTY
26
- The Software is provided "as is" without warranty of any kind. Licensor disclaims all warranties, express or implied, including but not limited to warranties of merchantability and fitness for a particular purpose.
27
-
28
- 6. LIMITATION OF LIABILITY
29
- In no event shall Licensor be liable for any damages arising out of the use or inability to use the Software, including but not limited to incidental, special, or consequential damages.
30
-
31
- 7. GOVERNING LAW
32
- This agreement shall be governed by and construed in accordance with the laws of Ireland, without regard to its conflict of law principles.
33
-
34
- For licensing inquiries, please contact: contact@safentic.com
35
-
36
- Copyright © 2025, Safentic. All rights reserved.
1
+ Safentic SDK Commercial License Agreement
2
+ =========================================
3
+
4
+ IMPORTANT – READ CAREFULLY:
5
+
6
+ This license governs the use of the Safentic SDK (“Software”) developed and owned by Safentic. By installing or using this Software, you (“Licensee”) agree to the following terms and conditions:
7
+
8
+ 1. GRANT OF LICENSE
9
+ Licensor grants Licensee a non-exclusive, non-transferable, non-sublicensable license to use the Software solely for internal business purposes and only in accordance with the terms of the commercial agreement executed between the parties. This license may include limited evaluation rights, subject to expiration or usage restrictions.
10
+
11
+ 2. RESTRICTIONS
12
+ Licensee shall NOT:
13
+ - Use the Software without a valid, active license key or subscription.
14
+ - Reverse engineer, decompile, or disassemble the Software.
15
+ - Modify, copy, or create derivative works based on the Software.
16
+ - Distribute, sublicense, lease, or otherwise make the Software available to any third party.
17
+ - Circumvent or attempt to disable any license verification, telemetry, or access control mechanisms.
18
+
19
+ 3. OWNERSHIP
20
+ The Software is licensed, not sold. Safentic retains all rights, title, and interest in and to the Software, including all intellectual property rights.
21
+
22
+ 4. TERMINATION
23
+ This license is effective until terminated. It will terminate automatically without notice if Licensee breaches any term of this agreement. Upon termination, Licensee must cease all use and destroy all copies of the Software.
24
+
25
+ 5. NO WARRANTY
26
+ The Software is provided "as is" without warranty of any kind. Licensor disclaims all warranties, express or implied, including but not limited to warranties of merchantability and fitness for a particular purpose.
27
+
28
+ 6. LIMITATION OF LIABILITY
29
+ In no event shall Licensor be liable for any damages arising out of the use or inability to use the Software, including but not limited to incidental, special, or consequential damages.
30
+
31
+ 7. GOVERNING LAW
32
+ This agreement shall be governed by and construed in accordance with the laws of Ireland, without regard to its conflict of law principles.
33
+
34
+ For licensing inquiries, please contact: contact@safentic.com
35
+
36
+ Copyright © 2025, Safentic. All rights reserved.
@@ -0,0 +1,15 @@
1
+ # Essentials
2
+ include LICENSE.txt
3
+ include README.md
4
+ include setup.py
5
+ include pyproject.toml
6
+ include requirements/requirements.txt
7
+ include requirements/requirements-dev.txt
8
+ include requirements/constraints.txt
9
+
10
+ # Include all relevant files inside safentic package
11
+ recursive-include safentic *.py *.txt *.yaml *.yml
12
+
13
+ # Ignore tests and cache
14
+ prune tests
15
+ global-exclude __pycache__ *.py[cod] *.pyo
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.4
2
+ Name: safentic
3
+ Version: 1.0.6
4
+ Summary: Safentic SDK for AI agent runtime enforcement interception.
5
+ Author-email: Safentic <contact@safentic.com>
6
+ License-Expression: LicenseRef-Proprietary
7
+ Project-URL: Homepage, https://safentic.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE.txt
13
+ Requires-Dist: PyYAML
14
+ Requires-Dist: langchain
15
+ Requires-Dist: langchain-community
16
+ Requires-Dist: langchain-openai
17
+ Requires-Dist: openai
18
+ Requires-Dist: python-dotenv
19
+ Requires-Dist: sentence-transformers==3.2.1
20
+ Requires-Dist: requests
21
+ Requires-Dist: SQLAlchemy
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest; extra == "dev"
24
+ Requires-Dist: coverage; extra == "dev"
25
+ Requires-Dist: black; extra == "dev"
26
+ Requires-Dist: isort; extra == "dev"
27
+ Requires-Dist: ruff; extra == "dev"
28
+ Requires-Dist: mypy; extra == "dev"
29
+ Requires-Dist: pip-audit-extra; extra == "dev"
30
+ Requires-Dist: types-requests; extra == "dev"
31
+ Requires-Dist: types-PyYAML; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # Safentic SDK
35
+
36
+ - **Safentic is a runtime guardrail SDK for agentic AI systems.**
37
+ - It intercepts and evaluates tool calls between agent intent and execution, enforcing custom safety policies and generating structured audit logs for compliance.
38
+
39
+ ## Installation
40
+ `pip install safentic`
41
+
42
+ # Quickstart: Wrap Your Agent
43
+
44
+ - Safentic works at the action boundary, not inside the model itself. You wrap your agent with SafetyLayer:
45
+
46
+ ```
47
+ from safentic.layer import SafetyLayer
48
+ from agent import AgentClassInstance # your existing agent
49
+
50
+ agent = AgentClassInstance()
51
+ ```
52
+
53
+ ## Wrap with Safentic
54
+ ``` layer = SafetyLayer(agent=agent, api_key="your-api-key", agent_id="demo-agent") ```
55
+
56
+ ## Example tool call
57
+ ```
58
+ try:
59
+ result = layer.call_tool("some_tool", {"body": "example input"})
60
+ print(result)
61
+ except Exception as e:
62
+ print("Blocked:", e)
63
+ ```
64
+
65
+ ## Output:
66
+
67
+ - Blocked: Blocked by policy
68
+
69
+ # Configuring Your Policy File
70
+
71
+ - Safentic enforces rules defined in a YAML configuration file (e.g. policy.yaml).
72
+ - By default, it looks for config/policy.yaml, or you can set the path with:
73
+
74
+ ```
75
+ export SAFENTIC_POLICY_PATH=/path/to/policy.yaml
76
+ ```
77
+
78
+ ## Schema
79
+
80
+ - At the moment, Safentic supports the llm_verifier rule type.
81
+
82
+ ```
83
+ tools:
84
+ <tool_name>:
85
+ rules:
86
+ - type: llm_verifier
87
+ description: "<short description of what this rule enforces>"
88
+ instruction: "<prompt instruction given to the verifier LLM>"
89
+ model: "<llm model name, e.g. gpt-4>"
90
+ fields: [<list of input fields to check>]
91
+ reference_file: "<path to reference text file, optional>"
92
+ response_format: boolean
93
+ response_trigger: yes
94
+ match_mode: exact
95
+ level: block # enforcement level: block | warn
96
+ severity: high # severity: low | medium | high
97
+ tags: [<labels for filtering/searching logs>]
98
+
99
+ logging:
100
+ level: INFO
101
+ destination: "safentic/logs/txt_logs/safentic_audit.log"
102
+ jsonl: "safentic/logs/json_logs/safentic_audit.jsonl"
103
+
104
+ Example Policy (obfuscated)
105
+ tools:
106
+ sample_tool:
107
+ rules:
108
+ - type: llm_verifier
109
+ description: "Block outputs that contain disallowed terms"
110
+ instruction: "Does this text contain disallowed terms or references?"
111
+ model: gpt-4
112
+ fields: [body]
113
+ reference_file: sample_guidelines.txt
114
+ response_format: boolean
115
+ response_trigger: yes
116
+ match_mode: exact
117
+ level: block
118
+ severity: high
119
+ tags: [sample, denylist]
120
+
121
+ another_tool:
122
+ rules: [] # Explicitly allow all actions for this tool
123
+
124
+ logging:
125
+ level: INFO
126
+ destination: "safentic/logs/txt_logs/safentic_audit.log"
127
+ jsonl: "safentic/logs/json_logs/safentic_audit.jsonl"
128
+ ```
129
+
130
+ ## Audit Logs
131
+
132
+ - Every decision is logged with context for compliance and debugging:
133
+
134
+ ```
135
+ {
136
+ "timestamp": "2025-09-09T14:25:11Z",
137
+ "agent_id": "demo-agent",
138
+ "tool": "sample_tool",
139
+ "allowed": false,
140
+ "reason": "Blocked by policy",
141
+ "rule": "sample_tool:denylist_check",
142
+ "severity": "high",
143
+ "level": "block",
144
+ "tags": ["sample", "denylist"]
145
+ }
146
+ ```
147
+
148
+ ### Log Fields
149
+
150
+ - timestamp – when the action was evaluated
151
+ - agent_id – the agent issuing the action
152
+ - tool – tool name
153
+ - allowed – whether the action was permitted
154
+ - reason – why it was allowed or blocked
155
+ - rule – the rule that applied (if any)
156
+ - severity – severity of the violation
157
+ - level – enforcement level (block, warn)
158
+ - tags – categories attached to the rule
159
+ - extra – additional metadata (e.g., missing fields, matched text)
160
+
161
+ # CLI Commands
162
+
163
+ - Safentic ships with a CLI for validating policies, running one-off checks, and inspecting logs:
164
+
165
+ ## Validate a policy file
166
+ ```
167
+ safentic validate-policy --policy config/policy.yaml --strict
168
+ ```
169
+
170
+ ## Run a one-off tool check
171
+ ```
172
+ safentic check-tool --tool sample_tool \
173
+ --input-json '{"body": "some text"}' \
174
+ --policy config/policy.yaml
175
+ ```
176
+ ## Tail the audit log (JSONL by default)
177
+ ```
178
+ safentic logs tail --path safentic/logs/json_logs/safentic_audit.jsonl -f
179
+ ```
180
+
181
+ ## Environment Variables
182
+
183
+ Set these before running Safentic:
184
+
185
+ - ```OPENAI_API_KEY``` – **required** for rules that use llm_verifier (e.g., GPT-4).
186
+ - ```SAFENTIC_POLICY_PATH``` – path to your policy.yaml (default: config/policy.yaml).
187
+ - ```SAFENTIC_LOG_PATH``` – override the default text audit log path.
188
+ - ```SAFENTIC_JSON_LOG_PATH``` – override the default JSONL audit log path.
189
+ - ```LOG_LEVEL``` – optional, sets verbosity (DEBUG, INFO, etc.).
190
+
191
+ # Supported Stacks
192
+
193
+ - Safentic integrates with frameworks like LangChain, AutoGen, and MCP by wrapping the tool dispatcher rather than modifying the model or prompts.
@@ -0,0 +1,160 @@
1
+ # Safentic SDK
2
+
3
+ - **Safentic is a runtime guardrail SDK for agentic AI systems.**
4
+ - It intercepts and evaluates tool calls between agent intent and execution, enforcing custom safety policies and generating structured audit logs for compliance.
5
+
6
+ ## Installation
7
+ `pip install safentic`
8
+
9
+ # Quickstart: Wrap Your Agent
10
+
11
+ - Safentic works at the action boundary, not inside the model itself. You wrap your agent with SafetyLayer:
12
+
13
+ ```
14
+ from safentic.layer import SafetyLayer
15
+ from agent import AgentClassInstance # your existing agent
16
+
17
+ agent = AgentClassInstance()
18
+ ```
19
+
20
+ ## Wrap with Safentic
21
+ ``` layer = SafetyLayer(agent=agent, api_key="your-api-key", agent_id="demo-agent") ```
22
+
23
+ ## Example tool call
24
+ ```
25
+ try:
26
+ result = layer.call_tool("some_tool", {"body": "example input"})
27
+ print(result)
28
+ except Exception as e:
29
+ print("Blocked:", e)
30
+ ```
31
+
32
+ ## Output:
33
+
34
+ - Blocked: Blocked by policy
35
+
36
+ # Configuring Your Policy File
37
+
38
+ - Safentic enforces rules defined in a YAML configuration file (e.g. policy.yaml).
39
+ - By default, it looks for config/policy.yaml, or you can set the path with:
40
+
41
+ ```
42
+ export SAFENTIC_POLICY_PATH=/path/to/policy.yaml
43
+ ```
44
+
45
+ ## Schema
46
+
47
+ - At the moment, Safentic supports the llm_verifier rule type.
48
+
49
+ ```
50
+ tools:
51
+ <tool_name>:
52
+ rules:
53
+ - type: llm_verifier
54
+ description: "<short description of what this rule enforces>"
55
+ instruction: "<prompt instruction given to the verifier LLM>"
56
+ model: "<llm model name, e.g. gpt-4>"
57
+ fields: [<list of input fields to check>]
58
+ reference_file: "<path to reference text file, optional>"
59
+ response_format: boolean
60
+ response_trigger: yes
61
+ match_mode: exact
62
+ level: block # enforcement level: block | warn
63
+ severity: high # severity: low | medium | high
64
+ tags: [<labels for filtering/searching logs>]
65
+
66
+ logging:
67
+ level: INFO
68
+ destination: "safentic/logs/txt_logs/safentic_audit.log"
69
+ jsonl: "safentic/logs/json_logs/safentic_audit.jsonl"
70
+
71
+ Example Policy (obfuscated)
72
+ tools:
73
+ sample_tool:
74
+ rules:
75
+ - type: llm_verifier
76
+ description: "Block outputs that contain disallowed terms"
77
+ instruction: "Does this text contain disallowed terms or references?"
78
+ model: gpt-4
79
+ fields: [body]
80
+ reference_file: sample_guidelines.txt
81
+ response_format: boolean
82
+ response_trigger: yes
83
+ match_mode: exact
84
+ level: block
85
+ severity: high
86
+ tags: [sample, denylist]
87
+
88
+ another_tool:
89
+ rules: [] # Explicitly allow all actions for this tool
90
+
91
+ logging:
92
+ level: INFO
93
+ destination: "safentic/logs/txt_logs/safentic_audit.log"
94
+ jsonl: "safentic/logs/json_logs/safentic_audit.jsonl"
95
+ ```
96
+
97
+ ## Audit Logs
98
+
99
+ - Every decision is logged with context for compliance and debugging:
100
+
101
+ ```
102
+ {
103
+ "timestamp": "2025-09-09T14:25:11Z",
104
+ "agent_id": "demo-agent",
105
+ "tool": "sample_tool",
106
+ "allowed": false,
107
+ "reason": "Blocked by policy",
108
+ "rule": "sample_tool:denylist_check",
109
+ "severity": "high",
110
+ "level": "block",
111
+ "tags": ["sample", "denylist"]
112
+ }
113
+ ```
114
+
115
+ ### Log Fields
116
+
117
+ - timestamp – when the action was evaluated
118
+ - agent_id – the agent issuing the action
119
+ - tool – tool name
120
+ - allowed – whether the action was permitted
121
+ - reason – why it was allowed or blocked
122
+ - rule – the rule that applied (if any)
123
+ - severity – severity of the violation
124
+ - level – enforcement level (block, warn)
125
+ - tags – categories attached to the rule
126
+ - extra – additional metadata (e.g., missing fields, matched text)
127
+
128
+ # CLI Commands
129
+
130
+ - Safentic ships with a CLI for validating policies, running one-off checks, and inspecting logs:
131
+
132
+ ## Validate a policy file
133
+ ```
134
+ safentic validate-policy --policy config/policy.yaml --strict
135
+ ```
136
+
137
+ ## Run a one-off tool check
138
+ ```
139
+ safentic check-tool --tool sample_tool \
140
+ --input-json '{"body": "some text"}' \
141
+ --policy config/policy.yaml
142
+ ```
143
+ ## Tail the audit log (JSONL by default)
144
+ ```
145
+ safentic logs tail --path safentic/logs/json_logs/safentic_audit.jsonl -f
146
+ ```
147
+
148
+ ## Environment Variables
149
+
150
+ Set these before running Safentic:
151
+
152
+ - ```OPENAI_API_KEY``` – **required** for rules that use llm_verifier (e.g., GPT-4).
153
+ - ```SAFENTIC_POLICY_PATH``` – path to your policy.yaml (default: config/policy.yaml).
154
+ - ```SAFENTIC_LOG_PATH``` – override the default text audit log path.
155
+ - ```SAFENTIC_JSON_LOG_PATH``` – override the default JSONL audit log path.
156
+ - ```LOG_LEVEL``` – optional, sets verbosity (DEBUG, INFO, etc.).
157
+
158
+ # Supported Stacks
159
+
160
+ - Safentic integrates with frameworks like LangChain, AutoGen, and MCP by wrapping the tool dispatcher rather than modifying the model or prompts.
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "safentic"
3
+ version = "1.0.6"
4
+ description = "Safentic SDK for AI agent runtime enforcement interception."
5
+ authors = [{ name = "Safentic", email = "contact@safentic.com" }]
6
+ readme = "README.md"
7
+ license = "LicenseRef-Proprietary" # SPDX-compatible custom license
8
+ requires-python = ">=3.10"
9
+
10
+ dependencies = [
11
+ "PyYAML",
12
+ "langchain",
13
+ "langchain-community",
14
+ "langchain-openai",
15
+ "openai",
16
+ "python-dotenv",
17
+ "sentence-transformers==3.2.1",
18
+ "requests",
19
+ "SQLAlchemy"
20
+ ]
21
+
22
+ classifiers = [
23
+ "Programming Language :: Python :: 3",
24
+ "Operating System :: OS Independent"
25
+ ]
26
+
27
+ [project.optional-dependencies]
28
+ dev = [
29
+ "pytest",
30
+ "coverage",
31
+ "black",
32
+ "isort",
33
+ "ruff",
34
+ "mypy",
35
+ "pip-audit-extra",
36
+ "types-requests",
37
+ "types-PyYAML"
38
+ ]
39
+
40
+ [project.urls]
41
+ Homepage = "https://safentic.com"
42
+
43
+ [project.scripts]
44
+ safentic = "safentic.cli.main:main"
45
+
46
+ [tool.setuptools.packages.find]
47
+ include = ["safentic*"]
48
+ exclude = ["config", "integrations", "safentic_poc", "policy_file_docs"]
49
+
50
+ [tool.setuptools]
51
+ license-files = ["LICENSE.txt"]
52
+
53
+ [build-system]
54
+ requires = ["setuptools>=61", "wheel"]
55
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,16 @@
1
+ # requirements/constraints.txt
2
+
3
+ # Security guardrails (transitives)
4
+ aiohttp>=3.12.14
5
+ pillow>=11.3.0
6
+ transformers>=4.53.0
7
+ torch!=2.7.1
8
+
9
+ # Core dependencies
10
+ PyYAML>=6.0.2
11
+ requests>=2.32.0
12
+ SQLAlchemy>=2.0.0
13
+ langchain>=0.2.16
14
+ langchain-community>=0.2.16
15
+ langchain-openai>=0.1.20
16
+ openai>=1.40.0
@@ -0,0 +1,21 @@
1
+ # requirements/requirements-dev.txt
2
+
3
+ # Pull in the SDK/runtime deps (relative to THIS file)
4
+ -r requirements.txt
5
+
6
+ # Testing
7
+ pytest
8
+ coverage
9
+
10
+ # Formatting / linting / typing
11
+ black
12
+ isort
13
+ ruff
14
+ mypy
15
+
16
+ # Security auditing
17
+ pip-audit-extra
18
+
19
+ # Type stubs
20
+ types-requests
21
+ types-PyYAML
@@ -1,10 +1,9 @@
1
- PyYAML
2
- langchain
3
- langchain-community
4
- langchain-openai
5
- openai
6
- python-dotenv
7
- sentence-transformers==3.2.1
8
- pyautogen
9
- pytest
10
- coverage
1
+ PyYAML
2
+ langchain
3
+ langchain-community
4
+ langchain-openai
5
+ openai
6
+ python-dotenv
7
+ sentence-transformers==3.2.1
8
+ requests
9
+ SQLAlchemy
@@ -0,0 +1,5 @@
1
+ from .layer import SafetyLayer
2
+ from ._internal.errors import SafenticError
3
+
4
+ __all__ = ["SafetyLayer", "SafenticError"]
5
+ __version__ = "1.0.6"
@@ -0,0 +1,26 @@
1
+ class SafenticError(Exception):
2
+ """Base class for all Safentic errors."""
3
+
4
+
5
+ class PolicyValidationError(SafenticError):
6
+ """Raised when a policy file or rule is invalid."""
7
+
8
+
9
+ class ReferenceFileError(SafenticError):
10
+ """Raised when a reference file is missing, unreadable, or empty."""
11
+
12
+
13
+ class EnforcementError(SafenticError):
14
+ """Raised when enforcement fails unexpectedly."""
15
+
16
+
17
+ class VerifierError(SafenticError):
18
+ """Raised when the LLM verifier fails unexpectedly."""
19
+
20
+
21
+ class InvalidAPIKeyError(SafenticError):
22
+ """Raised when an API key is missing or invalid."""
23
+
24
+
25
+ class InvalidAgentInterfaceError(SafenticError):
26
+ """Raised when the wrapped agent doesn't expose the expected interface."""
@@ -0,0 +1,46 @@
1
+ from typing import Any, Dict, Mapping, cast
2
+ from safentic.policy_enforcer import PolicyEnforcer
3
+
4
+
5
+ def handle_mcp_action(
6
+ action_request: Mapping[str, Any], enforcer: PolicyEnforcer
7
+ ) -> Dict[str, Any]:
8
+ """
9
+ Accepts an MCP ActionRequest and returns a Safentic policy enforcement result.
10
+ Requires a PolicyEnforcer instance to be passed in.
11
+
12
+ Expected shape (minimal):
13
+ {
14
+ "tool": {
15
+ "name": str,
16
+ "input": dict[str, Any]
17
+ },
18
+ "agent": {
19
+ "id": str
20
+ }
21
+ }
22
+ """
23
+
24
+ tool: Dict[str, Any] = cast(Dict[str, Any], action_request.get("tool", {}))
25
+ agent: Dict[str, Any] = cast(Dict[str, Any], action_request.get("agent", {}))
26
+
27
+ tool_name: str = cast(str, tool.get("name", "unknown_tool"))
28
+ tool_args: Dict[str, Any] = cast(
29
+ Dict[str, Any], tool.get("input", {})
30
+ ) # Expected to include "body" or "note"
31
+ agent_id: str = cast(str, agent.get("id", "unknown_agent"))
32
+
33
+ result: Dict[str, Any] = enforcer.enforce(
34
+ agent_id=agent_id,
35
+ tool_name=tool_name,
36
+ tool_args=tool_args,
37
+ )
38
+
39
+ return {
40
+ "tool": tool_name,
41
+ "agent_id": agent_id,
42
+ "allowed": result["allowed"],
43
+ "reason": result["reason"],
44
+ "agent_state": result.get("agent_state", {}),
45
+ "violation": result.get("violation"), # Optional violation metadata
46
+ }
@@ -0,0 +1,3 @@
1
+ from typing import List
2
+
3
+ __all__: List[str] = []
@@ -0,0 +1,47 @@
1
+ from typing import Any, Dict, Optional
2
+
3
+ from safentic.policy_engine import PolicyEngine
4
+ from safentic.policy_enforcer import PolicyEnforcer
5
+ from safentic.cli.utils import resolve_policy_path, load_json_arg, ok, error
6
+
7
+
8
+ def run(
9
+ policy: Optional[str],
10
+ tool_name: str,
11
+ agent_id: str,
12
+ input_json: Optional[str],
13
+ input_file: Optional[str],
14
+ dry_run: bool,
15
+ allow_fail: bool,
16
+ no_llm: bool = False,
17
+ ) -> Dict[str, Any]:
18
+ """
19
+ Run a one-off policy enforcement for a tool + payload.
20
+ Returns a JSON payload. Raises SystemExit(2) if blocked and allow_fail=False.
21
+ """
22
+ policy_path = resolve_policy_path(policy)
23
+
24
+ try:
25
+ engine = PolicyEngine(policy_path=policy_path, dry_run=dry_run, no_llm=no_llm)
26
+ enforcer = PolicyEnforcer(policy_engine=engine)
27
+
28
+ payload: Dict[str, Any] = load_json_arg(input_json, input_file)
29
+ decision = enforcer.enforce(
30
+ agent_id=agent_id, tool_name=tool_name, tool_args=payload
31
+ )
32
+
33
+ result = ok(
34
+ f"Check completed for tool: {tool_name}",
35
+ {"policy_path": policy_path, "decision": decision},
36
+ )
37
+
38
+ if not decision.get("allowed", False) and not allow_fail:
39
+ # Signal to CI callers that this is a block
40
+ raise SystemExit(2)
41
+
42
+ return result
43
+
44
+ except SystemExit:
45
+ raise
46
+ except Exception as e:
47
+ return error("check-tool failed", {"details": str(e)})