Fix audit findings: security, types, KID, retry, and version alignment
- Fix critical OpenCode plugin: read private key from file instead of embedding in JS - Add default KID (agent_id + '-key-1') matching Node and Go SDKs - Fix Operation.subject and Operation.action types from str to Dict[str, Any] - Fix retry off-by-one to give max_retries+1 total attempts - Fix OpenCode operation_type from 'tool_use' to 'ai.tool_use' - Update plugin path to .config/opencode/plugins matching Node SDK Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
21c63dbb28
commit
347d51febf
4 files changed
+18
-24
No files matched your search
+1
-1
@@ -46,7 +46,7 @@ from .types import (
|
||||
HealthResponse,
|
||||
)
|
||||
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.1.0"
|
||||
|
||||
__all__ = [
|
||||
"ElydoraClient",
|
||||
|
||||
+4
-4
@@ -72,7 +72,7 @@ class ElydoraClient:
|
||||
self.token = token
|
||||
|
||||
self._prev_chain_hash = GENESIS_CHAIN_HASH
|
||||
self._kid = ""
|
||||
self._kid = agent_id + '-key-1'
|
||||
self._session = requests.Session()
|
||||
|
||||
def set_kid(self, kid: str) -> None:
|
||||
@@ -106,14 +106,14 @@ class ElydoraClient:
|
||||
hdrs = headers or self._headers()
|
||||
|
||||
last_exc: Optional[Exception] = None
|
||||
for attempt in range(self.max_retries):
|
||||
for attempt in range(0, self.max_retries + 1):
|
||||
try:
|
||||
resp = self._session.request(
|
||||
method, url, json=json_body, params=params, headers=hdrs, timeout=30
|
||||
)
|
||||
# Retry on 429 or 5xx
|
||||
if resp.status_code == 429 or resp.status_code >= 500:
|
||||
if attempt < self.max_retries - 1:
|
||||
if attempt < self.max_retries:
|
||||
retry_after = resp.headers.get("Retry-After")
|
||||
if retry_after and retry_after.isdigit():
|
||||
delay = int(retry_after)
|
||||
@@ -126,7 +126,7 @@ class ElydoraClient:
|
||||
raise
|
||||
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as exc:
|
||||
last_exc = exc
|
||||
if attempt < self.max_retries - 1:
|
||||
if attempt < self.max_retries:
|
||||
time.sleep(min(2 ** attempt, 8))
|
||||
continue
|
||||
raise
|
||||
|
||||
+11
-17
@@ -10,8 +10,8 @@ import sys
|
||||
from .base import AgentPlugin, InstallConfig, PluginStatus
|
||||
|
||||
|
||||
PLUGIN_DIR = os.path.join(os.path.expanduser("~"), ".opencode", "plugins")
|
||||
PLUGIN_FILENAME = "elydora-audit.js"
|
||||
PLUGIN_DIR = os.path.join(os.path.expanduser("~"), ".config", "opencode", "plugins")
|
||||
PLUGIN_FILENAME = "elydora-audit.mjs"
|
||||
ELYDORA_DIR = os.path.join(os.path.expanduser("~"), ".elydora")
|
||||
|
||||
|
||||
@@ -62,11 +62,7 @@ class OpenCodePlugin(AgentPlugin):
|
||||
pass # chmod may fail on Windows
|
||||
|
||||
js_content = _generate_js_plugin(
|
||||
org_id=org_id,
|
||||
agent_id=agent_id,
|
||||
private_key=private_key,
|
||||
kid=kid,
|
||||
base_url=base_url,
|
||||
guard_script_path=guard_script_path,
|
||||
)
|
||||
|
||||
@@ -101,11 +97,7 @@ class OpenCodePlugin(AgentPlugin):
|
||||
|
||||
def _generate_js_plugin(
|
||||
*,
|
||||
org_id: str,
|
||||
agent_id: str,
|
||||
private_key: str,
|
||||
kid: str,
|
||||
base_url: str,
|
||||
guard_script_path: str = "",
|
||||
) -> str:
|
||||
guard_path_escaped = guard_script_path.replace("\\", "\\\\") if guard_script_path else ""
|
||||
@@ -121,13 +113,15 @@ const path = require("path");
|
||||
const os = require("os");
|
||||
const {{ spawnSync }} = require("child_process");
|
||||
|
||||
const ORG_ID = {_js_str(org_id)};
|
||||
const AGENT_ID = {_js_str(agent_id)};
|
||||
const PRIVATE_KEY = {_js_str(private_key)};
|
||||
const KID = {_js_str(kid)};
|
||||
const BASE_URL = {_js_str(base_url)};
|
||||
const CONFIG_DIR = path.join(os.homedir(), ".elydora", {_js_str(agent_id)});
|
||||
const CONFIG = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, "config.json"), "utf-8"));
|
||||
const PRIVATE_KEY = fs.readFileSync(path.join(CONFIG_DIR, "private.key"), "utf-8").trim();
|
||||
const ORG_ID = CONFIG.org_id;
|
||||
const AGENT_ID = CONFIG.agent_id;
|
||||
const KID = CONFIG.kid;
|
||||
const BASE_URL = CONFIG.base_url;
|
||||
|
||||
const CHAIN_STATE_PATH = path.join(os.homedir(), ".elydora", AGENT_ID, "chain-state.json");
|
||||
const CHAIN_STATE_PATH = path.join(CONFIG_DIR, "chain-state.json");
|
||||
|
||||
function base64urlEncode(buf) {{
|
||||
return Buffer.from(buf).toString("base64url");
|
||||
@@ -262,7 +256,7 @@ module.exports = {{
|
||||
issued_at: issuedAt,
|
||||
ttl_ms: 30000,
|
||||
nonce: nonce,
|
||||
operation_type: "tool_use",
|
||||
operation_type: "ai.tool_use",
|
||||
subject: {{ type: "tool", id: toolName }},
|
||||
action: {{ type: "execute", tool: toolName }},
|
||||
payload: payload,
|
||||
|
||||
+2
-2
@@ -79,8 +79,8 @@ class Operation(TypedDict):
|
||||
issued_at: int
|
||||
ttl_ms: int
|
||||
nonce: str
|
||||
subject: str
|
||||
action: str
|
||||
subject: Dict[str, Any]
|
||||
action: Dict[str, Any]
|
||||
payload_hash: str
|
||||
prev_chain_hash: str
|
||||
chain_hash: str
|
||||
|
||||
Reference in new issue
Block a user