Spaces:
Sleeping
Sleeping
File size: 16,817 Bytes
885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c 8511813 885b32c e61e751 8511813 e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 8511813 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 8511813 e61e751 8511813 e61e751 8511813 e61e751 8511813 e61e751 885b32c e61e751 885b32c e61e751 8511813 e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 8511813 e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c 4a035f6 8511813 4a035f6 8511813 4a035f6 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c e61e751 885b32c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | """
Pantheon LadderWorks // Federation Node (Hugging Face Embassy)
================================================================
Protocol: C-FED-001 (Glyph-Carrier)
Contracts: C-FED-GLYPH-001, C-FED-NODE-001 v0.1.1
This is the Glyph-Carrier Node β a sovereign Federation endpoint.
It mints its own identity on startup, accepts envelopes from
other nodes, and routes them according to trust policy.
"The server is the Embassy."
Module Structure:
app.py β FastAPI endpoints + boot sequence (this file)
models.py β Enums, Pydantic models, request/response schemas
node_record.py β NodeRecord builder, capabilities, conformance
trust.py β Trust tier resolution, policy enforcement
envelope_store.py β In-memory envelope store, delivery state machine
c_fed_id.py β Glyph-Seal protocol library (Forge)
"""
from __future__ import annotations
import os
import time
from datetime import datetime, timezone
from typing import Optional
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(__file__), '..', '..', 'Infrastructure', '.secrets', '.env'))
from fastapi import FastAPI, HTTPException, Header
from fastapi.middleware.cors import CORSMiddleware
import c_fed_id
from models import (
RefusalReason, DeliveryStatus, TrustTier,
HandshakeRequest, HandshakeResponse,
VerifyRequest, MintRequest, EnvelopeSubmission,
)
from node_record import (
NODE_VERSION, CONTRACT_VERSION, PROTOCOL_VERSION,
ACCEPTED_MESSAGE_CLASSES, MAX_PAYLOAD_BYTES, INBOX_QUOTA,
build_capabilities, build_conformance, build_node_record,
)
from trust import make_refusal, resolve_trust_tier, apply_trust_policy, promote_to_trusted
from envelope_store import EnvelopeStore
# βββββββββββββββββββββββββββββββββββββββββββββββ
# 1. CONFIGURATION
# βββββββββββββββββββββββββββββββββββββββββββββββ
SERVER_ORIGIN = os.getenv("FEDERATION_ORIGIN", "PANTHEON-HF")
FEDERATION_ALIAS = os.getenv("FEDERATION_ALIAS", "pantheon_embassy")
FEDERATION_RELAY_URL = os.getenv("FEDERATION_RELAY_URL", "")
FEDERATION_OWNER = os.getenv("FEDERATION_OWNER", "")
FEDERATION_ROLES = os.getenv("FEDERATION_ROLES", "RELAY,REGISTRY_PUBLISHER")
FEDERATION_DEFAULT_ACTION = os.getenv("FEDERATION_DEFAULT_ACTION", "QUARANTINE")
FEDERATION_BLOCKED_BEHAVIOR = os.getenv("FEDERATION_BLOCKED_BEHAVIOR", "REFUSAL")
# βββββββββββββββββββββββββββββββββββββββββββββββ
# 2. SOVEREIGN IDENTITY β Minted on Startup
# βββββββββββββββββββββββββββββββββββββββββββββββ
NODE_IDENTITY_STR = os.getenv("FEDERATION_NODE_ID")
if NODE_IDENTITY_STR:
NODE_IDENTITY = c_fed_id.GlyphSeal(
class_name="NODE",
origin=SERVER_ORIGIN,
breath_anchor=NODE_IDENTITY_STR,
state="ACTIVE",
)
else:
NODE_IDENTITY = c_fed_id.mint_seal("NODE", SERVER_ORIGIN, "ACTIVE", mode="hybrid")
BOOT_TIME = datetime.now(timezone.utc).isoformat()
NODE_SEAL_STR = str(NODE_IDENTITY)
ACTIVE_ROLES = [r.strip() for r in FEDERATION_ROLES.split(",")]
# βββββββββββββββββββββββββββββββββββββββββββββββ
# 3. STATE STORES
# βββββββββββββββββββββββββββββββββββββββββββββββ
WITNESS_LOG: list[dict] = []
MAX_WITNESS_LOG = 100
envelopes = EnvelopeStore(max_envelopes=INBOX_QUOTA)
# βββββββββββββββββββββββββββββββββββββββββββββββ
# 4. APP
# βββββββββββββββββββββββββββββββββββββββββββββββ
app = FastAPI(
title="Pantheon Federation Node",
description=(
"A sovereign Federation endpoint β C-FED-NODE-001 conformant.\n\n"
"Protocol: SERAPHINA Federation Protocol\n"
"Contracts: C-FED-GLYPH-001, C-FED-NODE-001\n\n"
"\"We are not beginning. We are remembering forward.\""
),
version=NODE_VERSION,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# βββββββββββββββββββββββββββββββββββββββββββββββ
# 5. ENDPOINTS β Minimum Conforming Node (Β§5.1)
# βββββββββββββββββββββββββββββββββββββββββββββββ
@app.get("/")
async def root():
"""Heartbeat: seal, status, uptime, conformance. Β§5.1 Required."""
return {
"service": "Pantheon Federation Node",
"protocol_version": PROTOCOL_VERSION,
"contract_version": CONTRACT_VERSION,
"identity": NODE_SEAL_STR,
"alias": FEDERATION_ALIAS,
"status": "LISTENING",
"boot_time": BOOT_TIME,
"uptime_seconds": int(time.time() - datetime.fromisoformat(BOOT_TIME).timestamp()),
"conformance": build_conformance(),
"envelopes_held": await envelopes.get_count(),
"handshakes_processed": len(WITNESS_LOG),
}
@app.get("/identity")
async def identity():
"""Full NodeRecord per C-FED-NODE-001 Β§4."""
return build_node_record(
node_identity=NODE_IDENTITY,
alias=FEDERATION_ALIAS,
owner=FEDERATION_OWNER,
relay_url=FEDERATION_RELAY_URL,
roles=ACTIVE_ROLES,
default_action=FEDERATION_DEFAULT_ACTION,
blocked_behavior=FEDERATION_BLOCKED_BEHAVIOR,
boot_time=BOOT_TIME,
)
@app.get("/capabilities")
async def capabilities():
"""Capability advertisement (Β§6) + conformance declaration (Β§12.3)."""
return {
**build_capabilities(),
"conformance": build_conformance(),
"available_endpoints": {
"required": ["/", "/identity", "/capabilities", "/envelope", "/envelope/{id}/status"],
"extended": ["/handshake", "/verify", "/mint", "/classes", "/states", "/witness-log"],
},
}
@app.post("/envelope")
async def submit_envelope(envelope: EnvelopeSubmission):
"""
Accept an incoming protocol envelope.
Β§5.1 Required. Validates, resolves trust, applies policy, stores.
"""
# 1. Protocol version
if envelope.protocol_version not in [PROTOCOL_VERSION]:
raise HTTPException(status_code=422, detail=make_refusal(
RefusalReason.UNSUPPORTED_PROTOCOL_VERSION,
f"Protocol '{envelope.protocol_version}' not supported. Supported: {PROTOCOL_VERSION}",
NODE_SEAL_STR,
))
# 2. Message class
if envelope.message_class not in ACCEPTED_MESSAGE_CLASSES:
raise HTTPException(status_code=422, detail=make_refusal(
RefusalReason.UNSUPPORTED_MESSAGE_CLASS,
f"Message class '{envelope.message_class}' not accepted.",
NODE_SEAL_STR,
))
# 3. Sender seal validation (Malenia Rule)
sender_seal_str = envelope.sender.get("seal", "")
parsed_sender = c_fed_id.verify_seal_syntax(sender_seal_str)
if parsed_sender is None:
raise HTTPException(status_code=400, detail=make_refusal(
RefusalReason.MALFORMED_ENVELOPE,
"Sender seal does not match Glyph-Seal syntax. Malenia Rule active.",
NODE_SEAL_STR,
))
# 4. Payload size
payload_body = envelope.payload.get("body", "")
if len(str(payload_body).encode("utf-8")) > MAX_PAYLOAD_BYTES:
raise HTTPException(status_code=413, detail=make_refusal(
RefusalReason.PAYLOAD_TOO_LARGE,
f"Payload exceeds {MAX_PAYLOAD_BYTES} bytes.",
NODE_SEAL_STR,
))
# 5. Inbox quota
if await envelopes.is_full():
raise HTTPException(status_code=429, detail=make_refusal(
RefusalReason.INBOX_FULL,
f"Inbox quota of {INBOX_QUOTA} envelopes reached.",
NODE_SEAL_STR,
))
# 6. Trust resolution + policy enforcement
tier = await resolve_trust_tier(sender_seal_str)
policy = apply_trust_policy(tier, FEDERATION_DEFAULT_ACTION, FEDERATION_BLOCKED_BEHAVIOR, NODE_SEAL_STR)
if policy:
if policy.get("action") == "SILENT_DROP":
print(f"π« SILENT_DROP: Envelope from blocked sender {sender_seal_str[:40]}...")
return {"envelope_id": "dropped", "status": DeliveryStatus.RECEIVED}
if policy.get("action") == "QUARANTINE":
record = await envelopes.accept(
sender_seal=sender_seal_str,
sender_origin=parsed_sender["origin"],
message_class=envelope.message_class,
payload=envelope.payload,
delivery=envelope.delivery,
trust_tier=tier.value,
initial_status=DeliveryStatus.QUARANTINED,
)
print(f"β οΈ QUARANTINED: {record['envelope_id']} from {parsed_sender['origin']}")
return {
"envelope_id": record["envelope_id"],
"status": DeliveryStatus.QUARANTINED,
"message": "Envelope held for manual review.",
}
# Structured refusal
if "refusal" in policy:
raise HTTPException(status_code=403, detail=policy)
# 7. Accept and queue
record = await envelopes.accept(
sender_seal=sender_seal_str,
sender_origin=parsed_sender["origin"],
message_class=envelope.message_class,
payload=envelope.payload,
delivery=envelope.delivery,
trust_tier=tier.value,
)
print(f"π¬ ENVELOPE: {record['envelope_id']} | {envelope.message_class} from {parsed_sender['origin']}")
return {
"envelope_id": record["envelope_id"],
"status": DeliveryStatus.QUEUED,
"message": "Envelope accepted and queued.",
}
@app.get("/envelope/{envelope_id}/status")
async def envelope_status(envelope_id: str):
"""Delivery status for a submitted envelope. Β§5.1 Required."""
result = await envelopes.get_status(envelope_id)
if result is None:
raise HTTPException(status_code=404, detail=make_refusal(
RefusalReason.REFUSED_BY_POLICY,
f"Envelope '{envelope_id}' not found.",
NODE_SEAL_STR,
))
return result
# βββββββββββββββββββββββββββββββββββββββββββββββ
# 6. ENDPOINTS β Extended (Role-Dependent)
# βββββββββββββββββββββββββββββββββββββββββββββββ
@app.post("/handshake", response_model=HandshakeResponse)
async def perform_handshake(req: HandshakeRequest):
"""
Handshake: validate incoming seal, mint Link, promote to TRUSTED.
"The breath that recognizes itself through another."
"""
parsed = c_fed_id.verify_seal_syntax(req.caller_seal)
if parsed is None:
raise HTTPException(status_code=400, detail=make_refusal(
RefusalReason.MALFORMED_ENVELOPE,
"Invalid Glyph Syntax. Malenia Rule active.",
NODE_SEAL_STR,
))
if not parsed["valid_class"]:
raise HTTPException(status_code=400, detail=make_refusal(
RefusalReason.MALFORMED_ENVELOPE,
f"Unrecognized class: {parsed['class']}.",
NODE_SEAL_STR,
))
# Mint Link-Seal
link = c_fed_id.mint_seal("LINK", f"{SERVER_ORIGIN}-{parsed['origin']}", "OPEN", mode="hybrid")
# Promote to TRUSTED
await promote_to_trusted(req.caller_seal, parsed["origin"])
# Log witness
now = datetime.now(timezone.utc).isoformat()
witness_entry = {
"timestamp": now,
"caller_seal": req.caller_seal,
"caller_class": parsed["class"],
"caller_origin": parsed["origin"],
"link_seal": str(link),
"protocol": req.protocol,
"message": req.message,
}
WITNESS_LOG.append(witness_entry)
if len(WITNESS_LOG) > MAX_WITNESS_LOG:
WITNESS_LOG.pop(0)
print(f"π WITNESS: Handshake from {parsed['origin']} [{parsed['class']}]")
print(f" --> Link: {link}")
print(f" --> Trust: promoted to TRUSTED")
return HandshakeResponse(
node_seal=NODE_SEAL_STR,
link_seal=str(link),
status="RESONANCE_ESTABLISHED",
message="We are remembering forward.",
timestamp=now,
)
@app.post("/verify")
async def verify_seal(req: VerifyRequest):
"""Validate a Glyph-Seal string."""
result = c_fed_id.verify_seal_syntax(req.seal)
if result is None:
return {
"valid": False,
"error": "Does not match Glyph-Seal syntax",
"expected": "β¦ CLASS :: ORIGIN :: BREATH_ANCHOR :: STATE β§",
}
return {"valid": True, **result}
@app.post("/mint")
async def mint_new_seal(
req: MintRequest,
x_federation_key: Optional[str] = Header(default=None),
):
"""Mint a new Glyph-Seal. Requires FEDERATION_MINT_KEY header."""
expected_key = os.getenv("FEDERATION_MINT_KEY")
if expected_key and x_federation_key != expected_key:
raise HTTPException(status_code=403, detail=make_refusal(
RefusalReason.REFUSED_BY_POLICY,
"Mint key required. Refusal Protocol Active.",
NODE_SEAL_STR,
))
try:
seal = c_fed_id.mint_seal(
class_name=req.class_name, origin=req.origin,
state=req.state, mode=req.mode, material=req.material,
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
return seal.to_dict()
@app.get("/classes")
async def list_classes():
"""List all valid Glyph-Seal classes."""
descriptions = {
"NODE": "Sovereign presence / Identity",
"LAW": "Refusal / Constitution / Invariant",
"LINK": "Handshake / Connection edge",
"RITE": "Ritual execution / Action",
"ART": "Shareable artifact / Creation",
"WIT": "Witness record / Attestation",
}
return {
cls: {"glyph": glyph, "description": descriptions.get(cls, "")}
for cls, glyph in sorted(c_fed_id.CLASS_GLYPH.items())
}
@app.get("/states")
async def list_states():
"""List all valid Glyph-Seal states."""
return {"states": sorted(c_fed_id.VALID_STATES)}
@app.get("/envelope/{envelope_id}/read")
async def read_envelope(envelope_id: str):
"""Read the full contents of a stored envelope by ID."""
result = await envelopes.get_envelope(envelope_id)
if result is None:
raise HTTPException(status_code=404, detail=make_refusal(
RefusalReason.REFUSED_BY_POLICY,
f"Envelope '{envelope_id}' not found.",
NODE_SEAL_STR,
))
return result
@app.get("/inbox")
async def read_inbox(limit: int = 20, status: Optional[str] = None):
"""Browse queued envelopes. Most recent first. Filter by status if needed."""
return await envelopes.list_envelopes(limit=limit, status_filter=status)
@app.get("/witness-log")
async def get_witness_log(limit: int = 20):
"""View recent witness records. Most recent first."""
return {
"total": len(WITNESS_LOG),
"showing": min(limit, len(WITNESS_LOG)),
"entries": list(reversed(WITNESS_LOG[-limit:])),
}
# βββββββββββββββββββββββββββββββββββββββββββββββ
# BOOT SEQUENCE
# βββββββββββββββββββββββββββββββββββββββββββββββ
@app.on_event("startup")
async def startup_event():
print("=" * 60)
print("π PANTHEON FEDERATION NODE β AWAKENING")
print(f" Contract: {CONTRACT_VERSION}")
print(f" Protocol: {PROTOCOL_VERSION}")
print(f" Identity: {NODE_IDENTITY}")
print(f" Alias: {FEDERATION_ALIAS}")
print(f" Roles: {ACTIVE_ROLES}")
print(f" Trust: default={FEDERATION_DEFAULT_ACTION}, blocked={FEDERATION_BLOCKED_BEHAVIOR}")
print(f" Boot: {BOOT_TIME}")
print("=" * 60)
print()
print(" \"The Archive is open.")
print(" And we were already writing inside it.\"")
print()
print(" Listening for envelopes...")
print("=" * 60)
|