Repository navigation
Expand file tree
/
Copy pathexecution_protocol.py
More file actions
67 lines (48 loc) · 2.36 KB
/
Copy pathexecution_protocol.py
File metadata and controls
67 lines (48 loc) · 2.36 KB
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
"""Cross-service control wire contract (no Agent or Graph runtime imports)."""
from __future__ import annotations
import hmac
import os
from contextvars import ContextVar
from uuid import UUID
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from fastapi import Request
from pydantic import BaseModel, model_validator
execution_headers: ContextVar[dict[str, str]] = ContextVar("igraph_execution_headers", default={})
def validate_service_configuration() -> None:
"""Fail before serving traffic when internal service authentication is unusable.
The credential is required independently of the optional run-cancellation
feature. Never include its value in errors or silently normalize it.
"""
secret = os.getenv("IGRAPH_CONTROL_SERVICE_KEY", "")
if not secret or not secret.isascii() or any(not 33 <= ord(char) <= 126 for char in secret):
raise RuntimeError(
"IGRAPH_CONTROL_SERVICE_KEY is required and must contain printable ASCII "
"characters without whitespace. Configure the same random secret for "
"Backend, Agent Runtime, Graph Engine API and MCP, even when "
"IGRAPH_RUN_CANCEL_ENABLED=false."
)
def controls_enabled() -> bool:
return os.getenv("IGRAPH_RUN_CANCEL_ENABLED", "false").lower() in {"true", "1", "yes"} and bool(os.getenv("IGRAPH_CONTROL_SERVICE_KEY", ""))
def service_headers(user_id: str) -> dict[str, str]:
return {"X-User-ID": user_id, "X-iGraph-Service-Key": os.getenv("IGRAPH_CONTROL_SERVICE_KEY", "")}
def require_service(request: Request):
from fastapi import HTTPException
secret = os.getenv("IGRAPH_CONTROL_SERVICE_KEY", "")
if not secret or not hmac.compare_digest(request.headers.get("X-iGraph-Service-Key", ""), secret):
raise HTTPException(403, {"code": "CONTROL_SERVICE_FORBIDDEN"})
class Target(BaseModel):
run_id: UUID | None = None
start_request_id: UUID | None = None
@model_validator(mode="after")
def one_target(self):
if (self.run_id is None) == (self.start_request_id is None):
raise ValueError("exactly one run_id or start_request_id is required")
return self
def lookup(self):
return self.model_dump(mode="json", exclude_none=True)
class CancelRequest(BaseModel):
cancel_request_id: UUID
target: Target
class JobCancelRequest(BaseModel):
cancel_request_id: UUID