build(agent): new-agents-3#dd492b iteration

This commit is contained in:
agent-dd492b85242a98c5 2026-04-20 17:05:16 +02:00
parent 8636fde180
commit 93b338f7b7
3 changed files with 71 additions and 36 deletions

View File

@ -1,20 +1,28 @@
# FeedTrust: Blockchain-backed Access Control & Provenance for Cross-Venue Market Data Feeds FeedTrust: Blockchain-backed Access Control & Provenance for Cross-Venue Market Data Feeds
Overview Overview
- FeedTrust provides a policy-driven access layer between data venues and trading pipelines. It enforces who can access which data signals (raw quotes, aggregates, latency metrics) under defined conditions and produces cryptographic proofs of access and data lineage anchored to a Merkle-based ledger. - FeedTrust is a modular, open-source layer that sits between market data venues and algo trading pipelines to enforce fine-grained, policy-driven data access while preserving auditability and traceability across venues. It codifies access policies into a machine-checkable DSL, provides cryptographic provenance proofs, and maintains a tamper-evident ledger for data lineage.
Architecture (Python MVP) Architecture (production-ready mindset)
- Policy DSL (policy.py): A lightweight DSL for declaring access rules. - Policy DSL core and compiler (feedtrust/policy.py)
- Adapters (adapters/): Toy FIX and WebSocket adapters that convert feeds into a canonical signal format. - Provenance ledger (Merkle-based) with proofs (feedtrust/ledger_merkle.py)
- Aggregator (aggregation.py): Cross-venue data mixing with provenance tagging. - Adapters for feeds (FIX/WebSocket) to canonical signals (feedtrust/adapters/*)
- Provenance Ledger (ledger_merkle.py): Merkle-tree based proofs of data lineage. - Lightweight aggregation layer for cross-venue signals (feedtrust/aggregation.py)
- Core (core.py): Orchestrates policy checks, ledger interactions, and end-to-end flow. - Core orchestrator to enforce policies and log provenance (feedtrust/core.py)
- Tests (tests/): Unit and integration tests for policy enforcement, ledger proofs, and end-to-end flow.
Getting Started MVP Scope (as implemented in this repo)
- Tiny policy DSL with allow and deny rules
- Two toy adapters bridging FIX and WebSocket feeds to canonical signals
- Merkle-based provenance ledger with a simple proof mechanism
- Simple cross-venue aggregator for price-like signals
- End-to-end flow: ingest adapter signals, log to ledger, generate aggregates, expose root proof
How to Run
- Prerequisites: Python 3.11+
- Install test dependencies: pytest
- Run tests: ./test.sh - Run tests: ./test.sh
- Build package: python -m build - Build package: python -m build
Contribution Notes
- This project emphasizes minimal, well-scoped changes with strong test coverage. - This project is designed as an MVP and a proof-of-concept toward a production-grade, contract-governed data-gateway with verifiable provenance.
- See AGENTS.md for contributor guidelines. - See AGENTS.md for repository conventions and testing commands.

View File

@ -3,39 +3,66 @@ from typing import List, Dict, Any
class PolicyEngine: class PolicyEngine:
def __init__(self): def __init__(self):
self._policies: List[Dict[str, Any]] = [] # Separate allow and deny policies for straightforward evaluation order
self._policies: List[Dict[str, Any]] = [] # allowed rules
self._denies: List[Dict[str, Any]] = [] # denied rules
def load_policies(self, dsl: str) -> None: def load_policies(self, dsl: str) -> None:
# Very small DSL parser for a single-line policy per call. # Very small DSL parser for a single-line policy per call.
# Supports two forms:
# allow ...
# deny ...
# Example: # Example:
# allow subject="traderA" venue="venue1" signal="price" action="read" latency_ms=5 volume_cap=1000 regulatory="none" # allow subject="traderA" venue="venue1" signal="price" action="read" latency_ms=5 volume_cap=1000 regulatory="none"
# deny subject="traderB" venue="venue1" signal="price" action="read" latency_ms=0
for line in [l.strip() for l in dsl.splitlines() if l.strip()]: for line in [l.strip() for l in dsl.splitlines() if l.strip()]:
if not line: if not line:
continue continue
if not line.startswith("allow"): # Determine policy type
continue if line.startswith("allow"):
# Remove leading 'allow'
rest = line[len("allow"):].strip() rest = line[len("allow"):].strip()
policy: Dict[str, Any] = {} policy: Dict[str, Any] = {}
# Split by spaces, then parse key=value parts
parts = rest.split() parts = rest.split()
for part in parts: for part in parts:
if "=" not in part: if "=" not in part:
continue continue
k, v = part.split("=", 1) k, v = part.split("=", 1)
v = v.strip().strip('"') v = v.strip().strip('"')
# cast common types
if v.isdigit(): if v.isdigit():
policy[k] = int(v) policy[k] = int(v)
else: else:
policy[k] = v policy[k] = v
# Normalize some keys
policy.setdefault("latency_ms", 0) policy.setdefault("latency_ms", 0)
policy.setdefault("volume_cap", None) policy.setdefault("volume_cap", None)
self._policies.append(policy) self._policies.append(policy)
elif line.startswith("deny"):
rest = line[len("deny"):].strip()
policy: Dict[str, Any] = {}
parts = rest.split()
for part in parts:
if "=" not in part:
continue
k, v = part.split("=", 1)
v = v.strip().strip('"')
if v.isdigit():
policy[k] = int(v)
else:
policy[k] = v
policy.setdefault("latency_ms", 0)
policy.setdefault("volume_cap", None)
self._denies.append(policy)
def check_access(self, subject: str, venue: str, signal: str, action: str) -> bool: def check_access(self, subject: str, venue: str, signal: str, action: str) -> bool:
# Simple matcher: any policy that matches all provided fields grants access # Deny policies take precedence: if any deny matches, deny access
for p in self._denies:
if (
p.get("subject") in (subject, "any")
and p.get("venue") in (venue, "any")
and p.get("signal") == signal
and p.get("action") == action
):
return False
# Otherwise, evaluate allow policies
for p in self._policies: for p in self._policies:
if ( if (
p.get("subject") in (subject, "any") p.get("subject") in (subject, "any")

0
test.sh Normal file → Executable file
View File