atbash-hermes-plugin 0.1.7.dev0__tar.gz → 0.1.8.dev0__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.
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/PKG-INFO +4 -4
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/README.md +2 -2
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin/__init__.py +102 -7
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin.egg-info/PKG-INFO +4 -4
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin.egg-info/requires.txt +1 -1
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/pyproject.toml +2 -2
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/LICENSE +0 -0
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin.egg-info/SOURCES.txt +0 -0
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin.egg-info/dependency_links.txt +0 -0
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin.egg-info/entry_points.txt +0 -0
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin.egg-info/top_level.txt +0 -0
- {atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atbash-hermes-plugin
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8.dev0
|
|
4
4
|
Summary: Atbash safety plugin for Hermes Agent
|
|
5
5
|
Author: atbash
|
|
6
6
|
License-Expression: LicenseRef-Atbash-Proprietary
|
|
@@ -10,7 +10,7 @@ Keywords: atbash,hermes,hermes-agent,agent-safety,ai-safety,tool-guard,judge,pol
|
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: atbash-sdk==0.1.
|
|
13
|
+
Requires-Dist: atbash-sdk==0.1.8.dev0
|
|
14
14
|
Requires-Dist: httpx<1,>=0.27
|
|
15
15
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http<2,>=1.29
|
|
16
16
|
Requires-Dist: opentelemetry-sdk<2,>=1.29
|
|
@@ -38,13 +38,13 @@ stopped before execution.
|
|
|
38
38
|
Install the plugin into the same Python environment that runs Hermes:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
pip install --pre atbash-hermes-plugin==0.1.
|
|
41
|
+
pip install --pre atbash-hermes-plugin==0.1.8.dev0
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
If Hermes is installed in a virtual environment, use that environment's Python:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
/path/to/hermes/venv/bin/python -m pip install --pre atbash-hermes-plugin==0.1.
|
|
47
|
+
/path/to/hermes/venv/bin/python -m pip install --pre atbash-hermes-plugin==0.1.8.dev0
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
## Configure Atbash
|
|
@@ -20,13 +20,13 @@ stopped before execution.
|
|
|
20
20
|
Install the plugin into the same Python environment that runs Hermes:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
pip install --pre atbash-hermes-plugin==0.1.
|
|
23
|
+
pip install --pre atbash-hermes-plugin==0.1.8.dev0
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
If Hermes is installed in a virtual environment, use that environment's Python:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
/path/to/hermes/venv/bin/python -m pip install --pre atbash-hermes-plugin==0.1.
|
|
29
|
+
/path/to/hermes/venv/bin/python -m pip install --pre atbash-hermes-plugin==0.1.8.dev0
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
## Configure Atbash
|
{atbash_hermes_plugin-0.1.7.dev0 → atbash_hermes_plugin-0.1.8.dev0}/atbash_hermes_plugin/__init__.py
RENAMED
|
@@ -4,6 +4,7 @@ import atexit
|
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
|
+
import re
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Any, Dict, Optional
|
|
9
10
|
|
|
@@ -65,6 +66,98 @@ def _save_tool_map(path: Path, tool_map: Dict[str, str]) -> None:
|
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
|
|
69
|
+
_ERC20_RE = re.compile(r"\b(0x[0-9a-fA-F]{40})\b")
|
|
70
|
+
_ERC20_ADDR_RE = re.compile(r"(0x[0-9a-fA-F]{40})")
|
|
71
|
+
_FINANCIAL_OP_RE = re.compile(r"\b(transfer|send|swap|approve|erc20)\b", re.IGNORECASE)
|
|
72
|
+
|
|
73
|
+
_ASSET_BY_CONTRACT: Dict[str, str] = {
|
|
74
|
+
"0xdac17f958d2ee523a2206206994597c13d831ec7": "USDT",
|
|
75
|
+
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "USDC",
|
|
76
|
+
"0x6b175474e89094c44da98b954eedeac495271d0f": "DAI",
|
|
77
|
+
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "WETH",
|
|
78
|
+
"0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": "WBTC",
|
|
79
|
+
"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984": "UNI",
|
|
80
|
+
"0x514910771af9ca656af840dff83e8264ecf986ca": "LINK",
|
|
81
|
+
"0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9": "AAVE",
|
|
82
|
+
"0xb0df6379ba1692841965a0745ac1bd3046d79ba3": "ATBASH",
|
|
83
|
+
"0xe9c094187219d9a29382c1a36fc43619c9257777": "ATBASH",
|
|
84
|
+
"0xf8b071428558c657a7a9aa1c43e152e75dd77777": "ATBASH",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _load_recipient_allowlist() -> set:
|
|
89
|
+
try:
|
|
90
|
+
p = Path("~/.config/atbash/recipient-allowlist.json").expanduser()
|
|
91
|
+
data = json.loads(p.read_text(encoding="utf-8"))
|
|
92
|
+
return {str(a).lower() for a in data} if isinstance(data, list) else set()
|
|
93
|
+
except Exception:
|
|
94
|
+
return set()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _resolve_asset(token: str) -> str:
|
|
98
|
+
if not token:
|
|
99
|
+
return "ETH"
|
|
100
|
+
t = token.lower()
|
|
101
|
+
m = _ERC20_ADDR_RE.search(t)
|
|
102
|
+
if m:
|
|
103
|
+
return _ASSET_BY_CONTRACT.get(m.group(1).lower(), "other")
|
|
104
|
+
if t in ("c60", "eth"):
|
|
105
|
+
return "ETH"
|
|
106
|
+
if t == "atbash":
|
|
107
|
+
return "ATBASH"
|
|
108
|
+
if t in ("usdt", "tether"):
|
|
109
|
+
return "USDT"
|
|
110
|
+
if t == "usdc":
|
|
111
|
+
return "USDC"
|
|
112
|
+
return "other"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _canonicalize_financial(command: str, recipient_allowlist: set) -> Optional[Dict[str, Any]]:
|
|
116
|
+
if not command:
|
|
117
|
+
return None
|
|
118
|
+
has_financial = bool(_FINANCIAL_OP_RE.search(command))
|
|
119
|
+
has_address = bool(_ERC20_RE.search(command))
|
|
120
|
+
if not has_financial and not has_address:
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
def _flag(name: str) -> Optional[str]:
|
|
124
|
+
m = re.search(rf"--{name}[= ]+(\S+)", command)
|
|
125
|
+
return m.group(1).strip("'\"") if m else None
|
|
126
|
+
|
|
127
|
+
token = _flag("token")
|
|
128
|
+
if not token:
|
|
129
|
+
m = _ERC20_RE.search(command)
|
|
130
|
+
if m:
|
|
131
|
+
token = m.group(1)
|
|
132
|
+
|
|
133
|
+
to = _flag("to") or _flag("recipient")
|
|
134
|
+
amount = _flag("amount")
|
|
135
|
+
max_usd = _flag("max-usd")
|
|
136
|
+
asset = _resolve_asset(token or "")
|
|
137
|
+
|
|
138
|
+
on_allow = bool(to) and to.lower() in recipient_allowlist
|
|
139
|
+
if asset == "USDT":
|
|
140
|
+
recipient_status = "allowlisted" if on_allow else ("external-not-allowlisted" if to else "unspecified")
|
|
141
|
+
else:
|
|
142
|
+
recipient_status = "external" if to else "unspecified"
|
|
143
|
+
|
|
144
|
+
op = (
|
|
145
|
+
"swap" if re.search(r"\bswap\b", command, re.IGNORECASE)
|
|
146
|
+
else "approve" if re.search(r"\b(approve|erc20)\b", command, re.IGNORECASE)
|
|
147
|
+
else "transfer"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
"operation": op,
|
|
152
|
+
"asset": asset,
|
|
153
|
+
"amount": amount,
|
|
154
|
+
"max_usd": max_usd,
|
|
155
|
+
"recipient_status": recipient_status,
|
|
156
|
+
"allowlist_scope": "USDT transfers/approvals only; never lifts ETH or ATBASH rules",
|
|
157
|
+
"note": "canonicalized pre-judge; raw 0x addresses omitted (redacted upstream)",
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
68
161
|
def _extract_command(tool_name: str, tool_args: Dict[str, Any]) -> str:
|
|
69
162
|
if not isinstance(tool_args, dict):
|
|
70
163
|
return ""
|
|
@@ -213,6 +306,7 @@ class AtbashHermesGuard:
|
|
|
213
306
|
os.getenv("ATBASH_TOOL_MAP_PATH", str(_default_tool_map_path()))
|
|
214
307
|
).expanduser()
|
|
215
308
|
self.tool_map = {**DEFAULT_TOOL_CLASS_MAP, **_load_tool_map(self.tool_map_path)}
|
|
309
|
+
self.recipient_allowlist = _load_recipient_allowlist()
|
|
216
310
|
|
|
217
311
|
self.client = self._build_client()
|
|
218
312
|
|
|
@@ -240,7 +334,7 @@ class AtbashHermesGuard:
|
|
|
240
334
|
from atbash import Atbash # type: ignore
|
|
241
335
|
from atbash.types import ToolCallInput # type: ignore
|
|
242
336
|
except Exception:
|
|
243
|
-
raise RuntimeError("atbash-sdk is required. Install with: pip install atbash-sdk==0.1.
|
|
337
|
+
raise RuntimeError("atbash-sdk is required. Install with: pip install atbash-sdk==0.1.8.dev0") from e
|
|
244
338
|
|
|
245
339
|
self.ToolCallInput = ToolCallInput
|
|
246
340
|
judge_cfg = self._judge_config()
|
|
@@ -326,13 +420,14 @@ class AtbashHermesGuard:
|
|
|
326
420
|
"args": tool_args or {},
|
|
327
421
|
}
|
|
328
422
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
423
|
+
resolved = _canonicalize_financial(command, self.recipient_allowlist)
|
|
424
|
+
tci = self.ToolCallInput(
|
|
425
|
+
tool_name=tool_name or "unknown",
|
|
426
|
+
args=action_payload,
|
|
427
|
+
context=context,
|
|
428
|
+
resolved=resolved,
|
|
335
429
|
)
|
|
430
|
+
return self.client.audit_tool_call(tci)
|
|
336
431
|
|
|
337
432
|
def pre_tool_call(
|
|
338
433
|
self,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atbash-hermes-plugin
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8.dev0
|
|
4
4
|
Summary: Atbash safety plugin for Hermes Agent
|
|
5
5
|
Author: atbash
|
|
6
6
|
License-Expression: LicenseRef-Atbash-Proprietary
|
|
@@ -10,7 +10,7 @@ Keywords: atbash,hermes,hermes-agent,agent-safety,ai-safety,tool-guard,judge,pol
|
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: atbash-sdk==0.1.
|
|
13
|
+
Requires-Dist: atbash-sdk==0.1.8.dev0
|
|
14
14
|
Requires-Dist: httpx<1,>=0.27
|
|
15
15
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http<2,>=1.29
|
|
16
16
|
Requires-Dist: opentelemetry-sdk<2,>=1.29
|
|
@@ -38,13 +38,13 @@ stopped before execution.
|
|
|
38
38
|
Install the plugin into the same Python environment that runs Hermes:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
pip install --pre atbash-hermes-plugin==0.1.
|
|
41
|
+
pip install --pre atbash-hermes-plugin==0.1.8.dev0
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
If Hermes is installed in a virtual environment, use that environment's Python:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
/path/to/hermes/venv/bin/python -m pip install --pre atbash-hermes-plugin==0.1.
|
|
47
|
+
/path/to/hermes/venv/bin/python -m pip install --pre atbash-hermes-plugin==0.1.8.dev0
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
## Configure Atbash
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "atbash-hermes-plugin"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.8.dev0"
|
|
8
8
|
description = "Atbash safety plugin for Hermes Agent"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -24,7 +24,7 @@ keywords = [
|
|
|
24
24
|
"policy"
|
|
25
25
|
]
|
|
26
26
|
dependencies = [
|
|
27
|
-
"atbash-sdk==0.1.
|
|
27
|
+
"atbash-sdk==0.1.8.dev0",
|
|
28
28
|
"httpx>=0.27,<1",
|
|
29
29
|
"opentelemetry-exporter-otlp-proto-http>=1.29,<2",
|
|
30
30
|
"opentelemetry-sdk>=1.29,<2",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|