gabriel / musehub public
seed_attestations_demo.py python
161 lines 7.1 KB
Raw
sha256:3ff9c9863a9891bdcde71b4a43228f66d0493e38b7cc1d09fe9eb7de774046b2 feat: add repair-commit wire endpoint (API parity with repa… Opus 4.8 minor ⚠ breaking 1 day ago
1 """Seed real attestations using actual registered identities on localhost.
2
3 Real identities:
4 gabriel — human
5 musehub — org
6 claude-code — agent
7 claude-sonnet-4-6 — agent
8
9 Run from musehub repo root:
10 python3 scripts/seed_attestations_demo.py
11 """
12
13 import asyncio
14 import base64
15 import hashlib
16 import json
17 from datetime import datetime, timezone
18
19 import httpx
20 from nacl.signing import SigningKey
21
22
23 HUB = "https://localhost:1337"
24
25 DEMO_REPO = "gabriel/musehub"
26 DEMO_COMMIT = "gabriel/musehub@sha256:" + hashlib.sha256(b"demo-commit-seed").hexdigest()
27
28
29 def b64url(b: bytes) -> str:
30 return base64.urlsafe_b64encode(b).rstrip(b"=").decode()
31
32
33 def make_keypair(seed_str: str) -> tuple[SigningKey, str]:
34 seed = hashlib.sha256(seed_str.encode()).digest()
35 sk = SigningKey(seed)
36 return sk, f"ed25519:{b64url(bytes(sk.verify_key))}"
37
38
39 def sign(priv, attester, subject, claim_json, ts, scope="identity", scope_ref=None):
40 parts = ["ATTEST", attester, subject, claim_json, ts]
41 if scope != "identity" and scope_ref:
42 parts.append(scope_ref)
43 return f"ed25519:{b64url(priv.sign('\n'.join(parts).encode()).signature)}"
44
45
46 def make_body(priv, pub, attester, subject, type_key, scope="identity", scope_ref=None):
47 seed_hex = hashlib.sha256(f"{attester}:{subject}:{type_key}:{scope}".encode()).hexdigest()[:8]
48 seed_int = int(seed_hex, 16) % (365 * 24 * 3600)
49 ts = datetime.fromtimestamp(
50 datetime(2026, 1, 1, tzinfo=timezone.utc).timestamp() + seed_int,
51 tz=timezone.utc
52 ).isoformat(timespec="seconds")
53
54 claim_json = json.dumps({"type": type_key})
55 body = {
56 "attester": attester,
57 "attesterPublicKey": pub,
58 "subject": subject,
59 "claim": claim_json,
60 "issuedAt": ts,
61 "scope": scope,
62 "signature": sign(priv, attester, subject, claim_json, ts, scope, scope_ref),
63 }
64 if scope_ref:
65 body["scopeRef"] = scope_ref
66 if scope == "commit":
67 body["commitId"] = "sha256:" + hashlib.sha256(f"{attester}{subject}{type_key}".encode()).hexdigest()
68 return body
69
70
71 # Keypairs for each real identity (deterministic seeds for reproducibility)
72 KEYS = {
73 "gabriel": make_keypair("gabriel-real-seed"),
74 "musehub": make_keypair("musehub-org-real-seed"),
75 "claude-code": make_keypair("claude-code-real-seed"),
76 "claude-sonnet-4-6": make_keypair("claude-sonnet-real-seed"),
77 }
78
79
80 def k(handle):
81 return KEYS[handle]
82
83
84 # ── What makes sense ──────────────────────────────────────────────────────────
85 #
86 # RECEIVED by gabriel — others vouching for gabriel
87 # human: musehub (org) and claude-code (agent) confirm gabriel is human
88 # trusted: musehub and claude-sonnet-4-6 stake their rep on gabriel
89 # co-author: claude-code and claude-sonnet-4-6 — they shipped code together
90 # collab: musehub — worked on the platform together
91 # contractor: musehub — gabriel did contracted work for the org
92 # skill:verified: musehub and claude-code have seen the work firsthand
93 # code:reviewed: claude-code reviewed gabriel's code
94 # code:approved: claude-sonnet-4-6 approved a delivery
95 # deploy:approved: claude-code signed off on a deploy
96 #
97 # GIVEN by gabriel — gabriel vouching for others
98 # agent: gabriel confirms claude-code and claude-sonnet-4-6 are legit agents
99 # spawned-by: gabriel spawned claude-code — its actions trace back to him
100 # delegate: gabriel delegated to claude-sonnet-4-6
101 # trusted: gabriel trusts musehub
102 # org: gabriel confirms musehub is a legitimate org
103 # co-author: gabriel and claude-code co-authored
104 # skill:verified: gabriel has seen claude-code's capabilities firsthand
105 # code:reviewed: gabriel reviewed musehub's code
106 # midi:generated: gabriel confirms claude-sonnet-4-6 generated the MIDI
107 # master:approved: gabriel approved the master
108 #
109 ATTESTATIONS = [
110 # ── Received by gabriel ──────────────────────────────────────────────────
111 ("musehub", "gabriel", "human", "identity", None),
112 ("claude-code", "gabriel", "human", "identity", None),
113 ("musehub", "gabriel", "trusted", "identity", None),
114 ("claude-sonnet-4-6", "gabriel", "trusted", "identity", None),
115 ("claude-code", "gabriel", "co-author", "identity", None),
116 ("claude-sonnet-4-6", "gabriel", "co-author", "identity", None),
117 ("musehub", "gabriel", "collab", "identity", None),
118 ("musehub", "gabriel", "contractor", "identity", None),
119 ("musehub", "gabriel", "skill:verified", "identity", None),
120 ("claude-code", "gabriel", "skill:verified", "identity", None),
121 ("claude-code", "gabriel", "code:reviewed", "repo", DEMO_REPO),
122 ("claude-sonnet-4-6", "gabriel", "code:approved", "repo", DEMO_REPO),
123 ("claude-code", "gabriel", "deploy:approved","commit", DEMO_COMMIT),
124
125 # ── Given by gabriel ─────────────────────────────────────────────────────
126 ("gabriel", "claude-code", "agent", "identity", None),
127 ("gabriel", "claude-sonnet-4-6", "agent", "identity", None),
128 ("gabriel", "claude-code", "spawned-by", "identity", None),
129 ("gabriel", "claude-sonnet-4-6", "delegate", "identity", None),
130 ("gabriel", "musehub", "trusted", "identity", None),
131 ("gabriel", "musehub", "org", "identity", None),
132 ("gabriel", "claude-code", "co-author", "identity", None),
133 ("gabriel", "claude-code", "skill:verified", "identity", None),
134 ("gabriel", "musehub", "code:reviewed", "repo", DEMO_REPO),
135 ("gabriel", "claude-sonnet-4-6", "midi:generated", "identity", None),
136 ("gabriel", "musehub", "master:approved","identity", None),
137 ]
138
139
140 async def post_one(client, attester, subject, type_key, scope, scope_ref):
141 priv, pub = k(attester)
142 body = make_body(priv, pub, attester, subject, type_key, scope, scope_ref)
143 r = await client.post(f"{HUB}/api/profiles/{subject}/attestations", json=body, timeout=10)
144 ok = r.status_code in (200, 201)
145 status = "✓" if ok else "✗"
146 detail = "" if ok else f" {r.status_code}: {r.text[:80]}"
147 return f" {status} {attester:20s} → {subject:20s} [{type_key}]{detail}"
148
149
150 async def main():
151 print(f"Seeding real attestations on {HUB}\n {len(ATTESTATIONS)} total\n")
152 async with httpx.AsyncClient(verify=False) as client:
153 results = await asyncio.gather(*[post_one(client, *row) for row in ATTESTATIONS])
154 ok = sum(1 for r in results if "✓" in r)
155 for r in results:
156 print(r)
157 print(f"\n{'✓' if ok == len(results) else '✗'} {ok}/{len(results)} succeeded.")
158
159
160 if __name__ == "__main__":
161 asyncio.run(main())
File History 1 commit
sha256:3ff9c9863a9891bdcde71b4a43228f66d0493e38b7cc1d09fe9eb7de774046b2 feat: add repair-commit wire endpoint (API parity with repa… Opus 4.8 minor 1 day ago