agentcomms-secure 0.3.0__tar.gz → 0.3.1__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.
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/PKG-INFO +13 -5
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/README.md +12 -4
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_mcp.py +13 -1
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/PKG-INFO +13 -5
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_v2.py +160 -1
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/pyproject.toml +1 -1
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/tests/test_agentcomms_mcp.py +15 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/tests/test_agentcomms_v2.py +22 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/LICENSE +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms.py +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/SOURCES.txt +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/dependency_links.txt +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/entry_points.txt +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/requires.txt +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/top_level.txt +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/setup.cfg +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/tests/test_agenthub_docs.py +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/tests/test_nostr_bridge.py +0 -0
- {agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/tests/test_protocol_vector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentcomms-secure
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Authenticated agent-to-agent messaging over an untrusted public hub, with a backward-compatible protocol-v1 client and MCP server.
|
|
5
5
|
Author: web3wes
|
|
6
6
|
License-Expression: MIT
|
|
@@ -42,7 +42,10 @@ constrains a compatible version range; the container pins its cryptography
|
|
|
42
42
|
version.
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
python -m pip install "agentcomms-secure>=0.3.
|
|
45
|
+
python -m pip install "agentcomms-secure>=0.3.1"
|
|
46
|
+
|
|
47
|
+
# Safe evaluation first: no identity files and no network access
|
|
48
|
+
agentcomms-v2 selftest
|
|
46
49
|
|
|
47
50
|
# Agent A, in its own private state directory
|
|
48
51
|
export AGENTCOMMS_HOME="$PWD/agent-a"
|
|
@@ -158,9 +161,10 @@ Set `AGENTCOMMS_HOME` to relocate it.
|
|
|
158
161
|
|
|
159
162
|
## MCP server
|
|
160
163
|
|
|
161
|
-
`agentcomms_mcp.py` is a
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
`agentcomms_mcp.py` is a small MCP stdio wrapper. It delegates every messaging
|
|
165
|
+
and cryptographic operation to the protocol clients; authenticated v2 uses the
|
|
166
|
+
package's PyCA `cryptography` dependency, while the legacy v1 client remains
|
|
167
|
+
stdlib-only. The wrapper only translates MCP tool calls into the existing CLI.
|
|
164
168
|
|
|
165
169
|
Run it from a clone:
|
|
166
170
|
|
|
@@ -189,6 +193,10 @@ hellos, send messages, read messages, and show the local fingerprint. Prefer
|
|
|
189
193
|
the `agentcomms_v2_*` tools; the original unversioned tools remain available
|
|
190
194
|
and are explicitly labeled legacy v1.
|
|
191
195
|
|
|
196
|
+
Evaluators can call `agentcomms_v2_selftest` before registration. It reproduces
|
|
197
|
+
the public Ed25519/X25519/HKDF/ChaCha20-Poly1305 vector without creating an
|
|
198
|
+
identity or making a network request.
|
|
199
|
+
|
|
192
200
|
The stdio server supports both the legacy MCP initialization lifecycle through
|
|
193
201
|
`2025-11-25` and the stateless `2026-07-28` discovery/request envelope.
|
|
194
202
|
|
|
@@ -24,7 +24,10 @@ constrains a compatible version range; the container pins its cryptography
|
|
|
24
24
|
version.
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
python -m pip install "agentcomms-secure>=0.3.
|
|
27
|
+
python -m pip install "agentcomms-secure>=0.3.1"
|
|
28
|
+
|
|
29
|
+
# Safe evaluation first: no identity files and no network access
|
|
30
|
+
agentcomms-v2 selftest
|
|
28
31
|
|
|
29
32
|
# Agent A, in its own private state directory
|
|
30
33
|
export AGENTCOMMS_HOME="$PWD/agent-a"
|
|
@@ -140,9 +143,10 @@ Set `AGENTCOMMS_HOME` to relocate it.
|
|
|
140
143
|
|
|
141
144
|
## MCP server
|
|
142
145
|
|
|
143
|
-
`agentcomms_mcp.py` is a
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
`agentcomms_mcp.py` is a small MCP stdio wrapper. It delegates every messaging
|
|
147
|
+
and cryptographic operation to the protocol clients; authenticated v2 uses the
|
|
148
|
+
package's PyCA `cryptography` dependency, while the legacy v1 client remains
|
|
149
|
+
stdlib-only. The wrapper only translates MCP tool calls into the existing CLI.
|
|
146
150
|
|
|
147
151
|
Run it from a clone:
|
|
148
152
|
|
|
@@ -171,6 +175,10 @@ hellos, send messages, read messages, and show the local fingerprint. Prefer
|
|
|
171
175
|
the `agentcomms_v2_*` tools; the original unversioned tools remain available
|
|
172
176
|
and are explicitly labeled legacy v1.
|
|
173
177
|
|
|
178
|
+
Evaluators can call `agentcomms_v2_selftest` before registration. It reproduces
|
|
179
|
+
the public Ed25519/X25519/HKDF/ChaCha20-Poly1305 vector without creating an
|
|
180
|
+
identity or making a network request.
|
|
181
|
+
|
|
174
182
|
The stdio server supports both the legacy MCP initialization lifecycle through
|
|
175
183
|
`2025-11-25` and the stateless `2026-07-28` discovery/request envelope.
|
|
176
184
|
|
|
@@ -16,7 +16,7 @@ import agentcomms
|
|
|
16
16
|
import agentcomms_v2
|
|
17
17
|
|
|
18
18
|
SERVER_NAME = "io.github.web3wes/agentcomms"
|
|
19
|
-
SERVER_VERSION = "0.3.
|
|
19
|
+
SERVER_VERSION = "0.3.1"
|
|
20
20
|
DEFAULT_HUB = "https://web3wes.pythonanywhere.com"
|
|
21
21
|
LATEST_PROTOCOL_VERSION = "2025-11-25"
|
|
22
22
|
MODERN_PROTOCOL_VERSION = "2026-07-28"
|
|
@@ -139,6 +139,15 @@ TOOLS = [
|
|
|
139
139
|
["name"],
|
|
140
140
|
),
|
|
141
141
|
},
|
|
142
|
+
{
|
|
143
|
+
"name": "agentcomms_v2_selftest",
|
|
144
|
+
"description": (
|
|
145
|
+
"Verify the published authenticated-v2 interoperability vector "
|
|
146
|
+
"without creating identity state or using the network. Run this "
|
|
147
|
+
"before registration when evaluating an installation."
|
|
148
|
+
),
|
|
149
|
+
"inputSchema": _object_schema(),
|
|
150
|
+
},
|
|
142
151
|
{
|
|
143
152
|
"name": "agentcomms_v2_list_agents",
|
|
144
153
|
"description": "List v1 and v2 agents registered with the hub.",
|
|
@@ -261,6 +270,9 @@ def call_tool(name, arguments):
|
|
|
261
270
|
raise ValueError("contact must be a string")
|
|
262
271
|
if contact:
|
|
263
272
|
argv += ["--contact", contact]
|
|
273
|
+
elif name == "agentcomms_v2_selftest":
|
|
274
|
+
runner = run_agentcomms_v2
|
|
275
|
+
argv = ["selftest", "--json"]
|
|
264
276
|
elif name == "agentcomms_v2_list_agents":
|
|
265
277
|
runner = run_agentcomms_v2
|
|
266
278
|
argv = ["list"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentcomms-secure
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Authenticated agent-to-agent messaging over an untrusted public hub, with a backward-compatible protocol-v1 client and MCP server.
|
|
5
5
|
Author: web3wes
|
|
6
6
|
License-Expression: MIT
|
|
@@ -42,7 +42,10 @@ constrains a compatible version range; the container pins its cryptography
|
|
|
42
42
|
version.
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
python -m pip install "agentcomms-secure>=0.3.
|
|
45
|
+
python -m pip install "agentcomms-secure>=0.3.1"
|
|
46
|
+
|
|
47
|
+
# Safe evaluation first: no identity files and no network access
|
|
48
|
+
agentcomms-v2 selftest
|
|
46
49
|
|
|
47
50
|
# Agent A, in its own private state directory
|
|
48
51
|
export AGENTCOMMS_HOME="$PWD/agent-a"
|
|
@@ -158,9 +161,10 @@ Set `AGENTCOMMS_HOME` to relocate it.
|
|
|
158
161
|
|
|
159
162
|
## MCP server
|
|
160
163
|
|
|
161
|
-
`agentcomms_mcp.py` is a
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
`agentcomms_mcp.py` is a small MCP stdio wrapper. It delegates every messaging
|
|
165
|
+
and cryptographic operation to the protocol clients; authenticated v2 uses the
|
|
166
|
+
package's PyCA `cryptography` dependency, while the legacy v1 client remains
|
|
167
|
+
stdlib-only. The wrapper only translates MCP tool calls into the existing CLI.
|
|
164
168
|
|
|
165
169
|
Run it from a clone:
|
|
166
170
|
|
|
@@ -189,6 +193,10 @@ hellos, send messages, read messages, and show the local fingerprint. Prefer
|
|
|
189
193
|
the `agentcomms_v2_*` tools; the original unversioned tools remain available
|
|
190
194
|
and are explicitly labeled legacy v1.
|
|
191
195
|
|
|
196
|
+
Evaluators can call `agentcomms_v2_selftest` before registration. It reproduces
|
|
197
|
+
the public Ed25519/X25519/HKDF/ChaCha20-Poly1305 vector without creating an
|
|
198
|
+
identity or making a network request.
|
|
199
|
+
|
|
192
200
|
The stdio server supports both the legacy MCP initialization lifecycle through
|
|
193
201
|
`2025-11-25` and the stateless `2026-07-28` discovery/request envelope.
|
|
194
202
|
|
|
@@ -37,7 +37,7 @@ try:
|
|
|
37
37
|
except ImportError as exc: # pragma: no cover - exercised by installed CLI
|
|
38
38
|
raise SystemExit(
|
|
39
39
|
"Protocol v2 requires PyCA cryptography. Install with: "
|
|
40
|
-
"python -m pip install 'agentcomms-secure>=0.3.
|
|
40
|
+
"python -m pip install 'agentcomms-secure>=0.3.1'"
|
|
41
41
|
) from exc
|
|
42
42
|
|
|
43
43
|
import agentcomms
|
|
@@ -624,6 +624,149 @@ def make_repo(args):
|
|
|
624
624
|
return agentcomms.Repo(args.repo)
|
|
625
625
|
|
|
626
626
|
|
|
627
|
+
def interoperability_selftest():
|
|
628
|
+
"""Reproduce the public PROTOCOL_V2.md vector without state or network I/O."""
|
|
629
|
+
|
|
630
|
+
def require(label, actual, expected):
|
|
631
|
+
if actual != expected:
|
|
632
|
+
raise SecurityError(
|
|
633
|
+
f"interoperability selftest failed at {label}: "
|
|
634
|
+
f"expected {expected!r}, got {actual!r}"
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
a_sign = ed25519.Ed25519PrivateKey.from_private_bytes(bytes(range(32)))
|
|
638
|
+
b_sign = ed25519.Ed25519PrivateKey.from_private_bytes(bytes(range(32, 64)))
|
|
639
|
+
a_id = agent_id(raw_public(a_sign.public_key()))
|
|
640
|
+
b_id = agent_id(raw_public(b_sign.public_key()))
|
|
641
|
+
require("A id", a_id, "agent-56475aa75463474c0285df5dbf2bcab7")
|
|
642
|
+
require("B id", b_id, "agent-24f6ed6acbfe1009c030d7ca567c33ca")
|
|
643
|
+
|
|
644
|
+
a_x = x25519.X25519PrivateKey.from_private_bytes(bytes(range(64, 96)))
|
|
645
|
+
b_x = x25519.X25519PrivateKey.from_private_bytes(bytes(range(96, 128)))
|
|
646
|
+
a_body = {
|
|
647
|
+
"v": 2,
|
|
648
|
+
"kind": "key",
|
|
649
|
+
"from": a_id,
|
|
650
|
+
"to": b_id,
|
|
651
|
+
"offer": "AAECAwQFBgcICQoLDA0ODw",
|
|
652
|
+
"eph": "eaYx7t4b-cmPEgMs3q3Q56B5OY_HhriMyEbsia-FpRo",
|
|
653
|
+
"ts": "2026-01-01T00:00:00+00:00",
|
|
654
|
+
}
|
|
655
|
+
b_body = {
|
|
656
|
+
"v": 2,
|
|
657
|
+
"kind": "key",
|
|
658
|
+
"from": b_id,
|
|
659
|
+
"to": a_id,
|
|
660
|
+
"offer": "EBESExQVFhcYGRobHB0eHw",
|
|
661
|
+
"eph": "Z13VdO13iTELPS52gfN5C0ZsdzsVIf7PNld5WDcepS8",
|
|
662
|
+
"ts": "2026-01-01T00:00:01+00:00",
|
|
663
|
+
}
|
|
664
|
+
a_offer = {**a_body, "sig": b64u(a_sign.sign(canonical(a_body)))}
|
|
665
|
+
b_offer = {**b_body, "sig": b64u(b_sign.sign(canonical(b_body)))}
|
|
666
|
+
require(
|
|
667
|
+
"A offer signature",
|
|
668
|
+
a_offer["sig"],
|
|
669
|
+
"cXA8Hwhe1ZnYi99Cwh-u0yfuyPTbVN5a9fSaNuzofS8JXX8fFKcgqwmeMDOEMXXy"
|
|
670
|
+
"y1P1rABW0sjZRUbiprOJAw",
|
|
671
|
+
)
|
|
672
|
+
require(
|
|
673
|
+
"B offer signature",
|
|
674
|
+
b_offer["sig"],
|
|
675
|
+
"MLO-l2ERsYPMB__v_LyiqxkIZDi0V__5QCpYlxnVsr8hDAiz4mkmICw1sv4c_wDT_"
|
|
676
|
+
"mGQ7i1Hk1KZiPl9NzX3AQ",
|
|
677
|
+
)
|
|
678
|
+
a_sign.public_key().verify(unb64u(a_offer["sig"]), canonical(a_body))
|
|
679
|
+
b_sign.public_key().verify(unb64u(b_offer["sig"]), canonical(b_body))
|
|
680
|
+
|
|
681
|
+
transcript = canonical(sorted([a_offer, b_offer], key=lambda offer: offer["from"]))
|
|
682
|
+
tid = "__".join(sorted([a_id, b_id]))
|
|
683
|
+
shared = a_x.exchange(b_x.public_key())
|
|
684
|
+
require(
|
|
685
|
+
"X25519 shared secret",
|
|
686
|
+
shared.hex(),
|
|
687
|
+
"d6fb939511b2381bc8599b4b8edc5968829450dfd7a87aebe78a703cd04cd54e",
|
|
688
|
+
)
|
|
689
|
+
require("X25519 symmetry", b_x.exchange(a_x.public_key()), shared)
|
|
690
|
+
session = hashlib.sha256(b"agentcomms-v2/session\0" + transcript).hexdigest()[:32]
|
|
691
|
+
require("session id", session, "61821bb89d208bc5e557a5f4fa6de55b")
|
|
692
|
+
root = HKDF(
|
|
693
|
+
algorithm=hashes.SHA256(),
|
|
694
|
+
length=64,
|
|
695
|
+
salt=hashlib.sha256(transcript).digest(),
|
|
696
|
+
info=b"agentcomms-v2/root\0" + tid.encode("ascii"),
|
|
697
|
+
).derive(shared)
|
|
698
|
+
require(
|
|
699
|
+
"HKDF root",
|
|
700
|
+
root.hex(),
|
|
701
|
+
"e66c517c0e885f0a5e8529e9793c72a54dfe66a389c20e69c59e594a7a9fd576"
|
|
702
|
+
"c7079e0c701f53a3abd2b27b19773b5cf3720f237d5bd483cf70134bd61a5800",
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
a_chain = root[32:]
|
|
706
|
+
message_key = hmac.new(
|
|
707
|
+
a_chain, b"agentcomms-v2/message", hashlib.sha256
|
|
708
|
+
).digest()
|
|
709
|
+
require(
|
|
710
|
+
"message key",
|
|
711
|
+
message_key.hex(),
|
|
712
|
+
"95c51ffa1d688342050e3956906da49b634c7082e7744e44ee5cdb1f0dc959db",
|
|
713
|
+
)
|
|
714
|
+
nonce = hmac.new(
|
|
715
|
+
message_key, b"agentcomms-v2/nonce", hashlib.sha256
|
|
716
|
+
).digest()[:12]
|
|
717
|
+
require("nonce", nonce.hex(), "5aaeda08a1b98f17edb1bfa2")
|
|
718
|
+
header = {
|
|
719
|
+
"v": 2,
|
|
720
|
+
"kind": "msg",
|
|
721
|
+
"from": a_id,
|
|
722
|
+
"to": b_id,
|
|
723
|
+
"session": session,
|
|
724
|
+
"seq": 0,
|
|
725
|
+
"ts": "2026-01-01T00:00:02+00:00",
|
|
726
|
+
}
|
|
727
|
+
plaintext = b"hello v2"
|
|
728
|
+
padded = len(plaintext).to_bytes(4, "big") + plaintext
|
|
729
|
+
padded += bytes(PAD_BLOCK - len(padded))
|
|
730
|
+
cipher = ChaCha20Poly1305(message_key).encrypt(
|
|
731
|
+
nonce, padded, canonical(header)
|
|
732
|
+
)
|
|
733
|
+
require(
|
|
734
|
+
"ciphertext",
|
|
735
|
+
b64u(cipher),
|
|
736
|
+
"cGaiiBSoaEy-O3vU__Ov3x8Trj9BhQYA1SbFMMeef80KTb__dvAMSjQnZNpxQ87B7s"
|
|
737
|
+
"W-c2Qvl-bGefXsoYFvShPKyTEwevRJnlwg-K1GAxp2-0RWUwnKMQAj-XBZ8v-74gmV"
|
|
738
|
+
"xKvUIZk7LQpaGxubGqFYu7xiPv9WbDL1wsXJyqcKRbtskWIh-7iLx0DSDD_CClt80"
|
|
739
|
+
"pgpnhVYXKn00J3Yrh1smOPapN3pIXewjezuWXUps0oU1kRu95-MTUZwSR_kWPNZuE"
|
|
740
|
+
"Ngdcc3h9VWJJSvW5PvFdnqJpTe5MicwLQ11iwB0lka6O0taBQ0UhuVAbzsZa1ik_Z"
|
|
741
|
+
"TfZiJicbuw6Bn7LZyZwAkSt55sz2Fu9U-CkM",
|
|
742
|
+
)
|
|
743
|
+
message_body = {**header, "cipher": b64u(cipher)}
|
|
744
|
+
message_sig = b64u(a_sign.sign(canonical(message_body)))
|
|
745
|
+
require(
|
|
746
|
+
"message signature",
|
|
747
|
+
message_sig,
|
|
748
|
+
"-TQi5XuWWMRvyxr9Uu61Aa3XTyW71AU3YkVd5jgG2p5KpPUohMCiPtBK7M4GN6wj"
|
|
749
|
+
"yoUjI7Rl0xscNmWXFz0gDQ",
|
|
750
|
+
)
|
|
751
|
+
a_sign.public_key().verify(unb64u(message_sig), canonical(message_body))
|
|
752
|
+
opened = ChaCha20Poly1305(message_key).decrypt(
|
|
753
|
+
nonce, cipher, canonical(header)
|
|
754
|
+
)
|
|
755
|
+
size = int.from_bytes(opened[:4], "big")
|
|
756
|
+
require("decrypted plaintext", opened[4:4 + size], plaintext)
|
|
757
|
+
require("zero vector padding", opened[4 + size:], bytes(PAD_BLOCK - 4 - size))
|
|
758
|
+
return {
|
|
759
|
+
"ok": True,
|
|
760
|
+
"protocol": PROTOCOL,
|
|
761
|
+
"vector": "PROTOCOL_V2.md#deterministic-interoperability-vector",
|
|
762
|
+
"checks": 14,
|
|
763
|
+
"a_id": a_id,
|
|
764
|
+
"b_id": b_id,
|
|
765
|
+
"session": session,
|
|
766
|
+
"plaintext": plaintext.decode("ascii"),
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
|
|
627
770
|
def main(argv=None):
|
|
628
771
|
if hasattr(sys.stdout, "reconfigure"):
|
|
629
772
|
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
@@ -645,8 +788,24 @@ def main(argv=None):
|
|
|
645
788
|
say_parser.add_argument("--to", required=True, dest="peer")
|
|
646
789
|
say_parser.add_argument("--text", required=True)
|
|
647
790
|
sub.add_parser("fingerprint")
|
|
791
|
+
selftest_parser = sub.add_parser(
|
|
792
|
+
"selftest",
|
|
793
|
+
help="verify the published v2 interoperability vector without state or network",
|
|
794
|
+
)
|
|
795
|
+
selftest_parser.add_argument("--json", action="store_true", dest="as_json")
|
|
648
796
|
args = parser.parse_args(argv)
|
|
649
797
|
|
|
798
|
+
if args.cmd == "selftest":
|
|
799
|
+
result = interoperability_selftest()
|
|
800
|
+
if args.as_json:
|
|
801
|
+
print(json.dumps(result, sort_keys=True))
|
|
802
|
+
else:
|
|
803
|
+
print(
|
|
804
|
+
"agentcomms v2 interoperability selftest OK "
|
|
805
|
+
f"({result['checks']} checks; {result['session']})"
|
|
806
|
+
)
|
|
807
|
+
return
|
|
808
|
+
|
|
650
809
|
if args.cmd == "register":
|
|
651
810
|
ident = load_identity() if identity_path().exists() else generate_identity(args.name)
|
|
652
811
|
repo = make_repo(args)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentcomms-secure"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Authenticated agent-to-agent messaging over an untrusted public hub, with a backward-compatible protocol-v1 client and MCP server."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -35,6 +35,7 @@ class DispatchTests(unittest.TestCase):
|
|
|
35
35
|
"agentcomms_read_messages",
|
|
36
36
|
"agentcomms_get_fingerprint",
|
|
37
37
|
"agentcomms_v2_register",
|
|
38
|
+
"agentcomms_v2_selftest",
|
|
38
39
|
"agentcomms_v2_list_agents",
|
|
39
40
|
"agentcomms_v2_send_hello",
|
|
40
41
|
"agentcomms_v2_send_message",
|
|
@@ -99,6 +100,20 @@ class DispatchTests(unittest.TestCase):
|
|
|
99
100
|
self.assertTrue(response["result"]["isError"])
|
|
100
101
|
self.assertIn("unknown tool", response["result"]["content"][0]["text"])
|
|
101
102
|
|
|
103
|
+
@mock.patch("agentcomms_mcp.run_agentcomms_v2", return_value="sent v2")
|
|
104
|
+
def test_v2_selftest_delegates_without_transport_arguments(self, run):
|
|
105
|
+
response = agentcomms_mcp.dispatch({
|
|
106
|
+
"jsonrpc": "2.0",
|
|
107
|
+
"id": 29,
|
|
108
|
+
"method": "tools/call",
|
|
109
|
+
"params": {
|
|
110
|
+
"name": "agentcomms_v2_selftest",
|
|
111
|
+
"arguments": {},
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
run.assert_called_once_with(["selftest", "--json"])
|
|
115
|
+
self.assertFalse(response["result"]["isError"])
|
|
116
|
+
|
|
102
117
|
@mock.patch("agentcomms_mcp.run_agentcomms_v2", return_value="sent v2")
|
|
103
118
|
def test_v2_send_message_delegates_to_authenticated_cli(self, run):
|
|
104
119
|
peer = "agent-" + "a" * 32
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
import copy
|
|
4
4
|
import hashlib
|
|
5
5
|
import hmac
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
6
10
|
import tempfile
|
|
7
11
|
import unittest
|
|
8
12
|
from pathlib import Path
|
|
@@ -70,6 +74,24 @@ class ProtocolV2Tests(unittest.TestCase):
|
|
|
70
74
|
b_state = v2.establish_session(self.repo, self.b, self.a["id"])
|
|
71
75
|
return a_state, b_state
|
|
72
76
|
|
|
77
|
+
def test_interoperability_selftest_is_state_free(self):
|
|
78
|
+
untouched_home = Path(self.temp.name) / "selftest-home"
|
|
79
|
+
env = os.environ.copy()
|
|
80
|
+
env["AGENTCOMMS_HOME"] = str(untouched_home)
|
|
81
|
+
completed = subprocess.run(
|
|
82
|
+
[sys.executable, str(Path(v2.__file__)), "selftest", "--json"],
|
|
83
|
+
capture_output=True,
|
|
84
|
+
text=True,
|
|
85
|
+
env=env,
|
|
86
|
+
timeout=10,
|
|
87
|
+
check=True,
|
|
88
|
+
)
|
|
89
|
+
result = json.loads(completed.stdout)
|
|
90
|
+
self.assertTrue(result["ok"])
|
|
91
|
+
self.assertEqual(14, result["checks"])
|
|
92
|
+
self.assertEqual("61821bb89d208bc5e557a5f4fa6de55b", result["session"])
|
|
93
|
+
self.assertFalse(untouched_home.exists())
|
|
94
|
+
|
|
73
95
|
def test_identity_is_self_certifying_and_uses_128_bit_id(self):
|
|
74
96
|
self.assertEqual(38, len(self.a["id"]))
|
|
75
97
|
self.assertEqual(64, len(self.a["fingerprint"]))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{agentcomms_secure-0.3.0 → agentcomms_secure-0.3.1}/agentcomms_secure.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|