Metadata-Version: 2.4
Name: robustrep
Version: 0.2.1
Summary: Robust, transport-agnostic reputation scoring for AI agents
Author: Dong Wang
License: Apache-2.0
Project-URL: Homepage, https://github.com/iamdongwang/robustrep
Project-URL: Repository, https://github.com/iamdongwang/robustrep
Project-URL: Issues, https://github.com/iamdongwang/robustrep/issues
Project-URL: Report, https://iamdongwang.github.io/robustrep/reports/latest/report.md
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas<4,>=2.0
Requires-Dist: numpy>=1.24
Requires-Dist: eth-abi>=5.0
Requires-Dist: eth-hash[pycryptodome]>=0.5
Requires-Dist: requests>=2.31
Requires-Dist: urllib3>=2.8
Requires-Dist: tabulate>=0.9
Requires-Dist: matplotlib>=3.7
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-cov>=5; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pip-audit; extra == "dev"
Dynamic: license-file

# robustrep

Robust, transport-agnostic reputation scoring for AI agents.

Feed it any table of `(rater, ratee, value, scale, tag, ts, evidence_uri, source)` and it returns a
robust score per ratee that resists Sybil raters and evidence-free ratings. Ships with a Base-chain
ERC-8004 adapter and a reproducible report.

Status: v0.1.1 released on PyPI. Design spec and plan live in the parent workspace; a summary is in `reports/latest/report.md`.
Release notes, including the security fixes in 0.1.1: [CHANGELOG.md](CHANGELOG.md).

## Install

    pip install robustrep

## Library

```python
import pandas as pd
from robustrep import Config, score

records = pd.DataFrame([...])  # columns: rater, ratee, value, scale, tag, ts, evidence_uri, source
result = score(records, Config())
```

## Base ERC-8004 report

    robustrep fetch  --db data/base.db          # pull events (resumable)
    robustrep score  --db data/base.db --out scores.csv
    robustrep report --db data/base.db --out-dir reports

The default endpoint list is rotated automatically and the `eth_getLogs` window adapts per
endpoint; `--rpc-url` (repeatable) replaces the list and `--chunk` caps the window.
RPC endpoint hostnames appear in the public report and `scores.json`; do not use an endpoint whose hostname embeds an account id or key.

Rater profiles (first-seen time and funder per rater, for sybil clustering) come from Alchemy when
`ALCHEMY_API_KEY` is set — its free plan covers Base (2.5 requests/sec; ~13k raters in about 1.5 h).
Blockscout closed its free Base API in 2026-10 and Etherscan's free plan never covered Base, so Alchemy
is now the practical source. Pick one explicitly with
`fetch --profile-source {auto,alchemy,blockscout,etherscan,none}`; `auto` prefers an Etherscan key, then
an Alchemy key, then keyless Blockscout.
The Alchemy key is read from the environment only (no flag), redacted from urllib3's debug log and
from robustrep's own log records that echo server text, and never appears in an error message —
Alchemy puts it in the request URL's path, so nothing that quotes a URL is ever raised or logged.

Latest scores: `reports/latest/scores.json`, also served at
https://iamdongwang.github.io/robustrep/reports/latest/scores.json

## Security considerations

Everything robustrep reads is written by untrusted parties: on-chain values, tags, evidence URIs and
addresses, plus whatever the RPC/Blockscout endpoints and evidence hosts return.

`robustrep fetch` makes outbound HTTP from *your* machine to evidence URIs chosen by the rated party.
Those go through an SSRF guard (scheme/host allowlist, parser cross-check, canonical rebuild, refusal
of private/reserved addresses, manual redirects, a size cap and per-socket-operation timeouts — not a
wall-clock bound). Its one known SSRF bypass, DNS rebinding, is unmitigated in v0.1 — so run `fetch`
on a host with no privileged reach into an internal network. API keys should come from the
environment (`ETHERSCAN_API_KEY`), never the source tree; `--etherscan-key` is an escape hatch that
takes precedence over the environment and is visible to anyone who can run `ps`.

Full threat model and private reporting instructions: [SECURITY.md](SECURITY.md).
