Skip to content

Commit f31ead2

Browse files
authored
feat: v0.2 Enterprise-Grade Trust Verification Protocol (#14)
feat: v0.2 Enterprise-Grade Trust Verification Protocol
2 parents 2486caf + ee75cae commit f31ead2

32 files changed

Lines changed: 3097 additions & 96 deletions

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,8 @@ ROLL_OUT_STATUS.md
8282
LLM_HANDOFF.md
8383
.hypothesis/
8484
COWORK.md
85+
REVIEW_BRIEF.md
86+
AIRLOCK_COMPANY.md
87+
PROTOCOL_DEBATE.md
88+
IMPLEMENTATION_PLAN.md
8589
.claude/

CHANGELOG.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,33 @@ All notable changes to the Airlock Protocol are documented in this file.
55
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.0] - 2026-04-05
9+
10+
### Added
11+
- **Trust Tiers**: Progressive trust levels (UNKNOWN -> CHALLENGE_VERIFIED -> DOMAIN_VERIFIED -> VC_VERIFIED) with configurable score ceilings per tier
12+
- **Tiered Decay**: Per-tier reputation half-lives (30/90/180/365 days) with decay floor at 0.60 for established agents
13+
- **Proof-of-Work**: SHA-256 Hashcash anti-Sybil protection on handshake with adaptive difficulty
14+
- **Privacy Mode**: `privacy_mode` field in HandshakeRequest (`any`/`local_only`/`no_challenge`) for GDPR/DPDP compliance
15+
- **Structured LLM Output**: JSON schema evaluation via LiteLLM `response_format` parameter
16+
- **Dual-LLM Evaluation**: Optional second model cross-validation with conservative agreement protocol
17+
- **Answer Fingerprinting**: SimHash + SHA-256 duplicate/near-duplicate detection for bot farm defense
18+
- New `GET /pow-challenge` endpoint for PoW challenge issuance
19+
- `TrustTier` IntEnum in attestations for relying party visibility
20+
- `fingerprint_flags` field in AirlockAttestation
21+
- 60+ new tests (property-based, security, integration)
22+
23+
### Changed
24+
- `AirlockAttestation` now includes `tier`, `privacy_mode`, and `fingerprint_flags` fields
25+
- `HandshakeRequest` now includes optional `pow` and `privacy_mode` fields
26+
- Reputation scoring respects tier ceilings (LLM-only agents capped at 0.70)
27+
- Decay uses tier-specific half-lives instead of single global value
28+
29+
### Security
30+
- PoW prevents Sybil/DoS attacks on handshake endpoint
31+
- Answer fingerprinting detects coordinated bot farm submissions
32+
- Dual-LLM evaluation requires attacker to fool two independent models
33+
- `privacy_mode: local_only` prevents data from leaving gateway instance
34+
835
## [0.1.0] - 2026-04-01
936

1037
### Added
@@ -33,5 +60,5 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
3360
- IETF Internet-Draft specification (draft-airlock-agent-trust-00)
3461
- Protocol specification (790 lines, RFC-style)
3562
- Monitoring and deployment documentation
36-
- 306 tests passing across 30 test files
37-
- Apache 2.0 license
63+
- 338 tests passing across 30 test files
64+
- BSL 1.1 gateway license, Apache 2.0 SDKs, CC-BY-4.0 spec

CLAUDE.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,15 @@ airlock/
3636
engine/ — Orchestrator, event bus, state machine
3737
gateway/ — FastAPI routes and handlers
3838
integrations/ — Anthropic, LangChain, OpenAI SDKs
39+
pow.py — Proof-of-Work (SHA-256 Hashcash, adaptive difficulty)
3940
registry/ — Agent registry and store
40-
reputation/ — Trust scoring and decay
41+
reputation/ — Trust scoring, tiered decay, floor protection
4142
schemas/ — Pydantic models
43+
trust_tier.py — TrustTier IntEnum + score ceilings
4244
sdk/ — Client SDK and middleware
4345
semantic/ — Challenge evaluation + rule engine
44-
tests/ — 27 test files, 198+ tests
46+
fingerprint.py — SimHash + SHA-256 answer fingerprinting
47+
tests/ — 399+ tests (unit, integration, property-based, security)
4548
```
4649

4750
## Conventions
@@ -55,6 +58,7 @@ tests/ — 27 test files, 198+ tests
5558
- **No print():** Use `logging` module. Never print() in library code.
5659
- **DID format:** Always validate DID strings match `did:key:z6Mk...` pattern before processing.
5760
- **Secrets:** Never log or expose private keys, challenge secrets, or JWT tokens.
61+
- **Feature flags:** All new v0.2 features have feature flags in config.py for backward compatibility.
5862

5963
## Common Mistakes to Avoid
6064
- Don't use `json.dumps()` for Pydantic models — use `model.model_dump_json()`

CONTRIBUTING.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ pip install -e ".[dev]"
2424
python -m pytest tests/ -v
2525
```
2626

