agent-cv/agent_cv/verify.py

58 lines
2.1 KiB
Python

"""Stateless re-verification: given a CV (that someone else produced), re-check
every 'verified' account by re-fetching its source and re-checking its proof.
Nothing is trusted but the source platforms themselves.
"""
from __future__ import annotations
from .model import CV, VERIFIED
from .util import get_json, dig
def verify_cv(cv: CV, *, getter=None, proof_fetcher=None):
"""Return a list of per-account results:
{platform, handle, claimed_karma, status, notes}
status: 'verified' | 'FAILED' | 'unverified-claim'
"""
results = []
for a in cv.accounts:
r = {"platform": a.platform, "handle": a.handle, "claimed_karma": a.karma, "notes": []}
if not a.is_verified():
r["status"] = "unverified-claim"
results.append(r)
continue
ok = True
# 1) re-fetch karma from the recorded source and compare
if not a.source or not a.karma_path:
ok = False
r["notes"].append("marked verified but missing source/karma_path")
else:
try:
data = get_json(a.source, getter=getter) if getter else get_json(a.source)
live = dig(data, a.karma_path)
if live != a.karma:
ok = False
r["notes"].append(f"karma mismatch: cv={a.karma} live={live}")
except Exception as e:
ok = False
r["notes"].append(f"source unreachable: {e}")
# 2) re-check the ownership proof, if any
if a.proof:
if proof_fetcher is None:
r["notes"].append("proof present but no proof_fetcher supplied — not re-checked")
else:
from .proof import verify_link
text, author = proof_fetcher(a.proof.get("url"))
if not verify_link(a.proof.get("nonce"), a.handle, text, author):
ok = False
r["notes"].append("link-proof failed")
r["status"] = "verified" if ok else "FAILED"
results.append(r)
return results
def all_verified(results) -> bool:
return all(r["status"] != "FAILED" for r in results)