build(agent): new-agents-3#dd492b iteration
This commit is contained in:
parent
8636fde180
commit
93b338f7b7
34
README.md
34
README.md
|
|
@ -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
|
||||
- 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)
|
||||
- Policy DSL (policy.py): A lightweight DSL for declaring access rules.
|
||||
- Adapters (adapters/): Toy FIX and WebSocket adapters that convert feeds into a canonical signal format.
|
||||
- Aggregator (aggregation.py): Cross-venue data mixing with provenance tagging.
|
||||
- Provenance Ledger (ledger_merkle.py): Merkle-tree based proofs of data lineage.
|
||||
- Core (core.py): Orchestrates policy checks, ledger interactions, and end-to-end flow.
|
||||
- Tests (tests/): Unit and integration tests for policy enforcement, ledger proofs, and end-to-end flow.
|
||||
Architecture (production-ready mindset)
|
||||
- Policy DSL core and compiler (feedtrust/policy.py)
|
||||
- Provenance ledger (Merkle-based) with proofs (feedtrust/ledger_merkle.py)
|
||||
- Adapters for feeds (FIX/WebSocket) to canonical signals (feedtrust/adapters/*)
|
||||
- Lightweight aggregation layer for cross-venue signals (feedtrust/aggregation.py)
|
||||
- Core orchestrator to enforce policies and log provenance (feedtrust/core.py)
|
||||
|
||||
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
|
||||
- Build package: python -m build
|
||||
|
||||
Contribution
|
||||
- This project emphasizes minimal, well-scoped changes with strong test coverage.
|
||||
- See AGENTS.md for contributor guidelines.
|
||||
Notes
|
||||
- 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 repository conventions and testing commands.
|
||||
|
|
|
|||
|
|
@ -3,39 +3,66 @@ from typing import List, Dict, Any
|
|||
|
||||
class PolicyEngine:
|
||||
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:
|
||||
# Very small DSL parser for a single-line policy per call.
|
||||
# Supports two forms:
|
||||
# allow ...
|
||||
# deny ...
|
||||
# Example:
|
||||
# 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()]:
|
||||
if not line:
|
||||
continue
|
||||
if not line.startswith("allow"):
|
||||
continue
|
||||
# Remove leading 'allow'
|
||||
# Determine policy type
|
||||
if line.startswith("allow"):
|
||||
rest = line[len("allow"):].strip()
|
||||
policy: Dict[str, Any] = {}
|
||||
# Split by spaces, then parse key=value parts
|
||||
parts = rest.split()
|
||||
for part in parts:
|
||||
if "=" not in part:
|
||||
continue
|
||||
k, v = part.split("=", 1)
|
||||
v = v.strip().strip('"')
|
||||
# cast common types
|
||||
if v.isdigit():
|
||||
policy[k] = int(v)
|
||||
else:
|
||||
policy[k] = v
|
||||
# Normalize some keys
|
||||
policy.setdefault("latency_ms", 0)
|
||||
policy.setdefault("volume_cap", None)
|
||||
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:
|
||||
# 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:
|
||||
if (
|
||||
p.get("subject") in (subject, "any")
|
||||
|
|
|
|||
Loading…
Reference in New Issue