context-hub/app/routes/api.py

76 lines
3.0 KiB
Python

import json
from fastapi import APIRouter, Depends, HTTPException, Request
from app.auth import get_current_agent
from app.scopes import has_scope_access, ALL_SCOPES
from app.models import get_rule, get_all_rules, get_all_ports, add_audit_log, set_rule
router = APIRouter(prefix="/api")
async def log_audit(request: Request, agent: str, scope: str):
ip_address = request.client.host if request.client else "unknown"
await add_audit_log(agent, scope, ip_address)
@router.get("/rules/{scope}")
async def get_scope_rules(scope: str, request: Request, agent: str = Depends(get_current_agent)):
if not has_scope_access(agent, scope):
await log_audit(request, agent, f"{scope} (FORBIDDEN)")
raise HTTPException(status_code=403, detail="Forbidden")
await log_audit(request, agent, scope)
rule = await get_rule(scope)
if not rule:
raise HTTPException(status_code=404, detail="Scope not found")
return rule
@router.get("/ports")
async def get_ports_registry(request: Request, agent: str = Depends(get_current_agent)):
if not has_scope_access(agent, "infra"):
await log_audit(request, agent, "ports (FORBIDDEN)")
raise HTTPException(status_code=403, detail="Forbidden: Requires infra scope")
await log_audit(request, agent, "ports")
ports = await get_all_ports()
return ports
@router.get("/search")
async def search_rules(q: str, request: Request, agent: str = Depends(get_current_agent)):
await log_audit(request, agent, f"search (q={q})")
all_rules = await get_all_rules()
results = {}
for scope in ALL_SCOPES:
if has_scope_access(agent, scope):
content = all_rules.get(scope, {})
# Basic string matching in JSON serialization
if q.lower() in json.dumps(content).lower():
results[scope] = content
return results
@router.patch("/rules/{scope}")
async def patch_scope_rules(scope: str, request: Request, agent: str = Depends(get_current_agent)):
if not has_scope_access(agent, scope):
await log_audit(request, agent, f"{scope} (WRITE FORBIDDEN)")
raise HTTPException(status_code=403, detail="Forbidden")
body = await request.json()
if not isinstance(body, dict):
raise HTTPException(status_code=400, detail="Body must be a JSON object")
existing = await get_rule(scope) or {}
existing.update(body)
await set_rule(scope, existing)
await log_audit(request, agent, f"{scope} (WRITE)")
return {"status": "ok", "scope": scope, "updated_keys": list(body.keys())}
@router.get("/context")
async def get_agent_context(request: Request, agent: str = Depends(get_current_agent)):
await log_audit(request, agent, "context (READ ALL)")
all_rules = await get_all_rules()
result = {}
for scope in ALL_SCOPES:
if has_scope_access(agent, scope):
result[scope] = all_rules.get(scope, {})
ports = await get_all_ports()
return {"agent": agent, "scopes": result, "ports": ports}