feat: complete phase 3 -- OpenAPI auto-discovery, SSRF protection, tool generation
- SSRF protection: private IP blocking, DNS rebinding defense, redirect validation - OpenAPI fetcher with SSRF guard, JSON/YAML auto-detection, 10MB limit - Structural spec validator (3.0.x/3.1.x) - Endpoint parser with $ref resolution, auto-generated operation IDs - Heuristic + LLM endpoint classifier with Protocol interface - Review API at /api/openapi (import, job status, classification CRUD, approve) - @tool code generator + Agent YAML generator - Import orchestrator (fetch -> validate -> parse -> classify pipeline) - 125 new tests, 322 total passing, 93.23% coverage
This commit is contained in:
67
backend/app/openapi/models.py
Normal file
67
backend/app/openapi/models.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""Data models for OpenAPI auto-discovery module.
|
||||
|
||||
Frozen dataclasses for all value objects to ensure immutability.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParameterInfo:
|
||||
"""Describes a single endpoint parameter."""
|
||||
|
||||
name: str
|
||||
location: str # "path", "query", "header", "cookie"
|
||||
required: bool
|
||||
schema_type: str # "string", "integer", "boolean", etc.
|
||||
description: str = ""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EndpointInfo:
|
||||
"""Describes a single API endpoint."""
|
||||
|
||||
path: str
|
||||
method: str # uppercase: GET, POST, PUT, DELETE, PATCH
|
||||
operation_id: str
|
||||
summary: str
|
||||
description: str
|
||||
parameters: tuple[ParameterInfo, ...] = field(default_factory=tuple)
|
||||
request_body_schema: dict | None = None
|
||||
response_schema: dict | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ClassificationResult:
|
||||
"""Result of classifying an endpoint for agent routing."""
|
||||
|
||||
endpoint: EndpointInfo
|
||||
access_type: str # "read" or "write"
|
||||
customer_params: tuple[str, ...] # param names that identify the customer
|
||||
agent_group: str # which agent group handles this endpoint
|
||||
confidence: float # 0.0 to 1.0
|
||||
needs_interrupt: bool # requires human approval before execution
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ImportJob:
|
||||
"""Tracks the state of an OpenAPI import job."""
|
||||
|
||||
job_id: str
|
||||
status: str # "pending", "fetching", "validating", "parsing", "classifying", "done", "failed"
|
||||
spec_url: str
|
||||
total_endpoints: int = 0
|
||||
classified_count: int = 0
|
||||
error_message: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GeneratedTool:
|
||||
"""A generated LangChain tool from a classified endpoint."""
|
||||
|
||||
function_name: str
|
||||
endpoint: EndpointInfo
|
||||
classification: ClassificationResult
|
||||
code: str
|
||||
Reference in New Issue
Block a user