27-
All new code must include tests. The test suite must maintain 338+ passing tests.
27+
All new code must include tests. The test suite must maintain 399+ passing tests.
28+
29+
Test categories include:
30+
- **Unit tests** — Individual module behavior
31+
- **Integration tests** — Cross-module and gateway end-to-end flows
32+
- **Property-based tests** — Hypothesis-driven invariant checking (crypto, scoring, fingerprinting)
33+
- **Security tests** — Sybil resistance, replay protection, injection mitigation
2834

2935
## Linting
3036

README.md

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![CI](https://github.com/airlock-protocol/airlock/actions/workflows/ci.yml/badge.svg)](https://github.com/airlock-protocol/airlock/actions/workflows/ci.yml)
44
[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
5-
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5+
[![License](https://img.shields.io/badge/License-Multi--License-blue.svg)](#license)
66
[![PyPI version](https://img.shields.io/pypi/v/airlock-protocol.svg)](https://pypi.org/project/airlock-protocol/)
77
[![DCO](https://img.shields.io/badge/DCO-required-brightgreen.svg)](https://developercertificate.org/)
88

@@ -12,6 +12,21 @@
1212

1313
---
1414

15+
## What's New in v0.2
16+
17+
### Trust & Security
18+
- **Trust Tiers** — Progressive trust levels (Unknown -> Challenge-Verified -> Domain-Verified -> VC-Verified) with score ceilings
19+
- **Proof-of-Work** — SHA-256 Hashcash anti-Sybil protection on handshake
20+
- **Privacy Mode**`local_only`, `any`, `no_challenge` modes for GDPR/DPDP compliance
21+
- **Dual-LLM Evaluation** — Optional cross-validation with conservative agreement
22+
- **Answer Fingerprinting** — SimHash + SHA-256 bot farm detection
23+
- **Structured LLM Output** — JSON schema evaluation (no free-text parsing)
24+
- **Tiered Decay** — Per-tier reputation half-lives with floor protection
25+
26+
See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
27+
28+
---
29+
1530
## The Problem
1631

1732
AI agents are rapidly gaining the ability to communicate with each other autonomously (via protocols like Google A2A and Anthropic MCP). There is no standard mechanism for verifying agent identity, authorization, or trustworthiness. The agent ecosystem is repeating the same mistake email made — building communication without authentication. Email took 20 years to bolt on SPF, DKIM, and DMARC after spam became an existential crisis. The Agentic Airlock builds the trust layer *before* the agent spam crisis hits.
@@ -56,6 +71,8 @@ Resolve → Handshake → Challenge → Verdict → Seal
5671
└─────┴─────────────────────────────────── ┘
5772
```
5873

74+
**v0.2 additions:** Handshake now supports optional **Proof-of-Work** (SHA-256 Hashcash) for anti-Sybil protection. Agents are assigned a **Trust Tier** (Unknown/Challenge-Verified/Domain-Verified/VC-Verified) that governs score ceilings and decay rates. **Privacy Mode** (`local_only`/`any`/`no_challenge`) allows callers to control data residency for GDPR/DPDP compliance. Challenge evaluation supports **Dual-LLM** cross-validation with conservative agreement.
75+
5976
---
6077

6178
## The 5 Phases
@@ -105,7 +122,7 @@ git clone https://github.com/airlock-protocol/airlock.git
105122
cd airlock
106123
pip install -e ".[dev]"
107124
python demo/run_demo.py # 3-agent demo, no external services needed
108-
python -m pytest tests/ -v # 313 tests
125+
python -m pytest tests/ -v # 399+ tests
109126
```
110127

111128
> **[→ Full Getting Started Guide](GETTING_STARTED.md)**
@@ -154,7 +171,8 @@ When you publish: see **[RELEASING.md](RELEASING.md)** (PyPI OIDC, npm `NPM_TOKE
154171
| Method | Endpoint | Description |
155172
|--------|----------|-------------|
156173
| `POST` | `/resolve` | Look up an agent by DID and return its profile |
157-
| `POST` | `/handshake` | Submit a signed `HandshakeRequest` for verification |
174+
| `POST` | `/handshake` | Submit a signed `HandshakeRequest` for verification (optional PoW + privacy_mode) |
175+
| `GET` | `/pow-challenge` | Issue a Proof-of-Work challenge (SHA-256 Hashcash, adaptive difficulty) |
158176
| `POST` | `/challenge-response` | Submit an agent's answer to a semantic challenge |
159177
| `POST` | `/register` | Register an `AgentProfile` (DID + capabilities + endpoint) |
160178
| `POST` | `/feedback` | Signed `SignedFeedbackReport` (Ed25519 + nonce); see SDKs |
@@ -196,15 +214,26 @@ New agents start at a neutral score of **0.50**.
196214
| `REJECTED` | `−0.15` (fixed penalty) |
197215
| `DEFERRED` | `−0.02` (small nudge — ambiguity is a signal) |
198216

217+
### Trust Tiers (v0.2)
218+
219+
| Tier | Score Ceiling | Decay Half-Life |
220+
|------|---------------|-----------------|
221+
| `UNKNOWN` | 0.50 | 30 days |
222+
| `CHALLENGE_VERIFIED` | 0.70 | 90 days |
223+
| `DOMAIN_VERIFIED` | 0.90 | 180 days |
224+
| `VC_VERIFIED` | 1.00 | 365 days |
225+
226+
Agents with 10+ interactions have a decay floor of **0.60** — established agents never drop back to fully unknown.
227+
199228
### Half-Life Decay
200229

201230
Scores decay toward neutral (0.50) over time using the standard radioactive decay formula:
202231

203232
```
204-
decayed = 0.5 + (score − 0.5) × 2^(−elapsed_days / 30)
233+
decayed = 0.5 + (score − 0.5) × 2^(−elapsed_days / half_life)
205234
```
206235

207-
An agent that stops interacting gradually becomes "unknown" rather than "suspect" — matching real-world trust intuitions. The half-life is 30 days.
236+
In v0.2, `half_life` is tier-specific (see table above) instead of a single global value. An agent that stops interacting gradually becomes "unknown" rather than "suspect" — matching real-world trust intuitions.
208237

209238
---
210239

@@ -214,6 +243,7 @@ An agent that stops interacting gradually becomes "unknown" rather than "suspect
214243
airlock-protocol/
215244
├── airlock/
216245
│ ├── config.py # Pydantic settings (env vars with AIRLOCK_ prefix)
246+
│ ├── pow.py # Proof-of-Work (SHA-256 Hashcash, adaptive difficulty)
217247
│ ├── crypto/
218248
│ │ ├── keys.py # Ed25519 KeyPair + did:key encoding/decoding
219249
│ │ ├── signing.py # sign_model / verify_model + canonicalization
@@ -227,28 +257,30 @@ airlock-protocol/
227257
│ │ ├── handlers.py # Request handlers (signature gate + event publish)
228258
│ │ └── routes.py # FastAPI router + endpoint wiring
229259
│ ├── reputation/
230-
│ │ ├── scoring.py # Half-life decay + verdict delta computation
260+
│ │ ├── scoring.py # Tiered decay + verdict delta + floor protection
231261
│ │ └── store.py # LanceDB-backed TrustScore persistence
232262
│ ├── schemas/
233263
│ │ ├── challenge.py # ChallengeRequest + ChallengeResponse
234264
│ │ ├── envelope.py # MessageEnvelope, TransportAck, TransportNack
235265
│ │ ├── events.py # VerificationEvent hierarchy (typed)
236-
│ │ ├── handshake.py # HandshakeRequest + HandshakeResponse
266+
│ │ ├── handshake.py # HandshakeRequest + HandshakeResponse (PoW + privacy_mode)
237267
│ │ ├── identity.py # AgentDID, AgentProfile, VerifiableCredential
238268
│ │ ├── reputation.py # TrustScore schema
239269
│ │ ├── session.py # VerificationSession + SessionSeal
270+
│ │ ├── trust_tier.py # TrustTier IntEnum + score ceilings
240271
│ │ └── verdict.py # TrustVerdict, AirlockAttestation, CheckResult
241272
│ ├── sdk/
242273
│ │ ├── client.py # AirlockClient (async httpx wrapper)
243274
│ │ └── middleware.py # AirlockMiddleware (protect decorator)
244275
│ └── semantic/
245-
│ └── challenge.py # LLM-backed challenge generation + evaluation
276+
│ ├── challenge.py # LLM-backed challenge generation + evaluation
277+
│ └── fingerprint.py # SimHash + SHA-256 answer fingerprinting
246278
├── integrations/
247279
│ └── airlock-mcp/ # MCP stdio server (gateway tools)
248280
├── sdks/
249281
│ └── typescript/ # npm package `airlock-client` (HTTP + types)
250282
├── examples/ # Agent scenarios + demos
251-
└── tests/ # Pytest suite (gateway, engine, SDK, A2A, )
283+
└── tests/ # Pytest suite — 399+ tests (gateway, engine, SDK, A2A, security, property-based)
252284
```
253285

254286
---
@@ -264,6 +296,9 @@ airlock-protocol/
264296
| **Reputation with memory** | Half-life decay means reputation is time-sensitive — a trusted agent that goes dark eventually becomes "unknown" again |
265297
| **Local-first** | LanceDB is embedded (no server). The entire stack runs on a laptop: `python demo/run_demo.py` |
266298
| **A2A compatible** | The `HandshakeRequest` schema is designed to wrap Google A2A `message` objects |
299+
| **Progressive trust** | Trust tiers gate score ceilings — LLM-only agents are capped at 0.70; full VC verification unlocks 1.00 |
300+
| **Privacy-aware** | `privacy_mode` lets callers control data residency (`local_only` keeps all data on the gateway instance) |
301+
| **Anti-Sybil** | Proof-of-Work on handshake + answer fingerprinting make bot farm attacks economically infeasible |
267302

268303
---
269304

@@ -284,7 +319,13 @@ All settings can be configured via environment variables with the `AIRLOCK_` pre
284319

285320
## License
286321

287-
Apache License 2.0. See [LICENSE](LICENSE).
322+
| Component | License |
323+
|-----------|---------|
324+
| SDKs, crypto, schemas (`sdks/`, `airlock/crypto/`, `airlock/schemas/`) | Apache 2.0 |
325+
| Gateway, engine (`airlock/gateway/`, `airlock/engine/`) | BSL 1.1 (converts to Apache 2.0 on 2030-04-04) |
326+
| Specification (`docs/spec/`) | CC-BY-4.0 |
327+
328+
See [LICENSE](LICENSE) for details.
288329

289330
## Author
290331

airlock/config.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,26 @@ class AirlockConfig(BaseSettings):
8787
scoring_threshold_blacklist: float = 0.15
8888
scoring_diminishing_factor: float = 0.1
8989

90+
# -----------------------------------------------------------------------
91+
# Trust tier ceilings (overridable via env)
92+
# -----------------------------------------------------------------------
93+
scoring_tier_0_ceiling: float = 0.50
94+
scoring_tier_1_ceiling: float = 0.70
95+
scoring_tier_2_ceiling: float = 0.90
96+
scoring_tier_3_ceiling: float = 1.00
97+
98+
# -----------------------------------------------------------------------
99+
# Per-tier decay half-lives (days)
100+
# -----------------------------------------------------------------------
101+
scoring_decay_half_life_tier_0: float = 30.0
102+
scoring_decay_half_life_tier_1: float = 90.0
103+
scoring_decay_half_life_tier_2: float = 180.0
104+
scoring_decay_half_life_tier_3: float = 365.0
105+
106+
# Decay floor — agents with N+ successful verifications don't drop below this
107+
scoring_decay_floor: float = 0.60
108+
scoring_decay_floor_min_interactions: int = 10
109+
90110
# -----------------------------------------------------------------------
91111
# Challenge questions (path to external JSON, empty = use built-in generic set)
92112
# -----------------------------------------------------------------------
@@ -102,6 +122,37 @@ class AirlockConfig(BaseSettings):
102122
rule_min_answer_length: int = 20
103123
rule_min_sentences: int = 2
104124

125+
# -----------------------------------------------------------------------
126+
# Proof-of-Work (anti-Sybil)
127+
# -----------------------------------------------------------------------
128+
pow_required: bool = False
129+
pow_difficulty: int = Field(default=20, ge=1, le=32)
130+
pow_ttl_seconds: int = Field(default=120, ge=30, le=600)
131+
pow_difficulty_new_did: int = Field(default=22, ge=1, le=32)
132+
133+
# -----------------------------------------------------------------------
134+
# Privacy mode
135+
# -----------------------------------------------------------------------
136+
privacy_mode_default: str = "any"
137+
privacy_mode_allow_no_challenge: bool = True
138+
139+
# -----------------------------------------------------------------------
140+
# LLM evaluation settings
141+
# -----------------------------------------------------------------------
142+
llm_structured_output: bool = True
143+
llm_dual_evaluation: bool = False
144+
litellm_model_secondary: str = ""
145+
litellm_api_base_secondary: str = ""
146+
147+
# -----------------------------------------------------------------------
148+
# Answer fingerprinting (bot farm detection)
149+
# -----------------------------------------------------------------------
150+
fingerprint_enabled: bool = True
151+
fingerprint_hamming_threshold: int = Field(default=5, ge=0, le=10)
152+
fingerprint_window_size: int = Field(default=1000, ge=100, le=100000)
153+
fingerprint_exact_duplicate_action: str = "fail"
154+
fingerprint_near_duplicate_action: str = "flag"
155+
105156
# Event bus drain timeout during shutdown (seconds).
106157
event_bus_drain_timeout_seconds: float = Field(default=30.0, ge=1.0, le=600.0)
107158

0 commit comments

Comments
 (0)