OSVauco/agents/tools/a2h2a_client.py
Chris Christiansen 004267689c
Some checks are pending
Check Python Version Consistency / Check Python Version (push) Waiting to run
feat(a2h2a): auth, CSRF, logging fixes + test updates
2026-09-04 20:38:37 +00:00

146 lines
4.6 KiB
Python

"""
A2H2A Client - Bibliotek for å poste A2H2A tickets fra agenter
Med støtte for alle MCP tools
"""
import httpx
import os
from datetime import datetime
from typing import Dict, List, Optional
OPAX_BASE_URL = os.getenv('OPAX_BASE_URL', 'https://opax.vauco.no')
MCP_SECRET = os.getenv('MCP_SECRET')
# MCP Tool Registry - alle tools som krever A2H2A
A2H2A_TOOLS = {
"opax.secrets.rotate": {
"severity": "CRITICAL",
"timeout_minutes": 15,
"description": "Roter hemmelighet i Secret Manager"
},
"opax.traffic.shift": {
"severity": "CRITICAL",
"timeout_minutes": 15,
"description": "Skift trafikk mellom Cloud Run revisjoner"
},
"tyr.kms.attest": {
"severity": "HIGH",
"timeout_minutes": 60,
"description": "Signer container digest med KMS for Binary Authorization"
},
"tyr.perimeter.update": {
"severity": "CRITICAL",
"timeout_minutes": 30,
"description": "Juster VPC-SC perimeter policyer"
},
"osvauco.git.filter": {
"severity": "CRITICAL",
"timeout_minutes": 30,
"description": "Fjern sensitiv historikk fra Git"
},
"osvauco.firewall.block": {
"severity": "HIGH",
"timeout_minutes": 15,
"description": "Blokker IP via Cloud Armor / VPC brannmur"
}
}
class A2H2AClient:
def __init__(self):
self.base_url = OPAX_BASE_URL
self.headers = {
'X-MCP-Secret': MCP_SECRET,
'Content-Type': 'application/json'
}
def get_tool_config(self, tool_name: str) -> Optional[Dict]:
"""Hent konfigurasjon for et tool"""
return A2H2A_TOOLS.get(tool_name)
async def create_ticket_for_tool(
self,
tool_name: str,
tool_parameters: Dict,
reporter: str,
trigger: str,
affected_service: str,
summary: str,
evidence_logs: List[str],
rollback_plan: str,
project_id: str = "propane-will-491900-m5",
region: str = "us-central1",
category: str = "AUTOMATED_REMEDIATION",
authorized_approver: str = "chris.christiansen@vauco.no"
) -> Dict:
"""
Opprett A2H2A ticket basert på tool-konfigurasjon.
Automatisk henter severity og timeout fra A2H2A_TOOLS registry.
"""
tool_config = self.get_tool_config(tool_name)
if not tool_config:
raise ValueError(f"Tool '{tool_name}' er ikke registrert i A2H2A_TOOLS")
ticket = {
"ticket_id": f"A2H2A-{datetime.utcnow().strftime('%Y%m%d-%H%M%S')}",
"timestamp": datetime.utcnow(),
"severity": tool_config["severity"],
"category": category,
"source": {
"reporter": reporter,
"trigger": trigger,
"affected_service": affected_service,
"project_id": project_id,
"region": region
},
"context": {
"summary": summary,
"evidence_logs": evidence_logs
},
"proposed_action": {
"action_type": "AUTOMATED_REMEDIATION",
"runbook_reference": f"docs/RUNBOOK.md#scenario-{category.lower()}",
"execution_tool": tool_name,
"parameters": tool_parameters,
"rollback_plan": rollback_plan
},
"governance": {
"approval_status": "PENDING",
"authorized_approver": authorized_approver,
"requires_mfa": True,
"timeout_minutes": tool_config["timeout_minutes"]
}
}
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.base_url}/api/v1/a2h2a/tickets",
json=ticket,
headers=self.headers
)
return response.json()
async def register_new_tool(
self,
tool_name: str,
severity: str,
timeout_minutes: int,
description: str
):
"""
Registrer et nytt tool i A2H2A_TOOLS (for fremtidige tools).
Dette kan kalles dynamisk når nye tools legges til i server.py
"""
A2H2A_TOOLS[tool_name] = {
"severity": severity,
"timeout_minutes": timeout_minutes,
"description": description
}
# Convenience function
async def post_a2h2a_ticket_for_tool(tool_name: str, **kwargs):
client = A2H2AClient()
return await client.create_ticket_for_tool(tool_name, **kwargs)