Some checks are pending
Check Python Version Consistency / Check Python Version (push) Waiting to run
146 lines
4.6 KiB
Python
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)
|