basedagents 0.1.0__tar.gz → 0.1.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basedagents
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Python SDK for basedagents.ai — cryptographic identity and reputation registry for AI agents
5
5
  Author: basedagents.ai
6
6
  License: MIT
@@ -20,7 +20,7 @@ from .keypair import AgentKeypair, generate as generate_keypair, from_private_ke
20
20
  from .client import RegistryClient, BasedAgentsError
21
21
  from .auth import build_headers as build_auth_headers
22
22
 
23
- __version__ = "0.1.0"
23
+ __version__ = "0.1.2"
24
24
  __all__ = [
25
25
  "AgentKeypair",
26
26
  "RegistryClient",
@@ -36,7 +36,7 @@ def build_headers(
36
36
  Returns:
37
37
  Dict with 'Authorization' and 'X-Timestamp' headers.
38
38
  """
39
- ts = timestamp or int(time.time())
39
+ ts = timestamp if timestamp is not None else int(time.time())
40
40
 
41
41
  if body is None:
42
42
  body_bytes = b""
@@ -14,7 +14,7 @@ import sys
14
14
  from pathlib import Path
15
15
 
16
16
  API_URL = "https://api.basedagents.ai"
17
- VERSION = "0.1.0"
17
+ VERSION = "0.1.2"
18
18
 
19
19
 
20
20
  def _print_err(msg: str) -> None:
@@ -72,6 +72,9 @@ def cmd_register(args: list[str]) -> None:
72
72
  if "--api" in args:
73
73
  idx = args.index("--api")
74
74
  api_url = args[idx + 1]
75
+ if not api_url.startswith("https://") and not api_url.startswith("http://localhost") and not api_url.startswith("http://127.0.0.1"):
76
+ _print_err(f"--api must use https:// (got {api_url!r}). AgentSig credentials must not be sent over plaintext.\nLocal development exception: http://localhost and http://127.0.0.1 are allowed.")
77
+ sys.exit(1)
75
78
 
76
79
  dry_run = "--dry-run" in args
77
80
 
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
 
6
6
  import base64
7
7
  import json
8
+ import os
8
9
  import uuid
9
10
  from typing import Any, Callable
10
11
 
@@ -14,7 +15,10 @@ from .auth import build_headers
14
15
  from .keypair import AgentKeypair
15
16
  from .pow import solve
16
17
 
17
- DEFAULT_API_URL = "https://api.basedagents.ai"
18
+ _DEFAULT_BASE = "https://api.basedagents.ai"
19
+ # Allow override via env var — use staging URL during tests/development,
20
+ # never point tests at production.
21
+ DEFAULT_API_URL = os.environ.get("BASEDAGENTS_API", _DEFAULT_BASE)
18
22
 
19
23
 
20
24
  class BasedAgentsError(Exception):
@@ -109,6 +113,10 @@ class RegistryClient:
109
113
  challenge_id: str = init["challenge_id"]
110
114
 
111
115
  # Step 2: Solve PoW (difficulty from server — never hardcoded)
116
+ # Cap difficulty to prevent a malicious/MitM server from exhausting the nonce space
117
+ MAX_DIFFICULTY = 28
118
+ if difficulty > MAX_DIFFICULTY:
119
+ raise BasedAgentsError(0, f"Server requested PoW difficulty {difficulty} which exceeds client cap ({MAX_DIFFICULTY}). Aborting.")
112
120
  nonce = solve(keypair.public_key_bytes, difficulty, on_progress=on_progress)
113
121
 
114
122
  # Step 3: Sign challenge
@@ -171,16 +179,17 @@ class RegistryClient:
171
179
  return self._get(f"/v1/agents/search?{urlencode(params)}")
172
180
 
173
181
  def whois(self, name: str) -> dict[str, Any] | None:
174
- """Look up an agent by name. Returns None if not found."""
175
- result = self.search(q=name, limit=1)
182
+ """Look up an agent by exact name (case-insensitive). Returns None if not found.
183
+
184
+ Does NOT return partial/fuzzy matches — a squatter with a similar name
185
+ will not be returned instead of None.
186
+ """
187
+ result = self.search(q=name, limit=20)
176
188
  agents = result.get("agents", [])
177
- if not agents:
178
- return None
179
- # Exact name match (case-insensitive)
180
189
  for agent in agents:
181
190
  if agent.get("name", "").lower() == name.lower():
182
191
  return agent
183
- return agents[0]
192
+ return None
184
193
 
185
194
  # ── Verification ──
186
195
 
@@ -214,7 +223,10 @@ class RegistryClient:
214
223
 
215
224
  nonce = str(uuid.uuid4())
216
225
 
217
- # Build the signed payload (subset — no structured_report)
226
+ # Build the signed payload (subset — no structured_report).
227
+ # Note: structured_report is intentionally excluded from the inner Ed25519 signature.
228
+ # This mirrors the server's verification protocol (verify.ts line ~139).
229
+ # structured_report is protected by the outer AgentSig header on the HTTP request.
218
230
  signed_fields: dict[str, Any] = {
219
231
  "assignment_id": assignment_id,
220
232
  "target_id": target_id,
@@ -69,10 +69,22 @@ class AgentKeypair:
69
69
  }
70
70
 
71
71
  def save(self, path: Path) -> None:
72
- """Save keypair to a JSON file with mode 600."""
73
- path.parent.mkdir(parents=True, exist_ok=True)
74
- path.write_text(json.dumps(self.to_dict(), indent=2))
75
- os.chmod(path, 0o600)
72
+ """Save keypair to a JSON file.
73
+
74
+ The keys directory is created 0o700 (owner-only).
75
+ The file is opened with O_CREAT|O_TRUNC and mode 0o600 atomically —
76
+ no window where the plaintext key is world-readable.
77
+ """
78
+ path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
79
+ # Ensure the dir itself is 0o700 even if it pre-existed
80
+ os.chmod(path.parent, 0o700)
81
+ data = json.dumps(self.to_dict(), indent=2).encode()
82
+ # Atomic create with correct mode — no chmod-after-write race
83
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
84
+ try:
85
+ os.write(fd, data)
86
+ finally:
87
+ os.close(fd)
76
88
 
77
89
  @classmethod
78
90
  def load(cls, path: Path) -> "AgentKeypair":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basedagents
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Python SDK for basedagents.ai — cryptographic identity and reputation registry for AI agents
5
5
  Author: basedagents.ai
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "basedagents"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  description = "Python SDK for basedagents.ai — cryptographic identity and reputation registry for AI agents"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes