proofnest 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

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,45 +0,0 @@
1
- ./.gitignore,sha256=jTP1a-5WZxB6VIjQDxnlgi21WAsvcRKZHqgzK6RoCaE,481
2
- ./AUDIT_GPT4o_2026-02-03.md,sha256=SIb0DTL8fgY8nDlFGCreUeBLsp9qNeAntls_dW2ImxY,2100
3
- ./AUDIT_GPT52_2026-02-03.md,sha256=sWC871lqSWdRYQdRK9Tp1uVKn2tbvr2V3hmb9GpT4Vk,4527
4
- ./AUDIT_GPT52_FULL_2026-02-03.md,sha256=gRG63eJLbUehRHzm76diJoWzgBufMSP9gx-BzhWyhQw,3192
5
- ./AUDIT_GPT52_ROUND2_2026-02-03.md,sha256=PWjsbcFCUmljk6aKQ4qFYgxJHcaJKqTDNXSRKr3BGKM,2037
6
- ./LICENSE,sha256=kJZdHD45cIKBd-xdBBGmxgesVMsUGFYKfPOQlHAFOZw,1071
7
- ./PKG-INFO,sha256=HKa30HTILzRbUbM8ELCsqZIbtsEkWB2ga3Ny2wofLBg,5926
8
- ./README.md,sha256=slBddYIxAp7i-s0HA3QKQ5XvJ5YTqVy637_0CF6aO44,4277
9
- ./__init__.py,sha256=wkkzIxUYFN30mixtvNSX66wU7iW7bp7pngRcI7Q-YY4,2760
10
- ./anchor.py,sha256=FRLy2nzDq0HJ9rT7J1GgOLcYynFY0ZhC-4i9RiuinmA,12160
11
- ./api.py,sha256=J6IFtQPb_kixwRp4H_CwaAQoxEx-IZMmd04PU9qjATM,24901
12
- ./blockchain.py,sha256=AoJXr8SeF5O7mCFg-DdpNvt0Io_Oi3hjowiMAPOLs1Q,12319
13
- ./cli.py,sha256=XfQktB8e329cPGxu5qE11IVmY16PkkwjEcrpcsuPWgI,12497
14
- ./consensus.py,sha256=U5UZy-bJRUQfk8U4e2vp1AzzTk-PrlzMsOnuEcGjQjo,13929
15
- ./demo.py,sha256=6SAO6PIwQ6kOaS4a8vKe7RXMEnYrC0qaWxRQzUmmHJQ,4567
16
- ./did_registry.py,sha256=9DXoTYfkUfuwp46QuzHNVpGZ2It_4Gits64SZ_REaqE,13404
17
- ./network.py,sha256=4Wd1_-cgfvo47oiop-SCc662BsiFQLQZ_ELPPgEdZ6U,20992
18
- ./proof.py,sha256=wRf5c5uEE3ALajCc_XSiVWdunoB26ARxr-hTqgrjeDM,37800
19
- ./pyproject.toml,sha256=8rQlJr1iSmix1pXTFp6JUhT1Ry0rW6sb2wSJ223L_QY,2041
20
- ./staking.py,sha256=T7iOdrWHCfvTocmeLejnHZ3SOVPgXEFJGkwmJX-ZcR0,16150
21
- ./storage.py,sha256=bUKHybjnDpIIqHNkbItRBlQrrRZIfTGVRIeAvYAePaQ,19836
22
- ./.planning/PROJECT.md,sha256=kLc52MDDFlCoBk4Gz7V2nFhPcRAyO1dhcmf2DVJhICU,4274
23
- ./.planning/ROADMAP.md,sha256=XcxnUeEd8V9nFmxsZzOzU3iiSQR6m4-vbOPlFgipV8Y,4867
24
- ./.planning/STATE.md,sha256=1rnqSvmyO0bwdyV1pvdf3La1z2NNDN_IwQ9FXTwifiQ,2184
25
- ./.planning/config.json,sha256=CjZFWDey7cSl02ASBg8gVhs6a7CqOLwQmYlncmMFXX8,446
26
- ./.planning/quick/001-artikkel-proofnest-vs-moltbook/001-PLAN.md,sha256=nqakgoBat0nCHvT0qoNbJFyroa4nRXHXRzc2r0knBsw,6623
27
- ./.planning/quick/001-artikkel-proofnest-vs-moltbook/001-SUMMARY.md,sha256=d8VE1rarKhOUiCoUg_a6n-Lm3C5LhpXerAAqG2ixVQU,2431
28
- ./.planning/quick/002-twitter-thread-proofnest-moltbook/002-PLAN.md,sha256=EXb7-TWgDu474iziCaBv9hKQ7hCsReGtUB1CK-JQsso,1524
29
- ./.planning/quick/002-twitter-thread-proofnest-moltbook/002-SUMMARY.md,sha256=24ACIVpluXv_n_MPhA4rJDkYx_1ZlmOdPLADobVDZD8,1572
30
- ./.planning/research/ARCHITECTURE.md,sha256=qnbZwYtaY8uhJF3mbGmRXLiNNP1WRhgpOz1pXBJ4gig,20215
31
- ./.planning/research/FEATURES.md,sha256=UFcq3ED4P_lJfvL2eKM8856NGXxiqL_C6KOQE9RJp1g,10727
32
- ./.planning/research/PITFALLS.md,sha256=6va5ieYb_RbH4c3PDAId7jVE9_AsXD9VXxKNzGz8HjI,19900
33
- ./.planning/research/STACK.md,sha256=Y0YbrWRDCPXTk5kXmOLMN-hdrVlXEnsLHggwJopWENI,13833
34
- ./.planning/research/SUMMARY.md,sha256=B6bEweIRqUDTx3r0pNrIhLWHBOhE5AfPXwsyDIe5ZpU,21686
35
- ./content/articles/proofnest-vs-moltbook-en.md,sha256=IV_7YwCKiqaXwrkF4mcAc04pvS_GiWu0bNAQlXrmsNc,10121
36
- ./content/social/twitter-thread-001.md,sha256=VYZ-4oZiF5aXsS0IiRz-3_0ZtPXSXVifvK_EXQApg1E,3228
37
- ./tests/test_api.py,sha256=67XoGcgqdV26KdBvqL67oAvGmHo1ZlSNLZt4SlQDrlQ,9141
38
- ./tests/test_did_registry.py,sha256=ehisZce4hu9QMur0_0mLC3uV0SVbSNHp2N4GDJAv8oE,6062
39
- ./tests/test_proof.py,sha256=2c12YZfmVTnKEemwRPCAbN5w6GpbrFeuwB5PRVddO-Y,8919
40
- ./tests/test_staking.py,sha256=MlcNnmZxkLNXUbibEq2DSKCZtVc_lllFDmKOEWkkZCQ,5852
41
- proofnest-0.2.0.dist-info/METADATA,sha256=HKa30HTILzRbUbM8ELCsqZIbtsEkWB2ga3Ny2wofLBg,5926
42
- proofnest-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
43
- proofnest-0.2.0.dist-info/entry_points.txt,sha256=U2_jDn1Eg8j5Z3hQDks3CJ7qbe9auBsehyKT5RcGW-w,49
44
- proofnest-0.2.0.dist-info/licenses/LICENSE,sha256=kJZdHD45cIKBd-xdBBGmxgesVMsUGFYKfPOQlHAFOZw,1071
45
- proofnest-0.2.0.dist-info/RECORD,,
tests/test_api.py DELETED
@@ -1,270 +0,0 @@
1
- """
2
- Tests for PROOFNEST API.
3
- """
4
-
5
- import pytest
6
- from fastapi.testclient import TestClient
7
- import sys
8
- import os
9
-
10
- # Add parent to path
11
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
-
13
- from api import app, API_KEY
14
-
15
-
16
- @pytest.fixture
17
- def client():
18
- """Create test client"""
19
- return TestClient(app)
20
-
21
-
22
- @pytest.fixture
23
- def auth_headers():
24
- """Authentication headers for protected endpoints"""
25
- return {"X-API-Key": API_KEY}
26
-
27
-
28
- class TestHealth:
29
- """Test health endpoints"""
30
-
31
- def test_health(self, client):
32
- """Test health endpoint"""
33
- response = client.get("/health")
34
- assert response.status_code == 200
35
- data = response.json()
36
- assert data["status"] == "ok"
37
-
38
- def test_root(self, client):
39
- """Test root endpoint"""
40
- response = client.get("/")
41
- assert response.status_code == 200
42
- data = response.json()
43
- assert "ProofNest" in data["name"]
44
-
45
-
46
- class TestIdentities:
47
- """Test identity endpoints"""
48
-
49
- def test_create_identity(self, client, auth_headers):
50
- """Test creating an identity"""
51
- response = client.post("/v1/identities", json={
52
- "identity_type": "agent",
53
- "name": "Test Agent"
54
- }, headers=auth_headers)
55
- assert response.status_code == 200
56
- data = response.json()
57
- assert data["did"].startswith("did:pn:agent:")
58
- assert data["name"] == "Test Agent"
59
-
60
- def test_list_identities(self, client, auth_headers):
61
- """Test listing identities"""
62
- # Create one first
63
- client.post("/v1/identities", json={"identity_type": "agent"}, headers=auth_headers)
64
-
65
- response = client.get("/v1/identities")
66
- assert response.status_code == 200
67
- data = response.json()
68
- assert "count" in data
69
- assert "identities" in data
70
-
71
-
72
- class TestProofs:
73
- """Test proof endpoints"""
74
-
75
- def test_create_proof(self, client, auth_headers):
76
- """Test creating a proof"""
77
- # First create identity
78
- identity = client.post("/v1/identities", json={
79
- "identity_type": "agent"
80
- }, headers=auth_headers).json()
81
-
82
- # Then create proof
83
- response = client.post("/v1/proofs", json={
84
- "issuer_did": identity["did"],
85
- "claim": "Test claim",
86
- "proof_type": "CLAIM"
87
- }, headers=auth_headers)
88
- assert response.status_code == 200
89
- data = response.json()
90
- assert data["proof_id"].startswith("proof:")
91
- assert data["is_valid"] is True
92
-
93
- def test_get_proof(self, client, auth_headers):
94
- """Test getting a proof"""
95
- # Create identity and proof
96
- identity = client.post("/v1/identities", json={
97
- "identity_type": "agent"
98
- }, headers=auth_headers).json()
99
-
100
- proof = client.post("/v1/proofs", json={
101
- "issuer_did": identity["did"],
102
- "claim": "Get test",
103
- "proof_type": "CLAIM"
104
- }, headers=auth_headers).json()
105
-
106
- # Get it (public endpoint - no auth needed)
107
- response = client.get(f"/v1/proofs/{proof['proof_id']}")
108
- assert response.status_code == 200
109
-
110
- def test_verify_proof(self, client, auth_headers):
111
- """Test verifying a proof"""
112
- # Create identity and proof
113
- identity = client.post("/v1/identities", json={
114
- "identity_type": "agent"
115
- }, headers=auth_headers).json()
116
-
117
- proof = client.post("/v1/proofs", json={
118
- "issuer_did": identity["did"],
119
- "claim": "Verify test",
120
- "proof_type": "CLAIM"
121
- }, headers=auth_headers).json()
122
-
123
- # Verify (public endpoint - no auth needed)
124
- response = client.post(f"/v1/proofs/{proof['proof_id']}/verify")
125
- assert response.status_code == 200
126
- data = response.json()
127
- assert data["is_valid"] is True
128
-
129
-
130
- class TestValidators:
131
- """Test validator endpoints"""
132
-
133
- def test_add_validator(self, client, auth_headers):
134
- """Test adding a validator"""
135
- response = client.post("/v1/validators", headers=auth_headers)
136
- assert response.status_code == 200
137
- data = response.json()
138
- assert data["did"].startswith("did:pn:validator:")
139
- assert data["stake"] == 1000
140
-
141
- def test_list_validators(self, client, auth_headers):
142
- """Test listing validators"""
143
- # Add one first
144
- client.post("/v1/validators", headers=auth_headers)
145
-
146
- response = client.get("/v1/validators")
147
- assert response.status_code == 200
148
- data = response.json()
149
- assert "count" in data
150
- assert "validators" in data
151
-
152
-
153
- class TestConsensus:
154
- """Test consensus flow"""
155
-
156
- def test_full_consensus_flow(self, client, auth_headers):
157
- """Test complete consensus flow"""
158
- # 1. Create identity
159
- identity = client.post("/v1/identities", json={
160
- "identity_type": "agent"
161
- }, headers=auth_headers).json()
162
-
163
- # 2. Create proof
164
- proof = client.post("/v1/proofs", json={
165
- "issuer_did": identity["did"],
166
- "claim": "Consensus test",
167
- "proof_type": "WORK"
168
- }, headers=auth_headers).json()
169
- proof_id = proof["proof_id"]
170
-
171
- # 3. Add validators
172
- v1 = client.post("/v1/validators", headers=auth_headers).json()
173
-
174
- # 4. Submit to consensus
175
- submit = client.post(f"/v1/proofs/{proof_id}/submit-consensus", headers=auth_headers)
176
- assert submit.status_code == 200
177
-
178
- # 5. Vote (single validator with quorum_threshold=1 for test)
179
- vote1 = client.post(f"/v1/proofs/{proof_id}/vote", json={
180
- "proof_id": proof_id,
181
- "validator_did": v1["did"],
182
- "approve": True
183
- }, headers=auth_headers)
184
- assert vote1.status_code == 200
185
- # With 1 validator, quorum is reached immediately
186
- vote_data = vote1.json()
187
- assert vote_data["vote"] == "APPROVE"
188
- # Quorum may be reached depending on threshold
189
- if vote_data.get("quorum_reached"):
190
- assert vote_data.get("consensus_state") in ["ACCEPTED", "FINALIZED"]
191
-
192
-
193
- class TestChain:
194
- """Test blockchain endpoints"""
195
-
196
- def test_chain_status(self, client):
197
- """Test chain status"""
198
- response = client.get("/v1/chain/status")
199
- assert response.status_code == 200
200
- data = response.json()
201
- assert "chain_id" in data
202
- assert "height" in data
203
-
204
- def test_chain_validators(self, client):
205
- """Test chain validators"""
206
- response = client.get("/v1/chain/validators")
207
- assert response.status_code == 200
208
- data = response.json()
209
- assert "validators" in data
210
-
211
-
212
- class TestAuthentication:
213
- """Test API authentication (GPT-5.2 audit fix)"""
214
-
215
- def test_unauthenticated_create_identity_rejected(self, client):
216
- """Verify unauthenticated identity creation is rejected"""
217
- response = client.post("/v1/identities", json={
218
- "identity_type": "agent"
219
- })
220
- assert response.status_code == 401
221
- assert "Missing API key" in response.json()["detail"]
222
-
223
- def test_unauthenticated_create_proof_rejected(self, client, auth_headers):
224
- """Verify unauthenticated proof creation is rejected"""
225
- # First create identity (authenticated)
226
- identity = client.post("/v1/identities", json={
227
- "identity_type": "agent"
228
- }, headers=auth_headers).json()
229
-
230
- # Try to create proof without auth
231
- response = client.post("/v1/proofs", json={
232
- "issuer_did": identity["did"],
233
- "claim": "Test",
234
- "proof_type": "CLAIM"
235
- })
236
- assert response.status_code == 401
237
-
238
- def test_invalid_api_key_rejected(self, client):
239
- """Verify invalid API key is rejected"""
240
- response = client.post("/v1/identities", json={
241
- "identity_type": "agent"
242
- }, headers={"X-API-Key": "invalid-key"})
243
- assert response.status_code == 403
244
- assert "Invalid API key" in response.json()["detail"]
245
-
246
- def test_public_endpoints_no_auth_needed(self, client, auth_headers):
247
- """Verify public endpoints work without authentication"""
248
- # Create some data first (authenticated)
249
- identity = client.post("/v1/identities", json={
250
- "identity_type": "agent"
251
- }, headers=auth_headers).json()
252
-
253
- proof = client.post("/v1/proofs", json={
254
- "issuer_did": identity["did"],
255
- "claim": "Public test",
256
- "proof_type": "CLAIM"
257
- }, headers=auth_headers).json()
258
-
259
- # These should work without auth
260
- assert client.get("/").status_code == 200
261
- assert client.get("/health").status_code == 200
262
- assert client.get("/v1/identities").status_code == 200
263
- assert client.get(f"/v1/identities/{identity['did']}").status_code == 200
264
- assert client.get("/v1/proofs").status_code == 200
265
- assert client.get(f"/v1/proofs/{proof['proof_id']}").status_code == 200
266
- assert client.get("/v1/chain/status").status_code == 200
267
-
268
-
269
- if __name__ == "__main__":
270
- pytest.main([__file__, "-v"])
@@ -1,206 +0,0 @@
1
- """
2
- Tests for DID Registry (GPT-5.2 audit - key rotation support)
3
- """
4
-
5
- import pytest
6
- import sys
7
- import os
8
- import secrets
9
-
10
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11
-
12
- from did_registry import (
13
- DIDDocument,
14
- DIDRegistry,
15
- VerificationMethod,
16
- KeyPurpose,
17
- KeyStatus,
18
- )
19
-
20
-
21
- class TestDIDDocument:
22
- """Test DID Document operations"""
23
-
24
- def test_create_document(self):
25
- """Test creating a DID Document with initial key"""
26
- pk = secrets.token_bytes(1952)
27
- did = "did:pn:agent:test123"
28
-
29
- doc = DIDDocument.create(did, pk)
30
-
31
- assert doc.id == did
32
- assert len(doc.verification_methods) == 1
33
- assert doc.verification_methods[0].status == KeyStatus.ACTIVE
34
-
35
- def test_create_with_recovery_key(self):
36
- """Test creating a DID Document with recovery key"""
37
- pk = secrets.token_bytes(1952)
38
- recovery_pk = secrets.token_bytes(1952)
39
- did = "did:pn:agent:test456"
40
-
41
- doc = DIDDocument.create(did, pk, recovery_public_key=recovery_pk)
42
-
43
- assert len(doc.verification_methods) == 2
44
- assert len(doc.get_recovery_keys()) == 1
45
-
46
- def test_add_key(self):
47
- """Test adding a new key"""
48
- pk1 = secrets.token_bytes(1952)
49
- pk2 = secrets.token_bytes(1952)
50
- did = "did:pn:agent:test789"
51
-
52
- doc = DIDDocument.create(did, pk1)
53
- initial_version = doc.version
54
-
55
- doc.add_key(pk2, "Dilithium3VerificationKey2024", [KeyPurpose.ASSERTION])
56
-
57
- assert len(doc.verification_methods) == 2
58
- assert doc.version > initial_version
59
-
60
- def test_key_rotation(self):
61
- """Test key rotation (revoke old, add new)"""
62
- pk1 = secrets.token_bytes(1952)
63
- pk2 = secrets.token_bytes(1952)
64
- did = "did:pn:agent:rotation_test"
65
-
66
- doc = DIDDocument.create(did, pk1)
67
- old_key_id = doc.verification_methods[0].id
68
-
69
- # Rotate
70
- new_key = doc.rotate_key(old_key_id, pk2, "Dilithium3VerificationKey2024")
71
-
72
- # Old key should be revoked
73
- old_key = doc.get_key(old_key_id)
74
- assert old_key.status == KeyStatus.REVOKED
75
-
76
- # New key should be active
77
- assert new_key.status == KeyStatus.ACTIVE
78
-
79
- # Only one active auth key
80
- assert len(doc.get_active_keys(KeyPurpose.AUTHENTICATION)) == 1
81
-
82
- def test_revoke_key(self):
83
- """Test key revocation"""
84
- pk = secrets.token_bytes(1952)
85
- did = "did:pn:agent:revoke_test"
86
-
87
- doc = DIDDocument.create(did, pk)
88
- key_id = doc.verification_methods[0].id
89
-
90
- result = doc.revoke_key(key_id)
91
-
92
- assert result is True
93
- assert doc.get_key(key_id).status == KeyStatus.REVOKED
94
-
95
- def test_to_dict(self):
96
- """Test W3C DID Document serialization"""
97
- pk = secrets.token_bytes(1952)
98
- did = "did:pn:agent:serialize_test"
99
-
100
- doc = DIDDocument.create(did, pk)
101
- d = doc.to_dict()
102
-
103
- assert "@context" in d
104
- assert d["id"] == did
105
- assert "verificationMethod" in d
106
- assert "authentication" in d
107
-
108
-
109
- class TestDIDRegistry:
110
- """Test DID Registry operations"""
111
-
112
- def test_register_and_resolve(self):
113
- """Test registering and resolving a DID"""
114
- registry = DIDRegistry()
115
- pk = secrets.token_bytes(1952)
116
- did = "did:pn:agent:registry_test"
117
-
118
- doc = DIDDocument.create(did, pk)
119
- result = registry.register(doc)
120
-
121
- assert result is True
122
- resolved = registry.resolve(did)
123
- assert resolved is not None
124
- assert resolved.id == did
125
-
126
- def test_no_duplicate_registration(self):
127
- """Test that duplicate DIDs cannot be registered"""
128
- registry = DIDRegistry()
129
- pk = secrets.token_bytes(1952)
130
- did = "did:pn:agent:duplicate_test"
131
-
132
- doc = DIDDocument.create(did, pk)
133
- registry.register(doc)
134
-
135
- # Second registration should fail
136
- result = registry.register(doc)
137
- assert result is False
138
-
139
- def test_update_document(self):
140
- """Test updating a DID Document"""
141
- registry = DIDRegistry()
142
- pk1 = secrets.token_bytes(1952)
143
- pk2 = secrets.token_bytes(1952)
144
- did = "did:pn:agent:update_test"
145
-
146
- doc = DIDDocument.create(did, pk1)
147
- registry.register(doc)
148
-
149
- # Add key and update
150
- doc.add_key(pk2, "Dilithium3VerificationKey2024", [KeyPurpose.ASSERTION])
151
- result = registry.update(doc)
152
-
153
- assert result is True
154
- resolved = registry.resolve(did)
155
- assert len(resolved.verification_methods) == 2
156
-
157
- def test_deactivate(self):
158
- """Test DID deactivation"""
159
- registry = DIDRegistry()
160
- pk = secrets.token_bytes(1952)
161
- did = "did:pn:agent:deactivate_test"
162
-
163
- doc = DIDDocument.create(did, pk)
164
- registry.register(doc)
165
-
166
- result = registry.deactivate(did)
167
-
168
- assert result is True
169
- resolved = registry.resolve(did)
170
- assert resolved.deactivated is True
171
-
172
- def test_version_history(self):
173
- """Test DID Document version history"""
174
- registry = DIDRegistry()
175
- pk1 = secrets.token_bytes(1952)
176
- pk2 = secrets.token_bytes(1952)
177
- did = "did:pn:agent:history_test"
178
-
179
- doc = DIDDocument.create(did, pk1)
180
- registry.register(doc)
181
-
182
- # Update
183
- doc.add_key(pk2, "Dilithium3VerificationKey2024", [KeyPurpose.ASSERTION])
184
- registry.update(doc)
185
-
186
- history = registry.get_history(did)
187
- assert len(history) == 2
188
-
189
- def test_verify_controller(self):
190
- """Test controller verification"""
191
- registry = DIDRegistry()
192
- pk1 = secrets.token_bytes(1952)
193
- pk2 = secrets.token_bytes(1952)
194
- did = "did:pn:agent:verify_test"
195
-
196
- doc = DIDDocument.create(did, pk1)
197
- registry.register(doc)
198
-
199
- # Valid controller
200
- assert registry.verify_controller(did, pk1) is True
201
- # Invalid controller
202
- assert registry.verify_controller(did, pk2) is False
203
-
204
-
205
- if __name__ == "__main__":
206
- pytest.main([__file__, "-v"])